在CV里面,很多时候需要自己手动截出一块区域,然后针对这块区域进行处理,OpenCV并没有提供直接可调用的函数,如果每次都要自己写的话,估计写获取鼠标圈定区域就需要花很有一段时间~
近来是在做视频跟踪这一块,有的跟踪是基于检测的跟踪,则不需要手动圈定,但很多时候,为了能直接看到跟踪的效果,则采取手动圈定的方式,如下图所示:
我在看粒子滤波源码的时候发现了其鼠标圈定函数写的已经比较好调用,后来再看到meanshift跟踪,发现所用获取鼠标圈定函数一样的,所以我将其收集下来,以备后用,唔,接下来就是贴代码,这上面有部分我自己的代码……
若能看懂其鼠标圈定函数,则对自己以后写此函数很有裨益,注释就不写那么多了,整体也比较容易吧:
1 #include <cv.h> 2 #include <highgui.h> 3
//-------------- 控制获取区域个数 4 const int MAX_OBJECTS = 1; 5
//-------- 对参数封装 cvSetMouseCallback 所需参数
6 typedef struct params { 7 CvPoint loc1[MAX_OBJECTS]; 8 CvPoint loc2[MAX_OBJECTS]; 9 IplImage* objects[MAX_OBJECTS]; 10 char* win_name; 11 IplImage* orig_img; 12 IplImage* cur_img; 13 int n; 14 } params; 15 16 int GetRegions( IplImage*, CvRect** ); 17 void mouse( int, int, int, int, void* ); 18 19 int main(void) 20 { 21 IplImage *frame, *frame_copy; 22 CvCapture *video; 23 CvScalar color; 24 CvRect* regions; 25 26 char *video_file = "E:\\Coding\\acivs\\1.AVI"; 27 28 video = cvCaptureFromFile( video_file ); 29 if(!video) 30 { 31 printf("Cannot open the video file!!!"); 32 return -1; 33 } 34 35 int frmNo = 0, nObjects = 0; 36 while( frame = cvQueryFrame( video ) ) 37 { 38 frame_copy = cvCloneImage( frame ); 39 if(frmNo == 0) 40 { 41 printf("Please select a region to track !"); 42 while( nObjects == 0 ) 43 { 44 nObjects = GetRegions( frame, ®ions ); 45 if( nObjects == 0 ) 46 printf( "Please select a object\n" ); 47 } 48 } 49 else 50 { 51 printf("This is the %d st frame\n", frmNo); 52 53 } 54 frmNo++; 55 cvReleaseImage(&frame_copy); 56 } 57 58 cvReleaseCapture( &video ); 59 return 0; 60 } 61 //-------- 获取的区域 regions 62 int GetRegions( IplImage* frame, CvRect** regions ) 63 { 64 char* win_name = "First frame"; 65 params p; 66 CvRect* r; 67 int i, x1, y1, x2, y2, w, h; 68 69 /* use mouse callback to allow user to define object regions */ 70 p.win_name = win_name; 71 p.orig_img = cvCloneImage( frame ); 72 p.cur_img = NULL; 73 p.n = 0; 74 cvNamedWindow( win_name, 1 ); 75 cvShowImage( win_name, frame ); 76 cvSetMouseCallback( win_name, &mouse, &p ); 77 cvWaitKey( 0 ); 78 cvDestroyWindow( win_name ); 79 cvReleaseImage( &(p.orig_img) ); 80 if( p.cur_img ) 81 cvReleaseImage( &(p.cur_img) ); 82 83 /* extract regions defined by user; store as an array of rectangles */ 84 if( p.n == 0 ) 85 { 86 *regions = NULL; 87 return 0; 88 } 89 r = (CvRect *)malloc( p.n * sizeof( CvRect ) ); 90 for( i = 0; i < p.n; i++ ) 91 { 92 x1 = MIN( p.loc1[i].x, p.loc2[i].x ); 93 x2 = MAX( p.loc1[i].x, p.loc2[i].x ); 94 y1 = MIN( p.loc1[i].y, p.loc2[i].y ); 95 y2 = MAX( p.loc1[i].y, p.loc2[i].y ); 96 w = x2 - x1; 97 h = y2 - y1; 98 99 /* ensure odd width and height */ 100 w = ( w % 2 )? w : w+1; 101 h = ( h % 2 )? h : h+1; 102 r[i] = cvRect( x1, y1, w, h ); 103 } 104 *regions = r; 105 return p.n; 106 } 107 108 void mouse( int event, int x, int y, int flags, void* param ) 109 { 110 params* p = (params*)param; 111 CvPoint* loc; 112 int n; 113 IplImage* tmp; 114 static int pressed = FALSE; 115 116 /* on left button press, remember first corner of rectangle around object */ 117 if( event == CV_EVENT_LBUTTONDOWN ) 118 { 119 n = p->n; 120 if( n == MAX_OBJECTS ) 121 return; 122 loc = p->loc1; 123 loc[n].x = x; 124 loc[n].y = y; 125 pressed = TRUE; 126 } 127 128 /* on left button up, finalize the rectangle and draw it in black */ 129 else if( event == CV_EVENT_LBUTTONUP ) 130 { 131 n = p->n; 132 if( n == MAX_OBJECTS ) 133 return; 134 loc = p->loc2; 135 loc[n].x = x; 136 loc[n].y = y; 137 cvReleaseImage( &(p->cur_img) ); 138 p->cur_img = NULL; 139 cvRectangle( p->orig_img, p->loc1[n], loc[n], CV_RGB(0,0,0), 1, 8, 0 ); 140 cvShowImage( p->win_name, p->orig_img ); 141 pressed = FALSE; 142 p->n++; 143 } 144 145 /* on mouse move with left button down, draw rectangle as defined in white */ 146 else if( event == CV_EVENT_MOUSEMOVE && flags & CV_EVENT_FLAG_LBUTTON ) 147 { 148 n = p->n; 149 if( n == MAX_OBJECTS ) 150 return; 151 tmp = cvCloneImage( p->orig_img ); 152 loc = p->loc1; 153 cvRectangle( tmp, loc[n], cvPoint(x, y), CV_RGB(255,255,255), 1, 8, 0 ); 154 cvShowImage( p->win_name, tmp ); 155 if( p->cur_img ) 156 cvReleaseImage( &(p->cur_img) ); 157 p->cur_img = tmp; 158 } 159 }