5.1.2.3 目标检测基本概念和YOLOv3设计思想——交并比 NMS

简介: 这篇文章详细解释了目标检测中的关键概念交并比(IoU)和非极大值抑制(NMS),包括它们的定义、计算方法和在目标检测中的应用,以及如何使用这些技术来优化预测结果和减少冗余预测框。

5.1.2.3 交并比

上面我们画出了以点(300,500)为中心,生成的三个锚框,我们可以看到锚框A1 与真实框 G1的重合度比较好。那么如何衡量这三个锚框跟真实框之间的关系呢?在检测任务中,使用交并比(Intersection of Union,IoU)作为衡量指标。这一概念来源于数学中的集合,用来描述两个集合A和B之间的关系,它等于两个集合的交集里面所包含的元素个数除以它们的并集里面所包含的元素个数,具体计算公式如下:

我们将用这个概念来描述两个框之间的重合度。两个框可以看成是两个像素的集合,它们的交并比等于两个框重合部分的面积除以它们合并起来的面积。下图“交集”中青色区域是两个框的重合面积,图“并集”中蓝色区域是两个框的相并面积。用这两个面积相除即可得到它们之间的交并比,如图7所示。

图7:交并比

假设两个矩形框A和B的位置分别为:

A:[xa1,ya1,xa2,ya2]

B:[xb1,yb1,xb2,yb2]

假如位置关系如图8所示:

图8:计算交并比


思考:

两个矩形框之间的相对位置关系,除了上面的示意图之外,还有哪些可能,上面的公式能否覆盖所有的情形?


交并比计算程序如下:

In [11]

# 计算IoU,矩形框的坐标形式为xyxy,这个函数会被保存在box_utils.py文件中
def box_iou_xyxy(box1, box2):
    # 获取box1左上角和右下角的坐标
    x1min, y1min, x1max, y1max = box1[0], box1[1], box1[2], box1[3]
    # 计算box1的面积
    s1 = (y1max - y1min + 1.) * (x1max - x1min + 1.)
    # 获取box2左上角和右下角的坐标
    x2min, y2min, x2max, y2max = box2[0], box2[1], box2[2], box2[3]
    # 计算box2的面积
    s2 = (y2max - y2min + 1.) * (x2max - x2min + 1.)
    
    # 计算相交矩形框的坐标
    xmin = np.maximum(x1min, x2min)
    ymin = np.maximum(y1min, y2min)
    xmax = np.minimum(x1max, x2max)
    ymax = np.minimum(y1max, y2max)
    # 计算相交矩形行的高度、宽度、面积
    inter_h = np.maximum(ymax - ymin + 1., 0.)
    inter_w = np.maximum(xmax - xmin + 1., 0.)
    intersection = inter_h * inter_w
    # 计算相并面积
    union = s1 + s2 - intersection
    # 计算交并比
    iou = intersection / union
    return iou
bbox1 = [100., 100., 200., 200.]
bbox2 = [120., 120., 220., 220.]
iou = box_iou_xyxy(bbox1, bbox2)
print('IoU is {}'.format(iou))

IoU is 0.47402644317607107

In [12]

# 计算IoU,矩形框的坐标形式为xywh
def box_iou_xywh(box1, box2):
    x1min, y1min = box1[0] - box1[2]/2.0, box1[1] - box1[3]/2.0
    x1max, y1max = box1[0] + box1[2]/2.0, box1[1] + box1[3]/2.0
    s1 = box1[2] * box1[3]
    x2min, y2min = box2[0] - box2[2]/2.0, box2[1] - box2[3]/2.0
    x2max, y2max = box2[0] + box2[2]/2.0, box2[1] + box2[3]/2.0
    s2 = box2[2] * box2[3]
    xmin = np.maximum(x1min, x2min)
    ymin = np.maximum(y1min, y2min)
    xmax = np.minimum(x1max, x2max)
    ymax = np.minimum(y1max, y2max)
    inter_h = np.maximum(ymax - ymin, 0.)
    inter_w = np.maximum(xmax - xmin, 0.)
    intersection = inter_h * inter_w
    union = s1 + s2 - intersection
    iou = intersection / union
    return iou
