日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数字图像处理合集终章——车流量统计(后附源码)

發(fā)布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数字图像处理合集终章——车流量统计(后附源码) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目要求:
包括1)基于高斯混合背景建模的運動目標(biāo)提取;2)基于矩形度/圓形度/面積的車輛目標(biāo)判別;3)區(qū)域生長法獲取完整的車輛目標(biāo);4)統(tǒng)計不同方向的車流量(單位是輛/分鐘),對于白天場景下車流量能夠有效的統(tǒng)計。

題目分析:
首先明白混合高斯背景建模,其基本思想為:定義每個像素點的分布模型為由多個單高斯模型組成的集合,根據(jù)每一個新的像素值更新模型參數(shù),按照一定的準(zhǔn)則判斷哪些像素點為背景點,哪些為前景點,從而實現(xiàn)對運動目標(biāo)的檢測。
使用混合高斯背景建模提取出前景之后,對前景進行圖像預(yù)處理,進行濾波、膨脹、腐蝕等操作得到較為完整的前景運動車輛二值圖。在這一操作時,使用While大循環(huán)對每一幀進行處理。辨識二值圖像中的車輛目標(biāo)時,可以使用opencv內(nèi)的Rect類,將前景車輛目標(biāo)圈出。在檢測時,將圖像中的一部分劃分出來作為檢測區(qū)域,當(dāng)車輛進入這一區(qū)域時對其進行計數(shù)。
綜上,重點在于辨識車輛目標(biāo)和進行計數(shù)。

算法分析
1.系統(tǒng)模塊劃分
根據(jù)第二部分的分析,將本車流量統(tǒng)計系統(tǒng)分為如下幾個模塊。
1.1混合高斯背景建模
使用opencv自帶的高斯建模函數(shù)createBackgroundSubtractorMOG2()對視頻進行背景建模。視頻中還可能存在影子等內(nèi)容,故使用setVarThreshold減少影子對之后測試的影響。使用BackgroundSubtractorMOG2中的操作apply對背景進行更新。使用Scalar對獲取到的前景保持像素不變,背景換成零像素。對前景二值化處理即可進行圖像預(yù)處理模塊。本模塊主要實現(xiàn)代碼如下所示。

Ptr<BackgroundSubtractorMOG2> pBgmodel = createBackgroundSubtractorMOG2(); pBgmodel->setVarThreshold(500); pBgmodel->apply(image, fgMask); foreGround = Scalar::all(0); image.copyTo(foreGround, fgMask);pBgmodel->getBackgroundImage(backGround);

1.2圖像預(yù)處理
對獲取到的每一幀二值圖進行預(yù)處理,本系統(tǒng)中對獲取到的二值圖進行了高斯濾波、膨脹、腐蝕等操作,使用的結(jié)構(gòu)元素為(13*13)大小的。主要實現(xiàn)代碼如下所示。

Mat element = getStructuringElement(MORPH_RECT, Size(13, 13)); GaussianBlur(fgMask, fgMask, Size(5, 5), 0);dilate(fgMask, fgMask, element);erode(fgMask, fgMask, element);

1.3分析辨識車輛目標(biāo)
本系統(tǒng)中使用Rect類標(biāo)記每一輛車,通過輪廓檢測將車輛標(biāo)識出來,并畫出矩形類的輪廓。對得到的每一個矩形陣,設(shè)定最小寬度及最大寬度排除一些偽目標(biāo),再對當(dāng)前幀中的所有輪廓進行排序,當(dāng)其中某個輪廓(連通分量)的面積小于當(dāng)前幀中最大輪廓(連通分量)面積的1/6時認(rèn)為其是偽目標(biāo)。將真實車輛目標(biāo)放入一個動態(tài)數(shù)組并將其畫出。通過兩層檢測基本能排除所有不是車輛的偽目標(biāo)并畫出車輛目標(biāo)。主要實現(xiàn)代碼如下所示。

