前言
通过PyQt与Opencv-python实现多线程显示摄像头信息至QLabel,可以同时拉伸窗口,摄像头显示区域自适应拉伸区域。
与Qt+Opencv实现同样功能的代码思路一致,仅仅是通过python语言实现。
工程环境:
(1)win10,
(2)Anaconda3管理python虚拟环境。
(3)cmd打开虚拟环境通过pip安装以下库pip install pyqt5 pip install pyqt5-tools pip install opencv-python(4)PC机外接一个USB摄像头,或者笔记本自带摄像头
效果
实验效果如下图所示。

资源下载
本次实验全部代码请至https://download.youkuaiyun.com/download/wang_chao118/86511419下载。
核心代码
编程思路
定义一个摄像头类Camera,在该类中实现摄像头相关操作,将摄像头相关的属性、方法放至一个子线程,与显示GUI的主线程区别开,这样做的好处是,后面如果在摄像头显示图片的基础上对图片做一些诸如“目标检测”等耗时的操作时,GUI主线程显示不至于卡顿。
再定义一个PyQt界面类Widget,在Widget类的构造函数中实例化一个Camera对象,将Camera对象产生的图像信号与Widget类中的图像显示槽函数进行连接,进而实现摄像头视频流的连续显示。
Camera.py
self.thread = QThread()创建一个名称为thread的QThread类
self.thread = QThread()将Camera类中的所有属性及方法全部转移至thread中去
sendPicture = pyqtSignal(QImage)定义一个pyqt信号,发出信号的类型为QIamge,信号名称为sendPicture
此处的发出的信号QIamge为定时器到时间时从摄像头中读出的图像数据
在Camera构造函数中实例化一个QTimer类,当QTimer到设定的事件时,调用槽函数
self.display,在槽函数self.display进行摄像头信号的读取工作以及一些耗时的图像操作(本次实验省略耗时操作,以time.sleep(0.5)替代,可以将注释取消看效果)
from PyQt5.Qt import *
from PyQt5 import QtGui
from PyQt5.QtCore import *
import cv2
import time
class Camera(QObject):
sendPicture = pyqtSignal(QImage)
def __init__(self, parent=None):
super(Camera, self).__init__(parent)
self.thread = QThread()
self.moveToThread(self.thread)
self.timer = QTimer()
self.init_timer()
self.cap = cv2.VideoCapture()
self.camera_num = 0
def init_timer(self):
self.timer.setInterval(30)
self.timer.timeout.connect(self.display)
def set_cam_number(self, n):
self.camera_num = n
def open_camera(self):
print("in open_camera")
self.cap.set(4, 480)
self.cap.set(3, 640)
self.cap.open(self.camera_num)
self.timer.start()
self.thread.start()
def close_camera(self):
self.cap.release()
def display(self):
flag, image = self.cap.read()
# time.sleep(0.5) # 耗时操作
showImage = QtGui.QImage(image.data, image.shape[1], image.shape[0],
QtGui.QImage.Format_RGB888).rgbSwapped()
self.sendPicture.emit(showImage)
Widget.py
在
Widget类的构造函数中实例化一个Camera类,并将Camera类发出的QImage信号与本类中的槽函数receive(self, img)连接,槽函数receive(self, img)是将Camera类发送过来的图像数据显示至Ui_Widget类中的self.label,且按Camera类中定时器的频率刷新。
self.camera_thread.sendPicture[QImage].connect(self.receive)这里要注意PyQt中信号与槽连接的写法与Qt还是大相径庭的。
Pyqt5的信号与槽的具体写法请参考此处https://www.riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html
槽函数
receive(self, img)中的img_height = self.label_2.height()不断更新图像大小,使其与label大小相同。这样便做到拉伸显示窗口,使得摄像头显示区域也一并变化的效果。
from UI.ui_Widget import *
from Camera import *
class Widget(QWidget, Ui_Widget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.setupUi(self)
self.camera_thread = Camera()
self.camera_thread.set_cam_number(0)
# 连接Camera的sendPicture信号与receive函数进行展示
self.camera_thread.sendPicture[QImage].connect(self.receive)
self.camera_thread.open_camera()
def receive(self, img):
img_height = self.label_2.height()
img_width = self.label_2.width()
new_img = img.scaled(QSize(img_width, img_height))
self.label_2.setPixmap(QPixmap.fromImage(new_img))
资源下载
本次实验全部代码请至https://download.youkuaiyun.com/download/wang_chao118/86511419下载。

该博客介绍了如何通过PyQt5和OpenCV-python在Python环境下实现多线程摄像头显示,确保GUI界面流畅。作者创建了一个Camera类用于处理摄像头操作,并在独立线程中运行,避免了图像处理导致的界面卡顿。同时,利用QThread和QImage信号槽机制,实现在QLabel上实时显示摄像头画面,并能随窗口拉伸自适应调整大小。
263

被折叠的 条评论
为什么被折叠?



