PyQt5学习笔记--摄像头实时视频展示、多线程处理、视频编解码

news2025/1/21 8:50:19

目录

1--前言

2--基于Qt Designer设计ui文件

3--视频的编解码操作

4--完整代码

5--结果展示

6--存在的问题

7--参考


1--前言

① 创建两个线程,主线程为ui线程,子线程用于读取摄像头视频,将处理后的图像帧数据(处理操作可以人为添加)返回到主线程进行可视化;

② 子线程向主线程传递视频帧数据集涉及图像的编码操作,主线程接收子线程的数据时涉及图像的解码操作;

2--基于Qt Designer设计ui文件

3--视频的编解码操作

① 编码操作:

# 图像编码函数
def Encoder(self, img):
    retval, buffer = cv2.imencode('.jpg', img)
    jpg_as_bytes = base64.b64encode(buffer)
    jpg_as_str = jpg_as_bytes.decode('ascii')
    json_object = json.dumps({'img_str': jpg_as_str})
    return json_object

注:img 为 opencv 读取图像的格式(默认uint8, BGR);  编码后的数据 json_object 可以直接通过signal.emit(json_object) 进行发送。

② 解码操作:

# 图片解码函数
def Decoder(self, img_json):
    jpg_as_str = json.loads(img_json)['img_str']
    jpg_as_bytes = jpg_as_str.encode('ascii')
    jpg_original = base64.b64decode(jpg_as_bytes)
    jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
    img = cv2.imdecode(jpg_as_np, flags=1)
    return img

注:输入的 img_json 与编码函数生成的 json_object 格式相同;解码生成的 img 可以通过cv2.imshow("window_name", img) cv2.waitKey(0)进行显示。

4--完整代码

import sys
import time

import json
import cv2
import base64
import numpy as np

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import uic

# 子线程1:打开摄像头,返回当前帧图像到主线程
class Open_Cam(QThread):
    Open_Cam_signal = pyqtSignal(str)  # 接受来自主线程的信号

    def __init__(self, main_signal):
        super().__init__()
        # 信号绑定槽函数
        self.Open_Cam_signal.connect(self.Open_Cam)
        self.opencam_complete_signal = main_signal  # 返回主线程的信号

    def Open_Cam(self, Cam):
        # 将json字符串转换
        Cam_index = json.loads(Cam)  # 0
        cap = cv2.VideoCapture(Cam_index)
        fps = cap.get(cv2.CAP_PROP_FPS)
        while True:
            ret, self.frame = cap.read()
            '''
            这里你可以添加对图像进行处理的操作
            '''
            json_object = self.Encoder(self.frame)  # 对图片进行编码
            self.opencam_complete_signal.emit(json_object)  # 发送编码到主线程
            cv2.waitKey(int((1 / fps) * 1000))

    # 图像编码函数
    def Encoder(self, img):
        retval, buffer = cv2.imencode('.jpg', img)
        jpg_as_bytes = base64.b64encode(buffer)
        jpg_as_str = jpg_as_bytes.decode('ascii')
        json_object = json.dumps({'img_str': jpg_as_str})
        return json_object

    def run(self):
        while True:  # 让子线程一直运行,等待主线程(ui线程)下发的任务
            print("子线程1正在等待执行....")
            time.sleep(2)

