Ubuntu下如何获取usb相机的PID/VID并打开指定的相机

项目需求控制和打开两个USB摄像头,并且根据相机的PID和VID来打开指定的相机,来区分主副相机,在Windows下可以通过AForge.Video.DirectShow库来实现,但是Ubuntu下没这个库,找了很多资料也没找到Ubuntu下怎么实现,最后只能借助Libusb库来实现,虽然不是很理想,但是应该可以勉强实现。

第一步:  先来了解  什么是USB Device Path/ 什么是PID、VID

Windows操作系统通过一个“设备路径”来唯一“标识”接入系统中的USB设备/接口,这个"设备路径"就是USB Device Path。USB Device Path 常常被传入 Win32 的API函数 CreatFile() 来与USB设备建立通信。更多解释参见 Windows USB Device Path,当然Ubuntu下也有。

VID和PID唯一标识一个设备,HardwareID是为了给系统识别的 ,他是根据PID/VID而生成的。这个与序列号没什么关系,序列号一般都是厂家固化到芯片中的信息而已。GUID只是为了标志你安装的设备是属于一个什么类当中,这个类可以显示再设备管理器中。比如:你可以定义一个类,当然这个类有与系统中任何类都不同的GUID,然后选择一个图标和类名,就可以同网卡等其他设备一起显示在设备管理器下的根目录中了

根据USB规范的规定,所有的USB设备都有供应商ID(VID)和产品识别码(PID),主机通过不同的VID和PID来区别不同的设备,VID和PID都是两个字节长,其中,供应商ID(VID)由供应商向USB执行论坛申请,每个供应商的VID是唯一的,PID由供应商自行决定,理论上来说,不同的产品、相同产品的不同型号、相同型号的不同设计的产品最好采用不同的PID,以便区别相同厂家的不同设备。

VID和PID通常情况下有两种存储方式,第一种是主控生产商的VID和PID,存储在主控的bootcode中;第二种是设备生产商的VID和PID,该VID和PID存储在主控外部的非易失性存储设备中(EEPROM或Flash)的设备固件中,当USB设备连接主机时,如果固件中有设备生产商的VID和PID,会将该VID和PID报告给主机,而忽略主控生产商的VID和PID。所以理论上一个USB存储设备的VID应该是设备生产商的VID,而不是主控生产商的VID,这两个VID应该是不同的(主控生产商自己生产的设备除外)。

由于VID和PID重复并不会对产品的使用带来严重影响,很多USB设备生产商(山寨厂居多)为了方便,并不会向USB执行论坛申请自己的VID,而是依然沿用主控生产商的VID或随便向产品写入VID和PID;同时,正规厂家只需要申请VID,PID由厂家自行确定,所以存在相同型号的产品,可能采用了不同的主控(商业需要,很正常),而他们的PID是一样的,基于上述原因通过VID和PID就不能准确识别USB设备的主控型号,这个问题大家在使用USB设备的过程中需要注意。

第二步:查看USB Device Path的方法

Windows系统下

1、鼠标右键“我的电脑”,选择“管理”,进入“计算机管理”。

2、在“计算机管理”界面,依次选择“设备管理器”、“图像设备”、摄像头的型号,选中点击鼠标右键,选择“属性”

选择硬件id,就可以看到usb相机的vid,pid是0x18EC,0x3399(这个是我电脑这款usb相机的pid、vid,不同的设备pid、vid是不一样的)的设备,右击属性里找到 Device instance path,别急,这还不是全部的USB Device Path。

最终 USB Device Path 组成格式是:\\?\(第一部分,固定的), hid#vid_1fc9&pid_0130#a&2eb8245&0&0000(第二部分,即Device instance path,\用#替换), #{4d1e55b2-f16f-11cf-88cb-001111000030}"(第三部分,HID类型标识值前加个#)。另外注意在脚本里写入此参数时需要用双引号括起来,类似如下:

"\\?\hid#vid_1fc9&pid_0130#6&20AC856D&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"

第三步:程序获取USB Device Path方法:

windows下,C#可以通过AForge.Video.DirectShow库来获取,并且非常方便,获取方法如下

 public static FilterInfoCollection videoDevices;
  // 枚举所有视频输入设备
 videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
 videoDevices[i].MonikerString   //返回值就是Device instance path

Ubuntu下获取方法1:

因为python可以跨平台,Windows下可以Ubuntu下都可以用:但是Windows下需要把dll放到系统目录。Ubuntu下不需要

pip3 install PyQt5

pip3 install pyqt5-tools

pip install pyusb

Download libusb from libusb releases

解压 libusb-xxx.7z并且把\MS64\dll\libusb-1.0.dll复制到C:\Windows\System32

代码如下:

# FileName : usbdemo.py
# Author   : Adil
# DateTime : 2019/9/1 10:26
# SoftWare : PyCharm
import usb

all_devs = usb.core.find(find_all=True)

print(all_devs)
for d in all_devs:
    if (d.idVendor == 'VID_04F2') & (d.idProduct == 'PID_B541'):
        print(d)

用libusb库的时候需要用知道usb相机的个数,因为libusb获取到的usb设备很多不是摄像头设备

import cv2

class Camera:
    def __init__(self, cam_preset_num=10):
        self.cam_preset_num = cam_preset_num

    def get_cam_num(self):
        cnt = 0
        for device in range(0, self.cam_preset_num):
            stream = cv2.VideoCapture(device)

            grabbed = stream.grab()
            stream.release()
            if not grabbed:
                break
            cnt = cnt + 1

        return cnt

if __name__ == '__main__':
    cam = Camera()
    cam_num = cam.get_cam_num()
    print(cam_num)

Ubuntu下获取方法2:

Ubuntu下所以的信息都是以文件形成储存,所以可以通过读取设备文件来区别索引号和pid 、vid

    def get_usb_camera_index(self):
        # 获取USB摄像头的索引
        camera_path = Path('/sys/class/video4linux/')
        camera_list = list(camera_path.glob('video*'))
        camera_list.sort()
        index = 0
        for i in range(len(camera_list)):
            camera = camera_list[i]
            name_file = camera.joinpath('name')
            with open(name_file, 'r') as f:
                info = f.readline()
                if 'USB' in info:
                    index = i
                    break
        return index

暂时先这样,后续再补充吧……

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 3
收藏 2
关注 19
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