【问题标题】:QGraphicsScene. How do I draw an ellipse over a loaded image in pyqt5?QGraphicsScene。如何在 pyqt5 中加载的图像上绘制椭圆?
【发布时间】:2020-08-21 19:02:18
【问题描述】:

我有一个带有 QGraphicsScene 的 QGraphicsView。在 QGraphicsScene 上,我使用 QGraphicsPixmapItem 输出图像。我想用鼠标在图像上画一个椭圆。 我现在有那个代码。椭圆在 MainWindow 上绘制。 我需要做什么才能在 QGraphicsView 中的图像上绘制椭圆?

代码 OFT_MainWindow

    # OFT_MainWindow

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(862, 710)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
        self.graphicsView.setGeometry(QtCore.QRect(10, 90, 841, 571))
        self.graphicsView.setMouseTracking(True)
        self.graphicsView.setObjectName("graphicsView")
        self.buttonBox = QtWidgets.QDialogButtonBox(self.centralwidget)
        self.buttonBox.setGeometry(QtCore.QRect(360, 670, 81, 31))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.buttonBox.setFont(font)
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(760, 10, 91, 31))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.pushButton.setFont(font)
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(10, 10, 731, 31))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setGeometry(QtCore.QRect(10, 670, 331, 31))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(10, 50, 841, 31))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.pushButton_2.setFont(font)
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Browse"))
        self.pushButton_2.setText(_translate("MainWindow", "Highlight field area"))

主要代码

import OFT_MainWindow  
import sys
import os
import numpy as np
import cv2
from PIL import Image, ImageQt, ImageEnhance
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.Qt import Qt

def main():
    app = QtWidgets.QApplication(sys.argv)  
    window = MainWindow()  
    window.show()  
    app.exec_()  
        
class MainWindow(QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow, QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene):
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self) 
        self.pushButton.clicked.connect(self.browse_file)
        self.pushButton_2.clicked.connect(self.imageFrame)
        self.begin = QtCore.QPoint()
        self.end = QtCore.QPoint()
        self.show()
        
###################################################################################    

    def browse_file(self):
        self.lineEdit.clear() 
        file = QtWidgets.QFileDialog.getOpenFileName(self, "Choose file")
        file = str(file[0])
        if file: 
            self.lineEdit.setText(file)   # добавить путь в lineEdit
#         cap = cv2.VideoCapture(file)

###################################################################################
        
    def imageFrame(self):
        file = self.lineEdit.text()
        self.drawing = False
        self.lastPoint = QPoint()
        scene = QtWidgets.QGraphicsScene(self)
        self.image = QPixmap(file)
        item = QtWidgets.QGraphicsPixmapItem(self.image)
        scene.addItem(item)
        view = self.graphicsView.setScene(scene)
#         self.show()

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        br = QtGui.QBrush(QtGui.QColor(0, 255, 0, 25))  
        qp.setBrush(br)   
        ellipse = qp.drawEllipse(QtCore.QRect(self.begin, self.end))
        coord_a = self.begin
        coord_a = str(coord_a)
        coord_a = coord_a[20:][:-1]
        coord_b = self.end
        coord_b = str(coord_b)
        coord_b = coord_b[20:][:-1]
        coord = ('begin = ' + coord_a + ' end = ' + coord_b)
        self.lineEdit_2.setText(coord)

    def mousePressEvent(self, event):
        self.begin = event.pos()
        self.end = event.pos()
        self.update()

    def mouseMoveEvent(self, event):
        self.end = event.pos()
        self.update()
        
###################################################################################

if __name__ == '__main__':  
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.aboutToQuit.connect(app.deleteLater)
    sys.exit(app.exec_())

【问题讨论】:

    标签: python python-3.x pyqt5


    【解决方案1】:

    如果你想在 QGraphicsView 上绘制一些东西,你必须将 QGraphicsItem 添加到它的场景中,否则你几乎没有用创建一个 QGraphicsView 开始。

    一个可能的解决方案是在场景中安装一个事件过滤器,监听鼠标按钮事件并在场景中绘制一个椭圆(使用QGraphicsEllipseItem),如果第一次单击是在 QGraphicsPixmapItem 的内容中完成的。

    请注意,另一种可能性是从 QGraphicsPixmapItem 继承并实现其鼠标事件。这完全取决于您将要做什么以及您需要从您的计划中获得什么。

    class MainWindow(QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            # ...
            self.ellipseItem = None
    
        def imageFrame(self):
            # ...
            scene.installEventFilter(self)
    
        def eventFilter(self, source, event):
            if event.type() == QtCore.QEvent.GraphicsSceneMousePress:
                for item in self.graphicsView.scene().items(event.scenePos()):
                    if isinstance(item, QtWidgets.QGraphicsPixmapItem):
                        self.reference = item
                        self.ellipseItem = QtWidgets.QGraphicsEllipseItem(item)
                        self.ellipseItem.setBrush(QtGui.QColor(0, 255, 0, 25))
                        self.start = item.mapFromScene(event.scenePos())
            elif event.type() == QtCore.QEvent.GraphicsSceneMouseMove and self.ellipseItem:
                end = self.reference.mapFromScene(event.scenePos())
                self.ellipseItem.setRect(QtCore.QRectF(self.start, end))
            elif event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and self.ellipseItem:
                self.ellipseItem = None
            return super().eventFilter(source, event)
    

    请注意,从所有这些类 (QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow, QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene) 中对主窗口进行子类化不仅没有必要且毫无意义,而且绝对是错误:只有在您知道自己是什么时才应该进行多重继承子类化。重新继承以及为什么,否则,只是不要。对于从 UI 文件加载的 Qt 小部件,只需从基本小部件类和 Ui 子类化。

    【讨论】:

    • 非常感谢您的回答。从程序中我需要在图像上绘制椭圆时,其起点和终点的坐标显示在“lineEdit_2”中。但现在我收到一条错误消息:TypeError: invalid result from MainWindow. eventFilter(), a 'bool' is expected not 'NoneType' 我必须做些什么来纠正这个错误?
    • 我似乎已经通过添加return QtWidgets.QMainWindow.eventFilter(self, source, event)修复了这个错误
    • 抱歉,复制粘贴后丢失了。我已经更新了答案。要更新坐标,只需在事件过滤器中设置这些值。
    • 再次感谢您。你帮了大忙。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 2021-11-20
    • 1970-01-01
    相关资源
    最近更新 更多