bbox1 = [100., 100., 200., 200.]
bbox2 = [120., 120., 220., 220.]
iou = box_iou_xywh(bbox1, bbox2)
print('IoU is {}'.format(iou))

IoU is 0.6902485659655831

为了直观的展示交并比的大小跟重合程度之间的关系,图9示意了不同交并比下两个框之间的相对位置关系,从 IoU = 0.95 到 IoU = 0.

图9:不同交并比下两个框之间相对位置示意图


问题:

  1. 什么情况下两个矩形框的IoU等于1?
  2. 什么情况下两个矩形框的IoU等于0?

5.1.2.4 NMS

在目标检测过程中,网络对同一个目标可能会产生多个预测框。因此需要消除重叠较大的冗余预测框。具体的处理方法就是非极大值抑制(Non-maximum suppression,NMS)。假设使用模型对图片进行预测,一共输出了11个预测框及其得分,在图上画出预测框。在每个人像周围,都出现了多个预测框,需要消除冗余的预测框以得到最终的预测结果。

In [13]

# 画图展示目标物体边界框
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.image import imread
import math
# 定义画矩形框的程序    
def draw_rectangle(currentAxis, bbox, edgecolor = 'k', facecolor = 'y', fill=False, linestyle='-'):
    # currentAxis,坐标轴,通过plt.gca()获取
    # bbox,边界框,包含四个数值的list, [x1, y1, x2, y2]
    # edgecolor,边框线条颜色
    # facecolor,填充颜色
    # fill, 是否填充
    # linestype,边框线型
    # patches.Rectangle需要传入左上角坐标、矩形区域的宽度、高度等参数
    rect=patches.Rectangle((bbox[0], bbox[1]), bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, linewidth=1,
                           edgecolor=edgecolor,facecolor=facecolor,fill=fill, linestyle=linestyle)
    currentAxis.add_patch(rect)
    
plt.figure(figsize=(10, 10))
filename = '/home/aistudio/000000086956.jpg'
im = imread(filename)
plt.imshow(im)
currentAxis=plt.gca()
# 预测框位置
boxes = np.array([[4.21716537e+01, 1.28230896e+02, 2.26547668e+02, 6.00434631e+02],
       [3.18562988e+02, 1.23168472e+02, 4.79000000e+02, 6.05688416e+02],
       [2.62704697e+01, 1.39430557e+02, 2.20587097e+02, 6.38959656e+02],
       [4.24965363e+01, 1.42706665e+02, 2.25955185e+02, 6.35671204e+02],
       [2.37462646e+02, 1.35731537e+02, 4.79000000e+02, 6.31451294e+02],
       [3.19390472e+02, 1.29295090e+02, 4.79000000e+02, 6.33003845e+02],
       [3.28933838e+02, 1.22736115e+02, 4.79000000e+02, 6.39000000e+02],
       [4.44292603e+01, 1.70438187e+02, 2.26841858e+02, 6.39000000e+02],
       [2.17988785e+02, 3.02472412e+02, 4.06062927e+02, 6.29106628e+02],
       [2.00241089e+02, 3.23755096e+02, 3.96929321e+02, 6.36386108e+02],
       [2.14310303e+02, 3.23443665e+02, 4.06732849e+02, 6.35775269e+02]])
# 预测框得分
scores = np.array([0.5247661 , 0.51759845, 0.86075854, 0.9910175 , 0.39170712,
       0.9297706 , 0.5115228 , 0.270992  , 0.19087596, 0.64201415, 0.879036])
# 画出所有预测框
for box in boxes:
    draw_rectangle(currentAxis, box)

NMS基本思想是,如果有多个预测框都对应同一个物体,则只选出得分最高的那个预测框,剩下的预测框被丢弃掉。

如何判断两个预测框对应的是同一个物体呢,标准该怎么设置?