vector<vector<Point>> contours; vector<vector<Point>>Realcontours; vector<Vec4i> hierarchy; findContours(fgMask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(0, 0));getSizeContours(contours); sort(contours.begin(), contours.end(), descSort); for (int i = 0; i < contours.size(); i++){//當(dāng)?shù)趇個連通分量的外接矩陣面積小于最大面積的1/6,則認(rèn)為是偽目標(biāo)if (contourArea(contours[i]) < contourArea(contours[0]) / 5)break;//包含輪廓的最小矩陣rct = boundingRect(contours[i]);Realcontours.push_back(contours[i]);}rectangle(image, rct, SCALAR_GREEN, 2); 使用的自定義函數(shù): void getSizeContours(vector<vector<Point>> &contours){int cmin = 100; // 最小輪廓長度int cmax = 1000; // 最大輪廓長度vector<vector<Point>>::const_iterator itc = contours.begin();while (itc != contours.end()){if ((itc->size()) < cmin || (itc->size()) > cmax){itc = contours.erase(itc);}else ++itc;}} bool descSort(vector<Point> p1, vector<Point> p2) {return contourArea(p1) > contourArea(p2);}

1.4建立檢測區(qū)域?qū)ζ渲械能囕v進行計數(shù)
本模塊中需要建立一個檢測區(qū)域,市面上大多數(shù)車流量檢測使用的都是直線檢測,使用車輛過線對車輛進行計數(shù),本系統(tǒng)沒有采用這樣的方法,而是使用一個檢測矩形框進行檢測。使用opencv中矩形類的特殊操作輔助。
在屏幕下方畫出一個矩形框作為檢測區(qū)域,每一個進入此區(qū)域的車輛對其進行計數(shù),但這里涉及到一個輪廓跟蹤的問題。即一個已經(jīng)進入框內(nèi)但并未出框的車輛多次計數(shù)的問題。本模塊使用一個標(biāo)志carFlag對該車輛是否已經(jīng)計數(shù)(即該車輛是否為新進入檢測區(qū)的車輛)。輪廓跟蹤部分,本系統(tǒng)使用中心點進行跟蹤,建立一個存放中心點的動態(tài)數(shù)組 centerPointArray,計算每一幀中出現(xiàn)的車輛的中心點,將該中心點與數(shù)組中已存在的中心點使用歐幾里得距離計算公式算出其距離,若該距離大于設(shè)定的一個距離值則認(rèn)為該車輛為一輛新的車輛并將該中心點加入中心點數(shù)組。若小于設(shè)定的距離值則認(rèn)為其是該幀中的某一個車輛的下一個位置,并對所有計算出的距離進行排序,距離差值最小的則認(rèn)為該中心點是數(shù)組中這一中心點車輛的下一個位置并將該中心值替換到數(shù)組中。本模塊的不足之處是設(shè)定的距離值需要通過多次統(tǒng)計檢測才能得出,且為人工計算出。
設(shè)定一個全局變量CarCount存儲車輛的數(shù)量,當(dāng)中心點距離小于距離設(shè)定值且carFlag值為True時才使CarCount自增一次。為了增加用戶體驗感,車輛在計數(shù)范圍內(nèi)并被計數(shù)時使用紅色進行畫框,其余時間使用綠色畫框。本模塊主要實現(xiàn)代碼如下所示。

