从opencv-python入门opencv--GUI功能之绘图鼠标与图像界面的交互

devtools/2024/10/19 14:40:22/

opencv-python入门opencv--GUI功能之绘图和鼠标操作

  • 一、文章介绍
  • 二、opencv绘制直线、矩形、圆形
    • 1、cv.line()
    • 2、cv.circle()
    • 3、cv.rectangle()
    • 4、在图像上绘制直线、矩形和圆形
    • 5、cv.ellipse()(在空白画布上绘制椭圆)
      • (1)img = cv.ellipse( img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]] )
      • (2)img = cv.ellipse( img, box, color[, thickness[, lineType]]
    • 6、cv.putText()
  • 三、opencv鼠标回调功能
    • 1、基本用法
    • 3、注册回调函数
    • 4、鼠标事件类型
  • 四、案例:鼠标和键盘配合在图像中绘制图形。
    • 1、代码
    • 2、思路
  • 五、案例:鼠标点击显示图像当前位置的像素和坐标
    • 1、代码
    • 2、思路
  • 六、案例:删除上一次鼠标绘制及一次性清空所有鼠标绘制
    • 1、代码
    • 2、思路

一、文章介绍

1、本文主要介绍opencv的绘图功能以及鼠标与图像界面的交互功能。
2、包含直线、矩形、圆形的绘制。
3、opencv鼠标回调功能介绍。
4、案例:鼠标和键盘配合在图像中绘制图形。
效果展示:
在这里插入图片描述
5、案例:鼠标点击显示图像当前位置的像素和坐标。
效果展示:
在这里插入图片描述

6、案例:删除上一次鼠标绘制及一次性清空所有鼠标绘制。
效果展示:
在这里插入图片描述

opencv_15">二、opencv绘制直线、矩形、圆形

1、cv.line()

在这里插入图片描述
【1】img指要绘制的图形,可以是空白的图像,也可以是读取的图像
【2】pt1和pt2表示要绘制直线的两个端点的坐标,(横坐标,纵坐标)表示
【3】color表示颜色,(B,G,R),如果是灰度图,只需传一个标量值。
【4】thickness: 图形边界的厚度。如果传 -1 就是像圆这样的闭合图形,它将填充形状。 默认 thickness = 1
【5】lineType:线条类型,如 8 连接,抗锯齿线等。默认情况下,它是 8 连接。cv.LINE_AA 画出抗锯齿线,非常好看的曲线。
【6】shift表示坐标单位表示的像素的个数(2^shift),默认是0,坐标1表示1个像素,如果是1,表示1个坐标2两个像素,精度就是0.5。

2、cv.circle()

在这里插入图片描述

3、cv.rectangle()

在这里插入图片描述
pt1和pt2分别表示矩形的左上角和右下角

4、在图像上绘制直线、矩形和圆形

代码:

python">
import cv2 as cv
img = cv.imread('data\gui\starry_night.jpg')
# 画一条 5px 宽的蓝色对角线
cv.line(img,(0,0),(200,300),(0,255,0),5)
cv.rectangle(img,(200,300),(300,500),(255,0,0),3)
cv.circle(img,(300,300), 50, (0,0,255), -1)
cv.imshow('img',img)
k=cv.waitKey(0)
if k == 27: # ESC 退出cv.destroyAllWindows()

效果:

5、cv.ellipse()(在空白画布上绘制椭圆)

在这里插入图片描述
opencv-python中,有两种方式绘制椭圆

(1)img = cv.ellipse( img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]] )

center 是椭圆的中心点,axes 是长轴和短轴的长度,angle 是椭圆的旋转角度,startAngle 和 endAngle 定义了绘制的角度范围。startAngle和endAngle 为0和360时,绘制的才是完整的椭圆。
代码:

python">import cv2 as cv
import numpy as np# 创建一个黑色图像
img = np.zeros((400, 400, 3), dtype=np.uint8)# 定义椭圆的参数
center = (200, 200)  # 中心点
axes = (100, 50)     # 半轴长度 (长轴, 短轴)
angle = 30           # 旋转角度
startAngle = 0       # 起始角度
endAngle = 360       # 结束角度
color = (255, 0, 0)  # 颜色 (B, G, R)
thickness = 2        # 线条厚度# 绘制椭圆
cv.ellipse(img, center, axes, angle, startAngle, endAngle, color, thickness)# 显示图像
cv.imshow("Ellipse Example", img)
cv.waitKey(0)
cv.destroyAllWindows()

