最近在学习OpenCV,网上关于OpenCV编程的介绍有很多,今天学习了MoreWindows博客中的鼠标绘图(http://blog.csdn.net/morewindows/article/details/8426283),自己动手按照教程一步步学习,并做了些改动,相当于是自己举一反三吧。所有代码均验证通过。
1.鼠标画线
这里就按照MoreWindows博客的介绍进行处理,只不过为了偷懒,有些变量名字就自己随便取了。
设计思想是鼠标按下之后,设置画图标志位有效,鼠标移动时调用回调函数进行画线,鼠标恢复之后画图标志位无效,鼠标移动时不再画线。
为了实现这样的功能,需要设置全局标志位draw_flag以及画线的起始点和终点point_start和point_end,每一次画线结束后将point_start用point_end的值进行更新。
#include <opencv2/opencv.hpp>
#include <cv.h>
#include <highgui.h>
bool img_flag=false;
char *window_name="test";
void mousecallback(int event,int x,int y,int flags,void *param)
{
static CvPoint point_start,point_end;
static bool draw_flag=false;
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
{
draw_flag=true;point_start=cvPoint(x,y);
break;
}
case CV_EVENT_LBUTTONUP:
{
draw_flag=false;
break;
}
case CV_EVENT_MOUSEMOVE:
{
if(draw_flag==true)
{
point_end=cvPoint(x,y);
cvLine((IplImage *)param,point_start,point_end,CV_RGB(0,255,0));
cvShowImage(window_name,(IplImage *)param);
point_start=point_end;
break;
}
}
}
}
int main(int argc, char* argv[])
{
IplImage *img=cvCreateImage(cvSize(800,600),IPL_DEPTH_8U,3);
cvRectangle(img,cvPoint(0,0),cvPoint(img->width,img->height),cvScalar(0xff,0xff,0xff));
cvNamedWindow(window_name,CV_WINDOW_AUTOSIZE);
cvShowImage(window_name,img);
cvSetMouseCallback(window_name,mousecallback,img);
while(1)
{
if(cvWaitKey(15)==27)
break;
}
cvDestroyWindow(window_name);
cvReleaseImage(&img);
return 0;
}
2.鼠标画单个矩形
这里与画线的改变在于,画完之后不保存在背景中,因此要复制背景的副本img_clone,并在该副本上进行操作。
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <cv.h>
#include <highgui.h>
bool img_flag=false;
char *window_name="test";
void mousecallback(int event,int x,int y,int flags,void *param)
{
static CvPoint point_start,point_end;
static bool draw_flag=false;
IplImage *img_clone=cvCloneImage((IplImage*)param);
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
{
draw_flag=true;
point_start=cvPoint(x,y);
break;
}
case CV_EVENT_LBUTTONUP:
{
draw_flag=false;
break;
}
case CV_EVENT_MOUSEMOVE:
{
if(draw_flag==true)
{
point_end=cvPoint(x,y);
cvRectangle(img_clone,point_start,point_end,CV_RGB(0,255,0));
cvShowImage(window_name,img_clone);
break;
}
}
}
}
int main(int argc, char* argv[])
{
IplImage *img=cvCreateImage(cvSize(800,600),IPL_DEPTH_8U,3);
cvRectangle(img,cvPoint(0,0),cvPoint(img->width,img->height),cvScalar(0xff,0xff,0xff));
cvNamedWindow(window_name,CV_WINDOW_AUTOSIZE);
cvShowImage(window_name,img);
cvSetMouseCallback(window_name,mousecallback,img);
while(1)
{
if(cvWaitKey(15)==27)
break;
}
cvDestroyWindow(window_name);
cvReleaseImage(&img);
return 0;
}
3.鼠标画矩形并保留
这里与第2个改动在于,在CV_EVENT_BUTTONUP事件发生后,将矩形画在背景中,而不是副本上。同时,CV_EVENT_MOUSEMOVE事件中的操作仍然是对副本进行。
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <cv.h>
#include <highgui.h>
bool img_flag=false;
char *window_name="test";
void mousecallback(int event,int x,int y,int flags,void *param)
{
static CvPoint point_start,point_end;
static bool draw_flag=false;
IplImage *img_clone=cvCloneImage((IplImage*)param);
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
{
draw_flag=true;
point_start=cvPoint(x,y);
break;
}
case CV_EVENT_LBUTTONUP:
{
draw_flag=false;
point_end=cvPoint(x,y);
cvRectangle((IplImage *)param,point_start,point_end,CV_RGB(0,255,0));
break;
}
case CV_EVENT_MOUSEMOVE:
{
if(draw_flag==true)
{
point_end=cvPoint(x,y);
cvRectangle(img_clone,point_start,point_end,CV_RGB(0,255,0));
cvShowImage(window_name,img_clone);
break;
}
}
}
}
int main(int argc, char* argv[])
{
IplImage *img=cvCreateImage(cvSize(800,600),IPL_DEPTH_8U,3);
cvRectangle(img,cvPoint(0,0),cvPoint(img->width,img->height),cvScalar(0xff,0xff,0xff));
cvNamedWindow(window_name,CV_WINDOW_AUTOSIZE);
cvShowImage(window_name,img);
cvSetMouseCallback(window_name,mousecallback,img);
while(1)
{
if(cvWaitKey(15)==27)
break;
}
cvDestroyWindow(window_name);
cvReleaseImage(&img);
return 0;
}