如何使用 OpenCV 打開指定攝像頭

在計算機視覺應用中,經常需要從特定的攝像頭設備獲取視頻流。例如,在多攝像頭環境中,當使用 OpenCV 的?cv::VideoCapture?類打開攝像頭時,如果不指定攝像頭的 ID,可能會隨機打開系統中的某個攝像頭,或者按照設備連接的順序打開第一個可用的攝像頭。
比如:

? ??// 打開兩個攝像頭cv::VideoCapture?cap0(0);if?(!cap0.isOpened()) {cap0.open(0);}cv::VideoCapture?cap1(1);if?(!cap0.isOpened() || !cap1.isOpened()) {std::cerr <<?"Error: Cannot open camera"?<< std::endl;return;}

在多攝像頭環境下,這種方式可能無法滿足應用需求。此外,直接使用攝像頭 ID 的方式可能不夠穩定,因為設備的連接順序或系統分配的 ID 可能會發生變化。

那如何使用 OpenCV 打開指定的攝像頭呢?我們知道,攝像頭都會在安裝后,操作系統會生成一個設備ID信息,

操作系統就是根據攝像頭的 PID(產品 ID)和 VID(供應商 ID)來精確識別并打開某個攝像頭的。

Image

如圖所示,對應關系分別如下:

VID_0BDA&PID_3787 (Front Camera)
VID_0BDA&PID_5846 (HBVCAM Camera)
VID_0BDA&PID_D567 (USB Camera)

解決辦法

那OpenCV是否支持在打開攝像頭時,根據個信息進行指定呢?當然可以。

在 Windows 系統中,攝像頭設備通常通過 DirectShow API 進行管理和操作。而 OpenCV 是一個功能強大的開源計算機視覺庫,提供了與攝像頭交互的接口。結合兩者的優勢,可以方便地實現對指定攝像頭的訪問。

通過以下步驟實現對指定攝像頭的打開:

  1. 1. 使用 DirectShow API 枚舉系統中的攝像頭設備,并獲取每個設備的詳細信息,包括設備路徑、PID 和 VID 等。

  2. 2. 根據用戶指定的 PID 和 VID,在設備列表中查找匹配的設備,并獲取其對應的設備 ID。

  3. 3. 使用 OpenCV 的?cv::VideoCapture?類,結合設備 ID 和 DirectShow API,打開指定的攝像頭設備。

以下是完整的 C++ 代碼,展示了如何使用 OpenCV 和 DirectShow API 打開指定 PID 和 VID 的攝像頭:

