Как нарисовать полигон из MouseEvents поверх изображения в Qlabel - PullRequest
1 голос
/ 25 марта 2020

Используя Python, PYQT5 Я хочу нарисовать многоугольник поверх изображения, которое находится в виджете Qlabel. Я использовал простое окно Qmainwindow с виджетом метки, сгенерированным в конструкторе QT (код приведен ниже).

Я знаю, что есть несколько сведений о рисовании в Qmainwindow, как здесь:

Дайте мне знать, если у вас есть решение этой проблемы.

import sys
from PyQt5.QtCore import Qt
from PyQt5 import QtWidgets, uic, QtCore, QtGui
from PyQt5.QtGui import QPixmap, QPainter, QPolygon, QPen, QBrush
from PyQt5.QtCore import QPoint

from polygon_ui import Ui_MainWindow


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, *args, obj=None, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)

        pixmap = QPixmap("img.png")
        self.label.setPixmap(pixmap)

        self.label.mousePressEvent = self.getPixel
        self.pol = []

    def getPixel(self, event):
        x = event.pos().x()
        y = event.pos().y()

        self.pol.append(QPoint(int(x),int(y)))

        print(x,y, self.pol)

    def paintEvent(self, event):
        painter = QPainter(self)
        #painter.drawPixmap(self.rect(), self.image)

        painter.setPen(QPen(Qt.black, 5, Qt.SolidLine))
        painter.setBrush(QBrush(Qt.red, Qt.VerPattern))

        #points = QPolygon([ QPoint(10,10), QPoint(10,100),
        #     QPoint(100,10), QPoint(100,100)])

        points = QPolygon(self.pol)
        painter.drawPolygon(points)

    def mouseMoveEvent(self, event):
        pass

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

код для polygon_ui здесь - просто сгенерирован QT-Designer с помощью Mainwindow + Qlabel:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(621, 641)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(10, 10, 600, 600))
        self.label.setObjectName("label")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 621, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(_translate("MainWindow", "TextLabel"))

1 Ответ

1 голос
/ 25 марта 2020

Если вы хотите добавить такие элементы, как многоугольники, линии, круги и т. Д. c. затем на изображении не усложняйте себя с помощью QLabel, поскольку, например, текущим кодом вы рисуете в окне, которое ниже QLabel, поэтому его не будет видно, возможное решение с использованием QLabel состоит в том, чтобы получите QPixmap и нарисуйте его сверху.

Лучшей альтернативой является использование Qt Graphics Framework, где для изображения установлено значение QGraphicsPixmapItem, а полигон является дочерним элементом для QGraphicsPixmapItem, как я покажу ниже:

from PyQt5 import QtCore, QtGui, QtWidgets