如果两个预测框的类别一样,而且他们的位置重合度比较大,则可以认为他们是在预测同一个目标。非极大值抑制的做法是,选出某个类别得分最高的预测框,然后看哪些预测框跟它的IoU大于阈值,就把这些预测框给丢弃掉。这里IoU的阈值是超参数,需要提前设置,YOLOv3模型里面设置的是0.5。

比如在上面的程序中,boxes里面一共对应11个预测框,scores给出了它们预测"人"这一类别的得分。

  • Step0:创建选中列表,keep_list = []
  • Step1:对得分进行排序,remain_list = [ 3, 5, 10, 2, 9, 0, 1, 6, 4, 7, 8],
  • Step2:选出boxes[3],此时keep_list为空,不需要计算IoU,直接将其放入keep_list,keep_list = [3], remain_list=[5, 10, 2, 9, 0, 1, 6, 4, 7, 8]
  • Step3:选出boxes[5],此时keep_list中已经存在boxes[3],计算出IoU(boxes[3], boxes[5]) = 0.0,显然小于阈值,则keep_list=[3, 5], remain_list = [10, 2, 9, 0, 1, 6, 4, 7, 8]
  • Step4:选出boxes[10],此时keep_list=[3, 5],计算IoU(boxes[3], boxes[10])=0.0268,IoU(boxes[5], boxes[10])=0.0268 = 0.24,都小于阈值,则keep_list = [3, 5, 10],remain_list=[2, 9, 0, 1, 6, 4, 7, 8]
  • Step5:选出boxes[2],此时keep_list = [3, 5, 10],计算IoU(boxes[3], boxes[2]) = 0.88,超过了阈值,直接将boxes[2]丢弃,keep_list=[3, 5, 10],remain_list=[9, 0, 1, 6, 4, 7, 8]
  • Step6:选出boxes[9],此时keep_list = [3, 5, 10],计算IoU(boxes[3], boxes[9]) = 0.0577,IoU(boxes[5], boxes[9]) = 0.205,IoU(boxes[10], boxes[9]) = 0.88,超过了阈值,将boxes[9]丢弃掉。keep_list=[3, 5, 10],remain_list=[0, 1, 6, 4, 7, 8]
  • Step7:重复上述Step6直到remain_list为空。

最终得到keep_list=[3, 5, 10],也就是预测框3、5、10被最终挑选出来了,如下图所示。

In [14]

# 非极大值抑制
def nms(bboxes, scores, score_thresh, nms_thresh):
    """
    nms
    """
    inds = np.argsort(scores)
    inds = inds[::-1]
    keep_inds = []
    while(len(inds) > 0):
        cur_ind = inds[0]
        cur_score = scores[cur_ind]
        # if score of the box is less than score_thresh, just drop it
        if cur_score < score_thresh:
            break
        keep = True
        for ind in keep_inds:
            current_box = bboxes[cur_ind]
            remain_box = bboxes[ind]
            iou = box_iou_xyxy(current_box, remain_box)
            if iou > nms_thresh:
                keep = False
                break
        if keep:
            keep_inds.append(cur_ind)
        inds = inds[1:]
    return np.array(keep_inds)

In [21]

plt.figure(figsize=(10, 10))
plt.imshow(im)
currentAxis=plt.gca()
colors = ['r', 'g', 'b', 'k']
# 画出最终保留的预测框
inds = nms(boxes, scores, score_thresh=0.01, nms_thresh=0.5)
# 打印最终保留的预测框是哪几个
print(inds)
for i in range(len(inds)):
    box = boxes[inds[i]]
    draw_rectangle(currentAxis, box, edgecolor=colors[i])

[ 3 5 10]

相关文章
|
安全 Linux iOS开发
Anaconda下载及安装保姆级教程(详细图文)
Anaconda下载及安装保姆级教程(详细图文)
31597 1
Anaconda下载及安装保姆级教程(详细图文)
|
10月前
|
算法 数据可视化 PyTorch
IoU已经out了,试试这几个变体:GIoU、DIoU和CIoU介绍与对比分析
本文探讨了目标检测中常用的交并比(IoU)及其变体,包括广义交并比(GIoU)、距离交并比(DIoU)和完全交并比(CIoU)。这些指标不仅提高了模型在处理不重叠、距离较远或形状差异大的边界框时的表现,还为模型的学习过程提供了更深入的洞察。文章详细解释了各指标的计算方法及应用场景,并提供了相应的代码示例,帮助读者更好地理解和应用这些先进的评估指标。
818 7
IoU已经out了,试试这几个变体:GIoU、DIoU和CIoU介绍与对比分析
|
7月前
|
机器学习/深度学习
YOLOv11改进策略【损失函数篇】| 替换激活函数为Mish、PReLU、Hardswish、LeakyReLU、ReLU6
YOLOv11改进策略【损失函数篇】| 替换激活函数为Mish、PReLU、Hardswish、LeakyReLU、ReLU6
1783 4
|
11月前
|
机器学习/深度学习 编解码 监控
目标检测实战(六): 使用YOLOv8完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)
这篇文章详细介绍了如何使用YOLOv8进行目标检测任务,包括环境搭建、数据准备、模型训练、验证测试以及模型转换等完整流程。
18352 59
目标检测实战(六): 使用YOLOv8完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)
|
11月前
|
机器学习/深度学习 人工智能 文字识别
ultralytics YOLO11 全新发布!(原理介绍+代码详见+结构框图)
本文详细介绍YOLO11,包括其全新特性、代码实现及结构框图,并提供如何使用NEU-DET数据集进行训练的指南。YOLO11在前代基础上引入了新功能和改进,如C3k2、C2PSA模块和更轻量级的分类检测头,显著提升了模型的性能和灵活性。文中还对比了YOLO11与YOLOv8的区别,并展示了训练过程和结果的可视化
17731 0
|
11月前
|
机器学习/深度学习 计算机视觉 Python
目标检测笔记(三):Mosaic数据增强完整代码和结果展示
本文介绍了Mosaic数据增强技术,通过将四张图片拼接成一张新图,极大丰富了目标检测的背景信息。文章提供了完整的Python代码,涵盖了如何处理检测框并调整其位置,以适应拼接后的图像。Mosaic技术不仅提高了学习效率,还在标准化BN计算时同时考虑了四张图片的数据,从而提升了模型的泛化能力。
1063 1
|
机器学习/深度学习 固态存储 数据挖掘
【YOLO系列】YOLOv3论文超详细解读(翻译 +学习笔记)
【YOLO系列】YOLOv3论文超详细解读(翻译 +学习笔记)
2306 1
【YOLO系列】YOLOv3论文超详细解读(翻译 +学习笔记)
|
网络协议 程序员
TCP报文格式全解析:网络小白变高手的必读指南
**TCP报文格式详解摘要** 探索TCP,传输层的关键协议,提供可靠数据传输。报文含源/目的端口(标识应用),32位序号(跟踪字节顺序),确认序号(确认接收),4位首部长度,6位标志(URG, ACK, PSH, RST, SYN, FIN),窗口大小(流量控制),检验和(数据完整性),紧急指针(优先数据)及可变长选项(如MSS, 时间戳)。了解这些字段,能更好地理解TCP连接的建立、管理和数据交换。
909 3
|
算法 计算机视觉
【YOLOv8训练结果评估】YOLOv8如何使用训练好的模型对验证集进行评估及评估参数详解
【YOLOv8训练结果评估】YOLOv8如何使用训练好的模型对验证集进行评估及评估参数详解
|
存储 人工智能 自然语言处理
打造专业高效的AI客服:从基础准备到深度训练的全面指南
【7月更文第14天】在数字化转型的浪潮中,人工智能客服(AI Customer Service)已成为提升企业服务质量和效率的关键。一个训练有素的AI客服不仅能提供24/7不间断服务,还能精准理解客户需求,有效提升客户满意度。本文将深入探讨如何构建这样一个系统,包括必备的硬性条件、训练流程及成本考量,辅以实际代码示例,为您的企业开启智能客服新时代。
3076 1