Ошибка при расчете координаты Bbox при загрузке фонового изображенияPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Ошибка при расчете координаты Bbox при загрузке фонового изображения

Сообщение Anonymous »

Я написал сценарий, который позволяет загрузить изображение, нарисовать 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
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»