#include?<iostream>
#include?<vector>
#include?<string>
#include?<algorithm>
#include?<opencv2/opencv.hpp>
#include?<DShow.h>
#include?<atlstr.h>
#pragma?comment(lib,"Strmiids.lib")// 定義導出函數的宏
#ifdef?_WIN32
#define?DLL_EXPORT __declspec(dllexport)
#else
#define?DLL_EXPORT
#endif// 獲取攝像頭ID的函數
DLL_EXPORT?int?getCamIDFromPidVid(const?char* pidvid)?{std::vector<std::string> devList;?// 設備列表int?iCameraNum =?0;?// 設備個數ICreateDevEnum* pDevEnum =?NULL;IEnumMoniker* pEnum =?NULL;HRESULT hr =?CoInitialize(NULL);if?(FAILED(hr)) {std::cerr <<?"COM 初始化失敗,錯誤碼: "?<< hr << std::endl;return-1;}hr =?CoCreateInstance(CLSID_SystemDeviceEnum,?NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,?reinterpret_cast<void**>(&pDevEnum));if?(FAILED(hr)) {std::cerr <<?"創建設備枚舉器失敗,錯誤碼: "?<< hr << std::endl;CoUninitialize();return-1;}hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum,?0);if?(hr != S_OK && hr != S_FALSE) {std::cerr <<?"枚舉視頻輸入設備類別失敗,錯誤碼: "?<< hr << std::endl;pDevEnum->Release();CoUninitialize();return-1;}if?(hr == S_FALSE) {std::cerr <<?"沒有找到視頻輸入設備"?<< std::endl;pDevEnum->Release();CoUninitialize();return-1;}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)) {VARIANT varName;VariantInit(&varName);varName.vt = VT_BSTR;hr = pPropBag->Read(L"DevicePath", &varName,?NULL);if?(SUCCEEDED(hr) && varName.vt == VT_BSTR && varName.bstrVal !=?nullptr) {std::wstring?wstrDevicePath(varName.bstrVal);std::string?strDevicePath(wstrDevicePath.begin(), wstrDevicePath.end());devList.push_back(strDevicePath);iCameraNum++;}?else?{std::cerr <<?"讀取設備路徑失敗,錯誤碼: "?<< hr << std::endl;}VariantClear(&varName);pPropBag->Release();}pMoniker->Release();}pEnum->Release();pDevEnum->Release();// 將輸入的pidvid轉換為小寫std::string lowerPidvid = pidvid;std::transform(lowerPidvid.begin(), lowerPidvid.end(), lowerPidvid.begin(), ::tolower);int?iRet =?-1;for?(int?i =?0; i < devList.size(); i++) {// 將設備路徑轉換為小寫std::string lowerDevicePath = devList[i];std::transform(lowerDevicePath.begin(), lowerDevicePath.end(), lowerDevicePath.begin(), ::tolower);if?(lowerDevicePath.find(lowerPidvid) != std::string::npos) {iRet = i;break;}}CoUninitialize();return?iRet;
}// 主函數示例
int?main()?{// 替換為你的攝像頭的PID和VID,支持大寫和小寫std::string targetPidVid =?"VID_XXXX&PID_XXXX";?// 例如:"VID_046D&PID_0825"int?camId =?getCamIDFromPidVid(targetPidVid.c_str());if?(camId ==?-1) {std::cout <<?"未找到匹配的攝像頭"?<< std::endl;return-1;}std::cout <<?"攝像頭ID: "?<< camId << std::endl;// 使用OpenCV打開攝像頭cv::VideoCapture cap;cap.open(camId, cv::CAP_DSHOW);if?(!cap.isOpened()) {std::cerr <<?"無法打開攝像頭,ID: "?<< camId << std::endl;return-1;}// 嘗試讀取一幀,驗證攝像頭是否真的可用cv::Mat frame;if?(!cap.read(frame)) {std::cerr <<?"無法從攝像頭讀取幀,ID: "?<< camId << std::endl;cap.release();return-1;}std::cout <<?"攝像頭已成功打開"?<< std::endl;while?(true) {cap >> frame;if?(frame.empty()) {std::cerr <<?"無法讀取幀"?<< std::endl;break;}cv::imshow("Camera", frame);if?(cv::waitKey(1) ==?27) {?// 按ESC鍵退出break;}}cap.release();cv::destroyAllWindows();return0;
}

注意細節

  1. 1. 確保安裝了 OpenCV 庫,并正確配置了開發環境。

  2. 2. 根據實際攝像頭的 PID 和 VID 修改代碼中的?targetPidVid?變量值。

  3. 3. 在編譯代碼時,鏈接必要的庫文件,如?Strmiids.lib?和 OpenCV 相關的庫。

  4. 4. 在選擇攝像頭時,我們要確保多個攝像頭要各不一樣(這樣即可保證通過VID/PID來區分攝像頭),但每一種都要采購統一(保證在不同電腦上VID/PID都一樣)。

  5. 5. 上述相關思想也可以在?*nix?等系統中使用。

通過上述代碼和方法,可以實現根據攝像頭的 PID 和 VID 精確打開指定的攝像頭設備,適用于多攝像頭環境和需要精確設備識別的場景。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89182.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89182.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89182.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JAVA面試寶典 -《分布式ID生成器:Snowflake優化變種》

&#x1f680; 分布式ID生成器&#xff1a;Snowflake優化變種 一場訂單高峰&#xff0c;一次鏈路追蹤&#xff0c;一條消息投遞…你是否想過&#xff0c;它們背后都依賴著一個“低調卻關鍵”的存在——唯一ID。本文將帶你深入理解分布式ID生成器的核心原理與工程實踐&#xff0…

