AI 社交距离检测器:使用 OpenCV 注释检测到的对象






2.90/5 (8投票s)
在本文中,我们将学习如何向图像添加注释。
在本系列文章的第一篇文章中,我们学习了如何使用 OpenCV 处理图像和视频序列。我们学习了如何从网络摄像头和视频文件读取、写入和显示图像和视频。
在本文中,我们将学习如何使用 OpenCV 标注图像中的对象,如下图所示。您通常在对象检测器训练期间需要这样做,以指示训练和测试数据集中的对象。
OpenCV 提供了一种机制,使您可以选择图像中的形状。也就是说,您可以将鼠标回调函数与使用 OpenCV 显示的窗口(imshow
或 namedWindow
方法)连接起来。通过这样做,您可以检测用户何时单击鼠标按钮以及他们放置指针的位置。
我将向您展示如何使用 OpenCV 和 Python 响应鼠标事件。您可以在这里找到配套源代码。
通用模块
为了对我在代码中使用的各种常量进行分组,我创建了 common.py 模块
import cv2 as opencv
LENA_FILE_PATH = '../Images/Lena.png'
WINDOW_NAME = 'Lena'
# Colors (BGR)
GREEN = (0, 255, 0)
LINE_THICKNESS = 3
# Image labeling parameters
FONT_FACE = opencv.FONT_HERSHEY_PLAIN
FONT_SCALE = 2
FONT_THICKNESS = 2
FONT_LINE = opencv.LINE_AA
TEXT_OFFSET = 4
该模块定义了几个常量
LENA_FILE_PATH
– 指向 Lena 图像的位置。WINDOW_NAME
– 存储窗口名称。GREEN
和LINE_THICKNESS
– 定义用于绘制矩形的颜色(BGR 格式)和线条粗细。FONT_FACE
,FONT_SCALE
等 – 用于显示对象标签的参数。TEXT_OFFSET
– 定义标签和矩形之间的间隙(以像素为单位)。
鼠标回调
要处理鼠标与 OpenCV 窗口的交互,您需要设置鼠标回调函数。为此,首先使用 namedWindow
函数创建窗口
import cv2 as opencv
import common
opencv.namedWindow(common.WINDOW_NAME)
然后,按如下方式调用 setMouseCallback
opencv.setMouseCallback(common.WINDOW_NAME, on_mouse_move)
回调函数应具有以下原型
def on_mouse_move(event, x, y, flags, param)
这些是五个输入参数
event
– 鼠标事件之一,例如EVENT_LBUTTONDOWN
、EVENT_LBUTTONUP
、EVENT_MOUSEWHEEL
、EVENT_RBUTTONDBLCLK
。x
,y
– 鼠标光标的坐标。flags
– 标志,指示鼠标按钮是否按下(EVENT_FLAG_LBUTTON, EVENT_FLAG_RBUTTON
、EVENT_FLAG_MBUTTON
)或者用户是否按下 Ctrl (EVENT_FLAG_CTRLKEY
)、Shift (EVENT_FLAG_SHIFTKEY
) 或 Alt (EVENT_FLAG_ALTKEY
)。param
- 一个可选参数。
设置回调函数后,OpenCV 会在触发鼠标事件时调用它。要让用户选择一个对象,您可以这样编写 on_mouse_move
回调函数
rectangle_points = []
def on_mouse_move(event, x, y, flags, param):
# User pressed left mouse button and started drawing the rectangle
if(event == opencv.EVENT_LBUTTONDOWN):
rectangle_points.clear()
rectangle_points.append((x,y))
# User has finished drawing the rectangle
elif event == opencv.EVENT_LBUTTONUP:
rectangle_points.append((x,y))
display_lena_image(True)
上面的函数将用户在 rectangle_points
列表中选择的矩形的两个坐标(两个对角)存储起来。当用户按下鼠标左键时,回调函数会调用两个语句
rectangle_points.clear()
rectangle_points.append((x,y))
第一个语句清除坐标列表,然后通过读取 OpenCV 传递给回调函数的 x
和 y
参数来附加新元素。这些坐标代表矩形的第一个角。然后,用户按住鼠标左键不放,并将光标移动到矩形的对角。然后,用户必须释放鼠标左键,这反过来会从 on_mouse_move
回调函数中调用以下语句
rectangle_points.append((x,y))
display_lena_image(True)
第一个语句将鼠标光标的 x
、y
坐标附加到 rectangle_points
列表中。第二个语句将使用以下方法显示 Lena 图像
def display_lena_image(draw_rectangle):
# File path
file_path = common.LENA_FILE_PATH
# Load image
lena_img = opencv.imread(file_path)
# Draw rectangle
if(draw_rectangle):
draw_rectangle_and_label(lena_img, 'Lena')
# Show image
opencv.imshow(common.WINDOW_NAME, lena_img)
opencv.waitKey(0)
上面显示的 display_lena_image
函数使用 OpenCV 的 imread
方法从文件中读取图像。然后,该函数检查输入参数 draw_rectangle
是否为 True
。如果是,则 display_lena_image
将绘制用户选择的矩形(参见下文),然后再向用户显示最终图像。为了显示图像,我使用 imshow
方法并使用 waitKey
等待用户按下任意键。
绘制矩形和标签
为了绘制用户选择的矩形,我实现了 draw_rectangle_and_label
函数
def draw_rectangle_and_label(img, label):
opencv.rectangle(img, rectangle_points[0], rectangle_points[1],
common.GREEN, common.LINE_THICKNESS)
text_origin = (rectangle_points[0][0], rectangle_points[0][1] - common.TEXT_OFFSET)
opencv.putText(img, label, text_origin,
common.FONT_FACE, common.FONT_SCALE, common.GREEN,
common.FONT_THICKNESS, common.FONT_LINE)
上面的方法使用了两个 OpenCV 函数:rectangle
和 putText
。
顾名思义,第一个函数绘制矩形。
第二个函数 putText
用于在矩形上方书写标签。
整合
我将上述函数组合成一个 Python 脚本,annotations.py(参见配套代码)
import cv2 as opencv
import common
rectangle_points = []
def draw_rectangle_and_label(img, label):
# Definition of the draw_rectangle_and_label
def display_lena_image(draw_rectangle):
# Definition of the display_lena_image
def on_mouse_move(event, x, y, flags, param):
# Definition of the on_mouse_move
# Prepare window and set mouse callback
opencv.namedWindow(common.WINDOW_NAME)
opencv.setMouseCallback(common.WINDOW_NAME, on_mouse_move)
# Display Lena image
display_lena_image(False)
要测试该应用程序,只需运行 annotations.py。该代码将创建窗口,设置鼠标回调函数,然后显示没有任何注释的 Lena 图像。然后您选择矩形,应用程序将在图像上绘制它,如简介中所示。
总结
我们学习了如何在 OpenCV 中使用鼠标回调函数来选择图像中的各种对象。此功能通常用于准备测试和训练数据集,以及指示检测到的对象。在下一篇文章中,我们将使用绘图函数来描绘检测到的对象。