You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 07:55:21