蘋果的機器學習框架將支持英偉達的CUDA平臺

蘋果專為Apple Silicon設計的MLX機器學習框架即將迎來CUDA后端支持&#xff0c;這意義重大。原因如下。 這項開發工作由GitHub開發者zcbenz主導&#xff08;據AppleInsider報道&#xff09;&#xff0c;他于數月前開始構建CUDA支持的原型。此后他將項目拆分為多個模塊&#xff…

golang語法-----變量、常量

變量1、聲明與初始化&#xff08;1&#xff09;標準聲明 (先聲明&#xff0c;后賦值)var age int // 聲明一個 int 類型的變量 age&#xff0c;此時 age 的值是 0 fmt.Println(age) // 輸出: 0age 30 // 給 age 賦值 fmt.Println(age) // 輸出: 30//int 的零…

Jenkins+Docker(docker-compose、Dockerfile)+Gitee實現自動化部署

項目目錄結構 project-root/ ├── pom.xml ├── docker │ ├── copy.sh │ ├── file │ │ ├── jar │ │ │ └── 存放執行copy.sh以后jar包的位置 │ │ └── Dockerfile │ └── docker-compose.yml ├── docker-only-test │ ├─…

TASK01【datawhale組隊學習】地瓜機器人具身智能概述

https://github.com/datawhalechina/ai-hardware-robotics 參考資料地址 具身智能&#xff08;Embodied AI&#xff09; 具身智能 智能的大腦 行動的身體。 比例&#xff08;Proportional&#xff09;、積分&#xff08;Integral&#xff09;、微分&#xff08;Derivative&a…

uni-app 配置華為離線推送流程

1、首先需要創建一個華為開發者賬號&#xff0c;我這個是個人開發賬號 申請開發者賬號 2、去AppGallery Connect登陸我們剛剛創建好的賬號&#xff0c;點擊頁面的APP進入到如下3 AppGallery Connect ????? ?3、在AppGallery Connect 網站中創建一個 Android應用、點擊…

當下主流攝像頭及其核心參數詳解

&#x1f4d6; 推薦閱讀&#xff1a;《Yocto項目實戰教程:高效定制嵌入式Linux系統》 &#x1f3a5; 更多學習視頻請關注 B 站&#xff1a;嵌入式Jerry 當下主流攝像頭及其核心參數詳解 一、攝像頭發展概述 攝像頭作為現代智能設備&#xff08;如手機、安防、車載、工業等&am…

下載了docker但是VirtualBox突然啟動不了了

今天下docker后發現 eNSP 路由器&#xff0c;防火墻啟動不了了去virtualbox檢查的時候發現無法啟動&#xff1a;報錯&#xff1a;不能為虛擬電腦 AR_Base 打開一個新任務.Raw-mode is unavailable courtesy of Hyper-V. (VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT).返回代碼: E_F…

C++11之lambda表達式與包裝器

lambda與包裝器lambda語法捕捉列表lambda的應用lambda的原理包裝器functionbindlambda語法 lambda 表達式本質是?個匿名函數對象&#xff0c;跟普通函數不同的是他可以定義在函數內部。 lambda 表達式語法使?層??沒有類型&#xff0c;所以我們?般是?auto或者模板參數定義…

有痛呻吟!!!

XiTuJueJin:YYDS 分盤 有些平臺吃相太難看&#xff0c;同樣的文章&#xff0c;我還先選擇現在這里發布&#xff0c;TMD. 莫名其妙將我的文章設置為僅VIP可見&#xff0c;還是今天才發現&#xff0c;之前只是將一兩篇設置為僅VIP可見&#xff0c;今天突然發現這種標識的都自動…

2025年7-9月高含金量數學建模競賽清單

2025年7-9月高含金量數學建模競賽 ——“高教社杯”國賽 & “華為杯”研賽作為過來人&#xff0c;真心覺得參加數學建模比賽是我本科階段做的最值的事之一。 它鍛煉的那種把實際問題轉化成模型求解的思維&#xff0c;對做研究、寫論文甚至以后工作都幫助很大。我當時就是靠…

