获取图像感兴趣地矩形区域实现

背景引言

虽然在开发APP中,鼠标操作开发非常简单,它属于用户接口设计,一直使用Misscoft Studio 中C/C++或.net来做,但是如果只需要简单的鼠标,键盘操作。而OpenCV并未直接提供库的函数进行鼠标操作。本节介绍使用OpenCV完成鼠标操作相关知识。

预备知识

鼠标操作主要理论有两点,第一是监控鼠标操作,鼠标点击,移动,松开,然后通过mouse_event识别判断出那一种鼠标的操作,根据不同的操作然后进行处理;第二是在主函数中加入鼠标的回调函数,将鼠标操作与程序的窗口绑定。每当滑动鼠标在窗口点击一下的时候,都会有固定三个动作,即点击动作(click),移动动作(Down)和松开动作(move)。因此,鼠标在点击时候执行onMouse函数。同时,还是有一个回调函数。如下所介绍:

回调函数setMouseCallback

OpenCV中,提供的鼠标回调函数是 setMouseCallback,函数声明如下:

//! assigns callback for mouse events
CV_EXPORTS void setMouseCallback(const string& winname, 
                                 MouseCallback onMouse, 
                                 void* userdata = 0);
 函数参数

  • const string& winname,windows视窗名称,对名为winname的视窗进行鼠标监控。
  • MouseCallback onMouse,鼠标响应处理函数,监听鼠标的点击,移动,松开,判断鼠标的操作类型,并进行响应的函数处理。
  • void* userdata = 0 鼠标响应处理函数的ID,与鼠标相应处理函数相匹配就行,暂时只用到默认为0的情况。

函数使用实例:

OpenCV1.X

cvNamedWindow("src",1);    
cvSetMouseCallback( "src", on_mouse, 0 );  
OpenCV2.X

namedWindow("img");  
setMouseCallback("img",on_mouse,0);

鼠标响应处理函数on_mouse

OpenCV中,鼠标相应处理函数一般默认形参和返回参数,函数形式如下:

void on_mouse(int event,int x,int y,int flags,void *ustc)
参数介绍:
  • int event,鼠标操作时间的整数代号,在opencv中,event鼠标事件总共有10中,从0-9依次代表如下:
    enum
    {
        EVENT_MOUSEMOVE      =0,    //滑动
        EVENT_LBUTTONDOWN    =1,    //左键点击
        EVENT_RBUTTONDOWN    =2,    //右键点击
        EVENT_MBUTTONDOWN    =3,    //中间点击
        EVENT_LBUTTONUP      =4,    //左键释放
        EVENT_RBUTTONUP      =5,    //右键释放
        EVENT_MBUTTONUP      =6,    //中间释放
        EVENT_LBUTTONDBLCLK  =7,    //左键双击
        EVENT_RBUTTONDBLCLK  =8,    //右键双击
        EVENT_MBUTTONDBLCLK  =9     //中间释放
    };
  • int x,int y,代表鼠标位于窗口的(x,y)坐标位置,窗口左上角默认为原点,向右为x轴,向下为y轴,
  • int flags,代表鼠标的拖拽事件,以及键盘鼠标联合事件,总共有32种事件,依次如下:
    enum
    {
        EVENT_FLAG_LBUTTON   =1,    //左键拖拽
        EVENT_FLAG_RBUTTON   =2,    //右键拖拽
        EVENT_FLAG_MBUTTON   =4,    //中间拖拽
        EVENT_FLAG_CTRLKEY   =8,    //(8~15)按Ctrl不放事件
        EVENT_FLAG_SHIFTKEY  =16,   //(16~31)按Shift不放事件
        EVENT_FLAG_ALTKEY    =32    //(32~39)按Alt不放事件(后面8-39还有待研究)
    };
    
  • void *ustc,函数参数的编号(暂时用不到)

字体结构初始化函数cvInitfont

