使用 C/C++ 和 OpenCV 調用攝像頭

使用 C/C++ 和 OpenCV 調用攝像頭 📸

OpenCV 是一個強大的計算機視覺庫,它使得從攝像頭捕獲和處理視頻流變得非常簡單。本文將指導你如何使用 C/C++ 和 OpenCV 來調用攝像頭、讀取視頻幀并進行顯示。


準備工作

在開始之前,請確保你已經正確安裝了 OpenCV 庫,并且你的開發環境(如 Visual Studio, Code::Blocks, CLion, 或者使用 CMake/GCC 的命令行環境)已經配置好可以鏈接 OpenCV 庫。

你需要包含以下頭文件:

#include <opencv2/opencv.hpp> // 包含 OpenCV 的核心功能和高級 GUI (highgui)
#include <iostream>          // 用于標準輸入輸出

1. 打開攝像頭

要從攝像頭捕獲視頻,我們首先需要創建一個 cv::VideoCapture 對象。它的構造函數可以接受一個整數作為參數,該整數表示攝像頭的索引。通常,0 代表系統默認的內置攝像頭,1 代表第一個外部攝像頭,以此類推。

cv::VideoCapture cap; // 創建一個 VideoCapture 對象int cameraIndex = 0; // 通常 0 是默認攝像頭
cap.open(cameraIndex); // 或者直接 cv::VideoCapture cap(0);// 檢查攝像頭是否成功打開
if (!cap.isOpened()) {std::cerr << "錯誤: 無法打開攝像頭 " << cameraIndex << std::endl;return -1; // 或者進行其他錯誤處理
}

提示:

  • 你也可以傳遞一個視頻文件的路徑字符串給 cv::VideoCapture 的構造函數或 open() 方法來讀取視頻文件。
  • 如果有多個攝像頭,你可以嘗試不同的索引(0, 1, 2, …)直到找到你想要的攝像頭。

2. 讀取視頻幀

一旦攝像頭成功打開,我們就可以在一個循環中逐幀讀取視頻。cv::VideoCapture::read() 方法或重載的 >> 運算符可以用來獲取新的幀。

read() 方法會返回一個布爾值,表示是否成功讀取到一幀。讀取到的幀會存儲在一個 cv::Mat 對象中。

cv::Mat frame; // 創建一個 Mat 對象來存儲每一幀while (true) {bool success = cap.read(frame); // 讀取新的一幀// 或者 cap >> frame;if (!success || frame.empty()) {std::cerr << "錯誤: 無法從攝像頭讀取幀" << std::endl;break; // 如果讀取失敗或幀為空,則退出循環}// 在這里可以對 'frame' 進行處理,例如:// cv::cvtColor(frame, grayFrame, cv::COLOR_BGR2GRAY); // 轉換為灰度圖// cv::GaussianBlur(frame, blurredFrame, cv::Size(5, 5), 0); // 高斯模糊// ... (接下來的步驟:顯示幀)
}

3. 顯示視頻幀

OpenCV 的 highgui 模塊提供了顯示圖像和視頻的功能。我們可以使用 cv::imshow() 函數來顯示捕獲到的幀。通常還需要配合 cv::waitKey() 來控制幀的顯示時間和處理用戶輸入。

    // ... (在讀取幀的循環內部)cv::imshow("攝像頭畫面", frame); // 在名為 "攝像頭畫面" 的窗口中顯示幀// 等待按鍵,延遲 1 毫秒。// 如果按下 'ESC'鍵 (ASCII 值為 27),則退出循環// waitKey 返回按下鍵的 ASCII 值,如果沒有按鍵則返回 -1int key = cv::waitKey(1);if (key == 27) { // ESC 鍵std::cout << "ESC鍵被按下,正在關閉..." << std::endl;break;} else if (key != -1) {// 可以添加其他按鍵的邏輯// std::cout << "按鍵: " << key << std::endl;}