SpringBoot為什么使用new RuntimeException() 來獲取調用棧?

為什么不直接使用 Thread.currentThread().getStackTrace()&#xff1f;這確實看起來有點“奇怪”或者“繞”&#xff0c;但其實這是 Java 中一種非常常見、巧妙且合法的技巧&#xff0c;用于在運行時動態獲取當前代碼的調用棧信息。Spring 選擇用 new RuntimeException().getS…

小白成長之路-haproxy負載均衡

文章目錄一、概述1、HAProxy簡介2、HAProxy特點和優點&#xff1a;3、HAProxy保持會話的三種解決方法4、HAProxy的balance 8種負載均衡算法1&#xff09;RR&#xff08;Round Robin&#xff09;2&#xff09;LC&#xff08;Least Connections&#xff09;3&#xff09;SH&#…

Kafka 與 RocketMQ 消息確認機制對比分析

目錄 生產者消息確認機制 Kafka 生產者 ACK 機制 RocketMQ 生產者確認機制 消費者消息確認機制 Kafka 消費者確認機制 RocketMQ 消費者確認機制 核心差異對比 選型建議 消息確認機制是分布式消息中間件的核心功能之一&#xff0c;它直接關系到消息傳遞的可靠性和系統性能…

C/C++---rdbuf()函數

在C中&#xff0c;rdbuf() 是I/O流庫中的一個核心成員函數&#xff0c;主要用于訪問和操作流對象的緩沖區。這個函數在底層數據處理、流重定向以及自定義流操作等場景中應用廣泛。下面將從多個方面詳細解析 rdbuf() 函數。 基本概念與函數原型 rdbuf() 是 std::basic_ios 類的成…

【LLM】從零到一構建一個小型LLM--MiniGPT

從零到一構建一個小型LLM (Small Language Model)暫時起名為MiniGPT。這個模型將專注于因果語言建模 (Causal Language Modeling)&#xff0c;這是許多現代LLM&#xff08;如GPT系列&#xff09;的核心預訓練任務。模型設計&#xff1a; 我們設計的模型是一個僅包含解碼器 (Dec…

網絡安全威脅下的企業困境與破局技術實踐

前言&#xff1a;網絡安全威脅下的企業困境 在數字化轉型的浪潮中&#xff0c;企業對信息技術的依賴程度日益加深&#xff0c;但隨之而來的網絡安全威脅也愈發嚴峻。據統計&#xff0c;全球每年因網絡安全事件造成的經濟損失高達數萬億美元&#xff0c;其中中小企業更是成為了網…

[RAG system] 信息檢索器 | BM25 Vector | Pickle格式 | HybridRetriever重排序

第六章&#xff1a;信息檢索器 在上一章中&#xff0c;我們成功完成了知識庫攝入流程。這是巨大的進步~ 我們精心準備了文檔"塊"&#xff08;類似獨立的索引卡&#xff09;&#xff0c;并將其存儲在兩套智能歸檔系統中&#xff1a;向量數據庫&#xff08;用于基于含…

Android 高通平臺修改音頻參數效果文件-優化音頻效果

Android 高通平臺如何音頻效果 修改音頻參數效果文件-優化音頻效果 按如下方式修改。 開發云 - 一站式云服務平臺 diff --git a/vendor/qcom/proprietary/mm-audio/audcal/family-b/acdbdata//MTP/workspaceFile.qwsp b/vendor/qcom/proprietary/mm-audio/audcal/family-b/acdb…

Install Docker Engine on UbuntuMySQL

Install Docker Engine on Ubuntu&&MySQL安裝docker安裝mysql客戶端連接數據庫我真氣鼠了&#xff0c;今天得到一個血淚的教訓&#xff0c;以后一定看官方文檔&#xff01;&#xff01;&#xff01;學的課用的centos&#xff0c;指令全是yum&#xff0c;我這邊不通用&a…