使用pysimplegui+opencv编写一个摄像头的播放器

需求

使用pysimplegui和opencv实现一个播放器,播放 摄像头的画面。

代码实现

python 复制代码
import cv2
import time
from typing import Iterable, NamedTuple, Optional

import PySimpleGUI as sg

class CameraSpec(NamedTuple):
    name: str
    index: int
    width: int
    height: int
    fps: int

def init_window(theme_name: str = "DarkBlack", window_name: str = "UVC capture"):
    print(f"init theme with name {theme_name!r}")
    sg.theme(theme_name)

    layout = [
      [sg.Text('UVC Demo', size=(60, 1), justification='center')],
      [sg.Image(filename='', key='-IMAGE-')],
      [sg.Button('退出', size=(10, 1), key='-Exit-')]
    ]

    print(f"init window with name {window_name!r}")
    window = sg.Window(window_name, layout, location=(10, 10), resizable=True)
    return window

def main(camera_spec: CameraSpec):
    print(f"init {camera_spec.index}th camera with name {camera_spec.name}")
    capture = cv2.VideoCapture(camera_spec.index)
    if capture == None:
        print(f"No matching camera with CameraSpec {camera_spec} found")
        return
    
    size = (int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    print(f"get size:{size}")

    wret = capture.set(cv2.CAP_PROP_FRAME_WIDTH, camera_spec.width)
    hret = capture.set(cv2.CAP_PROP_FRAME_HEIGHT, camera_spec.height)
    print(f"wret:{wret} hret:{hret}")
    size = (int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    print(f"get size:{size}")

    
    window = init_window(window_name=camera_spec.name)
    #last_update = time.perf_counter()

    try:
        keep_running = True
        i  = 0
        while keep_running:
            before = time.perf_counter()
            event, values = window.read(timeout=5)
            if event == '-Exit-' or event == sg.WIN_CLOSED:
                break

            after_event = time.perf_counter()
            print(f"====after_event:{after_event-before}====")

            try:
                _, frame = capture.read()
            except TimeoutError:
                pass
            else:
                after_frame = time.perf_counter()
                print(f"after_frame:{after_frame-after_event}")

                #将每一帧编码成png播放
                imgbytes = cv2.imencode('.png', frame)[1].tobytes()
                
                after_show = time.perf_counter()
                print(f"after_show:{after_show-after_frame}")
                print(f"sum:{after_show-before}")
                window['-IMAGE-'].update(data=imgbytes)

                #cv2.imshow(camera_spec.name, bgr)  
                # if cv2.waitKey(1) & 0xFF == 27:
                #    break  
                # with open(f"bgr{i}.bgr",'wb') as f:
                #     f.write(bgr)
                # i += 1
    except KeyboardInterrupt:
        pass

    capture.close()
    print(f"close camera:{camera_spec}")


if __name__ == "__main__":
    main(
            CameraSpec(
                name="播放摄像头测试",
                index=0, #摄像头编号
                width=1280,
                height=720,
                fps=10,
            ),

    )

效果:

代码说明

打开摄像头:

python 复制代码
capture = cv2.VideoCapture(camera_spec.index)

从摄像头取帧:

python 复制代码
_, frame = capture.read()

将帧送到窗口播放:

python 复制代码
#将每一帧编码成png图片
imgbytes = cv2.imencode('.png', frame)[1].tobytes()
window['-IMAGE-'].update(data=imgbytes)  #这里播放

由于使用PySimpleGUI的Image作为播放控件,所以每一帧都要转换成图片。除了png, 好像tif也可以,我没试。

从这里也可以看出来,pysimplegui播放的效率还是有点低的,要先编码成图片。但是作为一些小工具来讲,可以接受。

相关推荐
likerhood1 小时前
java中`==`和`.equals()`区别
java·开发语言·python
qq_283720052 小时前
Python Celery + FastAPI + Vue 全栈异步任务实战
vue.js·python·fastapi
2401_885885042 小时前
营销推广短信接口集成:结合营销策略实现的API接口动态变量填充方案
前端·python
telllong3 小时前
Python异步编程从入门到不懵:asyncio实战踩坑7连发
开发语言·python
lulu12165440785 小时前
Claude Code Harness架构技术深度解析:生产级AI Agent工程化实践
java·人工智能·python·ai编程
7年前端辞职转AI7 小时前
Python 文件操作
python·编程语言
龙文浩_7 小时前
AI梯度下降与PyTorch张量操作技术指南
人工智能·pytorch·python·深度学习·神经网络·机器学习·自然语言处理
呱牛do it7 小时前
企业级绩效考核系统设计与实现:基于FastAPI + Vue3的全栈解决方案
python·fastapi
7年前端辞职转AI7 小时前
Python 容器数据类型
python·编程语言
云霄IT7 小时前
安卓开发之java转dex再转smali
android·java·python