/* Initializes font structure used further in cvPutText */
CVAPI(void)  cvInitFont( CvFont* font, int font_face,
                         double hscale, double vscale,
                         double shear CV_DEFAULT(0),
                         int thickness CV_DEFAULT(1),
                         int line_type CV_DEFAULT(8));

参数介绍:

  • font   字体初始化。
  • font_face  字体名称标识符
    /* basic font types */
    #define CV_FONT_HERSHEY_SIMPLEX         0    //正常大小无衬线字体.
    #define CV_FONT_HERSHEY_PLAIN           1    //小号无衬线字体.
    #define CV_FONT_HERSHEY_DUPLEX          2    //正常大小无衬线字体(比CV_FONT_HERSHEY_SIMPLEX更复杂).
    #define CV_FONT_HERSHEY_COMPLEX         3    //正常大小有衬线字体.
    #define CV_FONT_HERSHEY_TRIPLEX         4    //正常大小有衬线字体(比CV_FONT_HERSHEY_COMPLEX更复杂).
    #define CV_FONT_HERSHEY_COMPLEX_SMALL   5    //CV_FONT_HERSHEY_COMPLEX的小译本
    #define CV_FONT_HERSHEY_SCRIPT_SIMPLEX  6    //手写风格字体.
    #define CV_FONT_HERSHEY_SCRIPT_COMPLEX  7    //手写风格字体(比CV_FONT_HERSHEY_SCRIPT_SIMPLEX更复杂).
    此参数可以由一个值及可选择的CV_FONT_ITALIC(斜体字)字体标记合成。
  • hscale  字体宽度。如果hscale =1.0F, 则字符宽度度是最初的字体宽度。如果hscale =0.5F,则字符宽度是最初字体宽度一半。
  • vscale  字体高度。如果hscale =1.0F, 则字符宽度度是最初的字体高度。如果hscale =0.5F,则字符宽度是最初字体高度一半。
  • shear   字体的斜度。当值为0 时,字符不倾。当值为1.0F时,字体45度。
  • thickness  字体笔划的粗细程度。
  • line_type  字体笔划的类型,见cvLine中的描述。

说明:

函数cvInitFont完成对字体结构的初始化。注opencv对中文不支持。

图像中加入文本函数PutText

/* Renders text stroke with specified font and color at specified location.
   CvFont should be initialized with cvInitFont */
CVAPI(void)  cvPutText( CvArr* img, const char* text, CvPoint org,
                        const CvFont* font, CvScalar color );

参数介绍:

  • img  输入图像
  • text 显示字符串
  • org  第一个字符左下角的坐标
  • font 初始化了的字体结构。
  • color 文本的字体颜色。

说明:

函数cvPutText将具有指定字体和指定颜色的文本加入到图像中。加入到图像中的文本被感兴趣的矩形框圈定。

参考代码

源始图片

1.OpenCV1.x版利用鼠标操作显示坐标

int bound(short i,short a,short b)    {   
    return min(max(i,min(a,b)),max(a,b)); }    
  
CvScalar InverseColor(CvScalar c){    
    CvScalar s;    
    for(int i=0;i<=2;++i)     
        s.val[i]=255-c.val[i];        
    return s;    
}       
int n=0;    
vector points;    
  
void on_mouse( int event, int x, int y, int flags, void* ustc){    
    CvPoint pt;    
    CvPoint tmp_pt = {-1,-1};

    CvFont font;    
    cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.4, 0.4, 0, 1, CV_AA);    
    char temp[16];    
    CvSize text_size;    
    int baseline;    
  
    CvScalar clrPoint=cvScalar(255,0,0,0);    
    CvScalar clrText=cvScalar(0, 0, 255, 0);    
  
    if( event == CV_EVENT_MOUSEMOVE )    
    {    
        cvCopy(dst,src);        
        x=bound(x,0,src->width-1);    
        y=bound(y,0,src->height-1);    
        pt = cvPoint(x,y);    

        cvCircle( src, pt, 2,clrPoint ,CV_FILLED, CV_AA, 0 );    
        sprintf(temp,"%d (%d,%d)",n+1,x,y); 
   
        cvGetTextSize(temp,&font,&text_size,&baseline);    
        tmp_pt.x = bound(pt.x,0,src->width-text_size.width);    
        tmp_pt.y = bound(pt.y,text_size.height+baseline,src->height-1-baseline); 
   
        cvPutText(src,temp, tmp_pt, &font, clrText);  
        cvShowImage( "src", src );    
    }     
    else if( event == CV_EVENT_LBUTTONDOWN)    
    {    
        pt = cvPoint(x,y);    
        points.push_back(pt); n++;    
        cvCircle( src, pt, 2, clrPoint ,CV_FILLED, CV_AA, 0 );    
  
        sprintf(temp,"%d (%d,%d)",n,x,y);    
        cvGetTextSize(temp,&font,&text_size,&baseline);    
        tmp_pt.x = bound(pt.x,0,src->width-text_size.width);    
        tmp_pt.y = bound(pt.y,text_size.height+baseline,src->height-1-baseline);    
        cvPutText(src,temp, tmp_pt, &font, clrText);    
  
        cvCopy(src,dst);  
        cvShowImage( "src", src );    
    }     
    else if( event == CV_EVENT_RBUTTONDOWN )    
    {    
        if(!points.empty())    
        {    
            cvCopy(dst,src);    
            pt=points.back();    
            points.pop_back(); 
    
            cvCircle( src, pt, 2, getInverseColor(clrPoint),CV_FILLED, CV_AA, 0 );   
            sprintf(temp,"%d (%d,%d)",n,pt.x,pt.y); 
            --n;    
            cvGetTextSize(temp,&font,&text_size,&baseline);    
            tmp_pt.x = bound(pt.x,0,src->width-text_size.width);    
            tmp_pt.y = bound(pt.y,text_size.height+baseline,src->height-1-baseline);    
            cvPutText(src,temp, tmp_pt, &font, getInverseColor(clrText));    
  
            cvCopy(src,dst); 
            cvShowImage( "src", src );    
        }    
    }   
}
输出结果

获取图像感兴趣地矩形区域实现_第1张图片  获取图像感兴趣地矩形区域实现_第2张图片

2. OpenCV1.x版获取图像感兴趣地矩形区域

void on_mouse( int event, int x, int y, int flags, void* ustc){    
    static CvPoint pre_pt = {-1,-1};    
    static CvPoint cur_pt = {-1,-1};    
    CvFont font;    
    cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA);    
    char temp[16];    
        
    if( event == CV_EVENT_LBUTTONDOWN){    
        cvCopy(dst,src);    
        sprintf(temp,"(%d,%d)",x,y); 
   
        pre_pt = cvPoint(x,y);    
        cvPutText(src,temp, pre_pt, &font, cvScalar(0,0, 0, 255));    
        cvCircle( src, pre_pt, 3,cvScalar(255,0,0,0) ,CV_FILLED, CV_AA, 0 );  
  
        cvShowImage( "src", src );    
        cvCopy(src,dst);    
    }    
    if( event == CV_EVENT_MOUSEMOVE && !(flags & CV_EVENT_FLAG_LBUTTON)){    
        cvCopy(dst,src);    
        sprintf(temp,"(%d,%d)",x,y); 
   
        cur_pt = cvPoint(x,y);          
        cvPutText(src,temp, cur_pt, &font, cvScalar(0,0, 0, 255));    
        cvShowImage( "src", src );    
    }    
    if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON)){    
        cvCopy(dst,src);    
        sprintf(temp,"(%d,%d)",x,y);    
        cur_pt = cvPoint(x,y);        
  
        cvPutText(src,temp, cur_pt, &font, cvScalar(0,0, 0, 255));    
        cvRectangle(src, pre_pt, cur_pt, cvScalar(0,255,0,0), 1, 8, 0 );   
        cvShowImage( "src", src );    
    }    
    if( event == CV_EVENT_LBUTTONUP){    
        sprintf(temp,"(%d,%d)",x,y);    
        cur_pt = cvPoint(x,y);       
   
        cvPutText(src,temp, cur_pt, &font, cvScalar(0,0, 0, 255));    
        cvCircle( src, cur_pt, 3,cvScalar(255,0,0,0) ,CV_FILLED, CV_AA, 0 );    
        cvRectangle( src, pre_pt, cur_pt, cvScalar(0,255,0,0), 1, 8, 0 ); 

        cvShowImage( "src", src );    
        cvCopy(src,dst);    
    }    
}    
输出结果

获取图像感兴趣地矩形区域实现_第3张图片  获取图像感兴趣地矩形区域实现_第4张图片

3.OpenCV2.x版获取图像感兴趣地矩形区域并显示

void on_mouse(int event,int x,int y,int flags,void *ustc){  
    static Point pre_pt = (-1,-1);  
    static Point cur_pt = (-1,-1);  
    char temp[16]; 
 
    if (event == CV_EVENT_LBUTTONDOWN){        
        org.copyTo(img);  
        sprintf(temp,"(%d,%d)",x,y); 
 
        pre_pt = Point(x,y);  
        putText(img,temp,pre_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255),1,8);  
        circle(img,pre_pt,2,Scalar(255,0,0,0),CV_FILLED,CV_AA,0); 
        imshow("img",img);  
    }  
    if (event == CV_EVENT_MOUSEMOVE && !(flags & CV_EVENT_FLAG_LBUTTON)){  
        img.copyTo(tmp);  
        sprintf(temp,"(%d,%d)",x,y); 
 
        cur_pt = Point(x,y);  
        putText(tmp,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));  
        imshow("img",tmp);  
    }  
    if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON)){  
        img.copyTo(tmp);  
        sprintf(temp,"(%d,%d)",x,y);  
        cur_pt = Point(x,y);  

        putText(tmp,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));  
        rectangle(tmp,pre_pt,cur_pt,Scalar(0,255,0,0),1,8,0);  
        imshow("img",tmp);  
    }  
    if (event == CV_EVENT_LBUTTONUP){      
        org.copyTo(img);  
        sprintf(temp,"(%d,%d)",x,y);  
        cur_pt = Point(x,y); 
 
        putText(img,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));  
        circle(img,pre_pt,2,Scalar(255,0,0,0),CV_FILLED,CV_AA,0);  
        rectangle(img,pre_pt,cur_pt,Scalar(0,255,0,0),1,8,0);  

        imshow("img",img);
        img.copyTo(tmp);   
        int width = abs(pre_pt.x - cur_pt.x);  
        int height = abs(pre_pt.y - cur_pt.y);  

        if (width == 0 || height == 0){  
            printf("width == 0 || height == 0");  
            return;  
        }  

        dst = org(Rect(min(cur_pt.x,pre_pt.x),min(cur_pt.y,pre_pt.y),width,height));  
        namedWindow("dst");  
        imshow("dst",dst); 
        waitKey(0);  
    }  
}  
输出结果

获取图像感兴趣地矩形区域实现_第5张图片  获取图像感兴趣地矩形区域实现_第6张图片

上图像中选择矩形区域的显示,如下图所示:

  获取图像感兴趣地矩形区域实现_第7张图片

如下图中,Img Win显示图像并为选择感兴趣地矩形区域,而Dst Win为显示选择感兴趣地矩形区域的图像。即:


注:OpenCV1.x版中贴出参考代码变量src,dst分别为输入图像和输出图像变量并且申明全局变量和变量类型为Ipllmage,OpenCV2.X版中贴出参考代码变量org, dst,img,tmp都申明全局变量并且为cv::Mat类型。其中如何调用on_Mouse函数,请见回调函数setMouseCallback中函数使用实例


关于Image Engineering & Computer Vision的更多讨论与交流,敬请关注本博和新浪微博songzi_tea.


你可能感兴趣的:(【OpenCV/Python】,探讨OpenCV)