转载:如何用OpenCV跟踪鼠标操作

http://blog.skyoung.org/2014/05/01/how-to-track-mouse/

在视频第一帧手动标记出目标的位置是在线视觉跟踪中最基本的一个操作,实现这个操作需要检测鼠标的移动和点击事件。OpenCV提供了setMouseCallback这个函数来响应鼠标的动作,并返回鼠标在绑定窗口上的坐标位置。下面就这个函数的使用做一个简单的介绍。

首先,setMouseCallback的C++函数声明如下:

  

 void onMouse(int event, int x, int y, int flag, void *param)
  • winname是窗口的名称
  • onMouse是响应事件的函数
  • userdata可选项,是用户提供给onMouse响应函数的指针。

这个函数是负责绑定鼠标响应的窗口,这样函数就只会响应关于该窗口的鼠标操作。onMouse定义的针对鼠标不同操作,用户需要做出的操作。

onMouse响应函数的声明为:

 void onMouse(int event, int x, int y, int flag, void *param)
  • event是鼠标响应事件,分别是:

    • EVENT_MOUSEMOVE 滑动
    • EVENT_LBUTTONDOWN 左击
    • EVENT_RBUTTONDOWN 右击
    • EVENT_MBUTTONDOWN 中键点击
    • EVENT_LBUTTONUP 左键放开
    • EVENT_RBUTTONUP 右键放开
    • EVENT_MBUTTONUP 中键放开
    • EVENT_LBUTTONDBLCLK 左键双击
    • EVENT_RBUTTONDBLCLK 右键双击
    • EVENT_MBUTTONDBLCLK 中键双击
  • x是鼠标在图像上的横坐标
  • y是鼠标在图像上的纵坐标
  • flag是标记鼠标某一event下,其附加的状态,比如EVENT_MOUSEMOVE下,flag为EVENT_FLAG_LBUTTON,左键拖拽状态。flag的状态有:
    • EVENT_FLAG_LBUTTON 左键拖拽
    • EVENT_FLAG_RBUTTON 右键拖拽
    • EVENT_FLAG_MBUTTON 中键拖拽
    • EVENT_FLAG_CTRLKEY 按住Ctrl不放
    • EVENT_FLAG_SHIFTKEY 按住Shift不放
    • EVENT_FLAG_ALTKEY 按住Alt不放
  • param是用户传入的指针, 即setMouseCallback中的userdata

下面给出一个画矩形框的代码实例来详细讲解。首先定义了一个MouseCapture的类,存放在MouseCapture.h中。定义的私有成员有存储的图像img,窗口的名称winName,所画方框rect的以及是否结束画框的标志符isMarked。成员函数分别是读取图像的函数loadImg(),画方框函数drawRect()以及鼠标响应事件函数onMouse(),注意这里onMouse定义为static成员函数,是因为setMouseCallBack()不是MouseCapture类的成员函数,如果onMouse为普通成员函数,则会因为函数声明不同而无法使用,而声明为static成员函数后,就可以直接在MouseCapture::作用域里直接访问该静态成员函数onMouse

MouseCapture.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef MOUSECAPTURE_H
#define MOUSECAPTURE_H #include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include <string> class MouseCapture
{
public:
MouseCapture();
void loadImg(std::string imgFile);
void drawRect();
static void onMouse(int event, int x, int y, int flag, void *parma); private:
cv::Mat img;
std::string winName;
cv::Rect rect;
bool isMarked; }; #endif // MOUSECAPTURE_H

接下面列出类MouseCapture的具体定义,在文件MouseCapture.cpp中。onMouse定义了当鼠标左击时,记录下矩形左上角的点,当鼠标抬起时,记录下矩形的宽高,当鼠标滑动且左击拖拽的时候,记录下矩形的宽高。注意这里flag的使用。指针paramsetMouseCallBack()调用的时候传入的this指针(参见50行),这个参数的传入负责把跟踪鼠标所画矩形的框的位置大小信息写入类的成员rect中。

MouseCapture.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "MouseCapture.h"
#include <iostream> using namespace cv;
using namespace std; void MouseCapture::onMouse(int event, int x, int y, int flag, void *param)
{
MouseCapture *MC = (MouseCapture *)param;
switch(event)
{
case EVENT_LBUTTONDOWN:
MC->rect.x = x;
MC->rect.y = y;
break; case EVENT_LBUTTONUP:
MC->rect.width = x - MC->rect.x;
MC->rect.height = y - MC->rect.y;
break; case EVENT_RBUTTONDOWN:
MC->isMarked = true;
break; case EVENT_MOUSEMOVE:
if(flag & EVENT_FLAG_LBUTTON)
{
MC->rect.width = x - MC->rect.x;
MC->rect.height = y - MC->rect.y;
}
break;
default:
break;
} } MouseCapture::MouseCapture():winName("MouseControl"),rect(Rect(0,0,0,0)),isMarked(false)
{} void MouseCapture::loadImg(string imgFile)
{
img = imread(imgFile);
} void MouseCapture::drawRect()
{
namedWindow(winName);
setMouseCallback(winName, onMouse, this);
Mat tmpImg;
while(!isMarked)
{
tmpImg = img.clone();
rectangle(tmpImg, rect, Scalar(0,0,255), 2); string str;
stringstream strStream;
strStream<<"Marked Region:"<<rect.x<<":"<<rect.y<<":"<<rect.width<<":"<<rect.height;
str = strStream.str();
putText(tmpImg, str, Point(20,20), CV_FONT_HERSHEY_COMPLEX, .8,Scalar(0,255,0),2); imshow(winName, tmpImg);
if(waitKey(10) == 'q')
break;
}
cout<<"Mark finished!"<<endl;
}