效果:
在这里插入图片描述
如果startAngle和endAngle 为0和90:
在这里插入图片描述
表明0度为横坐标方向,顺时针为角度增加。

(2)img = cv.ellipse( img, box, color[, thickness[, lineType]]

使用一个外接矩形的参数 box,box指的是旋转矩形,其中包含中心点的坐标、宽度和高度、旋转角度。
代码:

python">import cv2 as cv
import numpy as np# 创建一个黑色图像
img = np.zeros((400, 400, 3), dtype=np.uint8)# 定义 旋转矩阵RotatedRect 的参数
center = (200, 200)  # 中心点
size = (130, 80)     # (宽度, 高度)
angle = 30           # 旋转角度
# 创建 RotatedRect
rotated_rect = ((center[0], center[1]), (size[0], size[1]), angle)
color = (0, 255, 0)         # 颜色 (B, G, R)
thickness = 2               # 线条厚度# 绘制椭圆
cv.ellipse(img, rotated_rect, color,thickness)# 显示图像
cv.imshow("Ellipse Example", img)
cv.waitKey(0)
cv.destroyAllWindows()

效果:

6、cv.putText()

在这里插入图片描述
【1】img: 要在其上绘制文本的图像。
【2】text: 要绘制的文本字符串。
【3】org: 文本的左下角位置,格式为 (x, y)。
【4】fontFace: 字体类型,可以是以下常量之一:
cv.FONT_HERSHEY_SIMPLEX
cv.FONT_HERSHEY_PLAIN
cv.FONT_HERSHEY_DUPLEX
cv.FONT_HERSHEY_COMPLEX
cv.FONT_HERSHEY_TRIPLEX
cv.FONT_HERSHEY_COMPLEX_SMALL
cv.FONT_HERSHEY_SCRIPT_SIMPLEX
cv.FONT_HERSHEY_SCRIPT_COMPLEX
【5】fontScale: 字体大小的缩放因子。
【6】color: 文本颜色,格式为 (B, G, R)。
【7】thickness: 线条厚度(可选,默认为 1)。
【8】ineType: 线条类型(可选,默认为 LINE_8)。
【9】bottomLeftOrigin: 如果为 true,则文本的原点在左下角(可选,默认为 false)
代码:

python">import cv2 as cv
import numpy as np# 创建一个黑色图像
img = np.zeros((400, 600, 3), dtype=np.uint8)# 定义文本内容和属性
text = "Hello, OpenCV!"
org = (50, 200)  # 文本的左下角位置
fontFace = cv.FONT_HERSHEY_SIMPLEX
fontScale = 1
color = (255, 255, 255)  # 白色
thickness = 2# 在图像上绘制文本
cv.putText(img, text, org, fontFace, fontScale, color, thickness)# 显示图像
cv.imshow("Text Example", img)
cv.waitKey(0)
cv.destroyAllWindows()

效果:
在这里插入图片描述

opencv_164">三、opencv鼠标回调功能

OpenCV 的鼠标回调功能允许用户在图像窗口中处理鼠标事件,例如点击、移动、按下和释放鼠标键。这种功能在图形用户界面(GUI)开发和交互式应用程序中非常有用。

1、基本用法

(1)创建窗口:使用 cv2.namedWindow() 创建一个可用于接收鼠标事件的窗口。

(2)定义鼠标回调函数:创建一个回调函数,处理不同的鼠标事件。在这个函数中,可以获取鼠标的位置、按键状态等信息。

(3)注册回调函数:使用 cv2.setMouseCallback() 将定义的回调函数与窗口绑定。

(4)显示图像并等待事件:使用 cv2.imshow() 显示图像,然后使用 cv2.waitKey() 等待用户输入.

3、注册回调函数

在这里插入图片描述
其中,参数一是需要交互的窗口的名称,参数二是回调函数的名称,参数三是一个指向用户自定义数据的指针,可以用来在回调函数中传递额外的信息,可以将任何类型的数据传递给回调函数,以便在处理鼠标事件时使用,默认为 0(空指针),如果不需要传递额外数据,可以省略或传递 nullptr。

回调函数格式如下:
在这里插入图片描述
(1)event: 鼠标事件类型(如 EVENT_LBUTTONDOWN 表示左键按下)。
(2)x, y: 鼠标事件发生时的坐标。
(3)flags: 一些额外的标志(如 SHIFT、CTRL 键是否按下)。
(4)userdata: 传递给回调函数的用户数据。

4、鼠标事件类型

在 OpenCV 中,有多种鼠标事件可以使用,常用的包括:
cv2.EVENT_LBUTTONDOWN: 左键按下
cv2.EVENT_RBUTTONDOWN: 右键按下
cv2.EVENT_MOUSEMOVE: 鼠标移动
cv2.EVENT_LBUTTONUP: 左键释放
cv2.EVENT_RBUTTONUP: 右键释

四、案例:鼠标和键盘配合在图像中绘制图形。

1、代码

python">
import numpy as np
import cv2 as cv
drawing = False # 如果 True 是鼠标按下
mode = True # 如果 True,画矩形,按下‘m’切换到画圆点
ix,iy = -1,-1
# 鼠标回调函数
def draw_circle(event,x,y,flags,param):global ix,iy,drawing,modeif event == cv.EVENT_LBUTTONDOWN:drawing = Trueix,iy = x,yelif event == cv.EVENT_MOUSEMOVE:if drawing == True:if mode == True:cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)else:cv.circle(img,(x,y),1,(0,0,255),-1)elif event == cv.EVENT_LBUTTONUP:drawing = Falseif mode == True:cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)else:cv.circle(img,(x,y),10,(0,0,255),-1)if __name__ == "__main__":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) & 0xFFif k == ord('c'):mode = not modeelif k == 27:breakcv.destroyAllWindows()