class MyWindow(QWidget):
    opencam_complete_signal = pyqtSignal(str)  # 子线程返回摄像头图像到主线程的信号

    def __init__(self):
        super().__init__()
        self.init_ui()
        self.cam_idx = 0

    def init_ui(self):
        self.ui = uic.loadUi("./Cam.ui")  # 加载由Qt Designer设计的ui文件

        # 加载控件
        self.open_cam_btn = self.ui.pushButton
        self.cam_view = self.ui.graphicsView

        # 绑定槽函数
        self.open_cam_btn.clicked.connect(self.open_cam)
        self.opencam_complete_signal.connect(self.view_cam)

        self.Opencam_Thread = Open_Cam(self.opencam_complete_signal)  # 子线程1
        self.Opencam_Thread.start()  # 子线程1运行,等待下发任务

    def open_cam(self):  # 给子线程1发送打开摄像头的信号
        self.Opencam_Thread.Open_Cam_signal.emit(json.dumps(self.cam_idx))

    def view_cam(self, img_json):  # 接受来自子线程1返回的摄像头数据
        self.img_json = img_json
        img = self.Decoder(self.img_json)
        frame = QImage(img, img.shape[1], img.shape[0], img.strides[0], QImage.Format_RGB888).rgbSwapped()
        pix = QPixmap.fromImage(frame)
        item = QGraphicsPixmapItem(pix)  # 创建像素图元
        scene = QGraphicsScene()  # 创建场景
        scene.addItem(item)
        self.cam_view.setScene(scene)  # 将场景添加至视图
        self.cam_view.fitInView(item)  # 自适应大小

    # 图片解码函数
    def Decoder(self, img_json):
        jpg_as_str = json.loads(img_json)['img_str']
        jpg_as_bytes = jpg_as_str.encode('ascii')
        jpg_original = base64.b64decode(jpg_as_bytes)
        jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
        img = cv2.imdecode(jpg_as_np, flags=1)
        return img

if __name__ == '__main__':
    app = QApplication(sys.argv)  # 创建对象

    w = MyWindow()
    # 展示窗口
    w.ui.show()

    # 程序进行循环等待状态
    app.exec_()

5--结果展示

6--存在的问题

上述代码存在当关闭ui窗口时,子线程不会自动结束的问题,后续将补充如何解决这个问题的方案。

7--参考

使用python将opencv中读取的numpy矩阵json序列化

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

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

相关文章

开放域类型发现:Open Relation and Event Type Discovery with Type Abstraction

1 什么是type discovery? “relation discovery” (Yao et al., 2011; Marcheggiani and Titov, 2016),“open relation extraction” (Wu et al., 2019; Hu et al., 2020) and “event type induction” (Huang and Ji, 2020; Shen et al., 2021). In this paper, we unify …

[项目](美多商城)(数据库课设/软件工程大作业/软件工程课设)项目的创建、配置、说明文档与源码

文章目录💘 相关说明💘 美多商城前台前端项目创建与配置💖 项目的创建💖 配置UI组件库💝 安装💝 全局引入与全局注册💝 局部引入与局部注册💝 定制主题💖 配置axios&…

【并发】Java并发线程池底层原理详解与源码分析(上)

【并发】Java并发线程池底层原理详解与源码分析(上) 线程池与线程对比 使用线程的方式运行 使用线程池的方式运行 分析 单线程、多线程、线程池效率问题 详细代码 结果分析 单线程为什么是最快的? 单线程都这么快了,我…

第四周 牛背山云海——拍拍大场景,自拍延时片段

目录4.1 面对广阔云海拍张全景照片,再来一组延时片段4.2 认识镜头滤镜4.3 补充技术基础知识:白平衡、色温4.4 小博士课堂——延时摄影课件4.1 面对广阔云海拍张全景照片,再来一组延时片段 云海 雪山 雅安境内的牛背山拍摄云海 牛背山可以看到…

java刷题day 04

一. 单选题: 解析:队列:先到先服务解析:final不能修饰接口,成员变量可以用final修饰 解析: A: 算法是指解题方案的准确而完整的描述,算法不等于程序,也不等于计算方法 BC…

Linux 时间同步 ntpdchrony 内网

Linux 时间同步 ntpd&chrony 在任何服务器集群中,为了更好的协同工作,除了一些互信机制外,需要的就是时间同步功能,如果时间不同步,就好比让在中国的同事与美国的同事进行沟通,会造成各种奇奇怪怪的时…

excel笔记

1.快速填充 当需要提取出电子邮件里的名称,可以在第一行里手动输入Nancy后,直接按快捷键ctrl e进行快速填充,可以直接获得预期数据 如果不用快捷键,也可以点击指定位置的图标,实现这一功能 快速填充不仅可以将进行…

大数据中的R语言——中国大学MOOC课程笔记

第一章 R语言简介 1.1 简介 R的特性: • 免费的 • 一个全面的统计研究平台 • 拥有顶尖水准的制图功能 • 一个可进行交互式数据分析和探索的强大平台 • 轻松地从各种类型的数据源导入数据,包括文本文件、数据库管理系统、统计软件,乃…

