Anonymous
Ошибка при расчете координаты Bbox при загрузке фонового изображения
Сообщение
Anonymous » 02 апр 2025, 14:22
Я написал сценарий, который позволяет загрузить изображение, нарисовать Bbox на изображении и сохранить его на другое изображение вместе с его нормализованными координатами. Однако после этой проверки я вижу, что Bbox смещается вверх (что означает, что координата y неверна).
Я попытался сделать минимальный воспроизводимый пример, но выясняется, что когда я это делал, координаты рассчитываются правильно.
Я пытался определить, что вызывает ошибку. Поэтому я хотел бы получить помощь < /p>
Неправильный скрипт (немного длиной) < /p>
Код: Выделить всё
import sys
import os
import yaml
from PyQt6.QtWidgets import (
QApplication,
QGraphicsView,
QGraphicsScene,
QGraphicsPixmapItem,
QGraphicsItem,
QPushButton,
QFileDialog,
QVBoxLayout,
QWidget,
QLabel,
QHBoxLayout,
QGraphicsRectItem,
QCheckBox,
)
from PyQt6.QtGui import QPixmap, QTransform, QPen, QCursor, QPainter
from PyQt6.QtCore import Qt, QEvent, QRectF, QPointF
def load_config(filename="config.yaml"):
with open(filename, "r") as file:
return yaml.safe_load(file)
class StickerItem(QGraphicsPixmapItem):
def __init__(self, pixmap, parent_app):
super().__init__(pixmap)
self.setFlags(
QGraphicsItem.GraphicsItemFlag.ItemIsMovable
| QGraphicsItem.GraphicsItemFlag.ItemIsSelectable
| QGraphicsItem.GraphicsItemFlag.ItemIsFocusable
)
self.setTransformationMode(Qt.TransformationMode.SmoothTransformation)
self.parent_app = parent_app
self.setTransformOriginPoint(self.boundingRect().center())
def mousePressEvent(self, event):
self.parent_app.update_sticker_preview(self.pixmap())
super().mousePressEvent(event)
def keyPressEvent(self, event):
if event.key() == Qt.Key.Key_R:
self.setRotation(self.rotation() + 10)
elif event.key() == Qt.Key.Key_T:
self.setRotation(self.rotation() - 10)
elif event.key() == Qt.Key.Key_Plus:
self.setScale(self.scale() * 1.1)
elif event.key() == Qt.Key.Key_Minus:
self.setScale(self.scale() * 0.9)
elif event.key() == Qt.Key.Key_Delete:
self.scene().removeItem(self)
else:
super().keyPressEvent(event)
class RectangleItem(QGraphicsRectItem):
def __init__(self, rect, parent_app):
super().__init__(rect)
self.setPen(QPen(Qt.GlobalColor.green, 1, Qt.PenStyle.DashLine))
self.setFlags(
QGraphicsItem.GraphicsItemFlag.ItemIsMovable
| QGraphicsItem.GraphicsItemFlag.ItemIsSelectable
| QGraphicsItem.GraphicsItemFlag.ItemIsFocusable
)
self.parent_app = parent_app
self.update_transform_origin()
def setRect(self, rect):
super().setRect(rect)
self.update_transform_origin()
def update_transform_origin(self):
self.setTransformOriginPoint(self.boundingRect().center())
def keyPressEvent(self, event):
if event.key() == Qt.Key.Key_R:
self.setRotation(self.rotation() + 10)
elif event.key() == Qt.Key.Key_T:
self.setRotation(self.rotation() - 10)
elif event.key() == Qt.Key.Key_Plus:
self.setScale(self.scale() * 1.1)
elif event.key() == Qt.Key.Key_Minus:
self.setScale(self.scale() * 0.9)
elif event.key() == Qt.Key.Key_Delete:
self.scene().removeItem(self)
else:
super().keyPressEvent(event)
class StickerApp(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Sticker Editor")
self.resize(800, 600)
self.view = QGraphicsView()
self.scene = QGraphicsScene()
self.view.setScene(self.scene)
self.load_image_button = QPushButton("Load Background Image")
self.load_image_button.clicked.connect(self.load_background_image)
self.add_sticker_button = QPushButton("Add Sticker")
self.add_sticker_button.clicked.connect(self.add_sticker)
self.save_bboxes_checkbox = QCheckBox("Save Bounding Boxes")
self.save_bboxes_checkbox.setChecked(False)
self.save_button = QPushButton("Save Image")
self.save_button.clicked.connect(self.save_image)
self.sticker_preview_label = QLabel("Sticker Preview")
self.sticker_preview_label.setFixedSize(100, 100)
self.sticker_preview_label.setStyleSheet("border: 1px solid black;")
dir_data = load_config()
print(dir_data)
self.input_folder = dir_data["folders"]["images"]
self.sticker_folder = dir_data["folders"]["stickers"]
self.output_folder = dir_data["folders"]["output"]
self.loaded_image_path = ""
self.current_mode = "select" # 'select' or 'draw'
self.drawing = False
self.start_pos = None
self.current_rect = None
button_layout = QVBoxLayout()
button_layout.addWidget(self.load_image_button)
button_layout.addWidget(self.add_sticker_button)
button_layout.addWidget(self.save_bboxes_checkbox)
button_layout.addWidget(self.save_button)
button_layout.addWidget(self.sticker_preview_label)
main_layout = QHBoxLayout()
main_layout.addWidget(self.view)
main_layout.addLayout(button_layout)
self.setLayout(main_layout)
self.bg_pixmap_item = None
# Install event filter for viewport
self.view.viewport().installEventFilter(self)
def eventFilter(self, obj, event):
if obj is self.view.viewport() and self.current_mode == "draw":
if event.type() == QEvent.Type.MouseButtonPress:
if event.button() == Qt.MouseButton.LeftButton:
self.start_pos = self.view.mapToScene(event.pos())
self.drawing = True
self.current_rect = RectangleItem(QRectF(), self)
self.current_rect.setPen(
QPen(Qt.GlobalColor.green, 1, Qt.PenStyle.DashLine)
)
self.scene.addItem(self.current_rect)
return True
elif event.type() == QEvent.Type.MouseMove and self.drawing:
end_pos = self.view.mapToScene(event.pos())
self.current_rect.setRect(QRectF(self.start_pos, end_pos).normalized())
return True
elif event.type() == QEvent.Type.MouseButtonRelease and self.drawing:
self.drawing = False
self.current_rect = None
return True
return super().eventFilter(obj, event)
def keyPressEvent(self, event):
if event.key() == Qt.Key.Key_B:
self.current_mode = "draw" if self.current_mode == "select" else "select"
self.view.viewport().setCursor(
Qt.CursorShape.CrossCursor
if self.current_mode == "draw"
else Qt.CursorShape.ArrowCursor
)
elif event.key() == Qt.Key.Key_Delete:
# Delete all selected items
for item in self.scene.selectedItems():
self.scene.removeItem(item)
else:
super().keyPressEvent(event)
def load_background_image(self):
file_path, _ = QFileDialog.getOpenFileName(
self, "Open Image", self.input_folder, "Images (*.png *.jpg *.jpeg)"
)
if file_path:
self.input_folder = os.path.dirname(file_path)
self.loaded_image_path = file_path
pixmap = QPixmap(file_path)
if self.bg_pixmap_item:
self.scene.removeItem(self.bg_pixmap_item)
self.bg_pixmap_item = self.scene.addPixmap(pixmap)
self.bg_pixmap_item.setZValue(-1) # Send background to bottom
self.view.setSceneRect(pixmap.rect().translated(0, 0).toRectF())
self.resize(pixmap.width() + 200, pixmap.height() + 100)
# self.resize(pixmap.width(), pixmap.height())
def add_sticker(self):
file_path, _ = QFileDialog.getOpenFileName(
self, "Open Sticker", self.sticker_folder, "Images (*.png *.jpg *.jpeg)"
)
if file_path:
self.sticker_folder = os.path.dirname(file_path)
pixmap = QPixmap(file_path).scaled(
100,
100,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation,
)
sticker = StickerItem(pixmap, self)
self.scene.addItem(sticker)
# Center the sticker initially
sticker.setPos(self.view.width() / 2 - 50, self.view.height() / 2 - 50)
self.update_sticker_preview(pixmap)
def update_sticker_preview(self, pixmap):
self.sticker_preview_label.setPixmap(pixmap)
def save_image(self):
if not self.loaded_image_path:
return
default_name = os.path.basename(self.loaded_image_path)
file_path, _ = QFileDialog.getSaveFileName(
self,
"Save Image",
os.path.join(self.output_folder, default_name),
"PNG Files (*.png);;JPEG Files (*.jpg)",
)
if file_path:
self.output_folder = os.path.dirname(file_path)
# Get image dimensions
image = self.view.grab()
image_width, image_height = image.width(), image.height()
txt_file_path = os.path.splitext(file_path)[0] + ".txt"
bbox_data = []
if self.save_bboxes_checkbox.isChecked():
# Save without bounding boxes
image = self.view.grab()
image.save(file_path)
else:
# Hide bounding boxes before capturing
hidden_bboxes = []
for item in self.scene.items():
if isinstance(item, RectangleItem):
item.setVisible(False) # Temporarily hide bounding boxes
hidden_bboxes.append(item)
# Capture the scene with only stickers + background
image = self.view.grab()
image.save(file_path)
# Restore visibility of bounding boxes
for item in hidden_bboxes:
item.setVisible(True)
# Ensure UI Refreshes Properly**
self.view.viewport().update()
self.scene.update()
# Extract bounding box data
for item in self.scene.items():
if isinstance(item, RectangleItem):
rect = item.rect()
x_center = (rect.x() + rect.width() / 2) / image_width
y_center = (rect.y() + rect.height() / 2) / image_height
norm_width = rect.width() / image_width
norm_height = rect.height() / image_height
bbox_data.append(
f"0 {x_center:.6f} {y_center:.6f} {norm_width:.6f} {norm_height:.6f}"
)
transformed_rect = item.mapToScene(item.rect()).boundingRect()
x_center = (transformed_rect.x() + transformed_rect.width() / 2) / image_width
y_center = (transformed_rect.y() + transformed_rect.height() / 2) / image_height
norm_width = transformed_rect.width() / image_width
norm_height = transformed_rect.height() / image_height
bbox_data.append(
f"1 {x_center:.6f} {y_center:.6f} {norm_width:.6f} {norm_height:.6f}"
)
# Save bounding box data to a text file
with open(txt_file_path, "w") as f:
f.write("\n".join(bbox_data))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = StickerApp()
window.show()
sys.exit(app.exec())
< /code>
Один работает, это < /p>
import sys
from PyQt6.QtWidgets import (
QApplication,
QGraphicsView,
QGraphicsScene,
QGraphicsRectItem,
QPushButton,
QVBoxLayout,
QWidget,
QHBoxLayout,
QCheckBox,
QFileDialog,
)
from PyQt6.QtGui import QPen, QPixmap, QPainter, QColor
from PyQt6.QtCore import Qt, QEvent, QRectF, QPointF
class RectangleItem(QGraphicsRectItem):
def __init__(self, rect, parent=None):
super().__init__(rect, parent)
self.setPen(QPen(Qt.GlobalColor.green, 1, Qt.PenStyle.DashLine))
self.setFlags(
QGraphicsRectItem.GraphicsItemFlag.ItemIsMovable
| QGraphicsRectItem.GraphicsItemFlag.ItemIsSelectable
| QGraphicsRectItem.GraphicsItemFlag.ItemIsFocusable
)
class StickerApp(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Bounding Box Debugger")
self.resize(800, 600)
self.view = QGraphicsView()
self.scene = QGraphicsScene()
self.view.setScene(self.scene)
self.view.viewport().installEventFilter(self)
self.save_bboxes_checkbox = QCheckBox("Save Bounding Boxes")
self.save_bboxes_checkbox.setChecked(False)
self.save_button = QPushButton("Save Image")
self.save_button.clicked.connect(self.save_image)
button_layout = QVBoxLayout()
button_layout.addWidget(self.save_bboxes_checkbox)
button_layout.addWidget(self.save_button)
main_layout = QHBoxLayout()
main_layout.addWidget(self.view)
main_layout.addLayout(button_layout)
self.setLayout(main_layout)
self.current_mode = "select" # 'select' or 'draw'
self.drawing = False
self.start_pos = None
self.current_rect = None
self.draw_triangle()
def draw_triangle(self):
pixmap = QPixmap(800, 600)
pixmap.fill(Qt.GlobalColor.white)
painter = QPainter(pixmap)
painter.setBrush(QColor(255, 0, 0)) # Red triangle
painter.drawPolygon(
[
QPointF(200, 100), # Top vertex
QPointF(100, 300), # Bottom left
QPointF(300, 300), # Bottom right
]
)
painter.end()
self.bg_pixmap_item = self.scene.addPixmap(pixmap)
self.bg_pixmap_item.setZValue(-1) # Keep background at bottom
def eventFilter(self, obj, event):
if obj is self.view.viewport() and self.current_mode == "draw":
if (
event.type() == QEvent.Type.MouseButtonPress
and event.button() == Qt.MouseButton.LeftButton
):
self.start_pos = self.view.mapToScene(event.pos())
self.drawing = True
self.current_rect = RectangleItem(
QRectF(self.start_pos, self.start_pos)
)
self.scene.addItem(self.current_rect)
return True
elif event.type() == QEvent.Type.MouseMove and self.drawing:
end_pos = self.view.mapToScene(event.pos())
self.current_rect.setRect(QRectF(self.start_pos, end_pos).normalized())
return True
elif event.type() == QEvent.Type.MouseButtonRelease and self.drawing:
self.drawing = False
return True
return super().eventFilter(obj, event)
def keyPressEvent(self, event):
if event.key() == Qt.Key.Key_B:
self.current_mode = "draw" if self.current_mode == "select" else "select"
self.view.viewport().setCursor(
Qt.CursorShape.CrossCursor
if self.current_mode == "draw"
else Qt.CursorShape.ArrowCursor
)
elif event.key() == Qt.Key.Key_Delete:
for item in self.scene.selectedItems():
self.scene.removeItem(item)
else:
super().keyPressEvent(event)
def save_image(self):
file_path, _ = QFileDialog.getSaveFileName(
self, "Save Image", "output.png", "PNG Files (*.png)"
)
if file_path:
image = self.view.grab()
image_width, image_height = image.width(), image.height()
print(f"Image w h {image_width} {image_height}")
image.save(file_path)
if self.save_bboxes_checkbox.isChecked():
bbox_data = []
scene_rect = self.scene.sceneRect()
scene_width, scene_height = scene_rect.width(), scene_rect.height()
print(f"Scene w h {scene_width} {scene_height}")
for item in self.scene.items():
if isinstance(item, RectangleItem):
rect = item.rect()
# norm_x = rect.x() / scene_width
# norm_y = rect.y() / scene_height
norm_x = (rect.x() + rect.width() / 2) / scene_width
norm_y = (rect.y() + rect.height() / 2) / scene_height
norm_w = rect.width() / scene_width
norm_h = rect.height() / scene_height
# This is WRONG
bbox_data.append(
f"0 {norm_x:.6f} {norm_y:.6f} {norm_w:.6f} {norm_h:.6f}"
)
x_center = (rect.x() + rect.width() / 2) / image_width
y_center = (rect.y() + rect.height() / 2) / image_height
norm_width = rect.width() / image_width
norm_height = rect.height() / image_height
# This is WORKING
bbox_data.append(
f"1 {x_center:.6f} {y_center:.6f} {norm_width:.6f} {norm_height:.6f}"
)
with open(file_path.replace(".png", ".txt"), "w") as f:
f.write("\n".join(bbox_data))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = StickerApp()
window.show()
sys.exit(app.exec())
< /code>
способ рисовать Bbox - это сначала нажать B, а затем перетащить Bbox. После нажатия B снова мы можем удалить его, если хотим.folders:
images : "./data/images"
stickers : "./data/stickers"
output: "./data/output"
в первом скрипте, когда я менял self.resize (pixmap.width () + 200, pixmap.height () + 100) для self.resize (pixmap.width (), pixmap.height ()). сделать)
Может ли кто -нибудь указать, что такое ошибка?
Подробнее здесь:
https://stackoverflow.com/questions/795 ... ound-image
1743592938
Anonymous
Я написал сценарий, который позволяет загрузить изображение, нарисовать Bbox на изображении и сохранить его на другое изображение вместе с его нормализованными координатами. Однако после этой проверки я вижу, что Bbox смещается вверх (что означает, что координата y неверна). Я попытался сделать минимальный воспроизводимый пример, но выясняется, что когда я это делал, координаты рассчитываются правильно. Я пытался определить, что вызывает ошибку. Поэтому я хотел бы получить помощь < /p> Неправильный скрипт (немного длиной) < /p> [code]import sys import os import yaml from PyQt6.QtWidgets import ( QApplication, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QGraphicsItem, QPushButton, QFileDialog, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QGraphicsRectItem, QCheckBox, ) from PyQt6.QtGui import QPixmap, QTransform, QPen, QCursor, QPainter from PyQt6.QtCore import Qt, QEvent, QRectF, QPointF def load_config(filename="config.yaml"): with open(filename, "r") as file: return yaml.safe_load(file) class StickerItem(QGraphicsPixmapItem): def __init__(self, pixmap, parent_app): super().__init__(pixmap) self.setFlags( QGraphicsItem.GraphicsItemFlag.ItemIsMovable | QGraphicsItem.GraphicsItemFlag.ItemIsSelectable | QGraphicsItem.GraphicsItemFlag.ItemIsFocusable ) self.setTransformationMode(Qt.TransformationMode.SmoothTransformation) self.parent_app = parent_app self.setTransformOriginPoint(self.boundingRect().center()) def mousePressEvent(self, event): self.parent_app.update_sticker_preview(self.pixmap()) super().mousePressEvent(event) def keyPressEvent(self, event): if event.key() == Qt.Key.Key_R: self.setRotation(self.rotation() + 10) elif event.key() == Qt.Key.Key_T: self.setRotation(self.rotation() - 10) elif event.key() == Qt.Key.Key_Plus: self.setScale(self.scale() * 1.1) elif event.key() == Qt.Key.Key_Minus: self.setScale(self.scale() * 0.9) elif event.key() == Qt.Key.Key_Delete: self.scene().removeItem(self) else: super().keyPressEvent(event) class RectangleItem(QGraphicsRectItem): def __init__(self, rect, parent_app): super().__init__(rect) self.setPen(QPen(Qt.GlobalColor.green, 1, Qt.PenStyle.DashLine)) self.setFlags( QGraphicsItem.GraphicsItemFlag.ItemIsMovable | QGraphicsItem.GraphicsItemFlag.ItemIsSelectable | QGraphicsItem.GraphicsItemFlag.ItemIsFocusable ) self.parent_app = parent_app self.update_transform_origin() def setRect(self, rect): super().setRect(rect) self.update_transform_origin() def update_transform_origin(self): self.setTransformOriginPoint(self.boundingRect().center()) def keyPressEvent(self, event): if event.key() == Qt.Key.Key_R: self.setRotation(self.rotation() + 10) elif event.key() == Qt.Key.Key_T: self.setRotation(self.rotation() - 10) elif event.key() == Qt.Key.Key_Plus: self.setScale(self.scale() * 1.1) elif event.key() == Qt.Key.Key_Minus: self.setScale(self.scale() * 0.9) elif event.key() == Qt.Key.Key_Delete: self.scene().removeItem(self) else: super().keyPressEvent(event) class StickerApp(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Sticker Editor") self.resize(800, 600) self.view = QGraphicsView() self.scene = QGraphicsScene() self.view.setScene(self.scene) self.load_image_button = QPushButton("Load Background Image") self.load_image_button.clicked.connect(self.load_background_image) self.add_sticker_button = QPushButton("Add Sticker") self.add_sticker_button.clicked.connect(self.add_sticker) self.save_bboxes_checkbox = QCheckBox("Save Bounding Boxes") self.save_bboxes_checkbox.setChecked(False) self.save_button = QPushButton("Save Image") self.save_button.clicked.connect(self.save_image) self.sticker_preview_label = QLabel("Sticker Preview") self.sticker_preview_label.setFixedSize(100, 100) self.sticker_preview_label.setStyleSheet("border: 1px solid black;") dir_data = load_config() print(dir_data) self.input_folder = dir_data["folders"]["images"] self.sticker_folder = dir_data["folders"]["stickers"] self.output_folder = dir_data["folders"]["output"] self.loaded_image_path = "" self.current_mode = "select" # 'select' or 'draw' self.drawing = False self.start_pos = None self.current_rect = None button_layout = QVBoxLayout() button_layout.addWidget(self.load_image_button) button_layout.addWidget(self.add_sticker_button) button_layout.addWidget(self.save_bboxes_checkbox) button_layout.addWidget(self.save_button) button_layout.addWidget(self.sticker_preview_label) main_layout = QHBoxLayout() main_layout.addWidget(self.view) main_layout.addLayout(button_layout) self.setLayout(main_layout) self.bg_pixmap_item = None # Install event filter for viewport self.view.viewport().installEventFilter(self) def eventFilter(self, obj, event): if obj is self.view.viewport() and self.current_mode == "draw": if event.type() == QEvent.Type.MouseButtonPress: if event.button() == Qt.MouseButton.LeftButton: self.start_pos = self.view.mapToScene(event.pos()) self.drawing = True self.current_rect = RectangleItem(QRectF(), self) self.current_rect.setPen( QPen(Qt.GlobalColor.green, 1, Qt.PenStyle.DashLine) ) self.scene.addItem(self.current_rect) return True elif event.type() == QEvent.Type.MouseMove and self.drawing: end_pos = self.view.mapToScene(event.pos()) self.current_rect.setRect(QRectF(self.start_pos, end_pos).normalized()) return True elif event.type() == QEvent.Type.MouseButtonRelease and self.drawing: self.drawing = False self.current_rect = None return True return super().eventFilter(obj, event) def keyPressEvent(self, event): if event.key() == Qt.Key.Key_B: self.current_mode = "draw" if self.current_mode == "select" else "select" self.view.viewport().setCursor( Qt.CursorShape.CrossCursor if self.current_mode == "draw" else Qt.CursorShape.ArrowCursor ) elif event.key() == Qt.Key.Key_Delete: # Delete all selected items for item in self.scene.selectedItems(): self.scene.removeItem(item) else: super().keyPressEvent(event) def load_background_image(self): file_path, _ = QFileDialog.getOpenFileName( self, "Open Image", self.input_folder, "Images (*.png *.jpg *.jpeg)" ) if file_path: self.input_folder = os.path.dirname(file_path) self.loaded_image_path = file_path pixmap = QPixmap(file_path) if self.bg_pixmap_item: self.scene.removeItem(self.bg_pixmap_item) self.bg_pixmap_item = self.scene.addPixmap(pixmap) self.bg_pixmap_item.setZValue(-1) # Send background to bottom self.view.setSceneRect(pixmap.rect().translated(0, 0).toRectF()) self.resize(pixmap.width() + 200, pixmap.height() + 100) # self.resize(pixmap.width(), pixmap.height()) def add_sticker(self): file_path, _ = QFileDialog.getOpenFileName( self, "Open Sticker", self.sticker_folder, "Images (*.png *.jpg *.jpeg)" ) if file_path: self.sticker_folder = os.path.dirname(file_path) pixmap = QPixmap(file_path).scaled( 100, 100, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation, ) sticker = StickerItem(pixmap, self) self.scene.addItem(sticker) # Center the sticker initially sticker.setPos(self.view.width() / 2 - 50, self.view.height() / 2 - 50) self.update_sticker_preview(pixmap) def update_sticker_preview(self, pixmap): self.sticker_preview_label.setPixmap(pixmap) def save_image(self): if not self.loaded_image_path: return default_name = os.path.basename(self.loaded_image_path) file_path, _ = QFileDialog.getSaveFileName( self, "Save Image", os.path.join(self.output_folder, default_name), "PNG Files (*.png);;JPEG Files (*.jpg)", ) if file_path: self.output_folder = os.path.dirname(file_path) # Get image dimensions image = self.view.grab() image_width, image_height = image.width(), image.height() txt_file_path = os.path.splitext(file_path)[0] + ".txt" bbox_data = [] if self.save_bboxes_checkbox.isChecked(): # Save without bounding boxes image = self.view.grab() image.save(file_path) else: # Hide bounding boxes before capturing hidden_bboxes = [] for item in self.scene.items(): if isinstance(item, RectangleItem): item.setVisible(False) # Temporarily hide bounding boxes hidden_bboxes.append(item) # Capture the scene with only stickers + background image = self.view.grab() image.save(file_path) # Restore visibility of bounding boxes for item in hidden_bboxes: item.setVisible(True) # Ensure UI Refreshes Properly** self.view.viewport().update() self.scene.update() # Extract bounding box data for item in self.scene.items(): if isinstance(item, RectangleItem): rect = item.rect() x_center = (rect.x() + rect.width() / 2) / image_width y_center = (rect.y() + rect.height() / 2) / image_height norm_width = rect.width() / image_width norm_height = rect.height() / image_height bbox_data.append( f"0 {x_center:.6f} {y_center:.6f} {norm_width:.6f} {norm_height:.6f}" ) transformed_rect = item.mapToScene(item.rect()).boundingRect() x_center = (transformed_rect.x() + transformed_rect.width() / 2) / image_width y_center = (transformed_rect.y() + transformed_rect.height() / 2) / image_height norm_width = transformed_rect.width() / image_width norm_height = transformed_rect.height() / image_height bbox_data.append( f"1 {x_center:.6f} {y_center:.6f} {norm_width:.6f} {norm_height:.6f}" ) # Save bounding box data to a text file with open(txt_file_path, "w") as f: f.write("\n".join(bbox_data)) if __name__ == "__main__": app = QApplication(sys.argv) window = StickerApp() window.show() sys.exit(app.exec()) < /code> Один работает, это < /p> import sys from PyQt6.QtWidgets import ( QApplication, QGraphicsView, QGraphicsScene, QGraphicsRectItem, QPushButton, QVBoxLayout, QWidget, QHBoxLayout, QCheckBox, QFileDialog, ) from PyQt6.QtGui import QPen, QPixmap, QPainter, QColor from PyQt6.QtCore import Qt, QEvent, QRectF, QPointF class RectangleItem(QGraphicsRectItem): def __init__(self, rect, parent=None): super().__init__(rect, parent) self.setPen(QPen(Qt.GlobalColor.green, 1, Qt.PenStyle.DashLine)) self.setFlags( QGraphicsRectItem.GraphicsItemFlag.ItemIsMovable | QGraphicsRectItem.GraphicsItemFlag.ItemIsSelectable | QGraphicsRectItem.GraphicsItemFlag.ItemIsFocusable ) class StickerApp(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Bounding Box Debugger") self.resize(800, 600) self.view = QGraphicsView() self.scene = QGraphicsScene() self.view.setScene(self.scene) self.view.viewport().installEventFilter(self) self.save_bboxes_checkbox = QCheckBox("Save Bounding Boxes") self.save_bboxes_checkbox.setChecked(False) self.save_button = QPushButton("Save Image") self.save_button.clicked.connect(self.save_image) button_layout = QVBoxLayout() button_layout.addWidget(self.save_bboxes_checkbox) button_layout.addWidget(self.save_button) main_layout = QHBoxLayout() main_layout.addWidget(self.view) main_layout.addLayout(button_layout) self.setLayout(main_layout) self.current_mode = "select" # 'select' or 'draw' self.drawing = False self.start_pos = None self.current_rect = None self.draw_triangle() def draw_triangle(self): pixmap = QPixmap(800, 600) pixmap.fill(Qt.GlobalColor.white) painter = QPainter(pixmap) painter.setBrush(QColor(255, 0, 0)) # Red triangle painter.drawPolygon( [ QPointF(200, 100), # Top vertex QPointF(100, 300), # Bottom left QPointF(300, 300), # Bottom right ] ) painter.end() self.bg_pixmap_item = self.scene.addPixmap(pixmap) self.bg_pixmap_item.setZValue(-1) # Keep background at bottom def eventFilter(self, obj, event): if obj is self.view.viewport() and self.current_mode == "draw": if ( event.type() == QEvent.Type.MouseButtonPress and event.button() == Qt.MouseButton.LeftButton ): self.start_pos = self.view.mapToScene(event.pos()) self.drawing = True self.current_rect = RectangleItem( QRectF(self.start_pos, self.start_pos) ) self.scene.addItem(self.current_rect) return True elif event.type() == QEvent.Type.MouseMove and self.drawing: end_pos = self.view.mapToScene(event.pos()) self.current_rect.setRect(QRectF(self.start_pos, end_pos).normalized()) return True elif event.type() == QEvent.Type.MouseButtonRelease and self.drawing: self.drawing = False return True return super().eventFilter(obj, event) def keyPressEvent(self, event): if event.key() == Qt.Key.Key_B: self.current_mode = "draw" if self.current_mode == "select" else "select" self.view.viewport().setCursor( Qt.CursorShape.CrossCursor if self.current_mode == "draw" else Qt.CursorShape.ArrowCursor ) elif event.key() == Qt.Key.Key_Delete: for item in self.scene.selectedItems(): self.scene.removeItem(item) else: super().keyPressEvent(event) def save_image(self): file_path, _ = QFileDialog.getSaveFileName( self, "Save Image", "output.png", "PNG Files (*.png)" ) if file_path: image = self.view.grab() image_width, image_height = image.width(), image.height() print(f"Image w h {image_width} {image_height}") image.save(file_path) if self.save_bboxes_checkbox.isChecked(): bbox_data = [] scene_rect = self.scene.sceneRect() scene_width, scene_height = scene_rect.width(), scene_rect.height() print(f"Scene w h {scene_width} {scene_height}") for item in self.scene.items(): if isinstance(item, RectangleItem): rect = item.rect() # norm_x = rect.x() / scene_width # norm_y = rect.y() / scene_height norm_x = (rect.x() + rect.width() / 2) / scene_width norm_y = (rect.y() + rect.height() / 2) / scene_height norm_w = rect.width() / scene_width norm_h = rect.height() / scene_height # This is WRONG bbox_data.append( f"0 {norm_x:.6f} {norm_y:.6f} {norm_w:.6f} {norm_h:.6f}" ) x_center = (rect.x() + rect.width() / 2) / image_width y_center = (rect.y() + rect.height() / 2) / image_height norm_width = rect.width() / image_width norm_height = rect.height() / image_height # This is WORKING bbox_data.append( f"1 {x_center:.6f} {y_center:.6f} {norm_width:.6f} {norm_height:.6f}" ) with open(file_path.replace(".png", ".txt"), "w") as f: f.write("\n".join(bbox_data)) if __name__ == "__main__": app = QApplication(sys.argv) window = StickerApp() window.show() sys.exit(app.exec()) < /code> способ рисовать Bbox - это сначала нажать B, а затем перетащить Bbox. После нажатия B снова мы можем удалить его, если хотим.folders: images : "./data/images" stickers : "./data/stickers" output: "./data/output" [/code] в первом скрипте, когда я менял self.resize (pixmap.width () + 200, pixmap.height () + 100) для self.resize (pixmap.width (), pixmap.height ()). сделать) Может ли кто -нибудь указать, что такое ошибка? Подробнее здесь: [url]https://stackoverflow.com/questions/79550474/error-in-calculating-bbox-coordinate-y-when-uploading-a-background-image[/url]