采用 CAMSHIFT 算法快速跟踪和检测运动目标的 C/C++ 源代码

    在实现运动目标的跟踪的过程中,发现网上流传很广的一段跟踪与检测源代码,大家可以在各个网站上都找到其踪影。为了方便查阅和参考,特转发如下:

    因为转发地址不可考,就在此先谢谢提供最初版本的前辈。

 

 

    采用 CAMSHIFT 算法快速跟踪和检测运动目标的 C/C++ 源代码,OPENCV BETA 4.0 版本在其 SAMPLE 中给出了这个例子。算法的简单描述如下(英文):

    This application demonstrates a fast, simple color tracking algorithm that can be used to track faces, hands . The CAMSHIFT algorithm is a modification of the Meanshift algorithm which is a robust statistical method of finding the mode (top) of a probability distribution. Both CAMSHIFT and Meanshift algorithms exist in the library. While it is a very fast and simple method of tracking, because CAMSHIFT tracks the center and size of the probability distribution of an object, it is only as good as the probability distribution that you produce for the object. Typically the probability distribution is derived from color via a histogram, although it could be produced from correlation, recognition scores or bolstered by frame differencing or motion detection schemes, or joint probabilities of different colors/motions etc. 
    In this application, we use only the most simplistic approach: A 1-D Hue histogram is sampled from the object in an HSV color space version of the image. To produce the probability image to track, histogram "back projection" (we replace image pixels by their histogram hue value) is used.

    算法的详细情况,请看论文:

    http://www.assuredigit.com/incoming/camshift.pdf

    该运行文件在VC6.0环境下编译通过,是一个 stand-alone 运行程序,不需要OPENCVDLL库支持。在运行之前,请先连接好USB接口的摄像头。然后可以用鼠标选定欲跟踪目标。

 1. #ifdef _CH_ 2. #pragma package <opencv> 3. #endif 4. 5. #ifndef _EiC 6. #include "cv.h" 7. #include "highgui.h" 8. #include <stdio.h> 9. #include <ctype.h> 10. #endif 11. 12. IplImage *image = 0, *hsv = 0, *hue = 0, *mask = 0, *backproject = 0, *histimg = 0; 13. CvHistogram *hist = 0; 14. 15. int backproject_mode = 0; 16. int select_object = 0; 17. int track_object = 0; 18. int show_hist = 1; 19. CvPoint origin; 20. CvRect selection; 21. CvRect track_window; 22. CvBox2D track_box; // tracking 返回的区域 box,带角度 23. CvConnectedComp track_comp; 24. int hdims = 48; // 划分HIST的个数,越高越精确 25. float hranges_arr[] = {0,180}; 26. float* hranges = hranges_arr; 27. int vmin = 10, vmax = 256, smin = 30; 28. 29. void on_mouse( int event, int x, int y, int flags ) 30. { 31. if( !image ) 32. return; 33. 34. if( image->origin ) 35. y = image->height - y; 36. 37. if( select_object ) 38. { 39. selection.x = MIN(x,origin.x); 40. selection.y = MIN(y,origin.y); 41. selection.width = selection.x + CV_IABS(x - origin.x); 42. selection.height = selection.y + CV_IABS(y - origin.y); 43. 44. selection.x = MAX( selection.x, 0 ); 45. selection.y = MAX( selection.y, 0 ); 46. selection.width = MIN( selection.width, image->width ); 47. selection.height = MIN( selection.height, image->height ); 48. selection.width -= selection.x; 49. selection.height -= selection.y; 50. 51. } 52. 53. switch( event ) 54. { 55. case CV_EVENT_LBUTTONDOWN: 56. origin = cvPoint(x,y); 57. selection = cvRect(x,y,0,0); 58. select_object = 1; 59. break; 60. case CV_EVENT_LBUTTONUP: 61. select_object = 0; 62. if( selection.width > 0 && selection.height > 0 ) 63. track_object = -1; 64. #ifdef _DEBUG 65. printf("/n # 鼠标的选择区域:"); 66. printf("/n X = %d, Y = %d, Width = %d, Height = %d", 67. selection.x, selection.y, selection.width, selection.height); 68. #endif 69. break; 70. } 71. } 72. 73. 74. CvScalar hsv2rgb( float hue ) 75. { 76. int rgb[3], p, sector; 77. static const int sector_data[][3]= 78. {{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}}; 79. hue *= 0.033333333333333333333333333333333f; 80. sector = cvFloor(hue); 81. p = cvRound(255*(hue - sector)); 82. p ^= sector & 1 ? 255 : 0; 83. 84. rgb[sector_data[sector][0]] = 255; 85. rgb[sector_data[sector][1]] = 0; 86. rgb[sector_data[sector][2]] = p; 87. 88. #ifdef _DEBUG 89. printf("/n # Convert HSV to RGB:"); 90. printf("/n HUE = %f", hue); 91. printf("/n R = %d, G = %d, B = %d", rgb[0],rgb[1],rgb[2]); 92. #endif 93. 94. return cvScalar(rgb[2], rgb[1], rgb[0],0); 95. } 96. 97. int main( int argc, char** argv ) 98. { 99. CvCapture* capture = 0; 100. IplImage* frame = 0; 101. 102. if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) 103. capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); 104. else if( argc == 2 ) 105. capture = cvCaptureFromAVI( argv[1] ); 106. 107. if( !capture ) 108. { 109. fprintf(stderr,"Could not initialize capturing.../n"); 110. return -1; 111. } 112. 113. printf( "Hot keys: /n" 114. "/tESC - quit the program/n" 115. "/tc - stop the tracking/n" 116. "/tb - switch to/from backprojection view/n" 117. "/th - show/hide object histogram/n" 118. "To initialize tracking, select the object with mouse/n" ); 119. 120. //cvNamedWindow( "Histogram", 1 ); 121. cvNamedWindow( "CamShiftDemo", 1 ); 122. cvSetMouseCallback( "CamShiftDemo", on_mouse ); // on_mouse 自定义事件 123. cvCreateTrackbar( "Vmin", "CamShiftDemo", &vmin, 256, 0 ); 124. cvCreateTrackbar( "Vmax", "CamShiftDemo", &vmax, 256, 0 ); 125. cvCreateTrackbar( "Smin", "CamShiftDemo", &smin, 256, 0 ); 126. 127. for(;;) 128. { 129. int i, bin_w, c; 130. 131. frame = cvQueryFrame( capture ); 132. if( !frame ) 133. break; 134. 135. if( !image ) 136. { 137. /* allocate all the buffers */ 138. image = cvCreateImage( cvGetSize(frame), 8, 3 ); 139. image->origin = frame->origin; 140. hsv = cvCreateImage( cvGetSize(frame), 8, 3 ); 141. hue = cvCreateImage( cvGetSize(frame), 8, 1 ); 142. mask = cvCreateImage( cvGetSize(frame), 8, 1 ); 143. backproject = cvCreateImage( cvGetSize(frame), 8, 1 ); 144. hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); // 计算直方图 145. histimg = cvCreateImage( cvSize(320,200), 8, 3 ); 146. cvZero( histimg ); 147. } 148. 149. cvCopy( frame, image, 0 ); 150. cvCvtColor( image, hsv, CV_BGR2HSV ); // 彩色空间转换 BGR to HSV 151. 152. if( track_object ) 153. { 154. int _vmin = vmin, _vmax = vmax; 155. 156. cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0), 157. cvScalar(180,256,MAX(_vmin,_vmax),0), mask ); // 得到二值的MASK 158. cvSplit( hsv, hue, 0, 0, 0 ); // 只提取 HUE 分量 159. 160. if( track_object < 0 ) 161. { 162. float max_val = 0.f; 163. cvSetImageROI( hue, selection ); // 得到选择区域 for ROI 164. cvSetImageROI( mask, selection ); // 得到选择区域 for mask 165. cvCalcHist( &hue, hist, 0, mask ); // 计算直方图 166. cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 ); // 只找最大值 167. cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 ); // 缩放 bin 到区间 [0,255] 168. cvResetImageROI( hue ); // remove ROI 169. cvResetImageROI( mask ); 170. track_window = selection; 171. track_object = 1; 172. 173. cvZero( histimg ); 174. bin_w = histimg->width / hdims; // hdims: 条的个数,则 bin_w 为条的宽度 175. 176. // 画直方图 177. for( i = 0; i < hdims; i++ ) 178. { 179. int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 ); 180. CvScalar color = hsv2rgb(i*180.f/hdims); 181. cvRectangle( histimg, cvPoint(i*bin_w,histimg->height), 182. cvPoint((i+1)*bin_w,histimg->height - val), 183. color, -1, 8, 0 ); 184. } 185. } 186. 187. cvCalcBackProject( &hue, backproject, hist ); // 使用 back project 方法 188. cvAnd( backproject, mask, backproject, 0 ); 189. 190. // calling CAMSHIFT 算法模块 191. cvCamShift( backproject, track_window, 192. cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ), 193. &track_comp, &track_box ); 194. track_window = track_comp.rect; 195. 196. if( backproject_mode ) 197. cvCvtColor( backproject, image, CV_GRAY2BGR ); // 使用backproject灰度图像 198. if( image->origin ) 199. track_box.angle = -track_box.angle; 200. cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 ); 201. } 202. 203. if( select_object && selection.width > 0 && selection.height > 0 ) 204. { 205. cvSetImageROI( image, selection ); 206. cvXorS( image, cvScalarAll(255), image, 0 ); 207. cvResetImageROI( image ); 208. } 209. 210. cvShowImage( "CamShiftDemo", image ); 211. cvShowImage( "Histogram", histimg ); 212. 213. c = cvWaitKey(10); 214. if( c == 27 ) 215. break; // exit from for-loop 216. switch( c ) 217. { 218. case 'b': 219. backproject_mode ^= 1; 220. break; 221. case 'c': 222. track_object = 0; 223. cvZero( histimg ); 224. break; 225. case 'h': 226. show_hist ^= 1; 227. if( !show_hist ) 228. cvDestroyWindow( "Histogram" ); 229. else 230. cvNamedWindow( "Histogram", 1 ); 231. break; 232. default: 233. ; 234. } 235. } 236. 237. cvReleaseCapture( &capture ); 238. cvDestroyWindow("CamShiftDemo"); 239. 240. return 0; 241. } 242. 243. #ifdef _EiC 244. main(1,"camshiftdemo.c"); 245. #endif

 

    笔者在VC6.0中,代码通过编译,可以正常使用。但是如果将该代码转换到MFC中,则会出现,cvSetMouseCallback()函数不断报错的情况出现。笔者在网上搜索解决方法,高手们的建议,一个方向是:用MFC自行提供的消息机制,但是如何使用,并没有说。一个方向是:将该函数在声明的时候定义为static类型。但是解决方法回复为,即使定义后,仍然无法解决该问题。笔者查阅了大量的网页,还有侯俊杰老师的《深入浅出MFC,解决了该问题,可以使程序在MFC中正常运行。

    方法比较简单,希望,懂得如何利用MFC消息机制的高手,提点一二

    具体解决方法,见下篇文章

 

 

 

 

你可能感兴趣的:(Algorithm,算法,object,image,application,mfc)