cv::waitKey(delay) 函數會等待指定的 delay 毫秒數。

  • 如果 delay 為 0 或負數,它會無限期等待直到有按鍵按下。
  • 如果 delay 為正數,它會等待 delay 毫秒。如果在等待期間有按鍵按下,函數會返回按鍵的 ASCII 值;否則返回 -1。
  • 對于視頻流,通常使用一個較小的值(如 1 或 30)來確保視頻流暢播放,并允許程序響應按鍵事件。

4. 釋放資源

當不再需要攝像頭或程序即將退出時,務必釋放 cv::VideoCapture 對象,并銷毀所有創建的窗口。

// ... (在主函數末尾或退出前)cap.release(); // 釋放 VideoCapture 對象
cv::destroyAllWindows(); //銷毀所有由 OpenCV 創建的窗口

雖然 cv::VideoCapture 對象在析構時會自動釋放攝像頭,但顯式調用 release() 是一個好習慣。


5. 獲取和設置攝像頭屬性 (可選)

cv::VideoCapture 對象還允許你獲取和設置攝像頭的一些屬性,例如幀的寬度、高度、FPS(每秒幀數)等。這些屬性由 cv::CAP_PROP_* 枚舉定義。

  • 獲取屬性: cap.get(cv::CAP_PROP_FRAME_WIDTH)
  • 設置屬性: cap.set(cv::CAP_PROP_FRAME_WIDTH, newValue)
// 獲取攝像頭默認的幀寬度和高度
double frameWidth = cap.get(cv::CAP_PROP_FRAME_WIDTH);
double frameHeight = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
double fps = cap.get(cv::CAP_PROP_FPS);std::cout << "默認寬度: " << frameWidth << std::endl;
std::cout << "默認高度: " << frameHeight << std::endl;
std::cout << "默認FPS: " << fps << std::endl;// 嘗試設置新的寬度和高度 (攝像頭可能不支持所有值)
// bool setWidthSuccess = cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
// bool setHeightSuccess = cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720);
// if (setWidthSuccess && setHeightSuccess) {
//     std::cout << "成功設置分辨率為 1280x720" << std::endl;
// } else {
//     std::cout << "警告: 未能成功設置期望的分辨率" << std::endl;
//     // 再次獲取實際生效的寬度和高度
//     frameWidth = cap.get(cv::CAP_PROP_FRAME_WIDTH);
//     frameHeight = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
//     std::cout << "當前寬度: " << frameWidth << std::endl;
//     std::cout << "當前高度: " << frameHeight << std::endl;
// }

注意: 并非所有攝像頭都支持通過 set() 方法修改所有屬性,或者可能只支持特定的預設值。設置后最好再次 get() 以確認實際生效的值。


完整示例代碼

下面是一個將以上所有步驟整合在一起的完整示例:

