opencv 多线程读取和显示摄像头【python源码】

news2025/1/12 3:59:28

在Python中,使用OpenCV库实现多线程读取和显示摄像头通常涉及创建多个线程,每个线程负责从摄像头捕获视频帧并显示它们。但是,请注意,OpenCV本身并不直接支持多线程显示,因为cv2.imshow通常是在主线程中运行的。然而,你可以使用多线程来捕获视频帧,并将这些帧放入一个队列中,然后在主线程中处理并显示它们。

以下是一个使用Python的threading模块和OpenCV库来实现多线程摄像头捕获和显示的示例代码:

import cv2  
import threading  
import queue  
  
# 线程安全的队列  
q = queue.Queue()  
  
# 捕获摄像头的函数  
def capture_video(cap, q):  
    while True:  
        ret, frame = cap.read()  
        if not ret:  
            break  
        # 将捕获的帧放入队列  
        q.put(frame)  
    cap.release()  
  
# 显示视频的函数  
def show_video(q):  
    while True:  
        if not q.empty():  
            # 从队列中获取帧  
            frame = q.get()  
            cv2.imshow('Camera Feed', frame)  
              
            # 按 'q' 键退出  
            if cv2.waitKey(1) & 0xFF == ord('q'):  
                break  
        else:  
            # 如果没有帧,稍微等待一下  
            cv2.waitKey(1)  
    cv2.destroyAllWindows()  
  
# 主函数  
def main():  
    # 打开摄像头  
    cap = cv2.VideoCapture(0)  
    if not cap.isOpened():  
        print("Error: Could not open camera.")  
        return  
  
    # 创建捕获和显示视频的线程  
    capture_thread = threading.Thread(target=capture_video, args=(cap, q))  
    show_thread = threading.Thread(target=show_video, args=(q,))  
  
    # 启动线程  
    capture_thread.start()  
    show_thread.start()  
  
    # 等待线程结束  
    capture_thread.join()  
    show_thread.join()  
  
    cv2.destroyAllWindows()  
  
if __name__ == "__main__":  
    main()

在上面的代码中,capture_video函数负责从摄像头捕获视频帧,并将它们放入一个线程安全的队列中。show_video函数从队列中取出帧并在窗口中显示它们。两个函数分别在不同的线程中运行,通过队列来通信。

请注意,这段代码没有实现多个摄像头的同时捕获和显示。如果你需要同时显示来自多个摄像头的视频,你需要为每个摄像头创建一个捕获线程,并可能需要为每个摄像头创建不同的显示窗口。但是,由于cv2.imshow的限制,你可能需要实现更复杂的逻辑来在多个窗口中轮询显示视频帧。

在实际应用中,如果需要处理多个摄像头的视频流,并且希望每个摄像头都有自己的显示窗口,通常更好的做法是使用图形用户界面(GUI)库(如PyQt或Tkinter)来管理窗口和事件循环,而不是依赖OpenCV的imshow函数。这些GUI库通常提供了更灵活的多线程和多窗口支持。
在这里插入图片描述

拓展

主线程:界面显示、其他逻辑处理
#线程1:opencv读取摄像头到界面中
#线程2:采集数据显示到界面中
#逻辑:
from demo import Ui_MainWindow
点击按钮detect_Button则打开摄像头,再次点击detect_Button则关闭摄像头;
实时显示摄像头画面并且更新到主界面Ui_MainWindow中;
实时采集线程2中的数据,并且更新到主界面Ui_MainWindow中

要实现您描述的功能,我们需要用到Python的threading模块来创建和管理线程,以及OpenCV库来读取摄像头的视频流。首先,确保已经安装了OpenCV库,如果没有安装,可以通过以下命令安装:

bash
pip install opencv-python
接下来,我们需要编写主逻辑。这里假设您已经有了一个demo.py文件,其中包含了Ui_MainWindow类,这个类应该是一个基于Qt Designer生成的UI界面类。下面是一个简单的例子,演示了如何实现您的要求:

import sys  
import threading  
import cv2  
from PyQt5.QtWidgets import QApplication, QMainWindow  
from PyQt5.QtGui import QImage, QPixmap  
from PyQt5.QtCore import pyqtSignal, QThread  
from demo import Ui_MainWindow  
  
class CameraThread(QThread):  
    # 定义一个信号,用来发送图像数据到主线程  
    update_image_signal = pyqtSignal(QImage)  
  
    def __init__(self, camera_id):  
        super(CameraThread, self).__init__()  
        self.camera_id = camera_id  
        self.cap = None  
  
    def run(self):  
        self.cap = cv2.VideoCapture(self.camera_id)  
        if not self.cap.isOpened():  
            print("Error: Could not open video device")  
            return  
  
        while True:  
            ret, frame = self.cap.read()  
            if ret:  
                # 将OpenCV图像转换为Qt图像  
                rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  
                h, w, ch = rgb_image.shape  
                bytes_per_line = ch * w  
                qimg = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)  
                self.update_image_signal.emit(qimg)  
  
    def stop(self):  
        self.requestInterruption()  
        self.wait()  
        if self.cap:  
            self.cap.release()  
  
