[Python] pyqt6+opencv实现摄像头图像的实时读取并显示(完整源代码)

本文将会介绍如何通过opencv来实时捕获摄像头的图像,并通过pyqt6进行图像视频呈现。

实现思路

  1. 通过opencv的VideoCapture类读取摄像头的每一帧图像,通过pyqt6的QLabel来显示图像

  2. 根据获取的图像的宽和高大小以及QLabel的大小来动态调整最后输出的图像的宽和高

  3. 调整窗体大小,动态调整显示摄像头的标签图像大小

  4. 提供一个按钮来控制摄像头打开或者关闭

  5. 通过QTimer实现每20毫秒刷新获取的摄像头图像,也就是产生每秒50帧的视频效果。

安装依赖

复制代码
pip install opencv-python pyqt6

涉及知识点

opencv的VideoCapture(摄像头视频捕获)使用

Python opencv - 如何使用VideoCapture类进行摄像头视频捕获并显示

QTimer(定时器)使用

Python pyqt6 - Timer定时器介绍和使用场景(案例)

QGridLayout(网格布局)使用

Python pyqt6 - QGridLayout(网格布局)介绍和使用案例

QImage类使用

图像格式(Format)

QImage --- PyQt Documentation v6.6.0 (riverbankcomputing.com)

rgbSwap()和rgbSwapped()方法的区别

rgbSwap()进行内部转换,直接修改QImage对象; rdbSwapped() 返回交换完之后的对象,原图像不受影响。

scaled()方法

实现对图像进行按照新的高度和宽度进行缩放,可以选择是否保持原始摄像头图像的比例。

QImage --- PyQt Documentation v6.6.0 (riverbankcomputing.com)

完整源代码(带注释)

复制代码
import sys

from PyQt6 import QtCore
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QGridLayout, QPushButton, QWidget
from PyQt6.QtGui import QPixmap, QImage, QGuiApplication
import cv2


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('pyqt6显示opencv获取的摄像头图像')
        self.btn_camera = QPushButton('打开摄像头')  # 控制摄像头的状态
        self.lbl_img = QLabel('显示摄像头图像')  # 创建标签控件来显示摄像头的图像, 标签的大小由QGridLayout的布局来决定
        self.lbl_img.setStyleSheet('border: 1px solid black;')  # 给标签设置黑色边框
        self.lbl_img.setAlignment(Qt.AlignmentFlag.AlignCenter)  # 让标签要显示的内容居中
        self.lbl_img.setMinimumSize(640, 480)  # 宽和高保持和摄像头获取的默认大小一致
        self.btn_camera.clicked.connect(self.btn_camera_click)
        top_widget = QWidget()
        grid = QGridLayout()
        grid.addWidget(self.lbl_img, 0, 0, Qt.AlignmentFlag.AlignTop)  # 放置顶部
        grid.addWidget(self.btn_camera, 1, 0, Qt.AlignmentFlag.AlignBottom)  # 放置底部
        top_widget.setLayout(grid)
        self.setCentralWidget(top_widget)

        self.center_win()  # 居中显示主窗口

        self.is_open_camera = False  # 是否打开了摄像头标志位
        self.video_cap = None
        self.camera_timer = QtCore.QTimer(self)  # 创建读取摄像头图像的定时器
        self.camera_timer.timeout.connect(self.play_camera_video)

    def center_win(self):
        qr = self.frameGeometry()
        cp = QGuiApplication.primaryScreen().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def btn_camera_click(self):
        if not self.is_open_camera: # 按下 打开摄像头 按钮
            self.video_cap = cv2.VideoCapture(0)  # 打开默认摄像头(索引为0)
            print('camera fps:', self.video_cap.get(cv2.CAP_PROP_FPS))
            # 每个20毫秒获取一次摄像头的图像进行刷新, 具体设置多少合适, 可以参考你的摄像头帧率cv2.CAP_PROP_FPS,
            # 刷新频率设置一个小于 1000 / cv2.CAP_PROP_FPS 的值即可
            self.camera_timer.start(20)  
            self.is_open_camera = True
            self.btn_camera.setText('关闭摄像头')
        else:  # 按下 关闭摄像头 按钮
            self.camera_timer.stop()
            self.video_cap.release()
            self.video_cap = None
            self.lbl_img.clear()
            self.btn_camera.setText('打开摄像头')
            self.is_open_camera = False

    def play_camera_video(self):
        if self.is_open_camera:
            # ret, frame = self.video_cap.read()  # 读取视频流的每一帧
            self.video_cap.grab()
            ret, frame = self.video_cap.retrieve()  # 读取视频流的每一帧
            if ret:
                height, width, channel = frame.shape  # 获取图像高度、宽度和通道数, 通常为为640x480x3
                # opencv获取的图像默认BGR格式
                # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 转换BRG 到 RGB
                # 或者
                # 将OpenCV格式转换成QImage格式, 需要进行颜色通道交换(.rgbSwapped())
                img = QImage(frame.data, width, height, QImage.Format.Format_RGB888)
                img = img.rgbSwapped()
                # 或者
                # img = QImage(frame.data, width, height, QImage.Format.Format_RGB888)
                # img.rgbSwap()
                # 或者
                # img = QImage(frame.data, width, height, QImage.Format.Format_BGR888)
                pixmap = QPixmap.fromImage(img)  # 从QImage生成QPixmap对象
                #
                lbl_width = self.lbl_img.size().width()  # 通过size()获取图像标签的真实的宽度
                lbl_height = self.lbl_img.size().height()  # 通过size()获取图像标签的真实的高度
                # 按照图像标签的真实的宽和高进行缩放,但保持摄像头的宽和高的比例
                pixmap = QPixmap(pixmap).scaled(
                    self.lbl_img.width(), self.lbl_img.height(),
                    aspectRatioMode=Qt.AspectRatioMode.KeepAspectRatio)
                self.lbl_img.setPixmap(pixmap)  # 在标签上显示图片


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())
相关推荐
会飞锦鲤7 分钟前
基于 Mask R-CNN 的药片缺陷检测系统
人工智能·pytorch·python·神经网络·resnet-50
默 语10 分钟前
Java新手入门:从零开始安装JDK并配置环境变量
java·开发语言·python·mysql·group by·1024程序员节·数据去重
清水白石00841 分钟前
Python 异步编程深度解析:Cancellation 到底是异常还是控制信号?从 asyncio 取消机制到企业级事务设计最佳实践
开发语言·python
Patrick在香港1 小时前
Python 审计香港开放数据目录:两个端点差 10 倍,只有 9.3% 的资源标了「最后修改时间」
开发语言·数据库·python·数据分析·api·数据治理·开放数据
IT毕设梦工厂1 小时前
计算机毕业设计选题推荐:基于大数据的草鱼价格分析与可视化|毕业设计选题|计算机毕设|选题推荐|毕设指导|项目定制|源码|高质量项目
大数据·hadoop·python·数据挖掘·数据分析·课程设计·大数据毕设项目
GISHUB1 小时前
基于QGIS 3.44开发Python插件完整教程
python·qgis
大数据魔法师1 小时前
curl_cffi从入门到实战
爬虫·python
Sylvia33.1 小时前
火星数据体育API|一站式接入足球篮球电竞等18+项目实时数据
java·开发语言·python·websocket·游戏
程序员清风2 小时前
LangGraph 入门:用状态机设计可靠的 Agent 工作流
人工智能·python
Data_Journal2 小时前
使用 AutoScraper 进行网页抓取:分步教程
大数据·开发语言·数据库·python·scrapy