如何在Python Tkinter中获取摄像头名称(含虚拟摄像头)并实现选看画面?
解决摄像头名称枚举与实时画面显示问题
OpenCV本身无法直接获取摄像头的设备名称,要识别包括虚拟摄像头在内的所有设备并获取其名称,可借助Windows的DirectShow接口,通过pywin32库封装调用(无需直接编写Windows API代码)。以下是完整实现方案:
1. 安装依赖库
执行以下命令安装所需包:
pip install pywin32 opencv-python
2. 完整实现代码
import cv2 import tkinter as tk from tkinter import ttk import win32com.client # 枚举所有摄像头(包括虚拟摄像头)并获取名称 def enumerate_cameras(): camera_dict = {} # 初始化DirectShow设备枚举器 enumerator = win32com.client.Dispatch("SystemDeviceEnum") video_category = enumerator.CreateClassEnumerator("{860BB310-5D01-11D0-BD3B-00A0C911CE86}", 0) if video_category is None: return camera_dict # 遍历所有视频输入设备 while True: try: device = video_category.Next() friendly_name = device.Name # 获取设备路径(用于OpenCV打开) moniker = device.Moniker prop_bag = moniker.BindToStorage(None, None, "{55272A00-42CB-11CE-8135-00AA004BB851}") device_path = prop_bag.Read("DevicePath") # 测试设备是否可打开(排除不可用的设备) cap = cv2.VideoCapture(device_path, cv2.CAP_DSHOW) if cap.isOpened(): cap.release() camera_dict[friendly_name] = device_path except StopIteration: break return camera_dict # 更新摄像头画面 def update_frame(cap, label): ret, frame = cap.read() if ret: # 转换颜色空间:OpenCV是BGR,Tkinter需要RGB frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 转成Tkinter可用的PhotoImage img = tk.PhotoImage(width=frame_rgb.shape[1], height=frame_rgb.shape[0]) img.put(data=frame_rgb.tobytes(), format="RGB") label.config(image=img) label.image = img # 保留引用避免被垃圾回收 # 每隔10ms更新一次 label.after(10, update_frame, cap, label) # 选择摄像头后的回调函数 def on_camera_selected(event): selected_name = camera_menu.get() device_path = cameras[selected_name] # 关闭之前的摄像头(如果存在) if hasattr(on_camera_selected, 'cap'): on_camera_selected.cap.release() # 打开选中的摄像头 on_camera_selected.cap = cv2.VideoCapture(device_path, cv2.CAP_DSHOW) # 启动画面更新 update_frame(on_camera_selected.cap, video_label) # 初始化Tkinter窗口 root = tk.Tk() root.title("摄像头实时画面") root.geometry("640x520") # 枚举摄像头 cameras = enumerate_cameras() if not cameras: tk.Label(root, text="未检测到任何摄像头").pack(pady=20) root.mainloop() exit() # 创建下拉菜单 camera_menu = ttk.Combobox(root, values=list(cameras.keys()), state="readonly") camera_menu.current(0) camera_menu.pack(pady=10) camera_menu.bind("<<ComboboxSelected>>", on_camera_selected) # 用于显示视频的标签 video_label = tk.Label(root) video_label.pack() # 初始化显示第一个摄像头的画面 initial_path = cameras[list(cameras.keys())[0]] on_camera_selected.cap = cv2.VideoCapture(initial_path, cv2.CAP_DSHOW) update_frame(on_camera_selected.cap, video_label) root.mainloop() # 程序结束时释放摄像头 if hasattr(on_camera_selected, 'cap'): on_camera_selected.cap.release()
代码说明
- 枚举摄像头:通过
win32com.client调用DirectShow枚举器,筛选视频输入设备,获取设备的友好名称和设备路径,并用OpenCV测试设备是否可用。 - 下拉菜单:使用
ttk.Combobox创建下拉选择框,绑定选择事件以切换摄像头。 - 实时画面显示:将OpenCV捕获的BGR帧转换为RGB格式,转为Tkinter的
PhotoImage后显示,通过after方法定时更新画面。 - 设备兼容性:使用
cv2.CAP_DSHOW作为OpenCV的捕获后端,更好地支持虚拟摄像头。
内容的提问来源于stack exchange,提问作者333pwn
相关产品推荐
相关产品推荐