最后是主函数的调用:

main.cpp

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "MouseCapture.h" int main()
{
MouseCapture MC;
MC.loadImg("lena.jpg");
MC.drawRect();
return 0;
}

最后,对于onMouse()鼠标响应事件函数的声明问题还有另外一种解决方案,就是把onMouse()声明为类MouseCapture的友函数,而不把onMouse声明为类的成员函数。

如何用OpenCV跟踪鼠标操作的更多相关文章

  1. windows7如何用键盘模拟鼠标操作

    windows7如何用键盘模拟鼠标操作 https://jingyan.baidu.com/article/6dad5075104907a123e36e38.html 听语音 37453人看了这个视频 ...

  2. opencv鼠标操作及GUI矩形绘画

    OpenCV的鼠标操作是通过一个中介函数配合回调函数来实现的.指定鼠标操作消息回调函数的函数为SetMouseCallback. void setMouseCallback(const string& ...

  3. opencv:鼠标操作

    示例程序: #include <opencv.hpp> using namespace cv; #define WINDOW_NAME "程序窗口" // ------ ...

  4. opencv —— setMouseCallback 响应鼠标操作事件

    鼠标操作:setMouseCallback 函数 借助回调函数,实现对鼠标每次操作的相应,即每进行一步鼠标操作,都会执行一次回调函数. void setMouseCallback(const stri ...

  5. OpenCV——图像的载入、显示、输出到文件和滑动条、鼠标操作

    图像的载入.显示.输出到文件和滑动条 滑动条 示例: 鼠标操作

  6. HighGUI图形图像界面初步——鼠标操作

    OpenCV中的鼠标操作和滑动条的消息映射方式很类似,都是通过一个中介函数配合一个回调函数来实现的,创建和指定滑动条回调函数为createTrackbar, 而指定鼠标操作消息回调函数的函数为setM ...

  7. OpenCV学习笔记(2)——如何用OpenCV处理视频

    如何用OpenCV处理视频 读取视频文件,显示视频,保存视频文件 从摄像头获取并显示视频 1.用摄像头捕获视频 为了获取视频,需要创建一个VideoCapature对象.其参数可以是设备的索引号,也可 ...

  8. [opencv]常用阵列操作函数总结

    /*=========================================================================*/ // 阵列操作 /*============ ...

  9. Python模拟键盘输入和鼠标操作

    Python模拟键盘输入和鼠标操作 一.Python键盘输入模拟: import win32api import win32con win32api.keybd_event(17,0,0,0)  #c ...

随机推荐

  1. Memcached gets 命令

    Memcached gets 命令获取带有 CAS 令牌存 的 value(数据值) ,如果 key 不存在,则返回空. 语法: gets 命令的基本语法格式如下: gets key 多个 key 使 ...

  2. js数组与字符串的相互转换

    一.数组转字符串 需要将数组元素用某个字符连接成字符串,示例代码如下: var a, b,c; a = new Array(a,b,c,d,e); b = a.join('-'); //a-b-c-d ...

  3. 刷完了leetcode的数据库题目~

    很久很久很久之前,我上传了几条数据库题目,并没有坚持,今天跟新一下进度吧,其实没啥难度w(* ̄︶ ̄)

  4. 什么是JSON?

    JSON是一种取代XML的数据结构,和xml相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度. JSON就是一串字符串 只不过元素会使用特定的符号标注. {} 双 ...

  5. binding与属性

    Text="{Binding Path=SearchKeyWord, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 将“源”显 ...

  6. Linux命令详解-cal

    cal命令可以用来显示公历(阳历)日历.公历是现在国际通用的历法,又称格列历,通称阳历."阳历"又名"太阳历",系以地球绕行太阳一周为一年,为西方各国所通用,故 ...

  7. FreeMarker初探--介绍

    FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP.它不仅可以用作表现层的实现 ...

  8. 由浅入深了解Retrofit(一)

    Retrofit Retrofit与okhttp共同出自于Square公司,Retrofit是一个高质量和高效率的http库,Retrofit是对okhttp的网络框架做了一层封装,Retrofit内 ...

  9. Java复习7.输入输出流

    Java复习7.输入输出流 20131005 前言: Java中涉及数据的读写,都是基于流的,这一块的知识相当重要,而且在Java中的数据,char字符是16bit的,所以存在字节流和字符流的区别.如 ...

  10. bzoj3400

    题解: dp f[i][j]表示前i个,膜为j 最后记得判断0 代码: #include<bits/stdc++.h> using namespace std; ; int n,m,a[N ...