PYQT实现使用opencv获取摄像头并在上面框选

怎么使用PYQT和opencv

pyqt可以直接pip安装,opencv也是,但要注意这两个都不能使用太新的版本,不然两个不能兼容,后续打包上会存在问题

通过opencv获取摄像头流

首先创建一个opencv对象,我们要不断的去读取这个opencv的对象,就要不断去获取read
然后通过pyqt的超时Timer的timeout去不断调用这个获取read的方法,然后显示在pyqt的label上

    def __init__(self):
        self.cap = cv2.VideoCapture(ConfigManage.video)
        self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)  
        self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)

这边要指定一下分辨率,方便我们后续截图,ConfigManage.video默认是0,如果电脑上只有一个摄像头就为0,直接写入0就行,我这边的写法是从一个配置文件里获取摄像头的参数。

持续获取视频流

    def captureNextFrame(self):
        self.ret, self.read = self.cap.read()
        if (self.ret == True):
            self.video_error_state = True
            self.currentFrame = cv2.cvtColor(self.read, cv2.COLOR_BGR2RGB)
        else:
            # MESSAGEBOX.set_error_box('请检查摄像头是否接入')
            print('请检查摄像头是否接入')

    def convertFrame(self):
        try:
            height, width = self.currentFrame.shape[:2]
            img = QImage(self.currentFrame, width, height, QImage.Format_RGB888)
            img = QPixmap.fromImage(img)
            self.previousFrame = self.currentFrame
            return img
        except Exception as e:
            # MESSAGEBOX.set_error_box('请检查摄像头是否能读取')
            raise ValueError(e)

我们这边通过格式转换,然后在去调用实现摄像头流的实时预览

摄像头流在label上显示

    def set_pic(self, label):
        try:
            self.captureNextFrame()
            label.setPixmap(self.convertFrame())
            label.setScaledContents(True)
        except:
            print('No Frame')

这样写能支持在多个label上显示摄像头视频流,并且不会卡顿

定义一个timer定时器

self._timer = QTimer(self)
self._timer.start(16)
self.update()

这边代码就比较简单,自行查阅pyqt的库

timer的超时连接函数

self._timer.timeout.connect(lambda: set_pic(label))

在pyqt的label上进行框选

要先改写label

class MyLabel(QtWidgets.QLabel):
    x0 = 0
    y0 = 0
    x1 = 0
    y1 = 0
    flag = False
    pos_list = []

鼠标点击事件

    def mousePressEvent(self, event):
        self.flag = True
        self.x0 = event.x()
        self.y0 = event.y()
        self.pos_list.clear()

鼠标释放事件

    def mouseReleaseEvent(self, event):
        self.flag = False
        # print(self.x0,self.y0,self.x1,self.y1) #71 21 369 215
        self.pos_list.append((self.x0, self.y0))
        self.pos_list.append((self.x1, self.y1))

通过这里的pos_list的填充,我们能获取点击的点和释放的点,便能确定两个点,通过确定两个点可以画出一个长方形,同理,如果想画其他的形状,可以通过捕获多个点来画出这个图像

鼠标移动事件

    def mouseMoveEvent(self, event):
        if self.flag:
            self.x1 = event.x()
            self.y1 = event.y()
            self.update()

画出图像

    def paintEvent(self, event):
        super().paintEvent(event)
        rect = QRect(self.x0, self.y0, abs(self.x1 - self.x0), abs(self.y1 - self.y0))
        painter = QPainter(self)
        painter.setPen(QPen(Qt.red, 2, Qt.SolidLine))
        painter.drawRect(rect)

版权声明:本文为weixin_44697598原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。