我是靠谱客的博主 粗暴白昼,这篇文章主要介绍Opencv根据USB摄像头PID\VID号,获取对应摄像头索引,现在分享给大家,希望可以做个参考。

1.引言

电脑插多个USB摄像头时,当插拔或者开机之后,Opencv对应的摄像头索引会发生改变,导致Opencv打开摄像头会开错,比如笔记本自带一个摄像头,插上一个USB摄像头时,有时自带的摄像头索引是0,有时是1。十分困扰,因此本文通过获取摄像头设备的VID与PID号(这两个号是出厂自带的,不会发生改变),获取对应的Opencv索引值,打开摄像头。为了方便使用,本人将其导出动态库文件,并采用C++或Python调用该动态库。

温馨提示:同一厂家出的同一型号摄像头,他的vid和pid是一样的,利用上述方法就不得行,所以你可以在购买摄像头的时候跟客服说,让他们给每个摄像头不同的vidpid号,我经常在淘宝买摄像头,他们可以提供这个服务。

2.C++程序导出动态库

windows下获取所有摄像头VIDPID,及其索引的程序参考【通过Opencv打开指定摄像头的方法】。本人环境为vs2019,注意在属性设置里面,高级→字符集→使用多字节字符集

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream> #include <string> #include <vector> #include <DShow.h> #include <CString> #include <atlstr.h> #pragma comment(lib,"Strmiids.lib") #define LRDLLTEST_EXPORTS //先定义宏 #ifdef LRDLLTEST_EXPORTS #define LRDLLTEST_API __declspec(dllexport) #else #define LRDLLTEST_API __declspec(dllimport) #endif extern "C" LRDLLTEST_API int getCamIDFromPidVid(const char* pidvid); LRDLLTEST_API int getCamIDFromPidVid(const char* pidvid) { // example std::string pidvid = "0001"; std::vector<std::string> devList; //设备列表 int iCameraNum = 0; //设备个数 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); std::string strStr; strStr = sdev.GetBuffer(0); //std::cout << "----:n" << strStr<<std::endl; devList.push_back(strStr); iCameraNum++; pPropBag->Release(); } pMoniker->Release(); } } } //std::cout << devList.size() << std::endl; for (int i = 0; i < devList.size(); i++) { std::cout << devList[i] << std::endl; } int iRet = -1; //对比,得到id,没有符合的就返回-1 for (int i = 0; i < devList.size(); i++) { int index = devList[i].find(pidvid); if (index != -1) { iRet = i; break; } } CoUninitialize(); return iRet; }

程序编写完毕之后,在配置一下属性,方便导出动态库,如下。然后生成解决方案

 生成完毕,将在x64/Release文件夹下生成python_ues_cpp.dll与python_ues_cpp.lib,python_ues_cpp是我自己的名字,实际名字是根据你的方案来的。

3.python调用

查看usb设备的vid和pid,输出是这样的,也可以在设备管理器里面看

 

设备管理器里面的vid和pid是大写的字母(其实是16进制),在程序中我们使用的时候要改成小写

所以我们在程序中指定一些关键词就可,简单的调用程序如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# -*- coding: utf-8 -*- from ctypes import * import cv2 fileName="python_use_cpp.dll" func=cdll.LoadLibrary(fileName) string=bytes("vid_0001&pid_0001",encoding="utf-8") #string="vid_0001&pid_0001".encode() a=func.getCamIDFromPidVid(string) print(a) cap = cv2.VideoCapture(a,cv2.CAP_DSHOW) # 摄像头的ID不同设备上可能不同 while 1: ret,img0=cap.read() if not ret: continue cv2.imshow('result', img0) key =cv2.waitKey(1) # 1 millisecond if key & 0xFF == ord('q') or key == 27: break cv2.destroyAllWindows()

3.C++调用

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream> #include <opencv2/opencv.hpp> // //#pragma comment (lib,"python_use_cpp.lib") extern "C" __declspec(dllexport) int getCamIDFromPidVid(const char* pidvid); int main(int avgc, char** argv) { const char* pidvid = "vid_0001&pid_0001"; int A = getCamIDFromPidVid(pidvid); //int A=getCamIDFromPidVid(argv[1]); std::cout << A << std::endl; cv::VideoCapture camera0(A, cv::CAP_DSHOW); if (!camera0.isOpened()) { std::cout << "can not open" << std::endl; return 1; } while (true) { cv::Mat frame0; camera0 >> frame0; cv::imshow("frame", frame0); char c = cv::waitKey(1); if (c == 27) { break; cv::destroyAllWindows(); } } return 0; }

最后

以上就是粗暴白昼最近收集整理的关于Opencv根据USB摄像头PID\VID号,获取对应摄像头索引的全部内容,更多相关Opencv根据USB摄像头PID\VID号内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(108)

评论列表共有 0 条评论

立即
投稿
返回
顶部