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
posted @ 2015-06-29 16:44  若沿  阅读(4285)  评论(0编辑  收藏  举报