使用 C/C++ 和 OpenCV 構建智能停車場視覺管理系統

使用 C++ 和 OpenCV 構建智能停車場視覺管理系統

本文將詳細介紹如何利用 C++ 和 OpenCV 庫,從零開始創建一個智能停車場管理系統。該系統通過攝像頭捕捉的畫面,能自動完成兩項核心任務:

  1. 車位識別:通過檢測地面上的黃色停車線,自動識別并標定出所有停車位的位置。
  2. 狀態監控:實時監控每個車位,判斷其是**“空閑”還是“被占用”**,并進行可視化展示。

🧠 核心邏輯與方法

我們將整個系統分為兩個主要階段:校準階段監控階段

1. 校準階段 (Calibration Phase)

這個階段的目標是自動定義停車位。我們只需要對一張空停車場的圖片進行一次性處理。

  • 顏色分割: 將圖像從 BGR 轉換到 HSV 顏色空間。HSV 對光照變化不敏感,能更準確地提取出黃色。我們使用 cv::inRange 函數來創建一個只包含黃色標線的二值化“蒙版”。
  • 輪廓檢測: 在蒙版上,我們使用 cv::findContours 來尋找所有黃色區域的輪廓。
  • 車位標定: 通過對輪廓的面積形狀進行篩選,我們可以過濾掉噪聲,只保留代表停車位的矩形區域。我們使用 cv::minAreaRect 來獲取這些區域的精確位置(包括旋轉角度),并將這些位置信息保存到一個文件中(例如 parking_spots.xml)。

2. 監控階段 (Monitoring Phase)

這個階段是系統的核心,它在實時的視頻流上運行。

  • 加載車位數據: 程序首先從 parking_spots.xml 文件中加載所有預先標定好的停車位位置。
  • 占用檢測: 對每一個停車位區域(ROI),我們使用一種簡單而有效的方法來判斷是否有車:邊緣密度分析
    • 一個空車位(通常是瀝青或水泥地面)的紋理較少,因此邊緣也較少。
    • 一輛汽車具有復雜的輪廓、窗戶、輪胎和車身線條,會產生大量的邊緣
  • 狀態判斷: 我們在每個車位 ROI 上運行 Canny 邊緣檢測,然后計算邊緣像素的數量。如果數量超過一個預設的閾值,我們就判定該車位**“被占用”,否則為“空閑”**。
  • 可視化: 根據判斷結果,在視頻畫面上用不同顏色的矩形(例如紅色代表占用,綠色代表空閑)框出每個車位,并顯示可用的車位總數。

🛠? 環境與準備

  • C++ 編譯器: G++, Clang, 或 MSVC。
  • OpenCV 庫: 確保已正確安裝并配置。
  • 校準圖像: 一張停車場空無一車時的圖像,例如 empty_lot.jpg
  • 測試視頻/圖像: 一段停車場有車輛進出的視頻或圖像,例如 parking_video.mp4

💻 代碼實現

我們將代碼分為兩個獨立的文件:一個用于校準,一個用于監控。

第1部分: 校準程序 (calibrate.cpp)

這個程序只運行一次,用于生成車位坐標文件。

#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>int main(int argc, char** argv) {if (argc != 2) {std::cout << "Usage: ./calibrate_app <empty_lot_image>" << std::endl;return -1;}cv::Mat frame = cv::imread(argv[1]);if (frame.empty()) {std::cerr << "Error: Could not read the image." << std::endl;return -1;}// 1. 轉換為 HSVcv::Mat hsv;cv::cvtColor(frame, hsv, cv::COLOR_BGR2HSV);// 2. 顏色閾值分割 (針對黃色)// 注意: 這個范圍可能需要根據你的實際光照進行微調cv::Scalar lower_yellow(20, 100, 100);cv::Scalar upper_yellow(30, 255, 255);cv::Mat mask;cv::inRange(hsv, lower_yellow, upper_yellow, mask);// 3. 形態學操作去噪cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));cv::morphologyEx(mask, mask, cv::MORPH_CLOSE, kernel, cv::Point(-1,-1), 2);// 4. 尋找輪廓std::vector<std::vector<cv::Point>> contours;cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);std::vector<cv::RotatedRect> parkingSpots;for (const auto& contour : contours) {// 5. 過濾輪廓并獲取最小外接旋轉矩形double area = cv::contourArea(contour);if (area > 2000) { // 根據車位實際像素大小調整此閾值cv::RotatedRect rotatedRect = cv::minAreaRect(contour);parkingSpots.push_back(rotatedRect);}}// 6. 保存車位坐標到文件cv::FileStorage fs("parking_spots.xml", cv::FileStorage::WRITE);fs << "parking_spots" << parkingSpots;fs.release();std::cout << "Successfully detected and saved " << parkingSpots.size() << " parking spots." << std::endl;// 可選: 可視化檢測到的車位for (const auto& spot : parkingSpots) {cv::Point2f vertices[4];spot.points(vertices);for (int i = 0; i < 4; i++) {cv::line(frame, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 2);}}cv::imshow("Detected Parking Spots", frame);cv::waitKey(0);return 0;
}