class DataCollectionThread(QThread):  
    # 定义一个信号,用来发送采集的数据到主线程  
    update_data_signal = pyqtSignal(str)  
  
    def __init__(self):  
        super(DataCollectionThread, self).__init__()  
  
    def run(self):  
        while True:  
            # 这里模拟数据采集,您可以替换为实际的数据采集代码  
            data = "模拟数据: " + str(round(random.random(), 2))  
            self.update_data_signal.emit(data)  
            # 假设每秒更新一次数据  
            self.sleep(1)  
  
    def stop(self):  
        self.requestInterruption()  
        self.wait()  
  
class MainWindow(QMainWindow, Ui_MainWindow):  
    def __init__(self):  
        super(MainWindow, self).__init__()  
        self.setupUi(self)  
        self.camera_thread = CameraThread(0)  # 假设使用摄像头0  
        self.data_collection_thread = DataCollectionThread()  
        self.camera_thread.update_image_signal.connect(self.update_image)  
        self.data_collection_thread.update_data_signal.connect(self.update_data_label)  
        self.detect_Button.clicked.connect(self.toggle_camera)  
        self.camera_running = False  
  
    def toggle_camera(self):  
        if self.camera_running:  
            self.camera_thread.stop()  
            self.data_collection_thread.stop()  
            self.camera_running = False  
        else:  
            self.camera_thread.start()  
            self.data_collection_thread.start()  
            self.camera_running = True  
  
    def update_image(self, image):  
        self.label_image.setPixmap(QPixmap.fromImage(image))  
  
    def update_data_label(self, data):  
        self.label_data.setText(data)  
  
if __name__ == '__main__':  
    app = QApplication(sys.argv)  
    window = MainWindow()  
    window.show()  
    sys.exit(app.exec_())

在这个例子中,我们创建了两个线程类CameraThread和DataCollectionThread。CameraThread负责读取摄像头并发送图像信号,而DataCollectionThread

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1589204.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

imu6xl点灯(C语言)

参考正点原子开发指南 根据原理图可以看出,我们需要设置低电平导通电路。 在原理图上找到LED0,对应IO为GPIO3 IO复用配置 IMX6UL每个引脚都可以复用 在用户手册第30章可以找到IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03这个寄存器,地址为0x020E0068&…

JavaScript函数式编程

函数式编程 课程介绍 为什么要学习函数编程以及什么是函数式编程函数式编程的特性(纯函数、柯里化、函数组合等)函数式编程的应用场景函数式编程库Lodash 为什么要学习函数式编程 函数式编程是非常古老的一个概念,早于第一台计算机的诞生, 函数式编程…

gpt系列概述——从gpt1到chatgpt

GPT建模实战:GPT建模与预测实战-CSDN博客 OpenAI的GPT(Generative Pre-trained Transformer)系列模型是自然语言处理领域的重要里程碑。从2018年至2020年,该公司相继推出了GPT-1、GPT-2和GPT-3,这些模型在文本生…

是时候将 DevOps 可见性扩展到网络边缘了

尽管部署前运行了大量测试,但在部署应用程序后,性能问题经常让 DevOps 团队感到困惑。经过进一步调查,最常被忽视的问题是应用程序本身的分布式特性。从多个位置访问应用程序的最终用户永远不会拥有相同水平的互联网服务,因此在纽…

python使用ffmpeg分割视频为Hls分片文件/使用OpenSSL加密m3u8和TS文件

FFmpeg和OpenSSL是一个开源免费的软件,在官网上就能下载, FFmpage网址(建议选择文件名full结尾的文件):Builds - CODEX FFMPEG gyan.dev OpenSSL网址(建议选择win64的MSI文件):Win3…

OpenAI现已普遍提供带有视觉应用程序接口的GPT-4 Turbo

OpenAI宣布,其功能强大的GPT-4 Turbo with Vision模型现已通过公司的API全面推出,为企业和开发人员将高级语言和视觉功能集成到其应用程序中开辟了新的机会。 PS:使用Wildcard享受不受网络限制的API调用,详情查看教程 继去年 9 月…

LinkedHashMap部分底层源码解析

JDK版本为1.8.0_271,LinkedHashMap继承了HashMap,LinkedHashMap在HashMap的基础上维护了一个双向链表,实现了可以根据插入顺序/访问顺序(accessOrderfalse/true)访问Map集合。 关于HashMap的原理可以参考HashMap部分底…

