【问题标题】:PyQT4 - painting on an image for region selectionPyQT4 - 在图像上绘画以进行区域选择
【发布时间】:2017-01-21 04:13:17
【问题描述】:

我想用PyQT4写一个图片标注工具:

  • 从指定文件夹中加载多张图片;对于每个图像:
    • 用户通过用鼠标绘制该对象的区域,从图像中选择对象(例如汽车)
    • 选择完成后,对象蒙版显示在原始图像上
    • 当所有对象选择完成后,程序将每个对象掩码(背景:0,前景:255)保存为单独的 png 图像
  • 用户应该能够放大/缩小图像

我已经用 wxWidgets 在 c++ 中编写了一个类似的程序(没有放大/缩小)。 我对 PyQT4 很陌生,并试图了解事情是如何工作的。 即使用户放大/缩小,最困难的部分似乎也是正确绘制和获取对象蒙版。

哪些 PyQT 类最适合解决这个问题? 如何正确获取对象掩码(可能是 numpy 数组)并保存它们?

非常感谢。


根据您的建议,我编写了一段代码,用于显示图像并用鼠标在图像上绘图(仍处于实验和学习阶段)。

我将图像存储在 QGraphicsPixmapItem 中,将其添加到场景中。 然后,我通过覆盖其绘制方法来绘制图像。 最后,我重写了鼠标事件以获取鼠标位置并在那里画一个圆圈。 但是当我移动鼠标时,旧的圆圈被删除并绘制了一个新的圆圈。 也就是说,圆圈没有画在图像本身上。 我想,我应该使用类似下面的东西,这样绘画就在图像上永久存在:

painter = QPainter()
painter.begin(pixmap)
# here do the drawing
painter.end() 

但是,问题是,paint 函数已经将画家作为参数;在绘画功能中重新创建一个新的不起作用(显然)..

代码如下:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class ImageDrawPanel(QGraphicsPixmapItem):
    def __init__(self, pixmap=None, parent=None, scene=None):
        super(ImageDrawPanel, self).__init__()
        self.x, self.y = -1, -1        
        self.radius = 10

        self.pen = QPen(Qt.SolidLine)
        self.pen.setColor(Qt.black)
        self.pen.setWidth(2)

        self.brush = QBrush(Qt.yellow)


    def paint(self, painter, option, widget=None):               
        painter.drawPixmap(0, 0, self.pixmap())                
        painter.setPen(self.pen)
        painter.setBrush(self.brush)        
        if self.x >= 0 and self.y >= 0:
            painter.drawEllipse(self.x-self.radius, self.y-self.radius, 2*self.radius, 2*self.radius)
            self.x, self.y = -1, -1

    def mousePressEvent (self, event):
        print 'mouse pressed'
        self.x=event.pos().x()
        self.y=event.pos().y()            
        self.update()

    def mouseMoveEvent (self, event):
        print 'mouse moving'
        self.x=event.pos().x()
        self.y=event.pos().y()            
        self.update()        

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 800, 600)

        pixmap=self.openImage()        
        self.imagePanel = ImageDrawPanel(scene = self.scene)
        self.imagePanel.setPixmap(pixmap)
        self.scene.addItem(self.imagePanel)

        self.view = QGraphicsView(self.scene)

        layout = QHBoxLayout()        
        layout.addWidget(self.view)

        self.widget = QWidget()
        self.widget.setLayout(layout)

        self.setCentralWidget(self.widget)
        self.setWindowTitle("Image Draw")

    def openImage(self):
        fname = QFileDialog.getOpenFileName(self, "Open image", ".", "Image Files (*.bmp *.jpg *.png *.xpm)")
        if fname.isEmpty(): return None
        return QPixmap(fname)        

import sys
if __name__ == "__main__":    
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())

我现在应该怎么做才能在图像上永久绘制? 我可以存储所有点并在油漆中重新绘制它们,但这似乎效率不高。 我应该在 QGraphicsScene 中而不是在 QGraphicsPixmapItem 本身中进行绘图吗?

第二个问题是,在图像上绘制之后,如何获得选定区域的掩码? 比如,创建一个带有 alpha 通道的新图像,然后提取像素值? 或者,在空白图像上并行绘制?然后,我还应该跟踪放大/缩小..

【问题讨论】:

    标签: image mouseevent pyqt4 paint


    【解决方案1】:

    你有很多不同的选择,我会从高到低排序:

    1. 使用QGraphicsSceneQGraphicsViewQGraphicsItems。这组可能是图形密集型操作的主要选项和最佳选项。通过将QGLWidget 设置为视口,您甚至可以在许多系统上获得硬件加速。
    2. 使用QScrollArea支持放大图片,可以是简单的QLabel。通过更改查看区域,您将获得有效的缩放。 QLabel 可用于绘制图像,但您必须手动跟踪所选区域并进行任何选择覆盖。
    3. 使用单个QWidget 并进行自定义绘制。通过在各种事件之后调用update(),您将能够进行任何必要的更改。几乎所有事情都需要手动完成。

    我推荐第 1 种方法。您可以使用 QGraphicsPixmapItem 来保存您的图像。然后,您可以创建一个表示您的选择的图形项,并使用其边界矩形来查找intersecting 区域。 QGraphicsView 可以为你处理所有的zooming

    【讨论】:

    • 非常感谢这个好答案。我想,我会坚持你的建议并尝试第一种方法。你知道任何有用的示例代码、开源软件吗? (除了 imagewiever.py 示例,这也很有帮助)
    • 假设您可以阅读 C++(或找到等效的 Python 版本),请查看演示 (doc.trolltech.com/4.7/demos.html) 和示例 (doc.trolltech.com/4.7/examples-graphicsview.html) 的“图形视图”部分
    猜你喜欢
    • 2013-06-12
    • 1970-01-01
    • 2013-01-10
    • 1970-01-01
    • 1970-01-01
    • 2021-03-09
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多