当用户触发鼠标事件时,我们希望对该事件做出响应。可以通过创建OnMouseAction()函数实现。

语法及使用

鼠标响应函数需要按照固定的格式创建,格式为:

def OnMouseAction(event,x,y,flags,param):
  • event表示出发了何种事件,具体见表。

参数 event 的值及其含义

  • x,y表示触发鼠标事件时,鼠标在窗口中的坐标(x,y)
  • flags表示鼠标的拖拽时间,以及键盘鼠标的联合事件,如表所示:

参数 flags 的值及其含义

  • param为函数ID,标识所响应的事件函数,相当于自定义了一个OnMouseAction()的ID

定义响应函数以后,要将该函数与一个特定的窗口建立联系(绑定),让该窗口内的鼠标触 发 事 件 时 , 能 够 找 到 该 响 应 函 数 并 执 行 。 要 将 函 数 与 窗 口绑 定 , 可 以 通 过 函 数cv2.setMouseCallback()实现,其基本语法格式是:

cv2.setMouseCallback(winname,onMouse)
  • winname为绑定的窗口名称。
  • onMouse为绑定的响应函数名称。

设计一个小程序,对触发的鼠标事件进行判断。

import cv2
import numpy as np

# 鼠标交互
def Demo(event,x,y,flags,param):
    if event == cv2.EVENT_LBUTTONDOWN:
        print("单击了鼠标左键")
    elif event == cv2.EVENT_RBUTTONDOWN:
        print('单击了鼠标右键')
    elif event == cv2.EVENT_FLAG_LBUTTON:
        print("按住了左键拖动了鼠标")
    elif event == cv2.EVENT_MBUTTONDOWN:
        print("单击了中间键")


# 创建名称为 Demo 的响应(回调)函数 OnMouseAction
# 将响应函数 Demo 与窗口“Demo19.9”建立连接(实现绑定
img = np.ones((300,300,3),np.uint8)*255
cv2.namedWindow("demowindow")
# 将窗口和函数绑定到一起  cv2.setMouseCallback()
# 要将该函数与一个特定的窗口建立联系(绑定),让该窗口内的鼠标
# 触 发 事 件 时 , 能 够 找 到 该 响 应 函 数 并 执 行 。
cv2.setMouseCallback('demowindow',Demo)
cv2.imshow('demowindow',img)

cv2.waitKey()
cv2.destroyAllWindows()

使用鼠标,得到交互信息

简单示例

通过鼠标交互,以当前位置为顶点绘制随机大小、随机颜色的矩形。

import cv2
import numpy as np

# 实现 鼠标双击左键 绘制矩形的交互功能
# cv2.setMouseCallback(winname,onMouse)

d = 400
def draw(event,x,y,flags,param):
    if event == cv2.EVENT_LBUTTONDBLCLK: #如果发生了事件:左键双击
        p1x = x
        p1y = y
        p2x = np.random.randint(1,d-50)
        p2y = np.random.randint(1,d-50)
        color = np.random.randint(0,256,(3,)).tolist()
        cv2.rectangle(img,(p1x,p1y),(p2x,p2y),color,1)



img = np.ones((300,300,3),np.uint8)*255
cv2.namedWindow("demowindow")
# 将窗口和函数绑定到一起  cv2.setMouseCallback()
# 要将该函数与一个特定的窗口建立联系(绑定),让该窗口内的鼠标
# 触 发 事 件 时 , 能 够 找 到 该 响 应 函 数 并 执 行 。
cv2.setMouseCallback('demowindow',draw)
while   True:
    cv2.imshow('demowindow',img)
    if cv2.waitKey(20)==27:
        break


cv2.waitKey()
cv2.destroyAllWindows()

单击鼠标随机画矩形

进阶示例

设计一个交互程序,通过键盘与鼠标的组合控制显示不同的形状和文字。

import cv2
import numpy as np

thickness = -1
mode = 1
d = 400

def draw_circle(event,x,y,flags,param):
    if event == cv2.EVENT_LBUTTONDOWN:
        a = np.random.randint(1,d-50)
        r = np.random.randint(1,d/5)
        angle = np.random.randint(0,361)
        color = np.random.randint(0,high=256,size=(3,)).tolist()
        if mode == 1: # 根据传递的mode的值,来判断当前绘制的图像的形状
            cv2.rectangle(img,(x,y),(a,a),color,thickness)
        elif mode == 2:
            cv2.circle(img,(x,y),r,color,thickness)
        elif mode == 3:
            cv2.line(img,(a,a),(x,y),color,3)
        elif mode == 4:
            cv2.ellipse(img,(x,y),(100,150),angle,0,360,color,thickness)
        elif mode == 5:
            cv2.putText(img,'opencv',(0,round(d/2)),cv2.FONT_HERSHEY_SIMPLEX,2,color,5)

# 创建白色底板
img = np.ones((d,d,3),np.uint8)*255
cv2.namedWindow('image')

# 设置鼠标回调函数
cv2.setMouseCallback('image',draw_circle)

while True:
    cv2.imshow('image',img)
    k = cv2.waitKey(1)
    if k == ord('r'):
        mode = 1
    elif k == ord('c'):
        mode = 2
    elif k == ord('l'):
        mode = 3
    elif k == ord('e'):
        mode = 4
    elif k == ord('t'):
        mode = 5
    # 当键盘 按钮按下'f'时, 表示填充
    elif k == ord('f'):
        thickness=-1
    # 当按下'u'时,表示 线条宽度为3,  不是填充状态
    elif k == ord('u'):
        thickness=3
    elif k == 27: # ‘ESC’的ASCII值是27
        break

cv2.waitKey()
cv2.destroyAllWindows()

通过键盘控制单击鼠标左键时在图像内显示的对象。不同的按键,控制不同的显示内容:

  • 按下“r”键后,在窗体内单击鼠标左键,会显示以当前鼠标位置为顶点, 以任意位置为对角顶点的一个矩形。
  • 按下“c”键后,在窗体内单击鼠标左键,会显示以当前鼠标位置为圆心,以随机数为半径的一个圆。
  • 按下“l”键后,在窗体内单击鼠标左键,会显示以当前鼠标位置为端点,以任意位置为另一个端点的线段。
  • 按下“e”键后,在窗体内单击鼠标左键,会显示以当前鼠标位置为中心点,角度随机的一个椭圆。
  • 按下“t”键后,在窗体内单击鼠标左键,会在当前窗体内显示颜色随机的文字“OpenCV”。此外,还通过“f”键和“u”键控制各种图形是否为实心:
  • 按下“f”键后,图形为实心。
  • 按下“u”键后,图形为空心。

如果要结束程序,按“Esc”键(ASCII 码为 27),此时程序退出循环,停止运行。

效果


博主个人公众号
版权声明 ▶ 本网站名称:陶小桃Blog
▶ 本文链接:https://www.52txr.cn/2022/OpenCV60.html
▶ 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行核实删除。
▶ 转载本站文章需要遵守:商业转载请联系站长,非商业转载请注明出处!!

最后修改:2022 年 05 月 26 日
如果觉得我的文章对你有用,请随意赞赏