1.背景

最近在写摄像头部分的代码,构建一个UI界面,想要做个摄像头端口刷新的功能,在combbox里面刷新摄像头,根据选择的摄像头打开对应的摄像头,网上收到了资料使用PyCameraList库,最终能够调用摄像头端口号,但是这样有一个缺点,同一台笔记本的三个端口,当同一个外置摄像头插到不同的端口时,他为0为1的情况不固定,而我调用cv2来打开摄像头的时候,这个0,1的位置编号很重要,需要详细确定到底是哪个位置,才能真正实现我选摄像头的功能。

2.解决方法

尝试网上搜索各种资料,没有合适的库来解决这个问题,最后只能根据已有的相关思路,去找解决办法。思路,通过CMD命令行读取到相关数据,发现设备在命令行的位置是会随着插入端口的变化而变化的,在CMD中的指令如下:

powershell "Get-PnpDevice -PresentOnly | Where-Object { $_.InstanceId -match 'USB' } "

该指令可以直接在CMD命令中输入,在powershell中使用如下命令:

Get-PnpDevice -PresentOnly | Where-Object { $_.InstanceId -match \'USB\' }

得到如下结果:

Status     Class           FriendlyName                                                                     InstanceId
------     -----           ------------                                                                     ----------
OK         USB             通用 USB 集线器                                                                  USB\VID_...
OK         Camera          HD camera                                                                        USB\VID_...
OK         USB             USB 根集线器(USB 3.0)                                                            USB\ROOT...
OK         UCM             UCM-UCSI ACPI 设备                                                               ACPI\USB...
OK         Ports           USB-SERIAL CH340 (COM3)                                                          USB\VID_...
OK         Camera          Integrated Camera                                                                USB\VID_...
OK         USB             USB Composite Device                                                             USB\VID_...
OK         HIDClass        USB 输入设备                                                                     USB\VID_...
OK         USB             USB Composite Device                                                             USB\VID_...
OK         HIDClass        USB 输入设备                                                                     USB\VID_...
OK         USB             USB 根集线器(USB 3.0)                                                            USB\ROOT...
OK         USB             USB Composite Device                                                             USB\VID_...
OK         Bluetooth       Realtek Bluetooth Adapter                                                        USB\VID_...

我要区分的是上图的Intergrated Camera 和 HD camera 的相对位置,通过这个命令,可以很明显的做出区分,之后就是引用到代码中,主要用到subprocess 中的Popen,该模块能直接调用cmd命令,该部分代码如下:

from subprocess import Popen, PIPE
obj = Popen('powershell "Get-PnpDevice -PresentOnly | Where-Object { $_.InstanceId -match \'USB\' } "', shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
out, err = obj.communicate()

out里面存的就是CMD的命令结果,也就是上面命令的执行结果,然后进行如下运算,通过算法去纠正Camera的端口排序:

if not len(err):
    data = out.decode('gbk')
    for i in range(len(Camera_ports)):
         temp_ports.append(data.index(Camera_ports[i]))
        # 读取有异常无需执行后续排序
else:
    print("error")
    return
# 根据位置大小重新排序
order = sorted(temp_ports)
# 对端口重新赋给键值,通过键值确定当前端口位置
for i in range(len(Camera_ports)):
    new_dict[temp_ports[i]] = Camera_ports[i]
# 根据键值的位置进行重新排序,确定摄像头的前后顺序
for i in range(len(Camera_ports)):
    Camera_ports[i] = new_dict[order[i]]
return Camera_ports

但是该方法有个缺点,整体执行时间大概要0.5s在界面运行的时候可以很明显的感觉到会卡一下

3.结论

该方式暂时解决了眼前的问题,但是并不是很好,绕了个大弯来解决这个问题,暂时用用,不作为永久对策