基於opencv3.0下的運動車輛檢測


在opencv的初等應用上,對運動物體的識別主要有幀差背景差兩種方式。

幀差法主要的原理是當前幀與前一幀作差取絕對值

背景差主要的原理是當前幀與背景幀作差取絕對值

在識別運動車輛上主要需要以下9個步驟:

(1)讀取幀(VideoCapture,Mat)

(2)ROI選定(Rect) 

(3)平滑處理(GaussianBlur)

(4)灰度處理(cvtColor,CV_RGB2GRAY)

(5)幀差或背景差(absdiff)

(6)二值化(threshold)

(7)膨脹(dilate)

(8)腐蝕(erode)

(9)繪制運動車輛(findContours,rectangle)

(1)讀取幀(外部視頻讀取:Videocapture;幀讀取:Mat

這個屬於比較基礎的內容這里不做解釋,直接附上源碼:

 1 /******************************************************
 2 函數名稱: MyClass
 3 函數功能: 初始化
 4 傳入參數:
 5 返 回 值:
 6 建立時間: 2018-05-17
 7 修改時間:
 8 建 立 人: 
 9 修 改 人:
10 其它說明:
11 ******************************************************/
12 MyClass::MyClass()
13 {
14     //capture.open("F:/code/vsc++/Car_Find/Car_Find/交大七公里交通監控.avi");
15     capture.open("交大七公里交通監控.avi");
16     //capture = 0;
17     if (!capture.isOpened())//判斷是否打開視頻文件  
18     {
19         exit(1);
20     }
21     FPS = capture.get(CV_CAP_PROP_FPS);
22 }
23 /******************************************************
24 函數名稱: ~MyClass
25 函數功能: 釋放空間
26 傳入參數:
27 返 回 值:
28 建立時間: 2018-05-17
29 修改時間:
30 建 立 人: 
31 修 改 人:
32 其它說明:
33 ******************************************************/
34 MyClass::~MyClass()
35 {
36     capture.release();
37 }
38 /******************************************************
39 函數名稱: play
40 函數功能: 播放法
41 傳入參數:
42 返 回 值:
43 建立時間: 2018-05-17
44 修改時間:
45 建 立 人: 
46 修 改 人:
47 其它說明:
48 ******************************************************/
49 void MyClass::play(){
50     Mat frame;
51     namedWindow("播放界面按Esc退出", 0);
52     cvResizeWindow("播放界面按Esc退出", 600, 500);
53     while (true)
54     {
55         capture >> frame;
56         if (frame.empty())break;
57         imshow("播放界面按Esc退出", frame);
58         if (waitKey(1000.0 / FPS) == 27)//按原FPS顯示  
59         {
60             cout << "ESC退出!" << endl;
61             break;
62         }
63     }
64 }

 

處理結果:

 

(2)ROI選定(Rect)

這里使用Rect進行划ROI(感興趣區域),畫出一個矩陣的ROI。在這里最好的ROI是梯形(減少除了道路外的不必要的干擾)

這里提下做法:做一個灰度的mask(遮罩層),然后調整mask的形狀大小。ps:感興趣的可以做下。

(3)平滑處理(處理方法:GaussianBlur)

這里采用高斯平滑處理,在拍攝視頻的時候會受到電流的干擾,但這個干擾時均勻存在的,所以采用高斯平滑處理可以去除電流的干擾。

方法很簡單,源碼如下:

 1 /******************************************************
 2 函數名稱: getSmooth
 3 函數功能: 平滑處理
 4 傳入參數:
 5 返 回 值:
 6 建立時間: 2018-05-17
 7 修改時間:
 8 建 立 人: 
 9 修 改 人:
10 其它說明:
11 ******************************************************/
12 Mat MyClass::getSmooth(Mat frame)
13 {
14     Mat img;
15     GaussianBlur(frame, img, Size(13, 13),2,2);
16     return img;
17 }

 

處理結果:

(4)灰度處理(處理方法:cvtColor;核:CV_RGB2GRAY)

RGB的圖對我們的識別會造成一定的干擾或者說增加處理的難度,這里將原幀轉換為灰度圖像;

在平滑處理 后,直接調用opencv的cvtColor方法:

 

 1 /******************************************************
 2 函數名稱: getGray
 3 函數功能: 灰度處理
 4 傳入參數:
 5 返 回 值:
 6 建立時間: 2018-05-17
 7 修改時間:
 8 建 立 人: 
 9 修 改 人:
10 其它說明:
11 ******************************************************/
12 Mat MyClass::getGray(Mat frame)
13 {
14     Mat img;
15     cvtColor(frame, img, CV_RGB2GRAY);
16     return img;
17 }

 

 

處理結果:

(5)幀差或背景差(處理方法:absdiff)

不管是幀差和背景差都是需要獲取當前幀跟對比幀,其中對比幀的獲取幀的作差是處理的關鍵。

在獲取到處理好的灰度圖在進行幀差處理。

以下為對比幀的獲取 的源碼:

 1 /******************************************************
 2 函數名稱: play
 3 函數功能: 播放幀差法
 4 傳入參數:
 5 返 回 值:
 6 建立時間: 2018-05-17
 7 修改時間:
 8 建 立 人: 
 9 修 改 人:
10 其它說明:
11 ******************************************************/
12 void MyClass::play(){
13     Mat frame,preframe,curframe,result;
14     namedWindow("播放界面按Esc退出", 0);
15     //cvResizeWindow("播放界面按Esc退出", 600, 500);
16     while (true)
17     {
18         capture >> frame;
19         if (frame.empty())break;
20         if (preframe.empty())preframe = frame.clone();//首幀處理
21         curframe = frame.clone();
22         imshow("播放界面按Esc退出", frame);
23         if (waitKey(1000.0 / FPS) == 27)//按原FPS顯示  
24         {
25             cout << "ESC退出!" << endl;
26             break;
27         }
28         preframe = frame.clone();//記錄當前幀為下一幀的前幀
29     }
30 }

以下為幀差處理的源碼:

/******************************************************
函數名稱: getDiff
函數功能: 幀差化處理
傳入參數:
返 回 值:
建立時間: 2018-05-17
修改時間:
建 立 人: 
修 改 人:
其它說明:
******************************************************/
Mat MyClass::getDiff(Mat preframe,Mat frame)
{
    Mat img;
    absdiff(preframe, frame, img);
    return img;
}

 

處理結果:

這里一個車的灰度輪廓已經可以識別出來了,但是我們的目的是將車輛的輪廓識別處理,為了更加精准,去除不必要的干擾,需要下面的處理。

(6)二值化(處理方法:threshold,閾值類型:CV_THRESH_BINARY)

 

 Threshold函數詳解,其中CV_THRESH_BINARY:當前點值大於閾值時,取Maxval,也就是第四個參數,下面再不說明,否則設置為0

由於這些車輛原畫偏暗,這里設定閾值為30,處理當前點值大於閾值時,取白色255。

源碼如下:

 1 /******************************************************
 2 函數名稱: getEz
 3 函數功能: 二值化處理
 4 傳入參數:
 5 返 回 值:
 6 建立時間: 2018-05-17
 7 修改時間:
 8 建 立 人: 
 9 修 改 人:
10 其它說明:
11 ******************************************************/
12 Mat MyClass::getEz(Mat frame)
13 {
14     Mat img;
15     threshold(frame, img,30, 255, CV_THRESH_BINARY);
16     return img;
17 }

 

處理結果:

車的黑白輪廓已經顯示出來了,不過這里還不是一塊整體,所以需要進行膨脹處理。

ps:有些博文的處理方式是先腐蝕處理后膨脹處理,這個在一定程度上會消除干擾點。但是這里考慮到車輛中有摩托車,如果先腐蝕處理的話會將摩托車給消除掉,造成識別精度不高。

(7)膨脹(處理方法:dilate)

膨脹的目的在於將一輛車拼合成一塊完整的個體,以達到標識的目的

opencv提供了dilate的方法進行處理,源碼如下:

 1 /******************************************************
 2 函數名稱: getPz
 3 函數功能: 膨脹處理
 4 傳入參數:
 5 返 回 值:
 6 建立時間: 2018-05-17
 7 修改時間:
 8 建 立 人: 
 9 修 改 人:
10 其它說明:
11 ******************************************************/
12 Mat MyClass::getPz(Mat frame)
13 {
14     Mat img;
15     Mat element=getStructuringElement(MORPH_RECT, Size(11, 30));
16     dilate(frame, img, element);
17     return img;
18 }

 

處理結果:

這時候已經合成一塊了,但是如果旁邊的車靠的太近的話,會導致多輛車黏合成一塊,所以下面做腐蝕處理。

(8)腐蝕(處理方法:erode)

腐蝕的目的在於將因為膨脹而導致的黏合,還有非關鍵點和區域的清除,以達到區分標識的目的。

opencv提供了erode的方法進行處理,源碼如下:

 1 /******************************************************
 2 函數名稱: getFs
 3 函數功能: 腐蝕處理
 4 傳入參數:
 5 返 回 值:
 6 建立時間: 2018-05-17
 7 修改時間:
 8 建 立 人: 
 9 修 改 人:
10 其它說明:
11 ******************************************************/
12 Mat MyClass::getFs(Mat frame)
13 {
14     Mat img;
15     Mat element = getStructuringElement(MORPH_RECT, Size(10, 16));
16     erode(frame, img, element);
17     return img;
18 }

 

處理結果:

ps:這里截的圖不是很好,看不出效果分離的效果。感興趣的可以下載下源碼去調試。

(9)繪制運動車輛(處理方法:findContours,rectangle)

findContours函數參數詳解

這里需要將車輛的外圍輪廓描繪出來即可,所以findContours采用

mode取值“CV_RETR_EXTERNAL”,method取值“CV_CHAIN_APPROX_NONE”,即只檢測最外層輪廓,並且保存輪廓上所有點;

rectangle的使用並不難,但是這里要注意的是:

a.處理的圖像是原圖像的ROI;

b.findContours輸出的是處理過圖像的坐標位置

所以在使用rectangle的時候,畫區域的時候要加上原來ROI的起始位置的坐標,改成原來圖像的坐標位置。

 

源碼如下:

 1 /******************************************************
 2 函數名稱: Deal
 3 函數功能: ROI區域處理
 4 傳入參數:
 5 返 回 值:
 6 建立時間: 2018-05-17
 7 修改時間:
 8 建 立 人: 
 9 修 改 人:
10 其它說明:
11 ******************************************************/
12 Mat MyClass::Deal(Mat preframe, Mat frame)
13 {
14     Mat result = frame.clone();
15     Mat curimageROI = preframe(Rect(preframe.cols / 5, preframe.rows / 5, preframe.cols / 1.5, preframe.rows / 1.5));
16     Mat preimageROI = frame(Rect(frame.cols / 5, frame.rows / 5, frame.cols / 1.5, frame.rows / 1.5));
17 
18     Mat sm_pre, sm_cur;
19     sm_pre = getSmooth(preimageROI);
20     sm_cur = getSmooth(curimageROI);
21     imshow("平滑處理", sm_cur);
22 
23     Mat gray_pre, gray_cur;
24     gray_pre = getGray(sm_pre);
25     gray_cur = getGray(sm_cur);
26     imshow("灰度處理",gray_cur);
27 
28     Mat diff;
29     diff = getDiff(gray_pre, gray_cur);
30     imshow("幀差處理",diff);
31 
32     Mat ez;
33     ez = getEz(diff);
34     imshow("二值化處理", ez);
35 
36     Mat pz;
37     pz = getPz(ez);
38     imshow("膨脹處理", pz);
39 
40     Mat fs;
41     fs = getFs(pz);
42     imshow("腐蝕處理", fs);
43 
44     vector<vector<Point> > contours;
45     findContours(fs, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
46     vector<Rect> boundRect(contours.size());
47     for (int i = 0; i < contours.size(); i++)
48     {
49         boundRect[i] = boundingRect(contours[i]);
50         rectangle(result, Rect(boundRect[i].x + frame.cols/5, boundRect[i].y + frame.rows/5, boundRect[i].width, boundRect[i].height), Scalar(0, 255, 0), 1);//在result上繪制正外接矩形  
51     }
52     return result;
53 }

 

處理結果:

這里效果不是非常好可以勉強識別出車輛輪廓。但作為初級應用是足夠的。

如需要源碼請轉移至碼雲:https://gitee.com/cjqbaba/MediaTest/tree/Car_Find進行源碼克隆下載

如有問題請留言評論。轉載請注明出處,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM