大家好,我是小寒

今天给大家分享目标检测中的一个关键知识点,NMS

目标检测中的非最大抑制(Non-Maximum Suppression, NMS)是一个关键步骤,用于去除多余的候选框(bounding boxes),从而精简检测结果。它主要用于确保每个目标只被检测一次,避免多个重叠的候选框表示同一个目标。

目标检测简介

目标检测(Object Detection)是一种计算机视觉技术,其主要任务是识别图像或视频中的目标,并确定每个目标的位置和类别。

与图像分类不同,目标检测不仅需要识别图像中包含的物体,还需要定位这些物体在图像中的具体位置(通常用边界框表示)。

image-20240719114110061

  • 在第一幅图中,我们只是对图片中的物体进行 “分类”。这是一个分类问题
  • 在第二幅图中,我们只是在图像中“定位”物体。这是一个定位问题
  • 在第三幅图中,我们对物体进行 “分类和定位”。这是一个物体检测问题

目标检测任务有多种算法,这些算法在过去十年中不断发展。

为了进一步提高性能并捕捉不同形状和大小的物体,算法会预测多个不同大小和长宽比的边界框。

image-20240719114456873

但是在所有边界框中,如何选择最合适、最准确的边界框?这就是 NMS 发挥作用的地方。

什么是非最大抑制?

图片中的物体可能大小和形状各异,为了完美捕捉每个物体,目标检测算法会创建多个边界框(左图)。理想情况下,对于图片中的每个物体,我们都必须有一个边界框,类似于右图。

image-20240719114742631

为了从多个预测的边界框中选择最佳边界框,这些目标检测算法使用非最大抑制。

该技术用于“抑制”可能性较小的边界框并仅保留最佳边界框。

非最大抑制如何起作用?

非最大抑制的目的是为对象选择最佳边界框,并拒绝或 “抑制” 所有其他边界框。

该算法迭代地选择最佳边界框,比较重叠,并删除冗余框,直到收敛。

NMS 考虑了两件事

  • 客观性得分由模型给出
  • 边界框的重叠或 IOU

你可以在下图中看到,除了边界框之外,模型还会返回客观性分数。

该分数表示模型对目标对象存在于此边界框中的确定程度。

image-20240719115126523

你可以看到所有边界框都有物体,但只有绿色边界框是检测物体的最佳边界框。

现在我们如何摆脱其他边界框?

非最大抑制将首先选择客观性得分最高的边界框。然后删除所有其他重叠度高的边界框。

所以在上面的图片中,

  1. 我们将为狗选择绿色边界框(因为它的客观性得分最高,为 98%)
  2. 并移除狗的黄色和红色框(因为它们与绿色框重叠较高)

其余的框也采用相同的过程,这个过程不断迭代,直到不再减少框。

最后,我们将得到以下结果。

image-20240719133548433

这就是 NMS 的工作原理。

实现非最大抑制

现在你应该对非最大抑制有了很好的理解。让我们将非最大抑制的过程分解为几个步骤。

  • 选择客观性得分最高的框
  • 然后,比较此框与其他框的重叠(交集与并集)
  • 删除重叠(交集与并集)大于 50% 的边界框
  • 然后,转到下一个最高的客观性得分
  • 最后重复步骤2-4

image-20240719133944573

假设我们一个人和狗的图像,有六个边界框,每个边界框都有客观性分数。

image-20240719134558140

对于此图像,我们将使用 torchvision 库中的非最大抑制(NMS 算法)函数 nms() 。

此函数需要三个参数-

  • Boxes:x1、y1、x2、y2 格式的边界框坐标
  • 分数:每个边界框的客观性分数
  • iou_threshold:重叠(或 IOU)的阈值

这里,由于上述坐标采用 x1、y1、宽度、高度格式,我们将按以下方式确定 x2、y2

x2 = x1 + 宽度 y2 = y1 + 高度

import torch
from torchvision.ops import nms


boxes = torch.tensor([[190,380,(190+300),(380+150)],
                      [300,420,(300+150),(420+210)],
                      [320,360,(320+200),(360+230)],

                      [390,50,(390+300),(50+330)],
                      [490,45,(490+200),(45+500)],
                      [480,130,(480+150),(130+400)]], dtype=torch.float32)

scores = torch.tensor([[0.90],[0.98],[0.82], [0.87],[0.98],[0.82]], dtype=torch.float32)

nms(boxes = boxes, scores = scores, iou_threshold=0.2)

#tensor([1, 4])

对于我们的示例,这个 python 函数返回了边界框 1 和 4。