#include <opencv2/opencv.hpp>
#include <iostream>int main() {// 1. 打開攝像頭cv::VideoCapture cap;int cameraIndex = 0; // 嘗試不同的索引,如果默認攝像頭不工作cap.open(cameraIndex);// 檢查攝像頭是否成功打開if (!cap.isOpened()) {std::cerr << "錯誤: 無法打開攝像頭 " << cameraIndex << std::endl;// 嘗試下一個攝像頭索引,如果需要// cameraIndex = 1;// cap.open(cameraIndex);// if (!cap.isOpened()) {//     std::cerr << "錯誤: 仍然無法打開攝像頭 " << cameraIndex << std::endl;//     return -1;// }return -1;}std::cout << "攝像頭 " << cameraIndex << " 已成功打開." << std::endl;// (可選) 獲取和打印攝像頭屬性double frameWidth = cap.get(cv::CAP_PROP_FRAME_WIDTH);double frameHeight = cap.get(cv::CAP_PROP_FRAME_HEIGHT);double fps = cap.get(cv::CAP_PROP_FPS);std::cout << "幀寬度: " << frameWidth << std::endl;std::cout << "幀高度: " << frameHeight << std::endl;std::cout << "FPS: " << fps << std::endl; // 注意:FPS 可能不準確或不被所有攝像頭支持cv::Mat frame; // 用于存儲每一幀std::string windowName = "攝像頭畫面 - 按 ESC 退出";cv::namedWindow(windowName, cv::WINDOW_AUTOSIZE); // 創建一個窗口// 2. 讀取并顯示視頻幀while (true) {bool success = cap.read(frame); // 或者 cap >> frame;if (!success || frame.empty()) {std::cerr << "錯誤: 無法從攝像頭讀取幀或視頻已結束" << std::endl;break;}// 在這里可以對 'frame' 進行圖像處理// 例如:顯示幀號或時間戳// cv::putText(frame, "Frame: " + std::to_string(cap.get(cv::CAP_PROP_POS_FRAMES)),//             cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);// 3. 顯示幀cv::imshow(windowName, frame);// 等待按鍵,延遲 (1000/FPS) ms 以大致匹配視頻幀率,或者簡單用 1-30ms// 如果 fps > 0, 使用 int delay = 1000.0 / fps; 否則使用一個默認值int delay = (fps > 0) ? static_cast<int>(1000.0 / fps) : 30;if (delay <= 0) delay = 30; // 防止 delay 為0或負數導致無限等待int key = cv::waitKey(delay); // 等待約 30ms,或根據FPS計算if (key == 27) { // ESC 鍵的 ASCII 值std::cout << "ESC鍵被按下,正在關閉..." << std::endl;break;} else if (key == 's' || key == 'S') { // 示例:按 's' 保存當前幀std::string filename = "captured_frame.png";cv::imwrite(filename, frame);std::cout << "當前幀已保存為 " << filename << std::endl;}}// 4. 釋放資源cap.release();cv::destroyAllWindows();return 0;
}

編譯和運行 (以 g++ 為例):

假設你的 OpenCV 安裝在標準路徑,并且你已經設置了 pkg-config:

g++ your_code.cpp -o camera_app `pkg-config --cflags --libs opencv4`
./camera_app

如果未使用 pkg-config,你可能需要手動指定包含目錄和庫文件:

g++ your_code.cpp -o camera_app -I/path/to/opencv/include -L/path/to/opencv/lib -lopencv_core -lopencv_highgui -lopencv_videoio -lopencv_imgproc
./camera_app

(具體的庫名稱可能因 OpenCV 版本和模塊而略有不同,如 opencv_videoio 是處理視頻 I/O 的關鍵庫)。


常見問題與調試技巧

  • 無法打開攝像頭:
    • 確保攝像頭已連接并且驅動程序已正確安裝。
    • 檢查是否有其他應用程序正在使用該攝像頭。
    • 嘗試不同的 cameraIndex (0, 1, 2, …)。
    • 在 Linux 上,檢查 /dev/video* 設備文件是否存在以及你是否有權限訪問它們。
  • 視頻流卡頓或延遲:
    • 確保 cv::waitKey() 的延遲參數設置合理。太小的值可能導致 CPU 占用過高,太大的值則導致卡頓。
    • 圖像處理步驟如果過于復雜,會增加每幀的處理時間。
  • 窗口不顯示或一閃而過:
    • 確保在主循環之后調用 cv::destroyAllWindows(),并且 cv::waitKey() 在循環內部被正確調用以刷新窗口事件。
  • 幀為空 (frame.empty() 為 true):
    • 這可能發生在視頻文件結束,或者攝像頭出現問題時。

希望這篇文章能幫助你成功使用 C/C++ 和 OpenCV 調用你的攝像頭!

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

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

相關文章

使用微軟最近開源的WSL在Windows上優雅的運行Linux

install wsl https://github.com/microsoft/WSL/releases/download/2.4.13/wsl.2.4.13.0.x64.msi install any distribution from microsoft store, such as kali-linux from Kali office website list of distribution PS C:\Users\50240> wsl -l -o 以下是可安裝的有…

Win11安裝Dify

