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.结论
该方式暂时解决了眼前的问题,但是并不是很好,绕了个大弯来解决这个问题,暂时用用,不作为永久对策