Opencv 手动选择ROI以及鼠标交互


转自http://www.cnblogs.com/tornadomeet/archive/2012/05/04/2483444.html

一些图像处理算法要求用户的参与,比如分割算法GrabCut需要用户选定初始区域或前/背景掩模,在用OpenCV实现里,就涉及到利用鼠标在图片上选定这些区域,这里讲讲常见的几种鼠标绘图:

1、绘制矩形并获得矩形区域图像:在显示图片的窗口,通过拖动鼠标绘制矩形,按ESC键退出绘图模式。

涉及函数: 

 void cvSetMouseCallback( constchar* window_name, CvMouseCallback on_mouse, void* param=NULL );

  --window_name 窗口的名字。

  --on_mouse 指定窗口里每次鼠标事件发生的时候,被调用的函数指针。

  这个函数的原型应该为

    --voidFoo(int event,int x,int y,int flags,void* param);

      其中event是 CV_EVENT_*变量之一,x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系),flags是CV_EVENT_FLAG的组合(即上面的一些有关现在动作状态的预定义,现在鼠标没任何操作时为0),param是用户定义的传递到cvSetMouseCallback函数调用  的参数。

  --param 用户定义的传递到回调函数的参数。

  函数 cvSetMouseCallback设定指定窗口鼠标事件发生时的回调函数。

  详细使用方法,请参考opencv/samples/c/ffilldemo.c demo。

 1 #include "cv.h"
 2 #include "highgui.h"
 3 
 4 #include <iostream>
 5 
 6 using namespace std;  7 using namespace cv;  8 
 9 void DrawRect(IplImage*img,CvRect rect);  10 void MouseDraw(int event,int x,int y,int flags,void*param);  11 
 12 struct MouseArgs{  13     IplImage* img;  14  CvRect box;  15     bool Drawing;  16     // init
 17     MouseArgs():Drawing(false),img(0){  18         box=cvRect(0,0,-1,-1);  19  }  20     // destroy
 21     void Destroy(){  22         if(!img)  23             cvReleaseImage(&img);  24  }  25 };  26 
 27 int main(int argc, char** argv)  28 {  29     // loading image
 30     char* imf = argc >= 2 ? argv[1] :"audi-2009.jpg";  31 
 32     IplImage* pImg_org = cvLoadImage(imf,1);  33     if(!pImg_org){  34         cout<<"cann't load image!"<<endl;  35         return -1;  36  }  37 
 38     // 回调参数
 39     MouseArgs* m_arg = new MouseArgs();  40     m_arg->img = cvCloneImage(pImg_org);  41 
 42     // 画图窗口
 43     cvNamedWindow("Draw ROI",CV_WINDOW_AUTOSIZE);  44 
 45     // 设置鼠标事件的回调函数
 46     cvSetMouseCallback("Draw ROI",  47  MouseDraw,  48         (void*)m_arg);  49 
 50     // 拖动鼠标作画
 51     IplImage* temp=cvCloneImage(pImg_org);  52     while(1)  53  {  54         cvCopyImage(m_arg->img,temp);  55         if(m_arg->Drawing)  56             DrawRect(temp,m_arg->box);  57         cvShowImage("Draw ROI",temp);  58         // 按 esc 键退出绘图模式,获得矩形
 59         if(cvWaitKey(100)==27)  60             break;  61 
 62  }  63     cvReleaseImage( &temp );  64 
 65     // 获得ROI区域的图像
 66     IplImage* roi;  67     if(m_arg->box.width<10 || m_arg->box.height<10)  68  {  69         roi=cvCloneImage(pImg_org);  70  }  71     else
 72  {  73         roi=cvCreateImage(cvSize(m_arg->box.width,m_arg->box.height),  74             pImg_org->depth,  75             pImg_org->nChannels);  76         cvSetImageROI(pImg_org,m_arg->box);//设定ROI
 77         roi=cvCloneImage(pImg_org);//复制出ROI区域的图像
 78  cvResetImageROI(pImg_org);  79 
 80  }  81 
 82     cvNamedWindow( "ROI", 1 );  83     cvShowImage( "ROI", roi );  84 
 85     //  86     cvWaitKey(0);  87     cvDestroyWindow("Draw ROI");  88 
 89     m_arg->Destroy ();  90     delete m_arg;  91     cvReleaseImage(&pImg_org);  92     cvReleaseImage(&roi);  93     //  94     return 0;  95 
 96 }  97 
 98 /*
 99 描述:在图像上绘制矩形 100 */