1、打開Virtual Machine Platform功能 電腦系統為&#xff1a;Windows 11 家庭中文版24H2版本。 打開控制面板&#xff0c;點擊“程序”&#xff0c;點擊“啟用或關閉Windows功能”。 下圖標記的“Virtual Machine Platform”、“適用于 Linux 的 Windows 子系統”、“Windows…

C++模板類深度解析與氣象領域應用指南

支持開源&#xff0c;為了更好的后來者 ————————————————————————————————————————————————————By 我說的 C模板類深度解析與氣象領域應用指南 一、模板類核心概念 1.1 模板類定義 模板類是C泛型編程的核心機制&#x…

MongoDB(七) - MongoDB副本集安裝與配置

文章目錄 前言一、下載MongoDB1. 下載MongoDB2. 上傳安裝包3. 創建相關目錄 二、安裝配置MongoDB1. 解壓MongoDB安裝包2. 重命名MongoDB文件夾名稱3. 修改配置文件4. 分發MongoDB文件夾5. 配置環境變量6. 啟動副本集7. 進入MongoDB客戶端8. 初始化副本集8.1 初始化副本集8.2 添…

mac筆記本如何快捷鍵截圖后自動復制到粘貼板

前提&#xff1a;之前只會進行部分區域截圖操作&#xff08;commandshift4&#xff09;操作&#xff0c;截圖后發現未自動保存在剪貼板&#xff0c;還要進行一步手動復制到剪貼板的操作。 mac筆記本如何快捷鍵截圖后自動復制到粘貼板 截取 Mac 屏幕的一部分并將其自動復制到剪…

WPF 按鈕點擊音效實現

WPF 按鈕點擊音效實現 下面我將為您提供一個完整的 WPF 按鈕點擊音效實現方案&#xff0c;包含多種實現方式和高級功能&#xff1a; 完整實現方案 MainWindow.xaml <Window x:Class"ButtonClickSound.MainWindow"xmlns"http://schemas.microsoft.com/win…

C++ list基礎概念、list初始化、list賦值操作、list大小操作、list數據插入

list基礎概念&#xff1a;list中的每一部分是一個Node&#xff0c;由三部分組成&#xff1a;val、next、prev&#xff08;指向上一個節點的指針&#xff09; list初始化的代碼&#xff0c;見下 #include<iostream> #include<list>using namespace std;void printL…

【Pandas】pandas DataFrame equals

Pandas2.2 DataFrame Reindexing selection label manipulation 方法描述DataFrame.add_prefix(prefix[, axis])用于在 DataFrame 的行標簽或列標簽前添加指定前綴的方法DataFrame.add_suffix(suffix[, axis])用于在 DataFrame 的行標簽或列標簽后添加指定后綴的方法DataFram…

【ROS2】創建單獨的launch包

【ROS】郭老二博文之:ROS目錄 1、簡述 項目中,可以創建單獨的launch包來管理所有的節點啟動 2、示例 1)創建launch包(python) ros2 pkg create --build-type ament_python laoer_launch --license Apache-2.02)創建啟動文件 先創建目錄:launch 在目錄中創建文件:r…

GitHub 趨勢日報 (2025年05月23日)

本日報由 TrendForge 系統生成 https://trendforge.devlive.org/ &#x1f310; 本日報中的項目描述已自動翻譯為中文 &#x1f4c8; 今日整體趨勢 Top 10 排名項目名稱項目描述今日獲星總星數語言1All-Hands-AI/OpenHands&#x1f64c;開放式&#xff1a;少代碼&#xff0c;做…

鴻蒙OSUniApp 實現的數據可視化圖表組件#三方框架 #Uniapp

UniApp 實現的數據可視化圖表組件 前言 在移動互聯網時代&#xff0c;數據可視化已成為產品展示和決策分析的重要手段。無論是運營后臺、健康監測、還是電商分析&#xff0c;圖表組件都能讓數據一目了然。UniApp 作為一款優秀的跨平臺開發框架&#xff0c;支持在鴻蒙&#xf…

