使用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播放的效率还是有点低的,要先编码成图片。但是作为一些小工具来讲,可以接受。

相关推荐
蛐蛐蛐7 分钟前
昇腾910B4上安装新版本CANN的正确流程
人工智能·python·昇腾
m0_7020365313 分钟前
mysql如何处理不走索引的OR查询_使用UNION ALL优化重写
jvm·数据库·python
2401_8463395638 分钟前
MySQL在云环境如何选择存储类型_SSD与高性能云盘配置建议
jvm·数据库·python
2601_957780841 小时前
Claude 4.6 对阵 GPT-5.4:2026 开发者大模型 API 选型深度解析
人工智能·python·gpt·ai·claude
2601_957780841 小时前
GPT-5.5 深度解析:2026年4月OpenAI旗舰模型的技术跨越与商业决策指南
大数据·人工智能·python·gpt·openai
zhaoyong2222 小时前
SQL如何统计每个用户的首次行为时间_MIN聚合与分组
jvm·数据库·python
2501_901006472 小时前
C#怎么实现配置热更新 C#如何在运行时动态刷新配置文件不需要重启程序【技巧】
jvm·数据库·python
m0_470857642 小时前
HTML怎么创建响应式图片备选方案_HTML srcset与sizes结构【详解】
jvm·数据库·python
2301_795099743 小时前
如何优化SQL中大批量数据的物理删除_分批次与间隔控制
jvm·数据库·python
阿kun要赚马内3 小时前
后端数据操作组合:Pydantic与ORM
后端·python·orm·sqlalchemy