IOPaint部署,实现去水印效果

下载源代码 https://github.com/Sanster/IOPaint https://github.com/advimman/lama 创建虚拟环境 conda create --prefixD:\CondaEnvs\iopaint python3.10 conda activate D:\CondaEnvs\iopaint安装依赖包 pytorch最低2.0.0 # 查看cuda版本安装对应的pytorch nvcc -V # …

Prototype 原型

意图 用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。 结构 Prototype声明一个复制自身的接口。ConcretePrototype实现一个复制自身的操作。Client让一个原型复制自身从而创建一个新的对象。 适用性 当一个系统应该独立于他的产品创建、构成和…

HashMap的常见问题

Entry中的hash属性为什么不直接使用key的hashCode()返回值呢? 不管是JDK1.7还是JDK1.8中,都不是直接用key的hashCode值直接与table.length-1计算求下标的,而是先对key的hashCode值进行了一个运算,JDK1.7和JDK1.8关于hash()的实现…

如何卸载干净 IDEA(图文讲解)

更新时间 2022-12-20 11:一则或许对你有用的小广告 星球 内第一个项目:全栈前后端分离博客项目,演示地址:Weblog 前后端分离博客, 1.0 版本已经更新完毕,正在更新 2.0 版本。采用技术栈 Spring Boot Mybatis Plus Vue 3.x Vit…

lanqiao.602 迷宫

题目&#xff1a; 代码&#xff1a; #include<iostream> #include<cstring> #include<algorithm> #include<queue> using namespace std; char mp[31][51]; //稍微开大一点 char k[4]{D,L,R,U}; //按字典序记录路径 int dirx[]{1,0,0,-1},d…

给picgo上传的图片加个水印

之前给大家介绍了picgo和免费的图床神器。我们本可以开开心心的进行markdown写作了。 但是总是会有那么一些爬虫网站过来爬你的文章&#xff0c;还把你的文章标明是他们的原著。咋办呢&#xff1f;这里有一个好的办法就是把markdown中上传的图片加上自己的水印不就行了。 说干…

【复现】CVE-2024-29269 某国外路由器RCE漏洞_72

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 在 Telesquare TLR-2005Ksh 1.0.0 和 1.1.4 中发现的一个问题允许攻击者通过 Cmd 参数运行任意系统命令。 二 .漏洞影响 通过提交…

C语言---顺序表(二)

文章目录 前言1.准备工作2.代码的实现2.1.顺序表的创建、销毁和打印2.2.顺序表的扩容、头插\删、尾插\删2.2.1.扩容2.2.2.尾插2.2.3.头插2.2.3.尾删2.2.4.头删 2.3.指定位置之前插入/删除数据/查找数据2.3.1.指定位置之前插入数据2.3.2.指定位置之前删除数据2.3.3.查找特定数据…

vue3 依赖-组件tablepage-vue3说明文档,列表页快速开发,使用思路及范例(Ⅰ)配置项文档

vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例&#xff08;Ⅰ&#xff09;配置项文档 vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例&#xff08;Ⅱ&#xff09;搜索及数据获取配…

Linux-select剖析

一、select函数 select函数是IO多路复用的函数&#xff0c;它主要的功能是用来等文件描述符中的事件是否就绪&#xff0c;select可以使我们在同时等待多个文件缓冲区 &#xff0c;减少IO等待的时间&#xff0c;能够提高进程的IO效率。 select()函数允许程序监视多个文件描述符…

旋转编码器原理(超简单)

波形图 A相和B相的状态变化与旋转方向有关。当顺时针旋转时&#xff0c;A相引脚会先变化&#xff0c;然后是B相引脚。而逆时针旋转时&#xff0c;B相引脚会先变化&#xff0c;然后是A相引脚 这是两个引脚的实际波形采样&#xff0c;越密集的旋转的越快 可以发现特点&#xff0…

Redis从入门到精通(十四)Redis分布式缓存(二)Redis哨兵集群的搭建和原理分析

文章目录 前言5.3 Redis哨兵5.3.1 哨兵原理5.3.1.1 集群的结构和作用5.3.1.2 集群监控原理5.3.1.3 集群故障恢复原理 5.3.2 搭建哨兵集群5.3.3 RedisTemplate5.3.3.1 搭建测试项目5.3.3.2 场景测试 前言 Redis分布式缓存系列文章&#xff1a; Redis从入门到精通(十三)Redis分…

Git分布式版本控制系统——Git常用命令(二)

五、Git常用命令————分支操作 同一个仓库可以有多个分支&#xff0c;各个分支相互独立&#xff0c;互不干扰 分支的相关命令&#xff0c;具体如下&#xff1a; git branch 查看分支 git branch [name] 创建分支&#x…