用鼠标绘制图形是很有用的,我们在后面的目标跟踪中会使用鼠标将需要跟踪的目标标注出来,之后对目标进行实时跟踪,所以今天我们来了解一下OpenCV中的一些基础知识—鼠标画笔。

首先需要了解一个函数:

cv2.setMouseCallback(windowName, MouseCallback , param=None)

其各个参数为:

windowName:窗口名称
MouseCallback:鼠标响应回调函数
param:响应函数传递的的参数

在这里,我们创建一个简单的应用程序,无论我们在哪里双击它,都可以在图像上绘制一个圆。

首先,我们创建一个鼠标回调函数,该函数在发生鼠标事件时执行。该函数原型为(此函数为我们自己所定义,OpenCV库中是没有此函数的,名称可以自己任意定义):

MouseCallback (int event, int x, int y, int flags, void userdata)

其各个部分参数为:

event:一个MouseEventTypes 常量
x:鼠标的x坐标
y:鼠标的y坐标
flags:一个MouseEventFlags常量
userdata:可选参数

鼠标事件可以是与鼠标相关的任何东西,例如左键按下,右键按下,左键双击等。它为我们提供了每个鼠标事件的坐标(x,y)。 通过此活动和地点,我们可以做任何我们喜欢的事情。 要列出所有可用的可用参数,我们在pycharm终端中运行以下代码:

view plaincopy to clipboardprint?
1.import cv2 as cv  
2.  
3.events = [i for i in dir(cv) if 'EVENT' in i]  
4.print( events )

我们查看输出,会发现一大堆参数名称:

view plaincopy to clipboardprint?
1.['EVENT_FLAG_ALTKEY', 'EVENT_FLAG_CTRLKEY', 'EVENT_FLAG_LBUTTON', 'EVENT_FLAG_MBUTTON', 'EVENT_FLAG_RBUTTON', 'EVENT_FLAG_SHIFTKEY', 'EVENT_LBUTTONDBLCLK', 'EVENT_LBUTTONDOWN', 'EVENT_LBUTTONUP', 'EVENT_MBUTTONDBLCLK', 'EVENT_MBUTTONDOWN', 'EVENT_MBUTTONUP', 'EVENT_MOUSEHWHEEL', 'EVENT_MOUSEMOVE', 'EVENT_MOUSEWHEEL', 'EVENT_RBUTTONDBLCLK', 'EVENT_RBUTTONDOWN', 'EVENT_RBUTTONUP']

现在我们来看一下MouseCallback 函数中的event参数,其代表一个MouseEventFlags常量:

MouseEventFlags :

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不放

继续看MouseCallback 函数中的flags参数,其代表一个MouseEventFlags常量:

cv.MouseEventTypes :

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, 中健双击

cv.EVENT_MOUSEWHEEL = 10, 滚轮滑动

cv.EVENT_MOUSEHWHEEL = 11 横向滚轮滑动

接下来我们可以开始进行实验了,创建鼠标回调函数具有特定的格式,该格式在所有地方都是相同的。它仅在功能上有所不同。因此,现在我们用鼠标回调函数做一件事,在我们双击的地方绘制一个圆圈:

view plaincopy to clipboardprint?
1.import numpy as np  
2.import cv2 as cv  
3.
4.  
5.def draw_circle(event, x, y, flags, param):  
6.  if event == cv.EVENT_LBUTTONDBLCLK:  
7.      cv.circle(img, (x, y), 100, (255, 0, 0), -1)  
8.
9.
10.img = np.zeros((512, 512, 3), np.uint8)  
11.cv.namedWindow('image')  
12.cv.setMouseCallback('image', draw_circle)  
13.while (1):  
14. cv.imshow('image', img)  
15. if cv.waitKey(20) & 0xFF == 27:  
16.     break  
17.cv.destroyAllWindows()

Python画笔设置 python画笔控制_人工智能

这里面我们调用的参数是EVENT_LBUTTONDBLCLK,意思就是鼠标双击触发。我们双击任意一个区域,都会以此为圆心创建一个圆形出来:

鼠标画图形

现在我们需要进行更高级的操作, 在这种情况下,我们像在“画图”应用程序中一样,通过拖动鼠标来绘制矩形或圆形(取决于我们选择的模式)。 因此,我们的鼠标回调函数有两个部分,一个用于绘制矩形,另一个用于绘制圆形。这个将会非常有帮助,后期进行手动目标跟踪的时候,我们就会用鼠标自己手动标注这些图形,从而完成实时的目标跟踪。

现在我们来实现一个综合的例子,这个实例会帮助你理解图像交互的一些思想:

在图像上用鼠标画图,可以画圆或矩形,按q键在两种模式下切换。左键按下时开始画图,移动到哪儿画到哪儿,左键释放时结束画图。听上去很复杂,是吗?一步步分析下:

· 用鼠标画图:需要定义鼠标的回调函数mouse_event

· 画圆或矩形:需要定义一个画图的模式mode

· 左键单击、移动、释放:需要捕获三个不同的事件

