用鼠标在窗口中绘制矩形

来源:互联网 发布:网络电视机播放器 编辑:程序博客网 时间:2024/05/23 00:53
鼠标相应事件采用了回调函数的方式来处理。为了可以响应鼠标事件,首先创建一个回调函数,使得鼠标事件(如移动、点击等)发生时OpenCV可以调用这个函数。创建这个函数之后,还要在OpenCV中注册这个函数。

鼠标事件的回调函数格式为:

void CvMouseCallback(int event,int x,int y,int flags,void* param);
当回调函数被调用时,OpenCV就给上述函数传入合适的值,其中参数event为具体鼠标事件(是一系列以CV_EVENT_开头的宏定义,例如鼠标移动事件为CV_EVENT_MOUSEMOVE)。参数x、y为鼠标位置像素坐标值。参数flags指定了事件发生时的不同状态(如是否按下SHIFT键等,是一系列以CV_EVENT_FLAG_开头的宏定义)。参数param指向任何结构来传递额外的参数信息。

实现注册到OpenCV的函数结构如下:

void cvSetMouseCallback(const char* window_name,CvMouseCallback on_mouse,void* param=NULL);
第一个参数window_name指定了要注册到的窗口。第二个参数是回调函数。第三个参数用来传递额外的信息给上面的void* param参数。


以下是一个简单的例程,为了说明清楚做了尽可能详尽的注释。

#include "stdafx.h"#include "cv.h"#include "highgui.h"void my_mouse_callback(int event, int x, int y, int flags, void* param);//回调函数声明void draw_box(IplImage* img, CvRect rect);//绘制方框函数声明CvRect box; //声明CvRect结构boxbool drawing_box = false; //绘制方框标志位int i = 0;//方框计数int main(){box = cvRect(-1, -1, 0, 0); //box初始化IplImage* image = cvCreateImage(cvSize(500, 500), IPL_DEPTH_8U, 3);//创建背景图片cvZero(image);//图片矩阵所有元素置零(使之为黑色)IplImage* temp = cvCloneImage(image);cvNamedWindow("Box Example");//创建窗口cvSetMouseCallback("Box Example", my_mouse_callback, (void*)image);//注册鼠标事件while (1){cvCopyImage(image, temp); //不断更新背景,否则显示出的是一系列矩形if (drawing_box)draw_box(temp, box);cvShowImage("Box Example", temp);if (cvWaitKey(15) == 27)break;}cvReleaseImage(&image);cvReleaseImage(&temp);cvDestroyWindow("Box Example");}void draw_box(IplImage* img, CvRect rect)//绘制方框函数{cvRectangle(img,cvPoint(box.x, box.y),cvPoint(box.x + box.width, box.y + box.height),cvScalar(255, 0, 0)); //bgr:蓝色}void my_mouse_callback(int event, int x, int y, int flags, void* param){IplImage* image = (IplImage*)param;switch (event){ case CV_EVENT_MOUSEMOVE: { if (drawing_box) {box.width = x - box.x;box.height = y - box.y; } }break;case CV_EVENT_LBUTTONDOWN:{ drawing_box = true; box = cvRect(x, y, 0, 0);}break;case CV_EVENT_LBUTTONUP:{drawing_box = false;if (box.width < 0){  box.x = box.x + box.width;  box.width = -box.width;    }    if (box.height < 0){  box.y = box.y + box.height;  box.height = -box.height;    }draw_box(image, box);i++;printf("这是第%d个方框!\n", i);}break;}}

值得注意的是,在创建画矩形的背景(IplImage类的image)后,又将其赋给另一个同类矩阵temp,目的是避免移动鼠标的过程中一系列矩形留在画板上。具体实现的流程如下:

1. 鼠标移动,触发调用回调函数和绘制矩形函数,在temp上画矩形;

2. 在窗口中显示temp;

3. 用image更新temp,回到流程1。

这样,在鼠标移动的过程中,只存在一个随鼠标移动的矩形,而不是一系列矩形,松开鼠标左键即完成绘制,示意图如下:

图1 在循环中每次更新背景


图2 不在循环中每次更新背景

原创粉丝点击