QLabel中视频上的PyQt5绘画圈

问题描述 投票:0回答:1

我想画一个圆圈,当按下鼠标时,该圆圈显示在视频上的光标位置。视频正在MainWindow中的QLabel对象中播放。我正在使用OpenCV以10 fps的速度从网络摄像头读取帧。我将帧转换为QPixmap,并在QLabel对象(self.vidWindow)中显示它们。

在下面的代码中,当启动MainWindow时,圆圈立即被绘制(不是我想要的),然后被视频流覆盖。文本显示在遮罩Qlabel对象中,并在按下鼠标按钮时在MainWindow中显示一条消息。

我可以在QLabel对象中画一个圆吗?如果是这样,我应该使用遮罩QLabel对象还是可以直接在self.vidWindow中的视频上覆盖?

在代码的最小化版本中,视频显示,但是当我尝试绘制椭圆时会触发错误。

import sys, cv2
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel
from PyQt5.QtGui import QImage, QPixmap, QPainter, QPen, QFont
from PyQt5.QtCore import QTimer, Qt, QCoreApplication

class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()        
        self.initUI()        

    def initUI(self):                       
        self.statusBar().showMessage('Ready')        
        self.setGeometry(50, 50, 800, 600)
        self.setWindowTitle('Statusbar')
        self.vidWindow = QLabel(self)
        self.vidWindow.setGeometry(20, 20, 640, 480)
        self.maskWindow = QLabel(self)
        self.maskWindow.setGeometry(20, 20, 640, 480)
        self.maskWindow.setStyleSheet('background-color: rgba(0,0,0,0%)')
        font = QFont()
        font.setPointSize(18)
        font.setBold(True)
        font.setWeight(75)
        self.maskWindow.setFont(font)
        self.maskWindow.setText('Message is on the mask Qlabel object')
        self.msgLabel = QLabel(self)
        self.msgLabel.setGeometry(675, 300, 100, 20)
        self.cap = cv2.VideoCapture(0)
        self.pix = QImage()
        self.timer = QTimer()
        self.frame_rate = 5
        self.show()
        self.start()

    def nextFrameSlot(self):
        ret, frame = self.cap.read()
        if ret == True:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            img = QImage(frame,frame.shape[1], frame.shape[0], QImage.Format_RGB888)
            img = img.scaled(640, 480, Qt.KeepAspectRatio)
            self.pix = QPixmap.fromImage(img)
            self.vidWindow.setPixmap(self.pix)

    def mousePressEvent(self, QMouseEvent):        
        self.msgLabel.setText('Mouse Clicked!')

    def paintEvent(self, QMouseEvent):
        e = QMouseEvent
        painter = QPainter(self)
        painter.setPen(QPen(Qt.green,  4, Qt.SolidLine))
        painter.drawEllipse(e.x(), e.y(), 100)

    def start(self):
        rate = int(1000.0 / self.frame_rate)        
        self.timer.setTimerType(Qt.PreciseTimer)
        self.timer.timeout.connect(self.nextFrameSlot)
        self.timer.start(rate)

    def closeEvent(self, event):
        if self.cap.isOpened():
            self.cap.release()
            self.vidWindow.clear()        
        QCoreApplication.quit()

if __name__ == '__main__':    
    app = QApplication(sys.argv)
    ex = MainWindow()
sys.exit(app.exec_())
python video pyqt qpainter qlabel
1个回答
0
投票

尽管QPainter用于绘制窗口小部件,但在这种情况下将不起作用,因为它将其子级以下的“ MainWindow”绘制为QLabels。至少有两种可能的解决方案:

  • 创建自定义QLabel并检测单击并绘制圆圈,

  • 创建一个显示带有圆圈的QPixmap的QLabel,然后根据鼠标信息移动它。

在这种情况下,我将实现第二种方法:

import sys, cv2
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel
from PyQt5.QtGui import QImage, QPixmap, QPainter, QPen, QFont
from PyQt5.QtCore import QTimer, Qt


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

    def initUI(self):
        self.statusBar().showMessage("Ready")
        self.setGeometry(50, 50, 800, 600)
        self.setWindowTitle("Statusbar")
        self.vidWindow = QLabel(self)
        self.vidWindow.setGeometry(20, 20, 640, 480)
        self.maskWindow = QLabel(self)
        self.maskWindow.setGeometry(20, 20, 640, 480)
        self.maskWindow.setStyleSheet("background-color: rgba(0,0,0,0%)")
        font = QFont()
        font.setPointSize(18)
        font.setBold(True)
        font.setWeight(75)
        self.maskWindow.setFont(font)
        self.maskWindow.setText("Message is on the mask Qlabel object")
        self.msgLabel = QLabel(self)
        self.msgLabel.setGeometry(675, 300, 100, 20)

        self.marker_label = QLabel(self)

        pixmap = QPixmap(100, 100)
        pixmap.fill(Qt.transparent)

        painter = QPainter(pixmap)
        painter.setPen(QPen(Qt.green, 4, Qt.SolidLine))
        painter.drawEllipse(pixmap.rect().adjusted(4, 4, -4, -4))
        painter.end()

        self.marker_label.setPixmap(pixmap)
        self.marker_label.adjustSize()
        self.marker_label.hide()
        self.marker_label.raise_()

        self.cap = cv2.VideoCapture(0)
        self.timer = QTimer()
        self.frame_rate = 5
        self.show()
        self.start()

    def nextFrameSlot(self):
        ret, frame = self.cap.read()
        if ret == True:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            img = QImage(frame, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
            img = img.scaled(640, 480, Qt.KeepAspectRatio)
            pix = QPixmap.fromImage(img)
            self.vidWindow.setPixmap(pix)

    def mousePressEvent(self, event):
        self.msgLabel.setText("Mouse Clicked!")
        if self.vidWindow.rect().contains(event.pos()):
            self.marker_label.move(event.pos() - self.marker_label.rect().center())
            self.marker_label.show()
        super().mousePressEvent(event)

    def start(self):
        rate = int(1000.0 / self.frame_rate)
        self.timer.setTimerType(Qt.PreciseTimer)
        self.timer.timeout.connect(self.nextFrameSlot)
        self.timer.start(rate)

    def closeEvent(self, event):
        if self.cap.isOpened():
            self.cap.release()
        super().closeEvent(event)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = MainWindow()
    sys.exit(app.exec_())
© www.soinside.com 2019 - 2024. All rights reserved.