2、思路

代码中定义drawing变量判断鼠标是否按下。使用mode变量表示键盘’c’键是否按下。
按下鼠标左键,画一个绿色的点,移动鼠标绘制绿色的矩形。
按下‘c’键盘按键后,切换到画圆形。鼠标左键按下,绘制一个半径为5个像素点的圆形,鼠标滑动,连续绘制半径为1个像素点的圆形。

五、案例:鼠标点击显示图像当前位置的像素和坐标

1、代码

python">import numpy as np
import cv2 as cv
drawing = False # 如果 True 是鼠标按下
ix,iy = -1,-1
# 鼠标回调函数
def draw_circle(event,x,y,flags,param):global ix, iy, drawingif event == cv.EVENT_LBUTTONDOWN:drawing = Trueix,iy = x,yelif event == cv.EVENT_LBUTTONUP:if drawing==True:cv.putText(img, f'Coordinates: ({x}, {y})', (x, y), cv.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)cv.putText(img, f'value: ({img[y, x]})', (x, y + 25), cv.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)cv.circle(img, (x, y), 2, (0, 0, 255), -1)drawing = Falseif __name__ == "__main__":img = cv.imread('data\gui\starry_night.jpg')cv.namedWindow('image')cv.setMouseCallback('image', draw_circle)while (1):cv.imshow('image', img)k = cv.waitKey(1) & 0xFFif k == 27:breakcv.destroyAllWindows()

2、思路

使用drawing标识是否绘制,鼠标左键按下时,表示需要绘制,鼠标左键松开时,绘制坐标点和像素点,然后将drawing置为False表示绘制完毕。

六、案例:删除上一次鼠标绘制及一次性清空所有鼠标绘制

1、代码

