在基于OpenCV的项目中,实际开发过程会面临设备上存在多个摄像头,需要指定摄像头的pid和vid打开摄像头。在OpenCV通过MSMF打开摄像头时,需要传入摄像头的index,因此需要在打开该摄像头前需要找出摄像头的index,下面给出通过微软的MF API找出MSMF枚举摄像头index的代码:
cpp
#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 Foundation
MFStartup(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/VID
for (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;
}