面试问题总结——编程题关于IOU、NMS

一.关于IOU

1.1 IOU定义

Intersection over Union (IOU) 是目标检测领域中一个重要的评价值。
在这里插入图片描述
上图中框出了ground truth box和predict box。

  IOU 通过计算预测的边框和真实的边框之间的Intersection Area I(相交的面积) 和 Union Area U(总的面积) 的比值来获得,公式如下:
       在这里插入图片描述
(通过计算IoU的值可以得到两个边框的重合率,当它们完全重合时,IoU值等于1。)

1.2 IOU的优缺点

IOU的优点
  ①IOU可以作为距离表示,即IOUloss = 1 - IoU,但是当两个边框不相交时无法回传梯度;
  ②IOU对尺度变化具有不变性的特点,即不受两个物体尺度大小的影响。

IOU的缺点
  ①无法衡量两个框是相邻还是甚远,如下图所示,两种情况下IOU值均为0,可以发现,图(a)中两框距离较近,图(b)中两框距离明显要远,但是仅从IOU数值上无法判断两者距离较近还是较远(两个物体不相交时无法回传梯度);
在这里插入图片描述
  ②IOU不能反映两个物体如何重叠(相交方式),如下图所示,两种情况下的IOU均为0.143,图(a)中两框要比图(b)中的相交更整齐一些,但是IOU并没有反映出这个特点。
在这里插入图片描述

1.3 IOU的实现代码

计算过程
在这里插入图片描述
  条件:假设矩形A(左上角坐标xA1,yA1,右下角坐标xA2,yA2),矩形B(左上角坐标xB1,yB1,右下角坐标xB2,yB2),计算IOU。
在这里插入图片描述

程序思路:
矩形A和矩形B的交集的矩形部分,左上角就是A和B中左上角点坐标较大的那个点,右下角就是A和B中右下角坐标较小的那个点。

import cv2
import numpy as np

def CountIOU(RecA, RecB):
    xA = max(RecA[0], RecB[0])
    yA = max(RecA[1], RecB[1])
    xB = min(RecA[2], RecB[2])
    yB = min(RecA[3], RecB[3])

    # 计算交集部分面积
    interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)

    # 计算预测值和真实值的面积
    RecA_Area = (RecA[2] - RecA[0] + 1) * (RecA[3] - RecA[1] + 1)
    RecB_Area = (RecB[2] - RecB[0] + 1) * (RecB[3] - RecB[1] + 1)

    # 计算IOU
    iou = interArea / float(RecA_Area + RecB_Area - interArea)
    return iou

if __name__ == "__main__":
    # 定义一块500×500像素大小的白色背景
    img = np.zeros((500, 500, 3), np.uint8)
    img.fill(255)

    # 定义矩形A 和 矩形B
    RecA = [50, 50, 300, 300]   # x1,y1,x2,y2
    RecB = [60, 60, 320, 320]
    
    cv2.rectangle(img, (RecA[0], RecA[1]), (RecA[2], RecA[3]), (0, 255, 0), 5)
    cv2.rectangle(img, (RecB[0], RecB[1]), (RecB[2], RecB[3]), (255, 0, 0), 5)
    IOU = CountIOU(RecA, RecB)
    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(img, "IOU = %.2f" % IOU, (130, 190), font, 0.8, (0, 0, 0), 2)
    cv2.imshow("image", img)
    cv2.waitKey()
    cv2.destroyAllWindows()

假设矩形A(50, 50, 300, 300),矩形B(60, 60, 320, 320),
则IOU = (241×241) / (251×251 + 261×261 - 241×241) = 0.795
在这里插入图片描述

二.关于NMS

2.1 NMS的原理

  非极大值抑制(Non-Maximum Suppression,NMS),其思想是搜索局部极大值,抑制非极大值元素。

  比如在YOLO算法中依靠分类器得到目标的多个候选框,以及关于候选框中属于类别的概率值,根据分类器得到的类别分类概率做排序,具体算法流程如下:
  ①事先设定阈值iou_thresh,常用的阈值是0.5左右;
  ②对于所有的候选框dets: [[x1,y1,x2,y2,score],[x1,y1,x2,y2,score],…],根据置信度得分score进行降序排列;
  ③选取置信度最高的框A添加到输出列表,并将其从候选框列表中删除;
  ④计算框A与候选框列表中的所有框的IOU值,对于IOU大于设定阈值的候选框进行删除(目的是为了删除重复的候选框);
  ⑤重复上述过程,直到候选框列表为空,返回输出列表。

2.2 NMS的实现代码

补充:
np.where(condition)
在这里插入图片描述

def nms(dets, iou_thresh):
    if len(dets) == 0:
        return [], []
    bboxes = np.array(dets)

    # 计算 n 个候选框的面积大小
    x1 = bboxes[:, 0]
    y1 = bboxes[:, 1]
    x2 = bboxes[:, 2]
    y2 = bboxes[:, 3]
    scores = bboxes[:, 4]
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)

    # 对置信度进行排序, 获取排序后的下标序号, argsort 默认从小到大排序
    order = np.argsort(scores)

    picked_boxes = []  # 返回值
    while order.size > 0:
        # 将当前置信度最大的框加入返回值列表中
        index = order[-1]
        picked_boxes.append(dets[index])

        # 获取当前置信度最大的候选框与其他任意候选框的相交面积
        x11 = np.maximum(x1[index], x1[order[:-1]])
        y11 = np.maximum(y1[index], y1[order[:-1]])
        x22 = np.minimum(x2[index], x2[order[:-1]])
        y22 = np.minimum(y2[index], y2[order[:-1]])
        w = np.maximum(0.0, x22 - x11 + 1)
        h = np.maximum(0.0, y22 - y11 + 1)
        # 计算交集部分面积
        intersection = w * h

        # 利用相交的面积和两个框自身的面积计算框的交并比, 将交并比大于阈值的框删除
        ious = intersection / (areas[index] + areas[order[:-1]] - intersection)
        left = np.where(ious < iou_thresh)
        order = order[left]
    return picked_boxes

猜你喜欢

转载自blog.csdn.net/qq_45445740/article/details/120388487