· 开始画图,结束画图:需要定义一个画图的标记位drawing

好,开始代码:

```python
	view plaincopy to clipboardprint?
1. import numpy as np  
2. import cv2 as cv  
3.
4. drawing = False  # true if mouse is pressed  
5. mode = True  # if True, draw rectangle. Press 'm' to toggle to curve  
6. ix, iy = -1, -1  
7.
8. mouse callback function
9.
10.def draw_circle(event, x, y, flags, param):  
11. global ix, iy, drawing, mode  
12. if event == cv.EVENT_LBUTTONDOWN:  
13.     drawing = True  
14.     ix, iy = x, y  
15. elif event == cv.EVENT_MOUSEMOVE:  
16.     if drawing:  
17.         if mode:  
18.             cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)  
19.         else:  
20.             cv.circle(img, (x, y), 5, (0, 0, 255), -1)  
21. elif event == cv.EVENT_LBUTTONUP:  
22.     drawing = False  
23.     if mode:  
24.         cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)  
25.     else:  
26.         cv.circle(img, (x, y), 5, (0, 0, 255), -1)  
27.  
28.  
29.img = np.zeros((512, 512, 3), np.uint8)  
30.cv.namedWindow('image')  
31.cv.setMouseCallback('image', draw_circle)  
32.while 1:  
33.    cv.imshow('image', img)  
34. k = cv.waitKey(1) & 0xFF  
35. if k == ord('q'):  
36.     mode = not mode  
37. elif k == 27:  
38.     break  
39.cv.destroyAllWindows()

效果:

Python画笔设置 python画笔控制_opencv_02

ok,搞定。

但是假如我们想创建一个未填充的矩形怎么办呢?

那么我们需要修改一下代码,在上一节中就已经讲过,画矩形函数以及画圆函数等等函数,它们的最后一个参数当为-1时,代表为实心,当大于0时,即为空心,假如我们定义为1,那么画出的图形的轮廓的粗细程度就为1,我们来看代码:

view plaincopy to clipboardprint?
1. import numpy as np  
2. import cv2 as cv  
3.  
4. drawing = False  # true if mouse is pressed  
5. mode = True  # if True, draw rectangle. Press 'm' to toggle to curve  
6. ix, iy = -1, -1  
7.
8.
9. # mouse callback function  
10.def draw_circle(event, x, y, flags, param):  
11.global ix, iy, drawing, mode  
12.if event == cv.EVENT_LBUTTONDOWN:  
13.     drawing = True  
14.     ix, iy = x, y  
15. elif event == cv.EVENT_MOUSEMOVE:  
16.     if drawing:  
17.         if mode:  
18.             tmp = img.copy()  
19.             cv.rectangle(tmp, (ix, iy), (x, y), (0, 255, 0), 1)  
20.             cv.imshow('image', tmp)  
21. elif event == cv.EVENT_LBUTTONUP:  
22.     drawing = False  
23.     if mode:  
24.          cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 1)  
25.
26.
27.img = np.zeros((512, 512, 3), np.uint8)  
28.cv.namedWindow('image')  
29.cv.setMouseCallback('image', draw_circle)  
30.cv.imshow("image",img)  
31.while 1:  
32. k = cv.waitKey(1) & 0xFF  
33. if k == 27:  
34.     break  
35.cv.destroyAllWindows()

我们看一下效果:

Python画笔设置 python画笔控制_opencv_03

现在我们还可以修改一下代码,我们将EVENT_LBUTTONUP的参数语句执行的功能取消,这样的话,我们在画下一个矩形时上一个就会被自动清除:

view plaincopy to clipboardprint?
1. import numpy as np  
2. import cv2 as cv  
3.
4. drawing = False  # true if mouse is pressed  
5. mode = True  # if True, draw rectangle. Press 'm' to toggle to curve  
6. ix, iy = -1, -1  
7.
8.
9. # mouse callback function  
10.def draw_circle(event, x, y, flags, param):  
11. global ix, iy, drawing, mode  
12. if event == cv.EVENT_LBUTTONDOWN:  
13.     drawing = True  
14.     ix, iy = x, y  
15. elif event == cv.EVENT_MOUSEMOVE:  
16.     if drawing:  
17.         if mode:  
18.             tmp = img.copy()  
19.             cv.rectangle(tmp, (ix, iy), (x, y), (0, 255, 0), 1)  
20.             cv.imshow('image', tmp)  
21. elif event == cv.EVENT_LBUTTONUP:  
22.     drawing = False  
23.     # if mode:  
24.     #      cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 1)  
25.
26.
27.img = np.zeros((512, 512, 3), np.uint8)  
28.cv.namedWindow('image')  
29.cv.setMouseCallback('image', draw_circle)  
30.cv.imshow("image",img)  
31.while 1:  
32. k = cv.waitKey(1) & 0xFF  
33. if k == 27:  
34.     break  
35.cv.destroyAllWindows()

效果:

Python画笔设置 python画笔控制_Python画笔设置_04

至此,OpenCV的鼠标绘图部分就算结束了,大家要想熟练掌握,还是自己多多练习。