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 

 

 

posted on 2010-09-28 15:53  物联互通  阅读(3451)  评论(5编辑  收藏  举报