rabbitMQ 消息顺序性、消息幂等性、消息不丢失、最终一致性、补偿机制、消息队列设计

一、消息顺序性 消息队列中的若干消息如果是对同一个数据进行操作,这些操作具有前后的关系,必须要按前后的顺序执行,否则就会造成数据异常。 举例:   比如通过mysql binlog进行两个数据库的数据同步,由于对数据库的…

内存和函数

程序的内存布局 Linux默认情况下将高地址的1GB空间分配给内核,用户进程使用剩下2GB或者3GB的内存空间。在用户空间里,也有很多地址区间有特殊的地位,一般来讲,应用程序使用的内存空间里有如下"默认"的区域 1、栈&#…

疫情可视化part2

前言 这是疫情可视化最开始的文章,有需要了解的可前往查看:https://blog.csdn.net/xi1213/article/details/126824752。 本来说有时间就把这个项目完结了的,结果后面一直有事拖着,直到现在十一月份了才搞完。老样子,先…

F1. 生活在树上(easy version)树,dfs

题目链接 F1. 生活在树上(easy version) 题目背景 本题是 B 组的最后一题,是 F2 题的简单版本,两道题目的解法略有不同。本题和 F2 题在题意上的区别在于本题给定树上的边权,而不是点权。 小智生活在「传智国」&am…

汽车 Automotive > SOME/IP VS DDS调研和未来方向

参考:JASPAR, General incorporated association:What is the conqueror in the SOA platform for the future in-vehicle networks? 目录 SOME/IP介绍参考 DDS介绍 SOME/IP VS DDS 研究方向 SOME/IP介绍参考 汽车Automotive > SOME/…

MAC安全(防MAC泛洪攻击)

一、MAC地址表项分类: 1.1 动态表项:通过对帧内的源MAC进行学习而来,有老化时间 1.2 静态表项:由管理员手工配置,不会老化 1.3 黑洞表项:丢弃特定源MAC或目的MAC,不会老化 静态和黑洞表项不会被动态表项…

类与对象(下篇)

类与对象(下)再谈构造函数回顾构造函数初始化列表explicit 关键字拷贝构造函数也具有初始化列表友元 friend友元函数输入输出流的重载友元类static 成员内部类再谈构造函数 回顾构造函数 在上一篇博客中提到了构造函数,构造函数其主要目的是…

类与对象(中篇)

类中六个默认成员函数构造函数基本概念构造函数特性析构函数基本概念析构函数特性拷贝构造函数基本概念拷贝构造函数特性赋值运算符重载概念引入运算符重载函数的特性部分运算符的重载函数判等赋值前置 、前置--后置、后置--const 成员函数取地址只要生成一个类 ,那…

iOS_Custom Transition Animation 自定义转场动画

文章目录1、push-pop 动画协议2、present-dismiss 动画协议3、实现转场动画协议3.1 动画时长3.2 push or present animation (显示动画)3.3 动画结束3.4 pop or dismiss animation (消失动画)4、UIPresentationController4.1 设置presentVC的frame4.2 present 动画4.3 dismiss …

Docker快速安装Oracle 12c

【Oracle系列3】Docker快速安装Oracle 12c 背景 现在还很多企业用12c,以这个版本为例,介绍docker快速启动Oracle并做实验 步骤 1、docker环境的安装(略) 2、查询镜像,挑选镜像 docker search oracle结果 StoneM…

阿里P8架构师都在学习参考的SpringCloud微服务实战文档

我一直在使用Spring Boot、Spring Data等框架来进行开发工作。 作为一名Spring系列的忠实粉丝,我自然希望能够有更多的开发者参与进来,于是自己坚持写Spring Cloud相关的文章,并且将文章涉及的代码整理后放在GitHub上分享。 这使我得到了很…

【Hack The Box】Linux练习-- Luanne

HTB 学习笔记 【Hack The Box】Linux练习-- Luanne 🔥系列专栏:Hack The Box 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 📆首发时间:🌴2022年11月24日🌴 &#x1f3…