Windows10下用OpenCV获取USB摄像头唯一ID及按ID连接方法
解决Windows下OpenCV获取USB摄像头唯一ID及通过ID连接的问题
一、获取摄像头唯一ID
OpenCV的VideoCapture本身没有直接提供获取摄像头硬件唯一ID的API,需要借助Windows系统的设备枚举接口实现。可以通过comtypes库调用DirectShow接口枚举视频输入设备,获取每个设备的唯一标识(如设备实例ID、设备路径)。
实现步骤与代码
首先安装依赖库:
pip install comtypes
枚举设备并提取唯一ID的代码:
import comtypes from comtypes import GUID, HRESULT from comtypes.client import CreateObject # 定义DirectShow相关接口与CLSID class IEnumMoniker(comtypes.IUnknown): _iid_ = GUID("{00000102-0000-0000-C000-000000000046}") _methods_ = [ HRESULT("Next", ([comtypes.HRESULT], comtypes.c_ulong, comtypes.POINTER(comtypes.POINTER(comtypes.IUnknown)), comtypes.POINTER(comtypes.c_ulong))), HRESULT("Skip", ([comtypes.HRESULT], comtypes.c_ulong)), HRESULT("Reset", ([comtypes.HRESULT])), HRESULT("Clone", ([comtypes.HRESULT], comtypes.POINTER(comtypes.POINTER(IEnumMoniker)))), ] class ICreateDevEnum(comtypes.IUnknown): _iid_ = GUID("{29840822-5B84-11D0-BD3B-00A0C911CE86}") _methods_ = [ HRESULT("CreateClassEnumerator", ([comtypes.HRESULT], comtypes.POINTER(GUID), comtypes.POINTER(comtypes.POINTER(IEnumMoniker)), comtypes.c_ulong)), ] CLSID_SystemDeviceEnum = GUID("{62BE5D10-60EB-11D0-BD3B-00A0C911CE86}") CLSID_VideoInputDeviceCategory = GUID("{860BB310-5D01-11D0-BD3B-00A0C911CE86}") def get_camera_devices(): devices = [] # 创建系统设备枚举器 dev_enum = CreateObject(CLSID_SystemDeviceEnum, interface=ICreateDevEnum) # 获取视频输入设备枚举器 enum_moniker = comtypes.POINTER(IEnumMoniker)() dev_enum.CreateClassEnumerator(CLSID_VideoInputDeviceCategory, comtypes.byref(enum_moniker), 0) if enum_moniker: moniker = comtypes.POINTER(comtypes.IMoniker)() fetched = comtypes.c_ulong(0) while enum_moniker.Next(1, comtypes.byref(moniker), comtypes.byref(fetched)) == 0: prop_bag = moniker.BindToStorage(None, None, comtypes.IID_IPropertyBag) # 读取设备名称 name = comtypes.VARIANT() prop_bag.Read("FriendlyName", comtypes.byref(name), None) # 读取硬件唯一ID(设备实例ID) dev_id = comtypes.VARIANT() prop_bag.Read("DeviceInstanceId", comtypes.byref(dev_id), None) # 读取设备路径(用于直接连接) dev_path = comtypes.VARIANT() prop_bag.Read("DevicePath", comtypes.byref(dev_path), None) devices.append({ "name": name.value, "device_id": dev_id.value, "device_path": dev_path.value }) moniker.Release() enum_moniker.Release() return devices # 调用函数获取所有摄像头信息 cameras = get_camera_devices() for idx, cam in enumerate(cameras): print(f"索引 {idx}: 名称={cam['name']}, 唯一ID={cam['device_id']}, 设备路径={cam['device_path']}")
运行后会输出每个摄像头的名称、硬件唯一ID(device_id,不受连接顺序/USB端口变化影响)和设备路径。
二、通过唯一ID连接摄像头
OpenCV的CAP_MSMF后端支持直接使用设备路径(而非整数索引)创建VideoCapture实例,以此实现通过唯一ID关联连接的需求。
实现代码示例
import cv2 # 先枚举设备,筛选目标摄像头 cameras = get_camera_devices() # 根据唯一ID筛选目标设备(替换为你的摄像头ID) target_cam = next(cam for cam in cameras if "USB\\VID_XXXX&PID_XXXX" in cam["device_id"]) # 使用设备路径创建VideoCapture cap = cv2.VideoCapture(target_cam["device_path"], cv2.CAP_MSMF) # 验证连接状态 if cap.isOpened(): print("摄像头连接成功") # 读取帧测试 ret, frame = cap.read() if ret: cv2.imshow("Camera", frame) cv2.waitKey(0) cap.release() cv2.destroyAllWindows()
关键注意点
- 若已通过整数索引创建
cap实例,无法直接从该实例反向获取唯一ID(OpenCV未存储此信息),建议先枚举设备拿到ID和路径,再用路径创建连接。 - 设备路径可能随USB端口变化,但
device_id(硬件ID)始终唯一,可用于长期标识摄像头。 - 必须指定
cv2.CAP_MSMF后端,这是Windows下支持设备路径连接的可靠后端。
内容的提问来源于stack exchange,提问作者jxw
相关产品推荐
相关产品推荐

