65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.90/5 (8投票s)

2020年12月3日

CPOL

4分钟阅读

viewsIcon

6899

downloadIcon

171

在本文中,我们将学习如何向图像添加注释。

在本系列文章的第一篇文章中,我们学习了如何使用 OpenCV 处理图像和视频序列。我们学习了如何从网络摄像头和视频文件读取、写入和显示图像和视频。

在本文中,我们将学习如何使用 OpenCV 标注图像中的对象,如下图所示。您通常在对象检测器训练期间需要这样做,以指示训练和测试数据集中的对象。

OpenCV 提供了一种机制,使您可以选择图像中的形状。也就是说,您可以将鼠标回调函数与使用 OpenCV 显示的窗口(imshownamedWindow 方法)连接起来。通过这样做,您可以检测用户何时单击鼠标按钮以及他们放置指针的位置。

我将向您展示如何使用 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 – 存储窗口名称。
  • GREENLINE_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_LBUTTONDOWNEVENT_LBUTTONUPEVENT_MOUSEWHEELEVENT_RBUTTONDBLCLK
  • x, y – 鼠标光标的坐标。
  • flags – 标志,指示鼠标按钮是否按下(EVENT_FLAG_LBUTTON, EVENT_FLAG_RBUTTONEVENT_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 传递给回调函数的 xy 参数来附加新元素。这些坐标代表矩形的第一个角。然后,用户按住鼠标左键不放,并将光标移动到矩形的对角。然后,用户必须释放鼠标左键,这反过来会从 on_mouse_move 回调函数中调用以下语句

rectangle_points.append((x,y))
display_lena_image(True)

第一个语句将鼠标光标的 xy 坐标附加到 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 函数:rectangleputText

顾名思义,第一个函数绘制矩形。

第二个函数 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 中使用鼠标回调函数来选择图像中的各种对象。此功能通常用于准备测试和训练数据集,以及指示检测到的对象。在下一篇文章中,我们将使用绘图函数来描绘检测到的对象。

© . All rights reserved.