camshift算法(1)

 

       Camshift算法是Continuously Adaptive Mean Shift algorithm的簡稱。它是一個基於MeanSift的改進算法。它首次由Gary R.Bradski等人提出和應用在人臉的跟蹤上,並取得了不錯的效果。由於它是利用顏色的概率信息進行的跟蹤,使得它的運行效率比較高。Camshift算法的過程由下面步驟組成:

(1)確定初始目標及其區域;

(2)計算出目標的色度(Hue)分量的直方圖;

(3)利用直方圖計算輸入圖像的反向投影圖(後面做進一步的解釋);

(4)利用MeanShift算法在反向投影圖中迭代收索,直到其收斂或達到最大迭代次數。並保存零次矩;

(5)從第(4)步中獲得收索窗口的中心位置和計算出新的窗口大小,以此爲參數,進入到下一幀的目標跟蹤。(即跳轉到第(2)步);

幾點說明:

1. 在輸入圖像進行反向投影圖之前在HSV空間內做了一個閥值處理,用以濾掉一些噪聲。

2. 反向投影圖則是概率分佈圖,在反向投影圖中某一像素點的值指的是這個點符合目標的概率分佈的概率是多少,或者直接說其爲目標圖像像素點的像素點是多少。計算方法爲:根據像素點的像素值查目標的直方圖,其對應像素值的概率是多少就做爲該點在反向投影圖中的值。

3. Camshit算法到底是怎樣自適應調整窗口的大小的。擴大:Canshift算法在計算窗口大小前,在MeanShift算出的窗口的四個方向上增大了TOLERANCE,即高和寬都增大了2TOLERANCE(此值自己調整設置),這纔有可能使得窗口能夠變大。縮小:在擴大的窗口內重新計算0階矩,1階矩和2階矩,利用矩的值重新計算高和寬。因此Camshif算法相當於在MeanShift的結果上,再做了一個調整,從而使得跟蹤的窗口大小能夠隨目標的大小變化。

優點:算法的效率比較高,如果能利用多少特徵做出來的統計直方圖,我估計實驗效果會更好。

缺點:(1)只利用顏色統計做的跟蹤,在背景有相似顏色時,會出現跟蹤錯誤的情況。(2)不能做多目標跟蹤。(3)由於它只在初始位置(而不是從每個像素點)開始迭代,所以有可能在初始位置錯了後,收斂的位置還是原位置(即跟丟了後,可能會找不回來)。

問題:論文中有關於窗口大小調整,是根據直方圖來迭代求解,不知是怎麼回事?在代碼中沒看到實現。在此向大家請教!

