目的:在点击不同的鼠标键时,能得到不同的反馈或菜单选项。
API
setMouseCallback(窗口名, 鼠标事件反馈静态函数, (void*)(&image));
注:userdata用于传输数据。
onMouse的定义格式:
opencv鼠标事件官网查询:
OpenCV: Flags related creating and manipulating HighGUI windows and mouse events
实例:根据鼠标左键点击和抬起实时框出图像,并反馈ROI窗口
1、定义全局变量来辅助控制
//定义全局变量来辅助记录鼠标状态
Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
sp——鼠标左键点击点,初始化为(-1,-1)
ep——鼠标左键松开点,初始化为(-1,-1)
temp——用于保存原图,在实时反馈框图时不被过多的框遮住原图(即在鼠标移动绘制过程中,将带框图像重置为原图,并绘制新框图)
2、鼠标事件反馈静态函数定义
这里需要定义鼠标左键被点击时、鼠标移动时,鼠标左键抬起时的事件。
2、1鼠标左键被点击时
更新起始点,反馈点击位置即可。
2、2鼠标左键抬起时
更新终止点,当框图是从左上往右下绘制时,绘制方框,并显示被方框框住的ROI区域,最后重置起始点。
2、3鼠标移动时
在满足鼠标左键点击的判定条件下,更新终止点(暂时的),当框图是从左上往右下绘制时,首先重置上一步移动时绘制的带方框原图(利用暂存的Mat temp来实现),并绘制这一步移动的方框。
static void on_draw(int event, int x, int y, int flag, void* userdata) {
Mat image = *((Mat*)userdata);
if (event == EVENT_LBUTTONDOWN) {
sp.x = x;
sp.y = y;
cout << "start point :" << sp << endl;
}
else if (event == EVENT_LBUTTONUP) {
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0) {
Rect box(sp.x, sp.y, dx, dy);
rectangle(image, box, Scalar(0, 255, 0), 2, 8, 0);
imshow("鼠标绘制", image);
imshow("ROI区域", image(box));
//为下次绘制重置sp
sp.x = -1;
sp.y = -1;
}
cout << "end point :" << ep << endl;
}
else if (event == EVENT_MOUSEMOVE) {
//只有当鼠标左键按下时,鼠标移动事件才能有响应
if (sp.x > 0 && sp.y > 0) {
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0) {
//为了使矩形不重复绘制,遮盖原图,每次都用克隆的临时原图来进行重置,消除上一步鼠标移动绘制出的矩形
temp.copyTo(image);
Rect box(sp.x, sp.y, dx, dy);
rectangle(image, box, Scalar(0, 255, 0), 2, 8, 0);
imshow("鼠标绘制", image);
}
}
}
}
3、主体函数部分
void QuickDemo::mouse_drawing_demo(Mat& image)
{
namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
setMouseCallback("鼠标绘制",on_draw,(void*)(&image));
imshow("鼠标绘制", image);
temp = image.clone();
}
运行结果:
附:实时椭圆框图
static void on_draw(int event, int x, int y, int flag, void* userdata) {
Mat image = *((Mat*)userdata);
if (event == EVENT_LBUTTONDOWN) {
sp.x = x;
sp.y = y;
cout << "start point :" << sp << endl;
}
else if (event == EVENT_LBUTTONUP) {
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0) {
/*Rect box(sp.x, sp.y, dx, dy);
rectangle(image, box, Scalar(0, 255, 0), 2, 8, 0);*/
RotatedRect c;
c.center = sp;
c.size = Size(dx, dy);
c.angle = 0;
ellipse(image, c, Scalar(225, 0, 0), 2, 8);
imshow("鼠标绘制", image);
//为下次绘制重置sp
sp.x = -1;
sp.y = -1;
}
cout << "end point :" << ep << endl;
}
else if (event == EVENT_MOUSEMOVE) {
//只有当鼠标左键按下时,鼠标移动事件才能有响应
if (sp.x > 0 && sp.y > 0) {
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0) {
//为了使矩形不重复绘制,遮盖原图,每次都用克隆的临时原图来进行重置,消除上一步鼠标移动绘制出的矩形
temp.copyTo(image);
RotatedRect c;
c.center = sp;
c.size = Size(dx, dy);
c.angle = 0;
ellipse(image, c, Scalar(225, 0, 0), 2, 8);
/*Rect box(sp.x, sp.y, dx, dy);
rectangle(image, box, Scalar(0, 255, 0), 2, 8, 0);*/
imshow("鼠标绘制", image);
}
}
}
}
结果: