我们使用Opencv打开摄像头,一般是使用VideoCapture的open接口。
CV_WRAP virtual bool open(int index);
open接口要传入一个标识符,如果只有1个摄像机,那么就是0,如果系统中有多个摄像机,那么只要将其向上增加即可。
系统:
银河麒麟linux系统
问题:
现在我插入了一个双目摄像头(两个USB线,一个彩色,一个红外),那我就想打开彩色的,怎么办呢?每次我插入USB线,系统都会默认给设备分配一个video路径,例如 /dev/video3,根据插入USB线的顺序,每次分配的都不一样,这样通过open就不能指定打开哪一个。
解决思路:
每个设备都有自己的pid和vid,我要通过pid和vid找到特定的/dev/video,例如我获取到了路径 /dev/video3,那么取最后的数字3,通过open(3),即可打开指定的摄像头。需要使用libudev。
下面的函数是通过遍历所有的视频设备,再用摄像头的pid和vid与其对比,最后得到摄像头的路径。(这里注意麒麟linux和UOS系统,打开的序号可能会相差1,所以UOS系统需要可能要再-1)
int findCameraVideoPath(char *pid, char *vid, char *dpath)
{
struct udev *udev = NULL;
struct udev_enumerate *udev_enumerate = NULL;
struct udev_list_entry *list_entry = NULL;
int count = 0;
int flag = 0;
char devName[128]={0};
udev = udev_new();
if(udev == NULL)
{
//tips
return 0;
}
udev_enumerate = udev_enumerate_new(udev);
if(udev_enumerate == NULL)
{
//tips
return 0;
}
udev_enumerate_add_match_subsystem(udev_enumerate, "video4linux");
udev_enumerate_scan_devices(udev_enumerate);
udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate))
{
struct udev_device *device;
device = udev_device_new_from_syspath(udev_enumerate_get_udev(udev_enumerate), udev_list_entry_get_name(list_entry));
if(device!=NULL)
{
//tips
);
if(udev_device_get_property_value(device, "ID_VENDOR_ID")!=NULL &&
udev_device_get_property_value(device, "ID_MODEL_ID")!=NULL &&
!strcmp(vid, udev_device_get_property_value(device, "ID_VENDOR_ID")) &&
!strcmp(pid, udev_device_get_property_value(device, "ID_MODEL_ID")))
{
sprintf(devName,"/dev/video%s", udev_device_get_sysnum(device));
flag = 1;
count++;
}
udev_device_unref(device);
}
else
{
//tips
}
}
if(flag!=0)
{
if(strlen(devName)>0)
memcpy(dpath, devName, strlen(devName));
}
udev_enumerate_unref(udev_enumerate);
udev_unref(udev);
return flag;
}
下面附上win系统MFC的事例,与上面思路类似:
#include
#include
#include
#include
#include
#pragma comment(lib,"Strmiids.lib")
using namespace std;
//输入:pidvid exp: vid_1234&pid_1234
//输出:ID, 为-1则找不到设备
int getCamIDFromPidVid(char* pidvid)
{
int iRet = -1;
int iCameraNum = 0; //设备个数
vector devList; //设备列表
CString str ;
ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;
HRESULT hr = NULL;
CoInitialize(NULL);
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,reinterpret_cast(&pDevEnum));
if (SUCCEEDED(hr))
{
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEnum,0);
if (hr == S_OK)
{
//枚举捕获设备
IMoniker *pMoniker = NULL;
ULONG cFetched;
while (pEnum->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag,reinterpret_cast(&pPropBag));
if (SUCCEEDED(hr))
{
//获取设备路径,路径里包含pidvid的信息
VARIANT varName;
varName.vt = VT_BSTR;
VariantInit(&varName);
hr = pPropBag->Read(L"DevicePath", &varName, 0); //read函数只能够读取CLSID, FriendlyName, DevicePath这三种
CString sdev(varName);
devList.push_back(sdev);
iCameraNum ++;
pPropBag->Release();
}
pMoniker->Release();
}
}
}
//对比,得到id
for(int i = 0;i