下面是Camshift算法Demo的代碼:

   1 #ifdef _CH_
  2 #pragma package <opencv>
  3 #endif
  4 
  5 #define CV_NO_BACKWARD_COMPATIBILITY
  6 
  7 #ifndef _EiC
  8 #include "cv.h"
  9 #include "highgui.h"
 10 #include <stdio.h>
 11 #include <ctype.h>
 12 #endif
 13 
 14 IplImage *image = 0*hsv = 0*hue = 0*mask = 0*backproject = 0*histimg = 0;
 15 CvHistogram *hist = 0;
 16 
 17 int backproject_mode = 0;
 18 int select_object = 0;
 19 int track_object = 0;
 20 int show_hist = 1;
 21 CvPoint origin;
 22 CvRect selection;
 23 CvRect track_window;
 24 CvBox2D track_box;
 25 CvConnectedComp track_comp;
 26 int hdims = 16;
 27 float hranges_arr[] = {0,180};
 28 float* hranges = hranges_arr;
 29 int vmin = 10, vmax = 256, smin = 30;
 30 
 31 void on_mouse( int eventint x, int y, int flags, void* param )
 32 {
 33     if!image )
 34         return;
 35 
 36     if( image->origin )
 37         y = image->height - y;
 38 
 39     if( select_object )//表明還正在框選目標
 40     {
 41         selection.x = MIN(x,origin.x);
 42         selection.y = MIN(y,origin.y);
 43         selection.width = selection.x + CV_IABS(x - origin.x);
 44         selection.height = selection.y + CV_IABS(y - origin.y);
 45 
 46         //保證數據的有效性
 47         selection.x = MAX( selection.x, 0 );
 48         selection.y = MAX( selection.y, 0 );
 49         selection.width = MIN( selection.width, image->width );
 50         selection.height = MIN( selection.height, image->height );
 51         selection.width -= selection.x;
 52         selection.height -= selection.y;
 53     }
 54 
 55     switchevent )
 56     {
 57     case CV_EVENT_LBUTTONDOWN://框選目標
 58         origin = cvPoint(x,y);
 59         selection = cvRect(x,y,0,0);
 60         select_object = 1;
 61         break;
 62     case CV_EVENT_LBUTTONUP://框選結束
 63         select_object = 0;
 64         if( selection.width > 0 && selection.height > 0 )
 65             track_object = -1;
 66         break;
 67     }
 68 }
 69 
 70 
 71 CvScalar hsv2rgb( float hue )
 72 {
 73     int rgb[3], p, sector;
 74     static const int sector_data[][3]=
 75         {{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}};
 76     hue *= 0.033333333333333333333333333333333f;
 77     sector = cvFloor(hue);
 78     p = cvRound(255*(hue - sector));
 79     p ^= sector & 1 ? 255 : 0;
 80 
 81     rgb[sector_data[sector][0]] = 255;
 82     rgb[sector_data[sector][1]] = 0;
 83     rgb[sector_data[sector][2]] = p;
 84 
 85     return cvScalar(rgb[2], rgb[1], rgb[0],0);
 86 }
 87 
 88 int main( int argc, char** argv )
 89 {
 90     CvCapture* capture = 0;
 91 
 92     if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
 93         capture = cvCaptureFromCAM( argc == 2 ? argv[1][0- '0' : 0 );
 94     else if( argc == 2 )
 95         capture = cvCaptureFromAVI( argv[1] );
 96 
 97     if!capture )
 98     {
 99         fprintf(stderr,"Could not initialize capturing...\n");
100         return -1;
101     }
102 
103     printf( "Hot keys: \n"
104         "\tESC - quit the program\n"
105         "\tc - stop the tracking\n"
106         "\tb - switch to/from backprojection view\n"
107         "\th - show/hide object histogram\n"
108         "To initialize tracking, select the object with mouse\n" );
109 
110     cvNamedWindow( "Histogram"1 );
111     cvNamedWindow( "CamShiftDemo"1 );
112     cvSetMouseCallback( "CamShiftDemo", on_mouse, 0 );
113     cvCreateTrackbar( "Vmin""CamShiftDemo"&vmin, 2560 );
114     cvCreateTrackbar( "Vmax""CamShiftDemo"&vmax, 2560 );
115     cvCreateTrackbar( "Smin""CamShiftDemo"&smin, 2560 );
116 
117     for(;;)
118     {
119         IplImage* frame = 0;
120         int i, bin_w, c;
121 
122         frame = cvQueryFrame( capture );
123         if!frame )
124             break;
125 
126         if!image )
127         {
128             /* allocate all the buffers */
129             image = cvCreateImage( cvGetSize(frame), 83 );
130             image->origin = frame->origin;
131             hsv = cvCreateImage( cvGetSize(frame), 83 );
132             hue = cvCreateImage( cvGetSize(frame), 81 );
133             mask = cvCreateImage( cvGetSize(frame), 81 );
134             backproject = cvCreateImage( cvGetSize(frame), 81 );
135             hist = cvCreateHist(1&hdims, CV_HIST_ARRAY, &hranges, 1 );
136             histimg = cvCreateImage( cvSize(320,200), 83 );
137             cvZero( histimg );
138         }
139 
140         cvCopy( frame, image, 0 );
141         cvCvtColor( image, hsv, CV_BGR2HSV );
142 
143         if( track_object )
144         {
145             int _vmin = vmin, _vmax = vmax;
146 
147             cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0),
148                         cvScalar(180,256,MAX(_vmin,_vmax),0), mask ); //去除噪聲,在此數據內的值,確定mask爲1
149             cvSplit( hsv, hue, 000 ); //獲得色調分量,並以此來做反向投影圖
150 
151             if( track_object < 0 )
152             {
153                 float max_val = 0.f;
154                 cvSetImageROI( hue, selection );
155                 cvSetImageROI( mask, selection );
156                 cvCalcHist( &hue, hist, 0, mask );//計算選中部分直方圖
157                 cvGetMinMaxHistValue( hist, 0&max_val, 00 );
158                 cvConvertScale( hist->bins, hist->bins, max_val ? 255/ max_val : 0., 0 );
159                 cvResetImageROI( hue );
160                 cvResetImageROI( mask );
161                 track_window = selection;
162                 track_object = 1;
163 
164                 cvZero( histimg );
165                 bin_w = histimg->width / hdims;
166                 for( i = 0; i < hdims; i++ )
167                 {
168                     int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 );//獲取直方圖的中每一項的高
169                     CvScalar color = hsv2rgb(i*180.f/hdims);//直方圖每一項的顏色是根據項數變化的
170                     cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),  //畫直方圖
171                                  cvPoint((i+1)*bin_w,histimg->height - val),
172                                  color, -180 );
173                 }
174             }
175 
176             cvCalcBackProject( &hue, backproject, hist ); //計算反向投影圖backproject
177             cvAnd( backproject, mask, backproject, 0 );        //去除上下閥值外的點後的投影圖
178             cvCamShift( backproject, track_window,        //利用camshift搜索0-255的灰度圖像
179                         cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 101 ),
180                         &track_comp, &track_box );
181             track_window = track_comp.rect;    //獲得新的跟蹤窗口
182 
183             if( backproject_mode )
184                 cvCvtColor( backproject, image, CV_GRAY2BGR );
185         
186             if!image->origin ) //如果爲假,需要改變橢圓的角度
187                 track_box.angle = -track_box.angle; 
188             cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 );//畫跟蹤橢圓
189         }
190 
191         if( select_object && selection.width > 0 && selection.height > 0 )//在框住的時候反向顯示
192         {
193             cvSetImageROI( image, selection );
194             cvXorS( image, cvScalarAll(255), image, 0 );
195             cvResetImageROI( image );
196         }
197 
198         cvShowImage( "CamShiftDemo", image );
199         cvShowImage( "Histogram", histimg );
200 
201         c = cvWaitKey(10);
202         if( (char) c == 27 )
203             break;
204         switch( (char) c )
205         {
206         case 'b':
207             backproject_mode ^= 1;
208             break;
209         case 'c':
210             track_object = 0;
211             cvZero( histimg );
212             break;
213         case 'h':
214             show_hist ^= 1;
215             if!show_hist )
216                 cvDestroyWindow( "Histogram" );
217             else
218                 cvNamedWindow( "Histogram"1 );
219             break;
220         default:
221             ;
222         }
223     }
224 
225     cvReleaseCapture( &capture );
226     cvDestroyWindow("CamShiftDemo");
227 
228     return 0;
229 }
230 
231 #ifdef _EiC
232 main(1,"camshiftdemo.c");
233 #endif
234 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章