学习目标
- 学习处理鼠标事件
- 学习函数:cv2.setMouseCallback()
简单的例子
创建简单的应用,双击图片的任何位置,画出几何形状-圆。
首先创建鼠标回调函数,当点击鼠标时,执行回调函数(callback function)。鼠标事件包括 left-button down, left-button up, left-button double-click 等。对于每一次鼠标事件,会返回相应的坐标(x,y)。有了事件和位置,我们可以做任何事情。获得所有提供的鼠标事件,运行如下代码:
import cv2
events = [i for i in dir(cv2) if 'EVENT' in i]
print(events)
# outputs:
['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']
鼠标回调函数具有特定的格式,不同在于函数的作用。所以我们的回调函数只做一件事,当双击鼠标时,画圆。代码如下:
import cv2
import numpy as np
# mouse callback function
def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
print(x,y) # 返回圆心左边可以保存,用于数据标注
cv2.circle(img,(x,y),100,(255,0,0),-1)
# Create a black image, a window and bind the function to window
img = np.zeros((512,512,3), np.uint8)
# img = cv2.imread('2007_000170.jpg')
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
更加复杂的例子
现在我们给出更好的例子,通过拖曳鼠标,可以画圆或者矩形(取决于选择的模式)。所以,鼠标回调函数有两部分:画圆和画矩形。这个例子可以很好的理解交互应用,比如目标追踪和图像分割等。代码如下:
import cv2
import numpy as np
drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle. Press 'm' to toggle to curve
ix, iy = 5,5
# mouse callback function
def draw_circle(event,x,y,flags,param):
print('================')
global ix,iy,drawing,mode
print(drawing, mode)
print("ix+iy: ", ix,iy)
print('enent: ', enent)
if event == cv2.EVENT_LBUTTONDOWN: # 按下鼠标左键,drawing变为True
print('#1', cv2.EVENT_LBUTTONDOWN)
drawing = True
ix, iy = x, y
elif event == cv2.EVENT_MOUSEMOVE: # 移动鼠标,不按任何键
print('#2', cv2.EVENT_MOUSEMOVE)
if drawing == True:
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) # 绿色
else:
cv2.circle(img,(x,y),5,(255,0,255),-1) # 梅红色
elif event == cv2.EVENT_LBUTTONUP: # 松开鼠标左键,drawing变为False
print('#3', cv2.EVENT_LBUTTONUP)
drawing = False
if mode == True:
cv2.rectangle(img,(ix,iy), (x,y), (0,255,255), -1) # 黄色
else:
cv2.circle(img,(x,y),30, (0,0,255),-1) # 红色
# 绑定OpenCV窗口和回调函数
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
while(1):
# 持续显示图像,那么也就持续调用draw_circle
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == ord('m'):
print('$: ', k)
mode = not mode
elif k == 27:
break
cv2.destroyAllWindows()