用以标注图像的一个基本框架demo
python">import sys
from PySide6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QMainWindow, QLabel, QGraphicsPixmapItem
from PySide6.QtGui import QPixmap, QPainter, QTransform
from PySide6.QtCore import Qt, QPointF, Slot, Signalclass ImageViewer(QGraphicsView):mouse_pos = Signal(int, int) # 原图像素坐标信号def __init__(self, image_path, parent=None):super(ImageViewer, self).__init__(parent)# 场景的初始化def init_scene():# 设置场景self.scene = QGraphicsScene(self)self.setScene(self.scene)# 设置渲染提示self.setRenderHint(QPainter.Antialiasing) # 开启抗锯齿self.setRenderHint(QPainter.SmoothPixmapTransform) # 开启平滑缩放# 设置缩放锚点self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) # 转换时以鼠标为中心self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) # 缩放时以鼠标为中心# 创建基础的显示内容pixmap = QPixmap(image_path)self.pixmap_item = QGraphicsPixmapItem(pixmap)self.scene.addItem(self.pixmap_item)# 标记点的数量self.mark_count = 0# 遮罩的数量self.mask_count = 0init_scene()self.mouse_pos.connect(self.update_mouse_position)def add_mark(self, pixmap, pos=(0, 0), scale=1.0):"""添加标记到场景:param pixmap: 图像数据:param pos: 坐标:param scale: 缩放比例:return: None"""# 加载图像pixmap_item = QGraphicsPixmapItem(pixmap) # 创建图形项mark_x = pos[0] - pixmap.width() / 2 * scalemark_y = pos[1] - pixmap.height() / 2 * scalepixmap_item.setPos(mark_x, mark_y) # 设置位置if scale != 1.0: # 设置比例pixmap_item.setScale(scale)self.scene.addItem(pixmap_item)self.mark_count += 1def add_mask(self):"""添加遮罩:return:"""passdef remove_mark(self):"""删除一个标记:return: None"""if self.mark_count > 0:self.scene.removeItem(self.scene.items()[0])self.mark_count -= 1def remove_mask(self):"""删除一个遮罩:return: None"""if self.mask_count > 0:self.scene.removeItem(self.scene.items()[0])self.mask_count -= 1def remove_all_marks(self):"""删除所有标记:return:"""while self.mark_count > 0:self.scene.removeItem(self.scene.items()[0])self.mark_count -= 1# # 使用变换矩阵(如果需要)def transform(self, t):# self.transform = t# self.pixmap_item.setTransform(self.transform)pass# 处理滚轮事件以实现缩放def wheelEvent(self, event):factor = 1.001 ** event.angleDelta().y() # 滚轮每滚动一格,缩放比例变化self.scale(factor, factor)# 处理鼠标单击事件以显示原图像素坐标def mousePressEvent(self, event):super(ImageViewer, self).mousePressEvent(event)scene_pos = self.mapToScene(event.position().toPoint()) # 记录当前鼠标在场景中的位置pixmap_rect = self.pixmap_item.boundingRect() # 记录图像的边界矩形# 如果鼠标在图像边界矩形内,则显示像素坐标if pixmap_rect.contains(scene_pos):pos = self.pixmap_item.mapFromScene(scene_pos) # 计算图像坐标x, y = pos.x(), pos.y()print(f"鼠标在图像内,坐标为: ({x}, {y})")if event.button() == Qt.LeftButton: # 左键if event.modifiers() == Qt.ShiftModifier: # Shift 键self.remove_mark() # 删除标记else:self.add_mark(pixmap_mark, (x, y), 0.6) # 添加标记elif event.button() == Qt.RightButton: # 右键if event.modifiers() == Qt.ShiftModifier: # Shift 键self.remove_all_marks() # 删除所有标记else:self.add_mark(pixmap_unmark, (x, y), 0.6) # 添加标记@Slot()def update_mouse_position(self, x, y):pass# 更新状态栏显示# self.status_bar.showMessage(f"原图像素坐标: ({x}, {y})")class MainWindow(QMainWindow):def __init__(self, image_path):super(MainWindow, self).__init__()self.setGeometry(100, 100, 800, 600)# 创建状态栏self.status_bar = self.statusBar()# 创建 ImageViewer 实例self.image_viewer = ImageViewer(image_path, self)self.setCentralWidget(self.image_viewer)if __name__ == "__main__":app = QApplication(sys.argv)# 生成标记图像pixmap_mark = QPixmap("mark.png") # 标记图像(前景)pixmap_unmark = QPixmap("un_mark.png") # 未标记图像(背景)image_path = "IMG_PP.jpg" # 基础图像路径# 创建主窗口window = MainWindow(image_path)window.show()sys.exit(app.exec())
截图: