在基于OpenCV的項目中,實際開發過程會面臨設備上存在多個攝像頭,需要指定攝像頭的pid和vid打開攝像頭。在OpenCV通過MSMF打開攝像頭時,需要傳入攝像頭的index,因此需要在打開該攝像頭前需要找出攝像頭的index,下面給出通過微軟的MF API找出MSMF枚舉攝像頭index的代碼:
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <string>
#include <vector>
#include <iostream>
#include <opencv2/opencv.hpp>#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")struct CameraInfo {int index; // OpenCV 攝像頭索引int vid; // Vendor ID (e.g., 0x046D for Logitech)int pid; // Product ID (e.g., 0x0825 for C920)std::string symbolicLink; // 設備符號鏈接
};// 獲取所有 Media Foundation 攝像頭的 PID/VID
std::vector<CameraInfo> getMFCameraList() {std::vector<CameraInfo> cameras;IMFAttributes* pAttributes = nullptr;IMFActivate** ppDevices = nullptr;UINT32 count = 0;// 初始化 Media FoundationMFStartup(MF_VERSION);// 配置設備枚舉參數(僅視頻采集設備)MFCreateAttributes(&pAttributes, 1);pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);// 枚舉設備MFEnumDeviceSources(pAttributes, &ppDevices, &count);for (UINT32 i = 0; i < count; i++) {WCHAR* symbolicLink = nullptr;UINT32 length = 0;// 獲取設備 Symbolic Link(包含 VID/PID)ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,&symbolicLink,&length);if (symbolicLink) {std::wstring ws(symbolicLink);std::string devicePath(ws.begin(), ws.end());// 解析 VID/PID(格式:\\?\usb#vid_xxxx&pid_xxxx...)size_t vidPos = devicePath.find("vid_");size_t pidPos = devicePath.find("pid_");if (vidPos != std::string::npos && pidPos != std::string::npos) {std::string vidStr = devicePath.substr(vidPos + 4, 4);std::string pidStr = devicePath.substr(pidPos + 4, 4);int vid = std::stoi(vidStr, nullptr, 16);int pid = std::stoi(pidStr, nullptr, 16);cameras.push_back({-1, vid, pid, devicePath});}CoTaskMemFree(symbolicLink);}ppDevices[i]->Release();}if (pAttributes) pAttributes->Release();if (ppDevices) CoTaskMemFree(ppDevices);MFShutdown();return cameras;
}// 匹配 OpenCV 攝像頭索引
int findOpenCVCameraIndex(int targetVid, int targetPid) {auto cameras = getMFCameraList();int opencvIndex = 0;while (true) {cv::VideoCapture cap(opencvIndex, cv::CAP_MSMF);if (!cap.isOpened()) {break; // 沒有更多攝像頭}// 檢查當前攝像頭是否匹配目標 PID/VIDfor (const auto& cam : cameras) {if (cam.vid == targetVid && cam.pid == targetPid) {std::cout << "Found camera at OpenCV index: " << opencvIndex << std::endl;cap.release();return opencvIndex;}}cap.release();opencvIndex++;}return -1; // 未找到
}int main() {// 示例:查找 Logitech C920(VID=0x046D, PID=0x0825)int targetVid = 0x046D;int targetPid = 0x0825;int cameraIndex = findOpenCVCameraIndex(targetVid, targetPid);if (cameraIndex != -1) {cv::VideoCapture cap(cameraIndex, cv::CAP_MSMF);if (cap.isOpened()) {std::cout << "Successfully opened target camera!" << std::endl;// 進行視頻捕獲...}} else {std::cerr << "Target camera not found." << std::endl;}return 0;
}