设计一段程序完成的任务:根据我们选择的模式在拖动鼠标时绘制矩形或者是圆圈(就像画图程序中一样)。要求回调函数包含两部分,一部分画矩形,一部分画圆圈。

问题描述:

设计一段程序完成的任务:根据我们选择的模式在拖动鼠标时绘制矩形或者是圆圈(就像画图程序中一样)。要求回调函数包含两部分,一部分画矩形,一部分画圆圈。

import cv2
import numpy as np
# 当鼠标按下时变为 True
drawing = False
# 如果 mode 为 true 绘制矩形。按下'm' 变成绘制曲线。
mode = True
ix, iy = -1, -1

img = np.zeros((512, 512, 3), np.uint8)
img_copy = img.copy()
# 创建回调函数
def draw_circle(event, x, y, flags, param):
    global ix, iy, drawing, mode,img,img_copy
    # 只单纯的按下鼠标:只返回位置坐标
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        ix, iy = x, y
        print(x, y)
    # 按下鼠标并且移动:表示绘制图形。event 可以查看移动,flag 查看是否按下
    elif event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
        if drawing == True:  # 鼠标左键被按下
            if mode == True:  # 画矩形
                cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
            else:  # 画圆
                # 小圆点连在一起就成了线,3 代表了笔画的粗细
                cv2.circle(img, (x, y), 30, (0, 0, 255), -1)
                # 下面注释掉的代码是起始点为圆心,起点到终点为半径的
    # 当鼠标松开停止绘画。
    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
    elif event == cv2.EVENT_LBUTTONDBLCLK:  # 双击表示清除所画的图像
        img = img_copy.copy()
        print('double')



cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
while (1):
    cv2.imshow('image', img)
    k = cv2.waitKey(1) & 0xFF
    if k == ord('m'):
        mode = not mode
    elif k == 27:
        break

逐行分析上述代码的逻辑结构。 

问题解答:

这段代码的逻辑结构如下:

  1. 导入库

    import cv2
    import numpy as np
    

    导入 OpenCV 和 NumPy 库,前者用于图像处理,后者用于数组和矩阵操作。

  2. 初始化全局变量

    drawing = False  # 标记是否正在绘图
    mode = True      # 默认为绘制矩形,按下 'm' 切换到绘制圆
    ix, iy = -1, -1  # 初始坐标
    
    • drawing:用于判断鼠标是否正在绘图。
    • mode:控制绘制形状的类型,默认为矩形。
    • ixiy:用于存储鼠标按下时的坐标。
  3. 创建图像

    img = np.zeros((512, 512, 3), np.uint8)  # 创建一个全黑图像
    img_copy = img.copy()  # 复制图像,以便清空绘图时使用
    

  4. 定义鼠标回调函数

    def draw_circle(event, x, y, flags, param):
    

    这个函数在鼠标事件发生时被调用,包含五个参数:事件类型、鼠标位置、标志和其他参数。

  5. 处理鼠标事件

    • 左键按下

      if event == cv2.EVENT_LBUTTONDOWN:
          drawing = True
          ix, iy = x, y
          print(x, y)
      

      当鼠标左键按下时,设置 drawingTrue,并记录起始坐标。

    • 鼠标移动并按下左键

      elif event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
          if drawing:
              if mode:
                  cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)  # 绘制矩形
              else:
                  cv2.circle(img, (x, y), 30, (0, 0, 255), -1)  # 绘制圆
      

      当鼠标移动且左键被按下时,根据当前模式绘制矩形或圆。

    • 左键松开

      elif event == cv2.EVENT_LBUTTONUP:
          drawing = False
      

      当鼠标左键松开时,设置 drawingFalse,停止绘图。

    • 双击左键

      elif event == cv2.EVENT_LBUTTONDBLCLK:
          img = img_copy.copy()  # 清空图像
          print('double')
      

      双击左键时,图像恢复为初始状态(全黑)。

  6. 创建窗口并设置回调

    cv2.namedWindow('image')  # 创建一个窗口
    cv2.setMouseCallback('image', draw_circle)  # 将鼠标事件与回调函数绑定
    

  7. 主循环

    while (1):
        cv2.imshow('image', img)  # 显示当前图像
        k = cv2.waitKey(1) & 0xFF  # 等待键盘输入
        if k == ord('m'):
            mode = not mode  # 切换绘图模式
        elif k == 27:
            break  # 按下 ESC 键退出
    
    • 不断显示更新的图像。
    • 检查是否按下 'm' 键来切换绘图模式。
    • 检查是否按下 ESC 键来退出程序。

总结

整体逻辑是通过鼠标事件在图像上绘制矩形或圆,使用全局变量跟踪绘图状态和坐标,回调函数处理鼠标事件,最后在主循环中不断更新显示。

############################################################

这段代码只点击鼠标左键,不拖动鼠标也会打印光标所在的位置吗?

是的,代码中的这段逻辑会在鼠标左键按下时打印光标的位置,即使你不拖动鼠标:

if event == cv2.EVENT_LBUTTONDOWN:
    drawing = True
    ix, iy = x, y
    print(x, y)

这里的 EVENT_LBUTTONDOWN 事件会在鼠标左键按下时触发,因此每次按下左键时,都会打印出当前光标的位置 (x, y)。如果你希望仅在拖动时打印位置,可以修改逻辑,将打印位置的语句放在鼠标移动的条件分支中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神笔馬良

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值