python使用PyQT设计界面调用本地摄像头

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,

在QT里面定时器是一个非常重要的概念,尤其是在需要规律的执行某个任务时,我们可以设置任务的定时执行之间,从而完成一系列的自动化操作。在将摄像头的视频数据实时显示到label时就需要借助定时器的配合,将每一帧读取转换为QImage类型,显示到label中,然后继续读取下一帧执行上述操作。当然上面的操作我们也可以放在一个while里面执行,但是使用while在进行界面编程时会导致界面假死,不响应别的处理请求的问题,所以还是要使用更加灵活的定时器来完成这一部分工作。

在上一篇博客中提到了怎么给pycharm配置qt designer更加方便的设计自己的界面,这一篇博客算是上篇博客的补充,因为许多时候我们都需要对视频数据进行处理,例如下面的代码中我将实时视频数据进行边缘检测后输出到label中,所以这时看到的并不是彩色图像,而是一幅二值化的边缘图像。代码如下

下面是UI界面文件,相比于上一篇博客中的界面没有太大的改变,仅增加了一个按钮,用来打开本地的摄像头

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'demo.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(1066, 796)
        self.horizontalLayoutWidget = QtWidgets.QWidget(Form)
        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 1051, 80))
        self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.openimg = QtWidgets.QPushButton(self.horizontalLayoutWidget)
        self.openimg.setObjectName("openimg")
        self.horizontalLayout.addWidget(self.openimg)
        self.detect = QtWidgets.QPushButton(self.horizontalLayoutWidget)
        self.detect.setObjectName("detect")
        self.horizontalLayout.addWidget(self.detect)
        self.opencCanera = QtWidgets.QPushButton(self.horizontalLayoutWidget)
        self.opencCanera.setObjectName("opencCanera")
        self.horizontalLayout.addWidget(self.opencCanera)
        self.closewindow = QtWidgets.QPushButton(self.horizontalLayoutWidget)
        self.closewindow.setObjectName("closewindow")
        self.horizontalLayout.addWidget(self.closewindow)
        self.horizontalLayoutWidget_2 = QtWidgets.QWidget(Form)
        self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(10, 90, 1051, 701))
        self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.label = QtWidgets.QLabel(self.horizontalLayoutWidget_2)
        self.label.setObjectName("label")
        self.horizontalLayout_2.addWidget(self.label)

        self.retranslateUi(Form)
        self.openimg.clicked.connect(Form.shouImg)
        self.detect.clicked.connect(Form.edgeDetect)
        self.closewindow.clicked.connect(Form.close)
        self.opencCanera.clicked.connect(Form.showVideo)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.openimg.setText(_translate("Form", "打开图片"))
        self.detect.setText(_translate("Form", "边缘检测"))
        self.opencCanera.setText(_translate("Form", "打开本地摄像头"))
        self.closewindow.setText(_translate("Form", "关闭窗口"))
        self.label.setText(_translate("Form", "show Image"))
复制代码

对UI的调用代码如下,相对上一篇博客的改动较大

from demo import Ui_Form
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import cv2
import sys


class MainWindow(QMainWindow, Ui_Form):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=parent)
        self.setupUi(self)
        self.path = None
        self.cameraTimer = QTimer()
        self.msg = QMessageBox()


    # 打开图片按钮槽函数
    def shouImg(self):
        filePath = self.getFileDir()
        self.path = filePath[0][0]
        if self.cameraTimer.isActive() and self.path is not None:
            self.cameraTimer.stop()
            self.cap.release()
        img = cv2.imread(filePath[0][0])
        img_dis = QImage(img, img.shape[1], img.shape[0], QImage.Format_RGB888)
        # 加载图片,并设定图片大小
        img_dis = QPixmap(img_dis).scaled(int(img.shape[1]), int(img.shape[0]))
        width = img_dis.width()  ##获取图片宽度
        height = img_dis.height()  ##获取图片高度
        if width / self.label.width() >= height / self.label.height():  ##比较图片宽度与label宽度之比和图片高度与label高度之比
            ratio = width / self.label.width()
        else:
            ratio = height / self.label.height()
        new_width = int(width / ratio)  ##定义新图片的宽和高
        new_height = int(height / ratio)
        new_img = img_dis.scaled(new_width, new_height)  ##调整图片尺寸
        # img_dis = QPixmap(img_dis).scaled(int(img.shape[1]), int(img.shape[0]))
        self.label.setPixmap(new_img)

    # 获取文件地址函数
    def getFileDir(self):
        try:
            self.file_path = QFileDialog.getOpenFileNames(self, "select file", "./", "*.*")
        except Exception as e:
            print(e)
        return self.file_path
    
    # 边缘检测按钮槽函数
    def edgeDetect(self):
        if self.cameraTimer.isActive() and self.path is not None:
            self.cameraTimer.stop()
            self.cap.release()
        if self.path is None:
            QMessageBox.information(QWidget(), '这是提示框', '请先打开一幅图像', QMessageBox.Yes | QMessageBox.No)
        else:
            img = cv2.imread(self.path, 0)
            # print(img.shape)
            img = cv2.Canny(img, 50, 200)
            # print(img.shape)
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            img_dis = QImage(img, img.shape[1], img.shape[0], QImage.Format_RGB888)
            # 加载图片,并设定图片大小
            img_dis = QPixmap(img_dis).scaled(int(img.shape[1]), int(img.shape[0]))
            width = img_dis.width()  ##获取图片宽度
            height = img_dis.height()  ##获取图片高度
            if width / self.label.width() >= height / self.label.height():  ##比较图片宽度与label宽度之比和图片高度与label高度之比
                ratio = width / self.label.width()
            else:
                ratio = height / self.label.height()
            new_width = int(width / ratio)  ##定义新图片的宽和高
            new_height = int(height / ratio)
            new_img = img_dis.scaled(new_width, new_height)  ##调整图片尺寸
            # img_dis = QPixmap(img_dis).scaled(int(img.shape[1]), int(img.shape[0]))
            self.label.setPixmap(new_img)
    
    # 调用本地摄像头按钮槽函数
    def showVideo(self):
        self.cap = cv2.VideoCapture(0)
        self.cameraTimer.start(100)
        self.cameraTimer.timeout.connect(self.OpenFrame)
    
    
    # 调用本地摄像头显示视频,同时是定时器的槽函数
    def OpenFrame(self):
        ret, image = self.cap.read()
        # 这个地方,与下面的地方放开后,打开摄像头看到的是实时的边缘检测视频
        # image = cv2.Canny(image, 50, 180)
        if ret:
            if len(image.shape) == 3:
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                vedio_img = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_RGB888)
            elif len(image.shape) == 1:
                vedio_img = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_Indexed8)
            else:
                # 这里的注释和上面的注释放开后显示的是实时的边缘检测视频
                # image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                vedio_img = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_RGB888)
            self.label.setPixmap(QPixmap(vedio_img))
            self.label.setScaledContents(True)
        else:
            self.cap.release()
            self.cameraTimer.stop()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
复制代码

运行界面如下

image.png

打开图像进行显示

image.png

打开图像的边缘检测结果

image.png 说明一下,边缘检测按钮使用时需要先用打开图片按钮打开一幅图像,不然的话会弹窗提示

image.png

打开摄像头的原彩图这里就不展示了,展示一下实时边缘检测的图像

image.png

image.png

image.png

在后面的博客中误会分享更多的代码,跟大家一起学习,有什么问题大家可以在评论中随时提出,一起讨论。

猜你喜欢

转载自juejin.im/post/7107906757678071822