鼠标操作初级

前言

因为今天天气不错,所以没有前言。

测试代码:

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
69
70
71
72
73
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <string>
using namespace cv;
using namespace std;

#define WINDOW_NAME "SetMouseCallback Sample"

void on_MouseHandle(int event,int x,int y,int flags,void* param);
void DrawRectangle(Mat& img,Rect box);
void ShowHelpText();

Rect g_rectangle;
bool g_bDrawingBox = false;
RNG g_rng(12345);

int main(int argc,char** argv){
g_rectangle = Rect(-1,-1,0,0);
Mat srcImage(600,800,CV_8UC3),tempImage;
srcImage.copyTo(tempImage);
srcImage = Scalar::all(0);

namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME,on_MouseHandle,(void*)&srcImage);

while(1){
srcImage.copyTo(tempImage);
if(g_bDrawingBox) DrawRectangle(tempImage, g_rectangle);
imshow(WINDOW_NAME,tempImage);
if(waitKey(10) == 27) break;
}
return 0;
}
void on_MouseHandle(int event,int x,int y,int flags,void* param){
Mat& image = *(Mat*) param;
switch (event)
{
//鼠标移动消息
case EVENT_MOUSEMOVE:
{
if (g_bDrawingBox) {
g_rectangle.width = x - g_rectangle.x;
g_rectangle.height = y - g_rectangle.y;
}
}
break;

//左键按下消息
case EVENT_LBUTTONDOWN:
{
g_bDrawingBox = true;
g_rectangle = Rect(x,y,0,0);
}
break;

//左键抬起消息
case EVENT_LBUTTONUP:
{
g_bDrawingBox = false;
//对宽和高小于0的处理
if (g_rectangle.width < 0) {
g_rectangle.x += g_rectangle.width;
g_rectangle.width *= -1;
}
DrawRectangle(image,g_rectangle);
}
break;
}
}
void DrawRectangle(Mat& img,Rect box){
rectangle(img,box.tl(),box.br(),Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255)));
}

效果图:

setMouseCallback()函数
函数原型:
1
2
3
4
5
void setMouseCallback(
const String &winname,
MouseCallback onMouse,
void *userdata = (void *)0
)

第一个参数为窗口名称
第二个参数为MouseCallback类型的onMouse,窗口里每次鼠标操作的发生都会调用这个函数,这个函数的原型:
1
2
3
4
5
6
7
void on_MouseHandle(
int event,
int x,
int y,
int flags,
void *param
)

event是许多EVENT_变量,这个在测试程序中有所体现;x和y是在图像坐标系(?)的坐标值,flags是EVENT_FLAG的组合,param是用户定义的传递到setMouseCallback()函数调用的参数。
第三个参数是用户定义的传递到回调函数的参数,有默认值0

一、Scalar()函数:

函数定义:

1
2
3
4
typedef struct Scalar
{
double val[4];
}Scalar;

由函数定义可知Scalar()可以存储4个double类型的值,分别对应4通道(需要注意的是,在OpenCV中,前三个颜色通道分别是BGR而不是常识中的RGB,第四个通道则是透明度Alpha值),在使用Scalar()函数的过程中,具体需要使用几个值需要看Mat类型图像的type,比如常见的CV_8UC3类型,C就代表通道(channel),看到C3就知道这个图像有三个通道,因此应该写三个值,每个值分别赋值给对应通道内的所有矩阵元素,如果出现参数比通道数少的情况,那么未赋值的通道内所有矩阵元素全部为0。
另科普Mat类型的type参数:
1.bit_depth:比特数,代表8bite,16bites,32bites,64bites例如创建一个存储灰度图片的Mat对象,这个图像的大小为宽100,高100,那么,现在这张灰度图片中有10000个像素点,它每一个像素点在内存空间所占的空间大小是8bite,8位,所以它对应的就是CV_8
2.S|U|F
S代表signed int有符号整形
U代表unsigned int无符号整形
F代表float单精度浮点型
3.C(channel)代表一张图片的通道数
灰度图片grayImg是单通道图像
RGB彩色图像是3通道图像
带Alph通道的RGB图像是4通道图像

二、Rect()函数

函数定义:

1
2
3
4
5
6
7
typedef struct Rect 
{
int x; /* 方形的左上角的x-坐标 */
int y; /* 方形的左上角的y-坐标*/
int width; /* 宽 */
int height; /* 高 */
}

函数用法:
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
//如果创建一个Rect对象rect(100, 50, 50, 100),那么rect会有以下几个功能: 
rect.area(); //返回rect的面积 5000
rect.size(); //返回rect的尺寸 [50 × 100]
rect.tl(); //返回rect的左上顶点的坐标 [100, 50]
rect.br(); //返回rect的右下顶点的坐标 [150, 150]
rect.width(); //返回rect的宽度 50
rect.height(); //返回rect的高度 100
rect.contains(Point(x, y)); //返回布尔变量,判断rect是否包含Point(x, y)点
//还可以求两个矩形的交集和并集
rect = rect1 & rect2;
rect = rect1 | rect2;
//还可以对矩形进行平移和缩放
rect = rect + Point(-100, 100); //平移,也就是左上顶点的x坐标-100,y坐标+100
rect = rect + Size(-100, 100); //缩放,左上顶点不变,宽度-100,高度+100
//还可以对矩形进行对比,返回布尔变量
rect1 == rect2;
rect1 != rect2;
//判断rect1是否在rect2里面
bool isInside(Rect rect1, Rect rect2)
{
return (rect1 == (rect1&rect2));
}
//矩形中心点
Point getCenterPoint(Rect rect)
{
Point cpt;
cpt.x = rect.x + cvRound(rect.width/2.0);
cpt.y = rect.y + cvRound(rect.height/2.0);
return cpt;
}
//围绕矩形中心缩放
Rect rectCenterScale(Rect rect, Size size)
{
rect = rect + size;
Point pt;
pt.x = cvRound(size.width/2.0);
pt.y = cvRound(size.height/2.0);
return (rect-pt);
}

Rect()函数用法摘自:

三、Rectangle()函数

函数原型:

1
2
3
4
5
6
7
8
9
void rectangle(
InputOutputArray img,
Point pt1,
Point pt2,
const Scalar& color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0
)

第一个参数是要处理的图片
第二和第三个参数分别是矩形的左上角和右下角的坐标
第四个参数是矩形的颜色
第五个参数是线的粗细
第六个参数是线形

四、RNG随机数类型

RNG可以产生3种随机数:
RNG(int seed)使用种子seed产生一个64位随机整数,默认-1(计算机的伪随机数是由随机种子根据一定的计算方法计算出来的数值,所以只要计算方法一定,随机种子一定,那么产生的随机数就是固定的)
RNG::uniform()产生一个均匀分布的随机数(RNG::uniform(a, b )返回一个[a,b)范围的均匀分布的随机数,a,b的数据类型要一致,而且必须是int、float、double中的一种,默认是int)
RNG::gaussian( )产生一个高斯分布的随机数(返回一个均值为0,标准差为σ的随机数。如果要产生均值为λ,标准差为σ的随机数,可以λ+ RNG::gaussian( σ))

五、Mat& image = (Mat) param;的解释

param是用户定义的传递到setMouseCallback()函数调用的参数,在本行代码中先将param强制转换为Mat类型指针,然后取param的值赋值给左边作为Mat类型引用的image变量。