Pyqt5设计打开电脑摄像头+可选择哪个摄像头(如有多个)

目录

专栏导读

🌸 欢迎来到Python办公自动化专栏---Python处理办公问题,解放您的双手

🏳️‍🌈 博客主页:请点击------> 一晌小贪欢的博客主页求关注

👍 该系列文章专栏:请点击------>Python办公自动化专栏求订阅

🕷 此外还有爬虫专栏:请点击------>Python爬虫基础专栏求订阅

📕 此外还有python基础专栏:请点击------>Python基础学习专栏求订阅

文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏

❤️ 欢迎各位佬关注! ❤️

库的安装

安装 作用
PyQt5 pip install PyQt5 界面设计
opencv-python pip install opencv-python==4.3.0.38 识别匹配图片

代码介绍

1、CameraApp 类:这是主要的应用窗口,继承自 QWidget。里面有一个 QLabel 用于显示摄像头视频流。

2、cv2.VideoCapture(0):OpenCV 用来打开默认摄像头。参数 0 表示系统的默认摄像头。

3、QTimer:每 30毫秒触发一次 update_frame(),从摄像头读取新帧并更新到窗口。

4、cv2.cvtColor:OpenCV 默认读取的图片是BGR 格式,转换成 RGB 格式才能显示在 QLabel 上

5、关闭按钮:点击按钮可以关闭摄像头并退出应用。

1、摄像头选择功能:

新增了一个 QComboBox 下拉菜单用于选择可用的摄像头,摄像头列表通过 get_available_cameras() 函数动态生成。

当用户选择不同摄像头时,change_camera() 会触发并切换到对应摄像头。

2、get_available_cameras():

该函数循环遍历可用摄像头索引,通过 cv2.VideoCapture(index) 检查摄像头是否可用,并将其添加到可选项中。

3、start_camera():

负责启动选定的摄像头,并释放之前的摄像头。

4、change_camera():

当用户在下拉菜单中选择不同的摄像头时,调用该函数来切换摄像头。

1、resizeEvent():

重写了 resizeEvent() 方法,当窗口大小发生变化时,会触发该事件,并调用 update_frame() 更新摄像头画面,使其随窗口的大小变化动态调整。

2、self.label.setAlignment(Qt.AlignCenter):

使摄像头画面居中显示,保证在窗口改变时画面居中。

3、scaled() 方法:

使用 QImage.scaled() 方法,将摄像头画面按窗口大小比例缩放,保持宽高比,确保画面不会变形。

1、Qt.WindowStaysOnTopHint:

在 self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) 中添加了该标志,以确保窗口永远保持在屏幕的最上层。

2、窗口大小策略:

使用 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding),允许窗口自由扩大或缩小,并且设置了最小窗口尺寸,防止窗口缩得过小无法使用。

3、self.setMinimumSize(400, 300):

设置了窗口的最小尺寸,避免缩小到无法正常显示摄像头画面。

4、Qt.WindowStaysOnTopHint:

仍然保持"窗口置顶"功能,确保窗口在其他应用程序上方。

完整代码

python 复制代码
import sys
import cv2
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QPushButton, QComboBox, QHBoxLayout, QSizePolicy
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QImage, QPixmap

class CameraApp(QWidget):
    def __init__(self):
        super().__init__()

        # 初始化UI界面
        self.setWindowTitle("摄像头实时画面")
        self.setGeometry(100, 100, 800, 600)

        # 设置窗口永远置顶
        self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)

        # 设置窗口大小策略,允许自由调整
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setMinimumSize(400, 300)  # 设置最小窗口尺寸,避免窗口缩得过小

        # 设置布局
        self.main_layout = QVBoxLayout()
        self.controls_layout = QHBoxLayout()

        # QLabel用于显示摄像头画面
        self.label = QLabel(self)
        self.label.setAlignment(Qt.AlignCenter)  # 居中对齐
        self.main_layout.addWidget(self.label)

        # 摄像头选择下拉菜单
        self.camera_selector = QComboBox(self)
        self.available_cameras = self.get_available_cameras()
        self.camera_selector.addItems(self.available_cameras)
        self.camera_selector.currentIndexChanged.connect(self.change_camera)
        self.controls_layout.addWidget(self.camera_selector)

        # 添加关闭按钮
        self.button = QPushButton('关闭摄像头', self)
        self.button.clicked.connect(self.close_camera)
        self.controls_layout.addWidget(self.button)

        self.main_layout.addLayout(self.controls_layout)
        self.setLayout(self.main_layout)

        # 打开默认摄像头
        self.capture = None
        self.current_camera_index = 0
        self.start_camera(self.current_camera_index)

        # 定时器更新视频流
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_frame)
        self.timer.start(30)  # 每30ms更新一次画面

    def get_available_cameras(self):
        # 获取可用摄像头的列表
        index = 0
        available_cameras = []
        while True:
            cap = cv2.VideoCapture(index)
            if not cap.read()[0]:  # 没有更多的摄像头
                break
            available_cameras.append(f"Camera {index}")
            cap.release()
            index += 1
        return available_cameras

    def start_camera(self, camera_index):
        # 开启选定的摄像头
        if self.capture is not None:
            self.capture.release()  # 释放前一个摄像头
        self.capture = cv2.VideoCapture(camera_index)

    def change_camera(self, index):
        # 切换摄像头
        self.current_camera_index = index
        self.start_camera(self.current_camera_index)

    def update_frame(self):
        if self.capture is not None and self.capture.isOpened():
            ret, frame = self.capture.read()
            if ret:
                # 将OpenCV的BGR格式转换为RGB格式
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                h, w, ch = frame.shape
                bytes_per_line = ch * w
                convert_to_Qt_format = QImage(frame.data, w, h, bytes_per_line, QImage.Format_RGB888)

                # 动态调整图片大小,适应窗口的大小
                scaled_image = convert_to_Qt_format.scaled(self.label.width(), self.label.height(), Qt.KeepAspectRatio)
                self.label.setPixmap(QPixmap.fromImage(scaled_image))

    def close_camera(self):
        # 关闭摄像头
        if self.capture is not None:
            self.capture.release()
        self.close()

    def resizeEvent(self, event):
        # 重写resizeEvent,当窗口大小改变时触发
        if self.capture is not None and self.capture.isOpened():
            self.update_frame()  # 窗口大小变化时更新显示的画面
        super().resizeEvent(event)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CameraApp()
    window.show()
    sys.exit(app.exec_())

总结

希望对初学者有帮助

致力于办公自动化的小小程序员一枚

希望能得到大家的【一个免费关注】!感谢

求个 🤞 关注 🤞

此外还有办公自动化专栏,欢迎大家订阅:Python办公自动化专栏

求个 ❤️ 喜欢 ❤️

此外还有爬虫专栏,欢迎大家订阅:Python爬虫基础专栏

求个 👍 收藏 👍

此外还有Python基础专栏,欢迎大家订阅:Python基础学习专栏

相关推荐
幽兰的天空3 分钟前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10223 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou3 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
安静读书3 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
----云烟----5 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024065 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
小二·5 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it5 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康6 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud