zoukankan      html  css  js  c++  java
  • 鼠标作为画笔

    用鼠标绘制图形是很有用的,我们在后面的目标跟踪中会使用鼠标将需要跟踪的目标标注出来,之后对目标进行实时跟踪,所以今天我们来了解一下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终端中运行以下代码:


    import cv2 as cv
    
    events = [i for i in dir(cv) 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']

    现在我们来看一下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 横向滚轮滑动

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

    import numpy as np
    import cv2 as cv
    
    
    def draw_circle(event, x, y, flags, param):
        if event == cv.EVENT_LBUTTONDBLCLK:
            cv.circle(img, (x, y), 100, (255, 0, 0), -1)
    
    
    img = np.zeros((512, 512, 3), np.uint8)
    cv.namedWindow('image')
    cv.setMouseCallback('image', draw_circle)
    while (1):
        cv.imshow('image', img)
        if cv.waitKey(20) & 0xFF == 27:
            break
    cv.destroyAllWindows()

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

    image.png

    鼠标画图形

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

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

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

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

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

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

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

    好,开始代码:

    import numpy as np
    import cv2 as cv
    
    drawing = False  # true if mouse is pressed
    mode = True  # if True, draw rectangle. Press 'm' to toggle to curve
    ix, iy = -1, -1
    
    
    # mouse callback function
    def draw_circle(event, x, y, flags, param):
        global ix, iy, drawing, mode
        if event == cv.EVENT_LBUTTONDOWN:
            drawing = True
            ix, iy = x, y
        elif event == cv.EVENT_MOUSEMOVE:
            if drawing:
                if mode:
                    cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
                else:
                    cv.circle(img, (x, y), 5, (0, 0, 255), -1)
        elif event == cv.EVENT_LBUTTONUP:
            drawing = False
            if mode:
                cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
            else:
                cv.circle(img, (x, y), 5, (0, 0, 255), -1)
    
    
    img = np.zeros((512, 512, 3), np.uint8)
    cv.namedWindow('image')
    cv.setMouseCallback('image', draw_circle)
    while 1:
        cv.imshow('image', img)
        k = cv.waitKey(1) & 0xFF
        if k == ord('q'):
            mode = not mode
        elif k == 27:
            break
    cv.destroyAllWindows()

    效果:

    image.png

    ok,搞定。

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

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

    import numpy as np
    import cv2 as cv
    
    drawing = False  # true if mouse is pressed
    mode = True  # if True, draw rectangle. Press 'm' to toggle to curve
    ix, iy = -1, -1
    
    
    # mouse callback function
    def draw_circle(event, x, y, flags, param):
        global ix, iy, drawing, mode
        if event == cv.EVENT_LBUTTONDOWN:
            drawing = True
            ix, iy = x, y
        elif event == cv.EVENT_MOUSEMOVE:
            if drawing:
                if mode:
                    tmp = img.copy()
                    cv.rectangle(tmp, (ix, iy), (x, y), (0, 255, 0), 1)
                    cv.imshow('image', tmp)
        elif event == cv.EVENT_LBUTTONUP:
            drawing = False
            if mode:
                 cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 1)
    
    
    img = np.zeros((512, 512, 3), np.uint8)
    cv.namedWindow('image')
    cv.setMouseCallback('image', draw_circle)
    cv.imshow("image",img)
    while 1:
        k = cv.waitKey(1) & 0xFF
        if k == 27:
            break
    cv.destroyAllWindows()

    我们看一下效果:

    image.png

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

    import numpy as np
    import cv2 as cv
    
    drawing = False  # true if mouse is pressed
    mode = True  # if True, draw rectangle. Press 'm' to toggle to curve
    ix, iy = -1, -1
    
    
    # mouse callback function
    def draw_circle(event, x, y, flags, param):
        global ix, iy, drawing, mode
        if event == cv.EVENT_LBUTTONDOWN:
            drawing = True
            ix, iy = x, y
        elif event == cv.EVENT_MOUSEMOVE:
            if drawing:
                if mode:
                    tmp = img.copy()
                    cv.rectangle(tmp, (ix, iy), (x, y), (0, 255, 0), 1)
                    cv.imshow('image', tmp)
        elif event == cv.EVENT_LBUTTONUP:
            drawing = False
            # if mode:
            #      cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 1)
    
    
    img = np.zeros((512, 512, 3), np.uint8)
    cv.namedWindow('image')
    cv.setMouseCallback('image', draw_circle)
    cv.imshow("image",img)
    while 1:
        k = cv.waitKey(1) & 0xFF
        if k == 27:
            break
    cv.destroyAllWindows()

    image.png

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

  • 相关阅读:
    改变页面选择文字颜色和背景颜色----selection伪元素
    中文版Chrome浏览器不支持12px以下字体的解决方案
    css直接写出小三角
    解决ie6 闪动的问题
    去掉firefox点击按钮时的虚线边框
    去除input在谷歌下的focus效果
    文本输入框的两种div+css的写法
    常用排序算法
    wtforms
    Flask
  • 原文地址:https://www.cnblogs.com/wuyuan2011woaini/p/15638016.html
Copyright © 2011-2022 走看看