第2部分: 監控程序 (monitor.cpp)

這個程序加載校準數據,并對視頻進行實時分析。

#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>// 定義占用閾值
const int EDGE_PIXEL_THRESHOLD = 300; // 需要根據分辨率和場景微調int main(int argc, char** argv) {if (argc != 2) {std::cout << "Usage: ./monitor_app <video_file>" << std::endl;return -1;}// 1. 加載車位數據std::vector<cv::RotatedRect> parkingSpots;cv::FileStorage fs("parking_spots.xml", cv::FileStorage::READ);if (!fs.isOpened()) {std::cerr << "Error: Could not open parking_spots.xml. Run calibration first." << std::endl;return -1;}fs["parking_spots"] >> parkingSpots;fs.release();cv::VideoCapture cap(argv[1]);if (!cap.isOpened()) {std::cerr << "Error: Could not open video file." << std::endl;return -1;}cv::Mat frame, gray, roi, edges;while (cap.read(frame)) {int available_spots = 0;cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);for (const auto& spot : parkingSpots) {// 2. 提取每個車位的 ROIcv::Rect br = spot.boundingRect();// 保證 ROI 在圖像邊界內br &= cv::Rect(0, 0, frame.cols, frame.rows);if (br.width == 0 || br.height == 0) continue;roi = gray(br);// 3. 計算 ROI 內的邊緣密度cv::Canny(roi, edges, 100, 200);int edge_pixels = cv::countNonZero(edges);// 4. 判斷車位狀態并可視化cv::Point2f vertices[4];spot.points(vertices);bool occupied = edge_pixels > EDGE_PIXEL_THRESHOLD;cv::Scalar color = occupied ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 255, 0);for (int i = 0; i < 4; i++) {cv::line(frame, vertices[i], vertices[(i + 1) % 4], color, 2);}if (!occupied) {available_spots++;}}// 5. 顯示狀態信息std::string status_text = "Available: " + std::to_string(available_spots) + "/" + std::to_string(parkingSpots.size());cv::putText(frame, status_text, cv::Point(20, 40), cv::FONT_HERSHEY_SIMPLEX, 1.5, cv::Scalar(255, 255, 0), 3);cv::imshow("Parking Lot Monitor", frame);if (cv::waitKey(30) >= 0) break;}return 0;
}

🚀 編譯與運行

  1. 編譯: 打開終端,使用 g++pkg-config 編譯兩個程序。

    # 編譯校準程序
    g++ -o calibrate_app calibrate.cpp $(pkg-config --cflags --libs opencv4)# 編譯監控程序
    g++ -o monitor_app monitor.cpp $(pkg-config --cflags --libs opencv4)
    

    注意: 如果你的 OpenCV 版本不是 4,請將 opencv4 替換為你的版本。

  2. 運行:

    • 第一步:運行校準程序,傳入空停車場的圖片。
      ./calibrate_app empty_lot.jpg
      
      這會生成一個 parking_spots.xml 文件。
    • 第二步:運行監控程序,傳入要分析的視頻。
      ./monitor_app parking_video.mp4
      
      程序會加載 parking_spots.xml 并開始實時分析和顯示結果。

總結與改進

這個項目展示了如何用標準 OpenCV 功能構建一個實用的計算機視覺應用。它的優點是邏輯清晰、實現簡單。當然,它也有可以改進的地方:

  • 魯棒性: 在光照劇烈變化或有陰影的情況下,基于邊緣的檢測可能會不穩定。可以引入更高級的特征(如 HOG)和機器學習分類器(如 SVM)來提高準確性。
  • 靈活性: 對于非黃色標線或不規則車位,需要修改顏色分割和輪廓篩選邏輯。
  • 用戶界面: 可以創建一個簡單的 GUI,讓用戶通過鼠標點擊來手動調整或標定車位,而不是完全依賴自動檢測。

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

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

