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

在Ubuntu下链接多个usb相机时,通过OpenCV打开,只能通过,cv2.VideoCapture(index)来打开指定相机,但是一般情况哪个先上电,哪个index就是0,没法确定打开的是哪个相机。

最后通过端口重映射到新的固定名字,并且设置其权限为可读。使用对应的id端口映射到固定的名字上(看不懂无所谓,按教程来,往下走)终端输入:

sudo vi /etc/udev/rules.d/rplidar.rules

1.按i,进入编辑模式

2.复制以下代码,修改ID,自定义设备的名字,在此特别注意

在我使用的 ubuntu 18.04 环境下,插入一个 usb 相机,会出现两个 /dev/video*,这不是 bug 而是 v4l2 的特性。这里直接给出解决办法,参考了这个问题下的回答,加入 ATTR{index}=="0"来获取真实设备,对于多个 usb 摄像头的话,采用类似规则,ID 号查找的方式不变

KERNEL=="video*", ATTR{index}=="0",ATTRS{idVendor}=="038f", ATTRS{idProduct}=="6001", MODE:="0777", SYMLINK+="people_video"

3.按Esc,输入 :wq (保存退出)创建生效后重新插拔一下USB摄像头或者执行一下命令

sudo service udev reload
sudo service udev restart

查看USB摄像头是否重映射:

ls -l /dev |grep video

 可以看到已经映射成功

4.在Ubuntu下打开摄像头

平时是这样的

cap = cv2.VideoCapture(0) # 打开USB摄像头对象

现在就可以精准打开指定摄像头了

cap = cv2.VideoCapture("/dev/people_video")  # 打开人体识别摄像头
cap = cv2.VideoCapture("/dev/goods_video")  # 打开物体识别摄像头

这样就可以打开指定的摄像头,虽然有点曲线救国,但是完美解决问题

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux获取USB相机PID(产品标识符)和VID(供应商标识符)并打开指定相机可以通过以下步骤进行: 1. 确保已插入USB相机并已连接到计算机上。 2. 打开终端窗口,并使用以下命令列出所有已连接的USB设备及其信息: ``` lsusb ``` 3. 在输出列表中查找与相机相关的信息。通常可以在方括中找到类似于 "VID:PID" 的标识符。例如,[1234:5678]。其中,1234代表VID,5678代表PID。记住这些标识符以供后续使用。 4. 使用相应的编程语言(如C),创建一个程序来打开指定相机设备。可以使用Linux的udev机制或者libusb库来进行操作。以下是使用libusb库的示例: ```c #include <stdio.h> #include <libusb-1.0/libusb.h> #define VID 1234 // 替换为实际的VID #define PID 5678 // 替换为实际的PID int main() { libusb_device_handle *dev_handle; libusb_context *ctx = NULL; int r = libusb_init(&ctx); if (r < 0) { fprintf(stderr, "无法初始化libusb库\n"); return 1; } dev_handle = libusb_open_device_with_vid_pid(ctx, VID, PID); if (dev_handle == NULL) { fprintf(stderr, "无法打开指定相机\n"); libusb_exit(ctx); return 1; } // 在此处插入相机操作的代码 libusb_close(dev_handle); libusb_exit(ctx); return 0; } ``` 替换代码中的`VID`和`PID`为相机的实际标识符,并在代码中添加相机操作的逻辑。例如,使用libusb库的`libusb_bulk_transfer`函数进行数据传输等。 通过以上步骤,你可以获取USB相机PID/VID打开指定相机,以便进行后续的操作。请注意,具体实现可能因相机Linux发行版而有所不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值