vector<Point> centerPointArray; Rect Testrct(0, imageheigh,image.cols,100);rectangle(image, Testrct, SCALAR_GREEN, 2);for (int i = 0; i < Realcontours.size(); i++) {Rect Realrct = boundingRect(Realcontours[i]);//獲取中心點坐標(biāo)Point center;center = getCenterPoint(boundingRect(Realcontours[i]));if(center.y <= imageheigh+100 && center.y >= imageheigh ){double distance;//用于判斷是否進行了中心點坐標(biāo)替換,即是否是同一輛車false時不是同一輛車要計數(shù)bool carFlag = false;//判斷中心點數(shù)組中是否有值,如果有則遍歷匹配距離if (centerPointArray.size() > 0) {for (auto i = centerPointArray.begin(); i < centerPointArray.end(); i++){distance = sqrt(pow((center.x- i->x), 2) + pow((center.y - i->y), 2));if (distance <= 30){*i = center;carFlag = true;}}}if (carFlag == false){centerPointArray.push_back(center);CarCount++;}rectangle(image, Realrct, SCALAR_RED, 2);} else{rectangle(image, Realrct, SCALAR_GREEN, 2); }}

使用的自定義函數(shù):

Point getCenterPoint(Rect rect){Point cpt;cpt.x = rect.x + cvRound(rect.width / 2.0);cpt.y = rect.y + cvRound(rect.height / 2.0);return cpt;}

1.5尾處理
車流量計數(shù)完畢需要對用戶展示一些處理過程的處理結(jié)果如原視頻、視頻背景、視頻運動目標(biāo)、運動目標(biāo)二值圖、視頻處理結(jié)果并將計數(shù)展示在視頻處理結(jié)果的右上角。右上角顯示計數(shù)結(jié)果部分應(yīng)能根據(jù)視頻的大小進行字體大小的變換,在力所能及的部分增加用戶體驗感。本模塊主要實現(xiàn)代碼如下所示。

int intFontFace = CV_FONT_HERSHEY_SIMPLEX; //字體類型double dblFontScale = (image.rows * image.cols) / 300000.0;//文字大小int intFontThickness = (int)std::round(dblFontScale * 3.0);//字體粗細(xì)Size textSize = cv::getTextSize(std::to_string(CarCount), intFontFace, dblFontScale, intFontThickness, 0);//to_string將數(shù)字換為文字crossingLine.x = image.cols - 1 - (int)((double)textSize.width * 1.25);crossingLine.y = (int)((double)textSize.height * 1.25);putText(image, to_string(CarCount), crossingLine, intFontFace, dblFontScale, SCALAR_GREEN, intFontThickness);imshow("【視頻背景】", backGround);imshow("【視頻運動目標(biāo)】", foreGround);imshow("【運動目標(biāo)二值圖】", fgMask); imshow("【視頻】", image);

2.系統(tǒng)運行流程圖
根據(jù)系統(tǒng)模塊劃分,可得出本系統(tǒng)的流程圖如圖所示。
系統(tǒng)運行流程圖:

實現(xiàn)效果:
由于本系統(tǒng)是對視頻進行處理,故不能展示所有結(jié)果,在此展示本系統(tǒng)處理過程中某一幀的運行結(jié)果,并給出最終的統(tǒng)計結(jié)果,處理視頻來源與網(wǎng)站。
讀取原視頻如圖所示。
原視頻讀取:

混合高斯背景建模背景分離如圖所示,由于運行電腦的配置等原因,背景分離出現(xiàn)一些重影,這也是混合高斯背景建模的不足之處,其對運動緩慢的目標(biāo)無法很好的對其進行提取。
背景分離:

混合高斯背景建模前景提取如圖所示。此處將背景像素值置為0,僅留下前景目標(biāo)。
前景提取:

圖像預(yù)處理結(jié)果如圖所示。此時已對前景進行二值化、高斯濾波、膨脹、腐蝕等操作。
圖像預(yù)處理結(jié)果:

圖像計數(shù)過程如圖所示。進入此區(qū)域并被計數(shù)的車輛的輪廓最小正外接矩形被畫出。
圖像計數(shù):

圖像計數(shù)結(jié)果如圖所示。計數(shù)結(jié)果為52,針對該視頻,此計數(shù)結(jié)果正確。
圖像計數(shù)結(jié)果:

最終給出車流量統(tǒng)計的實驗源碼:

#include "stdafx.h" #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/video/background_segm.hpp> using namespace cv; using namespace std; void getSizeContours(vector<vector<Point>> &contours); bool descSort(vector<Point> p1, vector<Point> p2); Point getCenterPoint(Rect rect); const Scalar SCALAR_GREEN = Scalar(0.0, 200.0, 0.0); const Scalar SCALAR_RED = Scalar(0.0, 0.0, 255.0); int CarCount = 0; int main() {VideoCapture capture;Mat frame, image, foreGround, backGround, fgMask, findcontours;Rect rct;vector<vector<Point>> contours;vector<Vec4i> hierarchy;//聲明一個存儲中心點的數(shù)組vector<Point> centerPointArray;Point crossingLine; //定義2D點Ptr<BackgroundSubtractorMOG2> pBgmodel = createBackgroundSubtractorMOG2();pBgmodel->setVarThreshold(500);//檢測是否有影子capture.open("G:\\opencvdemo\\Guass\\CarsDrivingUnderBridge.mp4");if (!capture.isOpened()){cout << "open videp eror!" << endl;}while (true){vector<vector<Point>>Realcontours;Mat element = getStructuringElement(MORPH_RECT, Size(13, 13));//frame是原始幀capture >> frame;if (frame.empty())break;//縮小為原來四分之一,加快處理速度resize(frame, image, Size(frame.cols / 2, frame.rows / 2), INTER_LINEAR);if (foreGround.empty())foreGround.create(image.size(), image.type());//得到前景圖像,是黑白灰 3種灰度值的圖 pBgmodel->apply(image, fgMask);//背景更新// 下面是根據(jù)前景圖的操作,和原圖像融合得到有紋理的前景圖GaussianBlur(fgMask, fgMask, Size(5, 5), 0);dilate(fgMask, fgMask, element);erode(fgMask, fgMask, element);threshold(fgMask, fgMask, 10, 255, THRESH_BINARY);// 將foreGraound 所有像素置為0foreGround = Scalar::all(0);image.copyTo(foreGround, fgMask);pBgmodel->getBackgroundImage(backGround);int imageheigh = (int)std::round((double)image.rows * 0.5);findContours(fgMask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(0, 0));getSizeContours(contours);imshow("【原視頻】", image);//drawContours(image, contours, -1, SCALAR_RED, 5);sort(contours.begin(), contours.end(), descSort);for (int i = 0; i < contours.size(); i++){//當(dāng)?shù)趇個連通分量的外接矩陣面積小于最大面積的1/6,則認(rèn)為是偽目標(biāo)if (contourArea(contours[i]) < contourArea(contours[0]) / 5)break;//包含輪廓的最小矩陣rct = boundingRect(contours[i]);Realcontours.push_back(contours[i]);}rectangle(image, rct, SCALAR_GREEN, 2);//對車輛進行計數(shù)Rect Testrct(0, imageheigh,image.cols,100);rectangle(image, Testrct, SCALAR_GREEN, 2);for (int i = 0; i < Realcontours.size(); i++) {Rect Realrct = boundingRect(Realcontours[i]);Point center;center = getCenterPoint(boundingRect(Realcontours[i]));if(center.y <= imageheigh+100 && center.y >= imageheigh ){double distance;bool carFlag = false;if (centerPointArray.size() > 0) {for (auto i = centerPointArray.begin(); i < centerPointArray.end(); i++){distance = sqrt(pow((center.x- i->x), 2) + pow((center.y - i->y), 2));if (distance <= 30){*i = center;carFlag = true;}}}if (carFlag == false){centerPointArray.push_back(center);CarCount++;}rectangle(image, Realrct, SCALAR_RED, 2);} else{rectangle(image, Realrct, SCALAR_GREEN, 2);}}//將計數(shù)結(jié)果寫在右上角int intFontFace = CV_FONT_HERSHEY_SIMPLEX; //字體類型double dblFontScale = (image.rows * image.cols) / 300000.0; //文字大小int intFontThickness = (int)std::round(dblFontScale * 3.0); //字體粗細(xì)Size textSize = cv::getTextSize(std::to_string(CarCount), intFontFace, dblFontScale, intFontThickness, 0);crossingLine.x = image.cols - 1 - (int)((double)textSize.width * 1.25);crossingLine.y = (int)((double)textSize.height * 1.25);putText(image, to_string(CarCount), crossingLine, intFontFace, dblFontScale, SCALAR_GREEN, intFontThickness);imshow("【視頻背景】", backGround);imshow("【視頻運動目標(biāo)】", foreGround);imshow("【運動目標(biāo)二值圖】", fgMask);imshow("【視頻】", image);char key = waitKey(100);if (key == 27)//27 對應(yīng)得assic 碼是27break;} system("pause");return 0; } void getSizeContours(vector<vector<Point>> &contours) {int cmin = 100; // 最小輪廓長度int cmax = 1000; // 最大輪廓長度vector<vector<Point>>::const_iterator itc = contours.begin();while (itc != contours.end()){if ((itc->size()) < cmin || (itc->size()) > cmax){itc = contours.erase(itc);}else ++itc;} } bool descSort(vector<Point> p1, vector<Point> p2) {return contourArea(p1) > contourArea(p2); }Point getCenterPoint(Rect rect) {Point cpt;cpt.x = rect.x + cvRound(rect.width / 2.0);cpt.y = rect.y + cvRound(rect.height / 2.0);return cpt; }

數(shù)字圖像處理合集告一段落,希望這一合集對你學(xué)習(xí)數(shù)字圖像處理帶來幫助。
合集入口

最后附上資源下載鏈接,均為本合集的資源
資源下載

測試視頻觀看入口

總結(jié)

以上是生活随笔為你收集整理的数字图像处理合集终章——车流量统计(后附源码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。