本文详细介绍使用ubuntu+opencv采集多个免驱相机图像方法,包括绑定串口号和采集图像两个部分。使用多个免驱相机时,每次上电都可能导致相机的串口号发生变化。同时,如果是多个同一厂商相机还会因为相同的pid和vid,那么处理起来和绑定单一设备略有区别。
先通过usb确定一下相机是否连接成功:

插入相机前后,通过lsusb查看连接的设备,根据两次终端输出结果获得新插入的相机信息。如上图,下面倒数第3行的设备属于新添加的相机设备。其中ID需要着重记录:05a3 9230。这两个分别是供应商id和产品id,用于在串口绑定中发挥作用。
确定相机设备:
终端输入 ll /dev/video* 查找所有相机设备:
可以看到有两个相机设备,实际此时只插入一个相机设备。每个相机都会生成两个设备,其中偶数是能获得图像的设备。如果电脑上连接多个相机设备,需要在程序中通过opencv的 cv::VideoCapture 类定义一个相机对象,并通过.read函数读取设备采集的图像。
图像获取:
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
cv::VideoCapture cap;
cap.open("/dev/video0");
//或者cap.open(0);
cv::Mat right_frame;
cap.read(right_frame);
if (right_frame.empty())
{
cout << "没有读取到图像,串口号不对" << endl;
}
else
{
imshow("src", right_frame);
}
waitKey(1);
}
通过更改cap里面的设备编号(如:cap.open("/dev/video2)),检测连接的相机是哪个,如果设备号正确会获得相应的图像,设备编号直接从偶数号验证。

找到是哪个相机设备后,需要进行设备端口绑定,之后重新上电依然能找到该设备。
端口绑定
单一相机:
进入ubuntu的规则文件进行修改,在终端跳转到对应的规则文件 cd /etc/udev/rules.d ,然后新建立一个规则文件,如命名为actioncamera.rules,在该目录下终端输入sudo gedit actioncamera.rules,会进入编辑规则文件
文件中输入:
KERNEL =="video*[02468]",ATTRS{idVendor}== "05a3",ATTRS{idProduct}=="9230",GROUP="video",MODE="0777",SYMLINK+= "video_left"
其中idVendor是前面的vid, idProduct是前面查询到的pid,GROUP表示设备组别,MODE是权限,0777表示相机设备具有读写权限,SYMLINK是设备映射的别名,可以在绑定之后通过链接该别名读取设备采集到的图像,等同于前面的"/dev/video0"。但是有了这个别名,之后使用该设备就不会因为重新上电导致串口号出错了。
保存该文件,并在终端输入以下指令:
sudo udevadm control --reload
sudo service udev restart
最后重新插拔usb串口就完成串口的绑定。
之后的图像采集中直接使用"/dev/video_left" 即可。
多个相机:
如果是多个相机是不同厂商或者同一厂商但是不同类型的产品,只要pid和vid中有一个不一样就可以和单个相机类似编写规则文件即可。如果是pid vid完全相同的情况,需要在规则文件中添加一些额外的信息加以区分。在文章多usb摄像头串口设备名固定和永久授权_多路video设备号不固定问题-CSDN博客中提供了一种根据不同KERNELS的方法,不过在我自己设备尝试时候仍然不能正确绑定相机设备,因此本文提供一种根据devpath进行区分的方法:
首先确定好每个设备(以两个相机为例):
然后输出每个相机设备的详细信息
找到ATTRS{devpath}:
同样的方法输出video2的详细信息:
然后在规则文件里加入devpath限制,如下:
KERNEL =="video*[02468]",ATTRS{devpath}=="10.1",ATTRS{idVendor}== "05a3",ATTRS{idProduct}=="9230",GROUP="video",MODE="0777",SYMLINK+= "video_left"
KERNEL =="video*[02468]",ATTRS{devpath}=="1",ATTRS{idVendor}== "05a3",ATTRS{idProduct}=="9230",GROUP="video",MODE="0777",SYMLINK+= "video_right"
然后同样的方法重启,
sudo udevadm control --reload
sudo service udev restart
最终重新列出相机设备:
说明绑定成功。之后可以使用"/dev/video_left"和"/dev/video_right"读取相机设备。
几点注意事项:
单个usb口驱动能力有限,如果使用hub连接到usb上尽量不要连接多个相机设备,否则可能导致带宽不够不能同时获得两个相机图像。据说可以通过减小图像分辨率解决(未验证),方便起见多相机不要插入同一个usb串口。
通过devpath绑定的相机不要换usb口,因为devpath对应的也是实际的主机串口,因此相机设备要连接最初绑定的串口。
参考文献: