Opencv根据USB摄像头PIDVID号,获取对应摄像头索引

1.引言

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

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

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

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

#include <iostream>
#include <string>
#include <vector>
#include <dshow.h>
#include <cstring>
#include <atlstr.h>
#pragma   comment(lib,"Strmiids.lib")

#define LRDLLTEST_EXPORTS //&#x5148;&#x5B9A;&#x4E49;&#x5B8F;

#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; //&#x8BBE;&#x5907;&#x5217;&#x8868;
    int iCameraNum = 0;         //&#x8BBE;&#x5907;&#x4E2A;&#x6570;

    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)
        {
            //&#x679A;&#x4E3E;&#x6355;&#x83B7;&#x8BBE;&#x5907;
            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))
                {
                    //&#x83B7;&#x53D6;&#x8BBE;&#x5907;&#x8DEF;&#x5F84;,&#x8DEF;&#x5F84;&#x91CC;&#x5305;&#x542B;pidvid&#x7684;&#x4FE1;&#x606F;
                    VARIANT varName;
                    varName.vt = VT_BSTR;
                    VariantInit(&varName);
                    hr = pPropBag->Read(L"DevicePath", &varName, 0);        //read&#x51FD;&#x6570;&#x53EA;&#x80FD;&#x591F;&#x8BFB;&#x53D6;CLSID, FriendlyName, DevicePath&#x8FD9;&#x4E09;&#x79CD;

                    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;
    //&#x5BF9;&#x6BD4;,&#x5F97;&#x5230;id,&#x6CA1;&#x6709;&#x7B26;&#x5408;&#x7684;&#x5C31;&#x8FD4;&#x56DE;-1
    for (int i = 0; i < devList.size(); i++)
    {
        int index = devList[i].find(pidvid);
        if (index != -1)
        {
            iRet = i;
            break;
        }
    }
    CoUninitialize();
    return iRet;
}
</std::endl;></void**></void**></std::string></atlstr.h></cstring></dshow.h></vector></string></iostream>

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

Opencv根据USB摄像头PIDVID号,获取对应摄像头索引

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

3.python调用

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

Opencv根据USB摄像头PIDVID号,获取对应摄像头索引

Opencv根据USB摄像头PIDVID号,获取对应摄像头索引

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

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

-*- 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) # &#x6444;&#x50CF;&#x5934;&#x7684;ID&#x4E0D;&#x540C;&#x8BBE;&#x5907;&#x4E0A;&#x53EF;&#x80FD;&#x4E0D;&#x540C;

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++调用

#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;
}
</opencv2></iostream>

Original: https://blog.csdn.net/qq_41043389/article/details/124664485
Author: 机器鱼
Title: Opencv根据USB摄像头PIDVID号,获取对应摄像头索引

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/519430/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球