101 void DrawRect(IplImage*img,CvRect rect) 102 { 103  cvRectangle(img, 104  cvPoint(rect.x,rect.y), 105         cvPoint(rect.x+rect.width,rect.y+rect.height), 106         cvScalar(255,0,0),3); 107 } 108 
109 /*
110 描述:鼠标事件的回调函数 111 函数原型: void Foo(int event, int x, int y, int flags, void* param); 112 参数: event -- CV_EVENT_*变量之一, 113  x,y -- 鼠标指针在图像坐标系的坐标(不是窗口坐标系) 114  flags -- CV_EVENT_FLAG的组合 115  param -- 用户定义的传递到cvSetMouseCallback函数调用的参数 116 */
117 void MouseDraw(int event,int x,int y,int flags,void*param) 118 { 119     MouseArgs* m_arg = (MouseArgs*) param; 120     if(!m_arg->img) 121         return; 122 
123     switch(event) 124  { 125     case CV_EVENT_MOUSEMOVE: // 鼠标移动时
126  { 127             if(m_arg->Drawing) 128  { 129                 m_arg->box.width = x-m_arg->box.x; 130                 m_arg->box.height = y-m_arg->box.y; 131  } 132  } 133         break; 134     case CV_EVENT_LBUTTONDOWN: // 左键按下
135  { 136             m_arg->Drawing = true; 137             m_arg->box = cvRect(x,y,0,0); 138  } 139         break; 140     case CV_EVENT_LBUTTONUP: // 左键弹起
141  { 142             m_arg->Drawing = false; 143             if (m_arg->box.width<0) 144  { 145                 m_arg->box.x += m_arg->box.width; 146                 m_arg->box.width *= -1; 147  } 148             if (m_arg->box.height<0) 149  { 150                 m_arg->box.y += m_arg->box.height; 151                 m_arg->box.height *= -1; 152  } 153             DrawRect(m_arg->img, m_arg->box); 154  } 155         break; 156  } 157 }
View Code

 2、绘制任意形状并获得区域图像:原理同上,使用CvSeq记录轨迹点,然后用cvFillConvexPoly填充多边形区域形成掩模,最后用cvCopy拷贝区域图像。支持两种绘图模式,描点式(如PS之钢笔)和拖动式:

  1 // mouse.cpp : 定义控制台应用程序的入口点。
  2 //
  3 
  4 #include "stdafx.h"
  5 
  6 
  7 #include "cv.h"
  8 #include "highgui.h"
  9 #include "cxcore.h"
 10 
 11 #include <iostream>
 12 
 13 using namespace std;
 14 using namespace cv;
 15 void MouseDraw(int event,int x,int y,int flags,void*param);
 16 struct MouseArgs{
 17     IplImage* img;
 18     CvPoint p_start;
 19     CvPoint p_end;
 20     CvSeq* seq;
 21     CvMemStorage* storage;
 22     int points;
 23     // init
 24     MouseArgs():img(0),points(0){
 25         p_start = cvPoint(-1,-1);
 26         p_end = cvPoint(-1,-1);
 27         storage = cvCreateMemStorage(0);
 28         seq = cvCreateSeq( CV_32SC2,sizeof(CvSeq),sizeof(CvPoint), storage );
 29     }
 30     // destroy
 31     void Destroy(){
 32         if(!img)
 33             cvReleaseImage(&img);
 34         cvReleaseMemStorage(&storage );
 35         seq = NULL;
 36         img = NULL;
 37     }
 38 };
 39 
 40 int main( int argc,char** argv )
 41 {
 42     // loading image
 43     char* imf = argc >= 2 ? argv[1] :"5.jpg";
 44 
 45     IplImage* pImg_org = cvLoadImage(imf,1);
 46     if(!pImg_org){
 47         cout<<"cann't load image!"<<endl;
 48         return-1;
 49     }
 50 
 51     // 回调参数
 52     MouseArgs* m_arg =new MouseArgs();
 53     m_arg->img = cvCloneImage(pImg_org);
 54 
 55     // 画图窗口
 56     cvNamedWindow("Draw ROI",CV_WINDOW_AUTOSIZE);
 57 
 58     // 设置鼠标事件的回调函数
 59     cvSetMouseCallback("Draw ROI",MouseDraw,(void*)m_arg); 
 60 
 61     // 拖动鼠标作画
 62     while(1)
 63     {
 64         cvShowImage("Draw ROI",m_arg->img);
 65         // 按 esc 键退出绘图模式,获得矩形
 66         if(cvWaitKey(100)==27)
 67             break;
 68 
 69     }
 70 
 71     // 输出
 72     if(m_arg->points < 1)
 73         return 0;
 74     cout<<m_arg->points <<endl;
 75 
 76     // 获得掩模
 77     IplImage* mask = cvCreateImage( cvGetSize(pImg_org), 8, 1 );
 78     cvZero(mask);
 79 
 80     CvPoint* PointArr =new CvPoint[m_arg->points];
 81     cvCvtSeqToArray(m_arg->seq, PointArr);
 82     cvFillConvexPoly(mask,PointArr,m_arg->points,cvScalarAll(255),CV_AA,0);
 83     delete[] PointArr;
 84     cvNamedWindow("Mask",CV_WINDOW_AUTOSIZE);
 85     cvShowImage("Mask",mask);
 86 
 87     // 获得区域
 88     IplImage* roi = cvCreateImage( cvGetSize(pImg_org), 8, 3 );
 89     cvCopy(pImg_org,roi,mask);
 90     cvNamedWindow("ROI",CV_WINDOW_AUTOSIZE);
 91     cvShowImage("ROI",roi);
 92 
 93     //
 94     cvWaitKey(0);
 95     cvDestroyWindow("Draw ROI");
 96     cvDestroyWindow("Mask");
 97     cvDestroyWindow("ROI");
 98 
 99     //
100     m_arg->Destroy ();
101     delete m_arg;
102     cvReleaseImage(&pImg_org);
103     cvReleaseImage(&mask);
104     cvReleaseImage(&roi);
105     //
106     getchar();
107     return 0;
108 }
109     // 描点式
110 /*
111 void MouseDraw(int event,int x,int y,int flags,void*param)
112 {
113     MouseArgs* m_arg = (MouseArgs*) param;
114     if( !m_arg->img )
115         return;
116   
117     if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) )
118     {
119         m_arg->p_end = m_arg->p_start;
120     }
121     else if( event == CV_EVENT_LBUTTONDOWN )
122     {
123         m_arg->p_start = cvPoint(x,y);
124         cvSeqPush( m_arg->seq, &m_arg->p_start);  // 描点记录
125         m_arg->points += 1;
126         if(m_arg->p_start.x>0 && m_arg->p_end.x>0){
127             cvLine( m_arg->img, m_arg->p_start, m_arg->p_end, cvScalar(0,0,255) );
128             cvLine( m_arg->img, m_arg->p_start, m_arg->p_start, cvScalar(128,0,255) );
129         }
130     }
131   
132 }
133 */
134 // 拖动式
135 void MouseDraw(int event,int x,int y,int flags,void*param)
136 {
137     MouseArgs* m_arg = (MouseArgs*) param;
138     if( !m_arg->img )
139         return;
140   
141     if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) )
142     {
143         m_arg->p_start = cvPoint(x,y);
144     }
145     else if( event == CV_EVENT_LBUTTONDOWN )
146     {
147         m_arg->p_start = cvPoint(x,y);
148         cvSeqPush( m_arg->seq, &m_arg->p_start);
149         m_arg->points += 1;
150         if(m_arg->p_start.x>0 && m_arg->p_end.x>0){
151             cvLine( m_arg->img, m_arg->p_start, m_arg->p_start, cvScalar(128,0,255) );
152         }
153     }
154     else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON) )
155     {
156         CvPoint pt = cvPoint(x,y);
157         if( m_arg->p_start.x > 0 ){
158             cvLine( m_arg->img, m_arg->p_start, pt, cvScalar(128,0,255) );
159             m_arg->p_start = pt;
160             cvSeqPush( m_arg->seq, &m_arg->p_start);
161             m_arg->points += 1;
162         }
163   
164     }
165   
166 }
View Code

 3、鼠标控制动态缩放图像显示:在cvNamedWindow图像窗口中通过“ ALT和鼠标左键开始按下的时候放大图像”和“ALT和鼠标右键开始按下的时候缩小图像”:

 1 #include "cv.h"
 2 #include "highgui.h"
 3   
 4 #include <iostream>
 5   
 6 usingnamespace std;  7 usingnamespace cv;  8   
 9 structMouseArgs{  10     IplImage* img_src;  11     IplImage* img_dst;  12  doublescale;  13     // init
 14     MouseArgs():img_src(0),img_dst(0),scale(1.0){  15  }  16     // destroy
 17  voidDestroy(){  18         if(!img_src)  19             cvReleaseImage(&img_src);  20         if(!img_dst)  21             cvReleaseImage(&img_dst);  22  }  23 };  24   
 25 voidMouseResize(intevent,int x,int y,intflags,void*param);  26 IplImage* resize_img(IplImage* src,doubleimgzoom_scale);  27   
 28 int main( int argc,char** argv )  29 {  30     // loading image
 31     char* imf = argc >= 2 ? argv[1] :"audi-2009.jpg";  32   
 33     IplImage* pImg_org = cvLoadImage(imf,1);  34     if(!pImg_org){  35         cout<<"cann't load image!"<<endl;  36         return-1;  37  }  38   
 39     // 回调参数
 40     MouseArgs* m_arg =new MouseArgs();  41     m_arg->img_src = cvCloneImage(pImg_org);  42   
 43     // 画图窗口
 44     cvNamedWindow("Resize",CV_WINDOW_AUTOSIZE);  45   
 46     // 设置鼠标事件的回调函数
 47     cvSetMouseCallback("Resize",  48  MouseResize,  49         (void*)m_arg);  50   
 51     //  52     while(1)  53  {  54         cvShowImage("Resize",m_arg->img_src);  55         // 按 esc 键退出
 56         if(cvWaitKey(100)==27)  57             break;  58   
 59  }  60   
 61     //  62     cvWaitKey(0);  63     cvDestroyWindow("Resize");  64   
 65     //  66  getchar();  67  return0;  68 }  69   
 70 voidMouseResize( intevent, int x, int y, int flags, void* param )  71 {  72     MouseArgs* m_arg = (MouseArgs*) param;  73     if( !m_arg->img_src )  74         return;  75   
 76     if( (event==CV_EVENT_LBUTTONUP) &&  (flags==CV_EVENT_FLAG_CTRLKEY) )  77  {  78   
 79  }  80   
 81     // ALT和鼠标左键开始按下的时候放大图像
 82     if( (event==CV_EVENT_LBUTTONUP) &&  (flags==CV_EVENT_FLAG_ALTKEY) )  83  {  84   
 85         if(m_arg->scale<1.5)  86  {  87             m_arg->scale=1.1*m_arg->scale;  88  }  89         else
 90             m_arg->scale=1.0;  91   
 92         // 放大图像
 93         m_arg->img_dst = resize_img(m_arg->img_src, m_arg->scale);  94         m_arg->img_src = cvCloneImage(m_arg->img_dst);  95   
 96  }  97   
 98     //ALT和鼠标右键开始按下的时候缩小图像
 99     if( (event==CV_EVENT_RBUTTONUP) &&  (flags==CV_EVENT_FLAG_ALTKEY) ) 100  { 101   
102         if(m_arg->scale>0.0) 103  { 104             m_arg->scale=0.9*m_arg->scale; 105  } 106         else
107             m_arg->scale=0.5; 108   
109         // 缩小图像
110         m_arg->img_dst = resize_img(m_arg->img_src, m_arg->scale); 111         m_arg->img_src = cvCloneImage(m_arg->img_dst); 112   
113  } 114   
115 } 116   
117 IplImage* resize_img(IplImage* src,doubleimgzoom_scale) 118 { 119     IplImage* dst = cvCreateImage(cvSize(  (int)(src->width*imgzoom_scale),  (int)(src->height*imgzoom_scale) ), 120         src->depth, 121         src->nChannels); 122   
123  cvResize(src, dst, CV_INTER_AREA ); 124   
125  returndst; 126   }
View Code


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM