[openCV]基于Mouse Event的Paint的实现

1.关于Mouse Event

本文可能与图像处理不是有太大的关联,是openCV的HighGUI中关于Mouse Event的一些学习与练习,可能更偏向于编程吧。之前的程序中,也常常会使用cvWaitKey()去等待键盘的动作。与之相同的,Mouse Event也算是一个很典型的Callback机制了,对于Mouse Event的设置openCV中需要调用以下函数去实现。

void cvSetMouseCallback(const char* window_name, 
                        CvMouseCallback on_mouse, 
                        void* param=NULL )
  • const char* window_name当在特定的窗口下Mouse Event被触发的话,会调用Callback函数。
  • CvMouseCallback on_mouse 这里放置Callback函数
  • void* param=NULL这里可以放置一个任意的参数,可以为NULL。若程序中有需要调用别的参数的时候,可以由这里转交给Callback函数。

对于上述的Callback函数,需要使用以下这种结构去进行申明。

void mouse_paint_callback(int event,
                          int x, 
                          int y, 
                          int flags, 
                          void* param);
  • int event表示Enent事件的类型。(由下表给出,尝试使用下表格)
Event Value 说明
CV_EVENT_MOUSEMOVE 0 鼠标移动
CV_EVENT_LBUTTONDOWN 1 左键压下
CV_EVENT_RBUTTONDOWN 2 右键压下
CV_EVENT_MBUTTONDOWN 3 中键压下
CV_EVENT_LBUTTONUP 4 左键弹起
CV_EVENT_RBUTTONUP 5 右键弹起
CV_EVENT_MBUTTONUP 6 中键弹起
CV_EVENT_LBUTTONDBLCLK 7 左键双击
CV_EVENT_RBUTTONDBLCLK 8 右键双击
CV_EVENT_MBUTTONDBLCLK 9 中键双击
  • int x, int yMouse Event触发瞬间,Mouse位于特定窗口的位置(坐标)。

  • int flags这个是事件的标志位,和单片机的寄存器比较类似。发生某个时间后,该事件对应的标志位置位。

flags Value 说明
CV_EVENT_FLAG_LBUTTON 1 (0x01 << 0) 左键被压下
CV_EVENT_FLAG_RBUTTON 2 (0x01 << 1) 右键被压下
CV_EVENT_FLAG_MBUTTON 4 (0x01 << 2) 中建被压下
CV_EVENT_FLAG_CTRLKEY 8 (0x01 << 3) CTRL键被压下
CV_EVENT_FLAG_SHIFTKEY 16 (0x01 << 4) SHIFT键被压下
CV_EVENT_FLAG_ALTKEY 32 (0x01 << 5) ALT键被压下
  • void* param 和之前的说明一样,如果需要外部的参数的话,可以把那个参数(结构体)的指针给过来。

2.Paint的实现

这里使用了openCV的一些功能,实现了一个简单的Paint。当然,openCV没有Button的设置,让我不想去做更复杂的功能了。我实现以下功能。

  • 按住左键拖动鼠标可以完成一个矩形框的绘制。
  • 按住左键的同时,按住SHIFT键拖动鼠标,可以完成一个正方形的绘制。
  • 按住右键拖动,可以实现擦除。(橡皮擦的尺寸设置为11,按住右键的时候,黑色的矩形框显示出橡皮擦形状)
//------------------------------------------------------
// 内容:
//       Paintの実現
//    
//          
//          
//                   
//                                    2015.5.21
//                                    by zhou fan
// ------------------------------------------------------

#include "stdafx.h"

#include <iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  

using namespace std;  

CvRect box;
bool drawing_box = false;
CvRect Eraser;
bool drawing_eraser = false;
int Eraser_Size = 5; 

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


void draw_box( IplImage* img, CvRect box)
{
    cvRectangle(img,
                cvPoint(box.x,box.y),
                cvPoint(box.x+box.width,box.y+box.height),
                cvScalar(0x00,0xff,0x00)    //Green
                );
}

void draw_Eraser( IplImage* img, CvRect Eraser)
{
    cvRectangle(img,
                cvPoint(Eraser.x - Eraser_Size,Eraser.y - Eraser_Size),
                cvPoint(Eraser.x + Eraser_Size,Eraser.y + Eraser_Size),
                cvScalar(0xff,0xff,0xff),    
                CV_FILLED
                );
}

void show_Eraser( IplImage* img, CvRect Eraser)
{
    cvRectangle(img,
                cvPoint(Eraser.x - Eraser_Size,Eraser.y - Eraser_Size),
                cvPoint(Eraser.x + Eraser_Size,Eraser.y + Eraser_Size),
                cvScalar(0x00,0x00,0x00),    
                CV_FILLED
                );
}

int main(int argc, char** argv[])
{
    box = cvRect(-1,-1,0,0);
    Eraser = cvRect(-1,-1,0,0);

    IplImage* image = cvCreateImage(cvSize(500,500),
                                    IPL_DEPTH_8U,
                                    3);
    cvZero(image);
    cvAddS(image,cvScalarAll(255),image);
    IplImage* temp = cvCloneImage(image);

    cvNamedWindow("Paint");

    cvSetMouseCallback("Paint",
                       mouse_paint_callback,
                       (void*) image);

    while(1)
    {
        cvCopy(image,temp);
        if(drawing_box) draw_box(temp,box);
        if(drawing_eraser) show_Eraser(temp,Eraser);
        cvShowImage("Paint",temp);

        if(cvWaitKey(15) == 27) break;    //wait ESC key
    }

    return (int)0;
}


void mouse_paint_callback(int event,
                          int x, 
                          int y, 
                          int flags, 
                          void* param)
{
    IplImage* image = (IplImage*) param;

    switch(event)
    {
        case CV_EVENT_MOUSEMOVE: 
        {
            if(drawing_box)
            {
                //cout<< (flags & CV_EVENT_FLAG_SHIFTKEY) << "\n";
                if((flags & CV_EVENT_FLAG_SHIFTKEY) == CV_EVENT_FLAG_SHIFTKEY)
                {
                    if (box.x>box.y)
                    {           
                        box.width = x - box.x;
                        box.height= (y - box.y > 0)?abs(x - box.x):-abs(x - box.x);
                    }
                    else
                    {
                        box.width = (x - box.x > 0)?abs(y - box.y):-abs(y - box.y);
                        box.height= y - box.y;
                    }

                    //cout<< "TURE" << "\n";
                }
                else
                {
                    box.width = x - box.x;
                    box.height= y - box.y;
                }
            }

            if(drawing_eraser)
            {
               Eraser = cvRect(x,y,0,0);
               draw_Eraser(image,Eraser);
            }

        }
        break;

        case CV_EVENT_LBUTTONDOWN:
        {
            drawing_box = true;
            box = cvRect(x,y,0,0);
        }
        break;

        case CV_EVENT_RBUTTONDOWN:
        {
            drawing_eraser = true;
            Eraser = cvRect(x,y,0,0);
            draw_Eraser(image,Eraser);
        }
        break;

        case CV_EVENT_LBUTTONUP:
        {
            drawing_box = false;
            if(box.width<0)
            {
                box.x += box.width;
                box.width *= -1; 
            }
            if(box.height<0)
            {
                box.y += box.height;
                box.height *= -1; 
            }
            draw_box(image,box);
        }
        break;

        case CV_EVENT_RBUTTONUP:
        {
            drawing_eraser = false;
        }
        break;
    }

}

图中黑块位置为橡皮擦
这里写图片描述

原文发于博客:http://blog.csdn.net/thnh169/

=============更新日志===================

2015 - 5 - 21 初版

猜你喜欢

转载自blog.csdn.net/thnh169/article/details/45890053