python">import cv2 as cv
import numpy as np# 读取图像
img = cv.imread('data\gui\starry_night.jpg')
if img is None:print("Error: Could not read the image.")exit()# 保存原始图像
original_img = img.copy()
drawing = False  # 标记是否正在绘制
history = []  # 用于存储历史图像状态def mouse_callback(event, x, y, flags, param):global img, original_img, drawing, historyif event == cv.EVENT_LBUTTONDOWN:  # 左键按下# 保存当前状态到历史记录history.append(img.copy())drawing = Trueelif event == cv.EVENT_LBUTTONUP:  # 左键抬起drawing = Falsecv.circle(img, (x, y), 20, (0, 255, 0), -1)  # 绘制绿色圆形elif event == cv.EVENT_RBUTTONDOWN:  # 右键按下img = original_img.copy()  # 清空图像,恢复为原始图像history.clear()  # 清空历史记录# 创建窗口并设置鼠标回调
cv.namedWindow('image')
cv.setMouseCallback('image', mouse_callback)while True:cv.imshow('image', img)key = cv.waitKey(1) & 0xFFif key == ord('q'):  # 按 'q' 键退出breakelif key == ord('u'):  # 按 'u' 键撤销上一步if history:img = history.pop()  # 撤销上一步cv.destroyAllWindows()

2、思路

将原始图像拷贝备份。每次绘制之前,将当前图片保存,如果按下’u’,则删除一张图像,如果右键按下,显示原始图像。


http://www.ppmy.cn/devtools/127036.html

相关文章

[Raspberry Pi]如何在Ubuntu的python venv虛擬環境中,運行YOLOv5 物件辨識功能?

[YOLOv5 I Raspberry pi 4B]Object Detection test with Image and Video by yolov5s. 延續<[Python]如何在Ubuntu中建置python venv虛擬環境&#xff0c;並安裝TensorFlow和OpenCV函式庫?>文章&#xff0c;當建置 TensorFlow (2.10.0) 和 OpenCV (4.9.0) 的 Python 虛擬…

Python 数值计算与数值分析基础

Python 数值计算与数值分析基础 示例演示 当涉及到Python数值计算和数值分析时&#xff0c;下面是20个示例&#xff0c;涵盖了一些常见的用法&#xff1a; 1.数值积分&#xff1a; 在 Python 中&#xff0c;你可以使用 scipy.integrate 模块中的 quad 函数来进行数值积分 …

cartographer在ros和vscode上进行debug

一、概述 因为在对代码进行了解之后&#xff0c;需要运行过程中对代码进行调试&#xff0c;因而需要配置cartographer的Debug配置。 二、具体实现 &#xff08;一&#xff09;版本 使用Ubuntu20.04&#xff0c;vscode&#xff0c;ros-noetic&#xff0c;cartographer &#…

第21~22周Java主流框架入门-Spring 3.SpringJDBC事务管理

Spring JDBC模块与事务管理课程总结 1. 课程介绍 本课程主要讲解Spring框架中的JDBC模块及其事务管理的相关内容&#xff0c;重点包括以下三个方面&#xff1a; Spring JDBC模块及核心对象JDBC Template的使用 通过学习如何使用Spring JDBC模块&#xff0c;了解JDBC Template…

RabbitMQ 高级特性——死信队列

文章目录 前言死信队列什么是死信常见面试题死信队列的概念&#xff1a;死信的来源&#xff08;造成死信的原因有哪些&#xff09;死信队列的应用场景 前言 前面我们学习了为消息和队列设置 TTL 过期时间&#xff0c;这样可以保证消息的积压&#xff0c;那么对于这些过期了的消…

使用Docker启动的Redis容器使用的配置文件路径等问题以及Python使用clickhouse_driver操作clickhouse数据库

一、使用Docker启动的Redis容器使用的配置文件路径等问题 1.docker启动的redis使用的配置文件路径是什么 使用docker搭建redis服务&#xff0c;本身redis启动的时候可以指定配置文件的&#xff0c; redis-server /指定配置文件路径/redis.conf。 但手上也没有一个redis配置文件…

408算法题leetcode--第37天

1049. 最后一块石头的重量 II 题目地址&#xff1a;1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 题解思路&#xff1a;01背包 时间复杂度&#xff1a;O(n*m) 空间复杂度&#xff1a;O(m) 代码: class Solution { public:int lastStoneWeightII(…

Java基于SSM微信小程序物流仓库管理系统设计与实现(源码+lw+数据库+讲解等)

选题背景 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…