class GraphicsView(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(parent)
        scene = QtWidgets.QGraphicsScene(self)
        self.setScene(scene)

        self._pixmap_item = QtWidgets.QGraphicsPixmapItem()
        scene.addItem(self.pixmap_item)

        self._polygon_item = QtWidgets.QGraphicsPolygonItem(self.pixmap_item)
        self.polygon_item.setPen(QtGui.QPen(QtCore.Qt.black, 5, QtCore.Qt.SolidLine))
        self.polygon_item.setBrush(QtGui.QBrush(QtCore.Qt.red, QtCore.Qt.VerPattern))

    @property
    def pixmap_item(self):
        return self._pixmap_item

    @property
    def polygon_item(self):
        return self._polygon_item

    def setPixmap(self, pixmap):
        self.pixmap_item.setPixmap(pixmap)

    def resizeEvent(self, event):
        self.fitInView(self.pixmap_item, QtCore.Qt.KeepAspectRatio)
        super().resizeEvent(event)

    def mousePressEvent(self, event):
        sp = self.mapToScene(event.pos())
        lp = self.pixmap_item.mapFromScene(sp)

        poly = self.polygon_item.polygon()
        poly.append(lp)
        self.polygon_item.setPolygon(poly)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        view = GraphicsView()
        self.setCentralWidget(view)

        view.setPixmap(QtGui.QPixmap("img.png"))

        self.resize(640, 480)


if __name__ == "__main__":

    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

Обновление:

Если вы хотите использовать дизайн OP, реализация будет тривиальной.

Option1:

  1. Создайте файл с именем graphicsview.py, в котором реализовано графическое представление logView c:

    graphicsview.py

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class GraphicsView(QtWidgets.QGraphicsView):
        def __init__(self, parent=None):
            super().__init__(parent)
            scene = QtWidgets.QGraphicsScene(self)
            self.setScene(scene)
    
            self._pixmap_item = QtWidgets.QGraphicsPixmapItem()
            scene.addItem(self.pixmap_item)
    
            self._polygon_item = QtWidgets.QGraphicsPolygonItem(self.pixmap_item)
            self.polygon_item.setPen(QtGui.QPen(QtCore.Qt.black, 5, QtCore.Qt.SolidLine))
            self.polygon_item.setBrush(QtGui.QBrush(QtCore.Qt.red, QtCore.Qt.VerPattern))
    
        @property
        def pixmap_item(self):
            return self._pixmap_item
    
        @property
        def polygon_item(self):
            return self._polygon_item
    
        def setPixmap(self, pixmap):
            self.pixmap_item.setPixmap(pixmap)
    
        def resizeEvent(self, event):
            self.fitInView(self.pixmap_item, QtCore.Qt.KeepAspectRatio)
            super().resizeEvent(event)
    
        def mousePressEvent(self, event):
            sp = self.mapToScene(event.pos())
            lp = self.pixmap_item.mapFromScene(sp)
    
            poly = self.polygon_item.polygon()
            poly.append(lp)
            self.polygon_item.setPolygon(poly)
    
  2. Замените QLabel на QGraphicsView в polygon_ui:

    polygon_ui.py

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    <b>from graphicsview import GraphicsView</b>
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(621, 641)
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            <b>self.label = GraphicsView(self.centralwidget)</b>
            self.label.setGeometry(QtCore.QRect(10, 10, 600, 600))
            self.label.setObjectName("label")
            # ...
  3. Восстановите основную. py

    main.py

    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    from polygon_ui import Ui_MainWindow
    
    
    class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self, *args, obj=None, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
            self.setupUi(self)
    
            pixmap = QtGui.QPixmap("img.png")
            self.label.setPixmap(pixmap)
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        window = MainWindow()
        window.show()
        sys.exit(app.exec_())
    

Option2:

Другой подход заключается в продвижении виджета, и в SO есть много примеров такого типа, поэтому я не буду показывать процедуру:

Option3:

Другая более простая альтернатива - использовать QLabel в качестве контейнера и установить GraphicsView с макетом:

import sys

from PyQt5 import QtCore, QtGui, QtWidgets

from polygon_ui import Ui_MainWindow


class GraphicsView(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(parent)
        scene = QtWidgets.QGraphicsScene(self)
        self.setScene(scene)

        self._pixmap_item = QtWidgets.QGraphicsPixmapItem()
        scene.addItem(self.pixmap_item)

        self._polygon_item = QtWidgets.QGraphicsPolygonItem(self.pixmap_item)
        self.polygon_item.setPen(QtGui.QPen(QtCore.Qt.black, 5, QtCore.Qt.SolidLine))
        self.polygon_item.setBrush(QtGui.QBrush(QtCore.Qt.red, QtCore.Qt.VerPattern))

    @property
    def pixmap_item(self):
        return self._pixmap_item

    @property
    def polygon_item(self):
        return self._polygon_item

    def setPixmap(self, pixmap):
        self.pixmap_item.setPixmap(pixmap)

    def resizeEvent(self, event):
        self.fitInView(self.pixmap_item, QtCore.Qt.KeepAspectRatio)
        super().resizeEvent(event)

    def mousePressEvent(self, event):
        sp = self.mapToScene(event.pos())
        lp = self.pixmap_item.mapFromScene(sp)

        poly = self.polygon_item.polygon()
        poly.append(lp)
        self.polygon_item.setPolygon(poly)


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, *args, obj=None, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)

        self.graphicsview = GraphicsView()
        lay = QtWidgets.QVBoxLayout(self.label)
        lay.addWidget(self.graphicsview)

        pixmap = QtGui.QPixmap("img.png")
        self.graphicsview.setPixmap(pixmap)


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