相關文章

服務器靜態ip,網關不能占用*.*.*.1

網關不能占用*.*.*.1.1 通常用于運行關鍵服務&#xff08;如DHCP、NAT、DNS代理&#xff09;&#xff0c;.1 是網絡世界的"VIP包廂"&#xff0c;普通用戶強闖只會被"請出"。

自然語言處理【NLP】—— CBOW模型

文章目錄 引言一、CBOW模型概述1.1 什么是CBOW模型1.2 CBOW vs Skip-gram 二、CBOW模型原理詳解2.1 模型架構2.2 數學原理2.3 訓練過程 三、CBOW的PyTorch實現四、CBOW模型的應用與優化4.1 典型應用場景4.2 性能優化技巧 五、CBOW的局限性六、結語 引言 在自然語言處理(NLP)領…

為MTK 9300開發板移植Linux系統(以Debian為例)的詳細技術指南

以下是為MTK 9300開發板移植Linux系統(以Debian為例)的詳細技術指南,涵蓋環境搭建、內核移植、驅動適配(攝像頭/顯示器/WiFi)、系統集成與優化。 MTK 9300開發板Linux系統移植全流程指南 1 項目概述 1.1 硬件平臺 SoC:MediaTek MTK9300 (ARMv8-A架構,4Cortex-A78 + 4C…

Java Lambda 表達式與 Stream API 全解析:從基礎到進階

以下是對您博客內容的優化版本&#xff0c;在保留原有核心內容的基礎上&#xff0c;補充了Lambda表達式及Stream API的完整方法體系&#xff0c;并通過結構化排版和擴展說明提升可讀性。 Java Lambda表達式與Stream API全解析&#xff1a;從基礎到進階 一、Lambda表達式與Str…

Let’s Encrypt(樂此加密) 免費SSL證書申請

一、前言 騰訊云、阿里云等平臺都支持免費的SSL證書申請&#xff0c;但只支持單域名SSL證書申請&#xff0c;不支持泛域名證書申請&#xff0c;而且每年只有20張免費證書額度&#xff0c;自2024年4月25日之起免費申請的證書只有3個月有效期。域名比較多的情況下&#xff0c;更新…

SQLite3 性能優化

在嵌入式開發和輕量級應用場景中&#xff0c;SQLite3 作為輕量級數據庫引擎&#xff0c;憑借其無需獨立服務器、部署便捷等特點被廣泛應用。然而&#xff0c;當面對大量數據的高速讀寫需求時&#xff0c;默認配置下的 SQLite3 性能往往難以滿足要求。本文將從數據庫配置調整、W…

零基礎設計模式——行為型模式 - 狀態模式

第四部分&#xff1a;行為型模式 - 狀態模式 (State Pattern) 我們繼續學習行為型模式&#xff0c;接下來是狀態模式。這個模式允許一個對象在其內部狀態改變時改變它的行為&#xff0c;對象看起來就像是改變了它的類。 核心思想&#xff1a;允許一個對象在其內部狀態改變時改…

面向對象面試題集合

前言 記錄面向對象面試題相關內容&#xff0c;方便復習及查漏補缺 題1.簡述面向對象&#xff1f;主要特征是什么&#xff1f; 面向對象編程&#xff08;Object-Oriented Programming&#xff0c;簡稱OOP&#xff09;是一種以“對象”為核心的編程范式&#xff0c;通過將現實…

二十一、【用戶管理與權限 - 篇三】角色管理:前端角色列表與 CRUD 實現

【用戶管理與權限 - 篇三】角色管理:前端角色列表與 CRUD 實現 前言準備工作第一部分:更新 API 服務以包含角色管理第二部分:添加角色管理頁面的路由和側邊欄入口第三部分:實現角色列表頁面第四部分:實現角色表單對話框組件第五部分:全面測試總結前言 一個完善的權限系統…

Objective-c protocol 練習

題目描述&#xff1a; 請使用 Objective-C 中的 protocol 協議機制&#xff0c;實現一個簡易的門禁控制系統。 系統包含兩個類&#xff1a; AccessControlSystem —— 門禁系統&#xff0c;用于執行開門操作&#xff1b;Admin —— 實現權限判斷邏輯的管理員。 要求如下&am…

科技創新賦能產業創新,雙輪驅動助力新疆高質量發展!

在新疆維吾爾自治區成立70周年之際&#xff0c;中國產學研合作促進會于6月14日在烏魯木齊舉辦“天山對話&#xff1a;推動新疆科技創新與產業創新”盛會。多位院士、專家、學者及企業代表齊聚一堂&#xff0c;探尋推動新疆科技創新和產業創新的新路徑、新動能。活動現場&#x…

C#最佳實踐:推薦使用 nameof 而非硬編碼名稱

C#最佳實踐:推薦使用 nameof 而非硬編碼名稱 在 C# 編程領域,代碼的可維護性、健壯性和可讀性是衡量程序質量的重要指標。在日常開發中,我們常常會遇到需要引用類型、成員或變量名稱的場景,比如在拋出異常時指定錯誤相關的變量名、在日志記錄中標記關鍵元素名稱等。傳統的…

vue3 iframe 跨域-通訊

一、基礎嵌套方法 直接在 HTML 中使用 <iframe> 標簽指定 src 屬性&#xff1a; <iframe src"https://目標網址.com" width"800" height"600"></iframe>?限制?&#xff1a;若目標網站設置了 X-Frame-Options 響應頭&#x…

Iceberg與Hive集成深度

一、Iceberg在Hive中的ACID事務實現與實戰 1.1 傳統Hive的事務局限性 Hive原生僅支持非事務表&#xff08;Non-ACID&#xff09;&#xff0c;存在以下痛點&#xff1a; 不支持行級更新/刪除并發寫入時數據一致性無法保證無事務回滾機制歷史版本查詢需手動實現 1.2 Iceberg為…

深入剖析 Celery:分布式異步任務處理的利器

本文在創作過程中借助 AI 工具輔助資料整理與內容優化。圖片來源網絡。 文章目錄 引言一、Celery 概述1.1 Celery 的定義和作用1.2 Celery 的應用場景 二、Celery 架構分析2.1 Celery 的整體架構2.2 消息中間件&#xff08;Broker&#xff09;2.3 任務隊列&#xff08;Task Que…

Flask應用中處理異步事件(后臺線程+事件循環)的方法(2)

在上一節&#xff0c;我們講述了最簡單最基礎的后線程的建立&#xff0c;現在我們將進行拓展 Flask應用中處理異步事件&#xff08;后臺線程事件循環&#xff09;的方法&#xff08;1&#xff09; 在我們的實際應用當中&#xff0c;我們需要定義三個東西 一個多線程的信號旗&am…

C++(面向對象編程)

思維導圖 面向對象 1.面向對象思想 概念&#xff1a;面向對象編程&#xff08;OOP&#xff09;是一種以對象為基礎的編程范式&#xff0c;強調將數據和操作數據的方法封裝在一起。這就是上篇文章講過的。面向過程是以“怎么解決問題”為核心&#xff0c;而面向對象思想在于“誰…

驅動程序無法通過使用安全套接字層(SSL)加密與 SQL Server 建立安全連接,

驅動程序無法通過使用安全套接字層(SSL)加密與 SQL Server 建立安全連接,Error: “The server selected protocol version TLS10 is not accepted by client preferences [TLS13&#xff0c;TLS12]”. ClientConnectionId:d5fd8d69-ae88-4055-9f6d-6e8515224ce2】。 基本上就是…

【三大前端語言之一】交互:JavaScript詳解

【三大前端語言之一】交互&#xff1a;JavaScript詳解 在學習完HTML和CSS之后&#xff0c;最后一門前端語言——JavaScript&#xff0c;是重中之重。HTML負責頁面結構&#xff0c;CSS負責頁面樣式&#xff0c;而JavaScript則賦予網頁“生命”&#xff0c;讓網頁可以動起來、響…

LangChain面試內容整理-知識點12:檢索器(Retriever)接口與實現

在LangChain中,檢索器(Retriever)是一個抽象接口,負責根據用戶查詢從數據源中檢索相關文檔。可以把Retriever理解為“搜索工具”:給它一個未經結構化的查詢文本(如用戶問題),它返回一組與之相關的 Document 對象。內部可以基于向量相似度、數據庫查詢、甚至網絡搜索。 …