我们使用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 <iostream>
#include <string>
#include <vector>
#include <DShow.h>
#include <CString>
#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<CString> 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<void**>(&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<void**>(&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<devList.size();i++)
	{
		int index = devList[i].Find(pidvid);
		if(index != -1)
		{
			iRet = i;
			break;
		}
	}

	CoUninitialize();
	return iRet;
}

GitHub 加速计划 / opencv31 / opencv
77.38 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:2 个月前 )
c3747a68 Added Universal Windows Package build to CI. 12 天前
9b635da5 - 12 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