[ctfshow web入門] web124

信息收集 error_reporting(0); //聽說你很喜歡數學&#xff0c;不知道你是否愛它勝過愛flag if(!isset($_GET[c])){show_source(__FILE__); }else{//例子 c20-1$content $_GET[c];// 長度不允許超過80個字符if (strlen($content) > 80) {die("太長了不會算");}/…

Vue 技術文檔

一、引言 Vue 是一款用于構建用戶界面的漸進式 JavaScript 框架&#xff0c;具有易上手、高性能、靈活等特點&#xff0c;能夠幫助開發者快速開發出響應式的單頁面應用。本技術文檔旨在全面介紹 Vue 的相關技術知識&#xff0c;為開發人員提供參考和指導。 二、環境搭建 2.1…

Nodejs+http-server 使用 http-server 快速搭建本地圖片訪問服務

在開發過程中&#xff0c;我們經常需要臨時查看或分享本地的圖片資源&#xff0c;比如設計稿、截圖、素材等。雖然可以通過壓縮發送&#xff0c;但效率不高。本文將教你使用 Node.js 的一個輕量級工具 —— http-server&#xff0c;快速搭建一個本地 HTTP 圖片預覽服務&#xf…

通義智文開源QwenLong-L1: 邁向長上下文大推理模型的強化學習

&#x1f389; 動態 2025年5月26日: &#x1f525; 我們正式發布&#x1f917;QwenLong-L1-32B——首個采用強化學習訓練、專攻長文本推理的LRM模型。在七項長文本文檔問答基準測試中&#xff0c;QwenLong-L1-32B性能超越OpenAI-o3-mini和Qwen3-235B-A22B等旗艦LRM&#xff0c…

學習如何設計大規模系統,為系統設計面試做準備!

前言 在當今快速發展的技術時代&#xff0c;系統設計能力已成為衡量一名軟件工程師專業素養的重要標尺。隨著云計算、大數據、人工智能等領域的興起&#xff0c;構建高性能、可擴展且穩定的系統已成為企業成功的關鍵。然而&#xff0c;對于許多工程師而言&#xff0c;如何有效…

Python生成ppt(python-pptx)N問N答(如何繪制一個沒有背景的矩形框;如何繪制一個沒有背景的矩形框)

文章目錄 [toc]1. **如何安裝python-pptx庫&#xff1f;**2. **如何創建一個空白PPT文件&#xff1f;**3. **如何添加幻燈片并設置布局&#xff1f;**4. **如何添加文本內容&#xff1f;**5. **如何插入圖片&#xff1f;**6. **如何設置動畫和轉場效果&#xff1f;**9. **如何繪…

命令模式,觀察者模式,狀態模式,享元模式

什么是命令模式&#xff1f; 核心思想是將原本直接調用的方法封裝為對象&#xff08;如AttackCommand&#xff09;&#xff0c;對象包含??執行邏輯??和??上下文信息??&#xff08;如目標、參數&#xff09;。比如&#xff0c;玩家的按鍵操作被封裝成一個命令對象&#…

Window Server 2019--07 PKI、SSL網站與郵件安全

了解PKI、SSL技術的核心原理掌握PKI架構服務器配置掌握證書管理與應用 公鑰基礎設施&#xff08;Public Key Infrastructure&#xff0c;PKI&#xff09;是一個完整的頒發、吊銷、管理數字證書的系統&#xff0c;是支持認證、加密、完整性和可追究性服務的基礎設施。PKI通過第…

從C++編程入手設計模式2——工廠模式

從C編程入手設計模式 工廠模式 ? 我們馬上就要迎來我們的第二個創建型設計模式&#xff1a;工廠方法模式&#xff08;Factory Method Pattern&#xff09;。換而言之&#xff0c;我們希望使用一個這樣的接口&#xff0c;使用其他手段而不是直接創建的方式&#xff08;說的有…