背景
在日常使用opencv中,需要使用鼠标进行一些操作。如使用鼠标绘制矩形、画圆、鼠标点击触发特定事件等。下面对OpenCV-C++
中如何使用鼠标进行学习记录
使用的API以及参数介绍
API介绍
opencv中使用鼠标事件使用的是鼠标操作相关的回调函数:
cv::setMouseCallback(const string& windowname, MouseCallback onMouse, void* userdata=0)
// windowname: 要操作的窗口名称
// onMouse: 鼠标事件函数,鼠标事件发生以后,要执行的回调函数。函数原型是
// void onMouse(int event, int x, int y, int flags, void * para)
// userdata: 回调函数的参数
下面是回调函数 " onMouse "
void onMouse(int event, int x, int y, int flags, void *para)
// int event: 鼠标事件,见后续说明
// x, y 是鼠标在图像坐标系中的坐标
// flags :
// para: 是用户传递到回调函数中的参数
其他项目使用涉及到的函数代码:
cv::selectROIs("MultiTracker", frame, bboxes_, showCrosshair, fromCenter);
// “MultiTracker” : windowsName
// frame: 当前画面;格式为cv::Mat
// bboxes: 要存储的框框格式为:std::vector<cv::Rect>
// showCrosshair:默认为True
// fromCenter:从中心点还是从对角点,默认为false,为true时,选框从中心点开始
参数定义:
EVENT:
// EVENT的参数定义
enum
{
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//中键双击
};
flags:
enum
{
CV_EVENT_FLAG_LBUTTON =1,//左键拖拽
CV_EVENT_FLAG_RBUTTON =2,//右键拖拽
CV_EVENT_FLAG_MBUTTON =4,//中键拖拽
CV_EVENT_FLAG_CTRLKEY =8,//按CTRL不放
CV_EVENT_FLAG_SHIFTKEY =16,//按SHIFT不放
CV_EVENT_FLAG_ALTKEY =32//按ALT不放
};
使用案例:
在画面中右击鼠标时,进行ROI选取绘制的工作,即调用selectROIS()
函数。
此处的实现在鼠标事件函数onMouse()
中实现,selectROIS()
需要传入’frame’, 'bboxes’两个参数,而setMouseCallback()
中我们只能传递一个函数"void*paragram" ,并且,鼠标事件函数是无返回函数,我们可以通过全局变量或者类/结构体来实现参数赋值传递,, 所以我们在这里可以将frame和bboxes封装成一个类或者一个结构体。
当传入的是结构体或者类时,由于形参类型时void *
类型,我们需要在onMouse()
代码块中,对传入的形参para进行格式转换。使用中,我使用mousepara *p = (mousepara*)para;
实现。
// 编译时提示我onMouse()重定义,opnecv中已经有在用的onMouse()函数。所以我在这里重新定义了下函数名。
void MouseEvent(int event, int x,int y, int flags, void *para)
{
mousepara *p = (mousepara*)para;
switch (event)
{
case cv::EVENT_RBUTTONDOWN:
cv::selectROIs("MultiTracker",p->frame, p->bboxes);
default:
break;
}
}
实际代码中,该设想并没有实现。在上述代码中设断点调试时,地址显示没有变化,而且在此处的参数值都做了对应的改变。但是返回调用处时,值又变回成0,或者说时值又没了。目前没找到原因。
上述问题通过使用全局变量代替要修改的变量参数成功
TODO: 打个标记,弄明白了回来补上
–>补充:
上面的问题解决了,原因是我imshow()
之后,对参数进行了重置处理,最后才是waitKey()
, 把等待延时写在imshow()之后,再对数值进行处理,问题就解决了。具体更细节的原因没有完全理解。不过在其他的代码中没有出现该问题。
指针传值测试成功的小程序:
#pragma once
#include <iostream>
using namespace std;
typedef struct teststruct
{
int a;
int b;
std::vector<int> c;
};
void func(void * para)
{
teststruct *c = (teststruct*)para;
c->a = 3;
c->b = 4;
for (int i = 0;i < 4;i++)
{
c->c.push_back(i);
}
cout << "id -->c:" << c << endl;
cout << "id-->para:" << para << endl;
}
int main()
{
teststruct a;
teststruct *p = &a;
p->a = 1;
p->b = 2;
func(p);
cout << "id -->p:" << p << endl;
cout << p->b << endl;
cout << p->c.back() << endl;
system("pause");
return 0;
}
代码跳转链接:基于KCF的多目标跟踪实现。
水平有限,仅作为自己的学习记录,如有错误还请不吝赐教。谢谢!