前面已經有3篇博文介紹了背景減圖方面相關知識(見下面的連接),在第3篇博文中本身也實現了gmm簡單算法,但效果不是很好,下面來體驗下opencv自帶2個gmm算法。html
opencv實現背景減圖法1(codebook和平均背景法)算法
http://www.cnblogs.com/tornadomeet/archive/2012/04/08/2438158.htmldom
opencv實現背景減圖法2(幀差法)ide
http://www.cnblogs.com/tornadomeet/archive/2012/05/01/2477629.html函數
opencv實現背景減圖法3(GMM)tornado
http://www.cnblogs.com/tornadomeet/archive/2012/06/02/2531565.html學習
工程環境opencv2.3.1+vs2010測試
實現功能:與上面第三篇博文同樣,完成動態背景的訓練,來檢測前景。ui
數據來源和前面的同樣: http://research.microsoft.com/en-us/um/people/jckrumm/WallFlower/TestImages.htm 因爲該數據是286張bmp格式的圖片,因此用的前200張圖片來做爲GMM參數訓練,後186張做爲測試。訓練的過程當中樹枝被很大幅度的擺動,測試過程當中有行人走動,該行人是須要遷就檢測的部分。this
Opencv自帶的gmm算法1的實驗結果以下:
其工程代碼以下:
1 // gmm_wavetrees.cpp : 定義控制檯應用程序的入口點。 2 // 3 4 #include "stdafx.h" 5 6 #include "opencv2/core/core.hpp" 7 #include "opencv2/video/background_segm.hpp" 8 #include "opencv2/highgui/highgui.hpp" 9 #include "opencv2/imgproc/imgproc.hpp" 10 #include <stdio.h> 11 12 using namespace std; 13 using namespace cv; 14 15 //this is a sample for foreground detection functions 16 string src_img_name="WavingTrees/b00"; 17 const char *src_img_name1; 18 Mat img, fgmask, fgimg; 19 int i=-1; 20 char chari[500]; 21 bool update_bg_model = true; 22 bool pause=false; 23 24 //第一種gmm,用的是KaewTraKulPong, P. and R. Bowden (2001). 25 //An improved adaptive background mixture model for real-time tracking with shadow detection. 26 BackgroundSubtractorMOG bg_model; 27 28 void refineSegments(const Mat& img, Mat& mask, Mat& dst) 29 { 30 int niters = 3; 31 32 vector<vector<Point> > contours; 33 vector<Vec4i> hierarchy; 34 35 Mat temp; 36 37 dilate(mask, temp, Mat(), Point(-1,-1), niters);//膨脹,3*3的element,迭代次數爲niters 38 erode(temp, temp, Mat(), Point(-1,-1), niters*2);//腐蝕 39 dilate(temp, temp, Mat(), Point(-1,-1), niters); 40 41 findContours( temp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );//找輪廓 42 43 dst = Mat::zeros(img.size(), CV_8UC3); 44 45 if( contours.size() == 0 ) 46 return; 47 48 // iterate through all the top-level contours, 49 // draw each connected component with its own random color 50 int idx = 0, largestComp = 0; 51 double maxArea = 0; 52 53 for( ; idx >= 0; idx = hierarchy[idx][0] )//這句沒怎麼看懂 54 { 55 const vector<Point>& c = contours[idx]; 56 double area = fabs(contourArea(Mat(c))); 57 if( area > maxArea ) 58 { 59 maxArea = area; 60 largestComp = idx;//找出包含面積最大的輪廓 61 } 62 } 63 Scalar color( 0, 255, 0 ); 64 drawContours( dst, contours, largestComp, color, CV_FILLED, 8, hierarchy ); 65 } 66 67 int main(int argc, const char** argv) 68 { 69 bg_model.noiseSigma = 10; 70 img=imread("WavingTrees/b00000.bmp"); 71 if(img.empty()) 72 { 73 namedWindow("image",1);//不能更改窗口 74 namedWindow("foreground image",1); 75 namedWindow("mean background image", 1); 76 } 77 for(;;) 78 { 79 if(!pause) 80 { 81 i++; 82 itoa(i,chari,10); 83 if(i<10) 84 { 85 src_img_name+="00"; 86 } 87 else if(i<100) 88 { 89 src_img_name+="0"; 90 } 91 else if(i>285) 92 { 93 i=-1; 94 } 95 if(i>=230) 96 update_bg_model=false; 97 else update_bg_model=true; 98 99 src_img_name+=chari; 100 src_img_name+=".bmp"; 101 102 img=imread(src_img_name); 103 if( img.empty() ) 104 break; 105 106 //update the model 107 bg_model(img, fgmask, update_bg_model ? 0.005 : 0);//計算前景mask圖像,其中輸出fgmask爲8-bit二進制圖像,第3個參數爲學習速率 108 refineSegments(img, fgmask, fgimg); 109 110 imshow("image", img); 111 imshow("foreground image", fgimg); 112 113 src_img_name="WavingTrees/b00"; 114 115 } 116 char k = (char)waitKey(80); 117 if( k == 27 ) break; 118 119 if( k == ' ' ) 120 { 121 pause=!pause; 122 } 123 } 124 125 return 0; 126 }
Opencv自帶的gmm算法2的實驗結果以下:
其工程代碼以下:
1 // gmm2_wavetrees.cpp : 定義控制檯應用程序的入口點。 2 // 3 4 #include "stdafx.h" 5 6 #include "opencv2/core/core.hpp" 7 #include "opencv2/video/background_segm.hpp" 8 #include "opencv2/highgui/highgui.hpp" 9 #include "opencv2/imgproc/imgproc.hpp" 10 #include <stdio.h> 11 12 using namespace std; 13 using namespace cv; 14 15 //this is a sample for foreground detection functions 16 string src_img_name="WavingTrees/b00"; 17 const char *src_img_name1; 18 Mat img, fgmask, fgimg; 19 int i=-1; 20 char chari[500]; 21 bool update_bg_model = true; 22 bool pause=false; 23 24 //第一種gmm,用的是KaewTraKulPong, P. and R. Bowden (2001). 25 //An improved adaptive background mixture model for real-time tracking with shadow detection. 26 BackgroundSubtractorMOG2 bg_model; 27 28 void refineSegments(const Mat& img, Mat& mask, Mat& dst) 29 { 30 int niters = 3; 31 32 vector<vector<Point> > contours; 33 vector<Vec4i> hierarchy; 34 35 Mat temp; 36 37 dilate(mask, temp, Mat(), Point(-1,-1), niters); 38 erode(temp, temp, Mat(), Point(-1,-1), niters*2); 39 dilate(temp, temp, Mat(), Point(-1,-1), niters); 40 41 findContours( temp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); 42 43 dst = Mat::zeros(img.size(), CV_8UC3); 44 45 if( contours.size() == 0 ) 46 return; 47 48 // iterate through all the top-level contours, 49 // draw each connected component with its own random color 50 int idx = 0, largestComp = 0; 51 double maxArea = 0; 52 53 for( ; idx >= 0; idx = hierarchy[idx][0] ) 54 { 55 const vector<Point>& c = contours[idx]; 56 double area = fabs(contourArea(Mat(c))); 57 if( area > maxArea ) 58 { 59 maxArea = area; 60 largestComp = idx; 61 } 62 } 63 Scalar color( 255, 0, 0 ); 64 drawContours( dst, contours, largestComp, color, CV_FILLED, 8, hierarchy ); 65 } 66 67 int main(int argc, const char** argv) 68 { 69 img=imread("WvingTrees/b00000.bmp"); 70 if(img.empty()) 71 { 72 namedWindow("image",1);//不能更改窗口 73 //cvNamedWindow("image",0); 74 namedWindow("foreground image",1); 75 // namedWindow("mean background image", 1); 76 } 77 for(;;) 78 { 79 if(!pause) 80 { 81 i++; 82 itoa(i,chari,10); 83 if(i<10) 84 { 85 src_img_name+="00"; 86 } 87 else if(i<100) 88 { 89 src_img_name+="0"; 90 } 91 else if(i>285) 92 { 93 i=-1; 94 } 95 // if(i>=230) 96 // update_bg_model=false; 97 // else update_bg_model=true; 98 99 src_img_name+=chari; 100 src_img_name+=".bmp"; 101 102 img=imread(src_img_name); 103 if( img.empty() ) 104 break; 105 106 //update the model 107 bg_model(img, fgmask, update_bg_model ? 0.005 : 0);//計算前景mask圖像,其中輸出fgmask爲8-bit二進制圖像,第3個參數爲學習速率 108 refineSegments(img, fgmask, fgimg); 109 110 imshow("foreground image", fgimg); 111 imshow("image", img); 112 113 src_img_name="WavingTrees/b00"; 114 115 } 116 char k = (char)waitKey(100); 117 if( k == 27 ) break; 118 119 if( k == ' ' ) 120 { 121 pause=!pause; 122 } 123 } 124 125 return 0; 126 }
能夠看出gmm1效果比gmm2的好,可是研究發現,gmm2是在gmm1上改進的,不會越該越差吧,除非2個函數的使用方法不一樣(雖然函數形式同樣),也就是說相同的參數值對函數功能的影響不一樣。之後有時間在研究了。