鼠标事件
首先,我们将创建一个简单的小demo,通过在图像上双击鼠标然后在点击地点绘制一个圆。
我们需要创建一个鼠标的回调函数(callback),这个函数会鼠标事件触发的时候被调用。鼠标事件绑定到所有的鼠标操作上,如左键按下、右键按下、左键抬起、右键抬起、左键双击等等。系统可以捕获到发生鼠标事件的位置坐标,通过这个坐标我们可以做出相应的定位和处理(坐标以及事件类型都会以参数形式传递到回调函数中)。以下代码可以列出所有可用的事件。
import cv2 events = [i for i in dir(cv2) if 'EVENT' in i] print(events)
结果如下所示:
['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 #鼠标回调函数,双击画圆 def draw_circle(event, x, y, flags, param): bg = param['background'] if event == cv2.EVENT_LBUTTONDBLCLK: cv2.circle(bg, (x, y), 100, (255, 0, 0), -1) #背景图 img = np.zeros((512, 512, 3), np.uint8) cv2.namedWindow('circle', cv2.WINDOW_NORMAL) cv2.setMouseCallback('circle', draw_circle, {'background': img}) while True: cv2.imshow('circle', img) #esc键推出 if cv2.waitKey(20) == 27: break cv2.destroyAllWindows()
效果如下所示:
复杂的演示
现在我们做一个稍微复杂一点的demo。我们需要画矩形和圆(具体画什么取决于我们拖拽鼠标的方式)。所以我们的callback中有两个部分,一个是画矩形,一个是画圆。这个demo有助于我们理解一些交互应用,如对象追踪,图像分割等。
import cv2 import numpy as np #鼠标回调函数 def draw_callback(event,x,y,flags,param): global bg, drawing, mode, ix ,iy if event == cv2.EVENT_MBUTTONDOWN: drawing = True ix, iy = x, y elif event == cv2.EVENT_MOUSEMOVE: if drawing == True: if mode == True: cv2.rectangle(bg, (ix, iy), (x, y), (0, 255, 0), -1) else: cv2.circle(bg, (x, y), 5, (0, 0, 255), -1) elif event == cv2.EVENT_LBUTTONUP: drawing = False if mode == True: cv2.rectangle(bg, (ix, iy), (x, y), (0, 255, 0), -1) else: cv2.circle(bg, (x, y), 5, (0, 0, 255), -1) if __name__ == '__main__': drawing = False mode = True ix, iy = -1,-1 bg = np.ones([512, 512, 3], np.uint8) * 255 cv2.namedWindow('mouse') cv2.setMouseCallback('mouse', draw_callback) while True: cv2.imshow('mouse', bg) k = cv2.waitKey(1) if k == ord('r'): mode = True elif k == ord('c'): mode = False elif k == 27: break cv2.destroyAllWindows()
演示效果如下:
学以致用,知行合一
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期