image - PyQT4 - 在图像上绘画以进行区域选择

标签 image mouseevent pyqt4 paint

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

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

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

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

    非常感谢。

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

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

    但是,问题是,paint 函数已经将画家作为参数;在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 channel 的新图像,然后提取像素值?
    或者,在空白图像上并行绘制?然后,我还应该跟踪放大/缩小..

    最佳答案

    您有许多不同的选项,我将从较高级别到较低级别排序:

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

  • 我推荐方法 1。您可以使用 QGraphicsPixmapItem保持你的形象。然后,您可以创建一个代表您的选择的图形项目,并使用它的边界矩形来查找 intersecting领域。 QGraphicsView 可以处理所有zooming为你。

    关于image - PyQT4 - 在图像上绘画以进行区域选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6681822/

    相关文章:

    javascript - 循环浏览多个 body 背景图像

    Python:如何使用鼠标点击来工作?

    jquery - 延迟 jquery 悬停事件?

    python - 绘制 TreeViewItem 展开按钮和兄弟/子线

    python - PyQt Drop Event 没有子类化?

    javascript - 如何获取远程图像以在 Canvas 中显示?

    python PIL : Find the size of image without writing it as a file

    java - 不显示二值图像

    c# - 在 wpf 中单击鼠标时如何控制较低的 zindex?

    python - PyQt4:如何使图标大于 QPushButton? (像素图按钮)