【目标检测】NMS在目标检测中的代码实现

发布于:2024-09-19 ⋅ 阅读:(206) ⋅ 点赞:(0)

一、主要内容:
计算重叠,这里有一个阈值就是thresh,按照下面几条原则:
1、删除交并比大于阈值的框
2、如果ab相交的交并比大于阈值0.1,请问删除哪个框
删除置信度最小的框,第五列是置信度

二、注意:
这里如何理解阈值为啥要设置成0.1,其实版面识别的阈值我一般设置为0,但是0不太合适,我一般是设置为特别小的值,比如说0.0001,为啥呢?
因为版面识别我不需要有重叠的框,所以要这样设置

def nms(dets, thresh):
    # 打印输入的检测框 dets
    print(dets)
    '''
    [[         90        1036         528        1292     0.98149           0]
    [        542        1033         988        1167     0.97097           0]
    [         88         177         978         446     0.97066           3]
    [        544        1210         989        1292     0.95167           0]
    [        240         480         862         991     0.92897           4]
    [        549        1182         758        1200     0.88909           1]
    [         88         126         976         175     0.88162           0]
    [         87          96         151         111     0.86345           6]
    [        813          92         974         104     0.85024           6]
    [        192         998         881        1026     0.81056           0]
    [        526        1306         545        1323     0.78073           7]]
    '''
    "Pure Python NMS baseline"

    # dets[:, 0] 是所有检测框的左上角 x 坐标
    x1 = dets[:, 0] # [         90         542          88         544         240         549          88          87         813         192         526]
    print("x1:  ",x1)   
    # dets[:, 1] 是所有检测框的左上角 y 坐标
    y1 = dets[:, 1]
    # dets[:, 2] 是所有检测框的右下角 x 坐标
    x2 = dets[:, 2]
    # dets[:, 3] 是所有检测框的右下角 y 坐标
    y2 = dets[:, 3]
    # dets[:, 4] 是所有检测框的置信度分数(score)
    scores = dets[:, 4]

    # 计算每个检测框的面积 (width * height)
    areas = (y2 - y1 + 1) * (x2 - x1 + 1) #[ 1.1282e+05       60345  2.4057e+05       37018  3.1898e+05        3990       44450        1040        2106       20010         360]
    print("面积:",areas)
    # 按照 scores 的大小进行排序,得到从大到小的索引顺序
    order = scores.argsort()[::-1]  #[ 0  1  2  3  4  5  6  7  8  9 10]
    print("排序:",order)
    # 用于保存最终筛选出的检测框的索引
    keep = []

    # 当 order 中还有剩余的检测框索引时,继续处理
    while order.size > 0:
        # 取出当前得分最高的检测框的索引 i
        i = order[0]
        # 将得分最高的检测框索引加入 keep 列表中
        keep.append(i)  #第一次为0

        # 找到 i 框与剩下的所有框的相交区域的左上角和右下角坐标
        xx1 = numpy.maximum(x1[i], x1[order[1:]])  # 相交区域左上角的 x 坐标
        
        '''
        1、官方例子
        a = np.array([1, 2, 3])
        b = np.array([2, 1, 4])
        result = np.maximum(a, b)
        返回[2,2,4]

        2、这里的例子:
        x1[i]:88.0
        x1[order[1:]]: [         85         809          84          88]
        xx1:[         88         809          88          88]
        '''
        yy1 = numpy.maximum(y1[i], y1[order[1:]])  # 相交区域左上角的 y 坐标
        xx2 = numpy.minimum(x2[i], x2[order[1:]])  # 相交区域右下角的 x 坐标
        yy2 = numpy.minimum(y2[i], y2[order[1:]])  # 相交区域右下角的 y 坐标

        # 计算相交区域的宽度 w 和高度 h,重叠部分面积为 w * h
        w = numpy.maximum(0, xx2 - xx1 + 1)  # 确保宽度为正,否则重叠为0
        print("w:",w) # [        169         890         885          95]
        h = numpy.maximum(0, yy2 - yy1 + 1)  # 确保高度为正,否则重叠为0
        print("h",h) #[          0           0           0           0]
        inter = w * h  # 重叠区域的面积

        # 计算 IoU(Intersection over Union):相交面积 / (两检测框的总面积 - 相交面积)
        ovr = inter / (areas[i] + areas[order[1:]] - inter)
        print("ovr",ovr)
        # 保留 IoU 小于给定阈值的检测框索引
        indx = numpy.where(ovr <= thresh)[0]  #交并比小于阈值thresh的都记录
        print("indx:",indx)

        '''
        ovr = np.array([0.1, 0.5, 0.3, 0.7])
        thresh = 0.4
        indx = np.where(ovr <= thresh)[0]
        indx是[0 2]
        '''
        # 更新 order 列表,移除与当前框的 IoU 超过阈值的检测框
        # indx 是基于 order[1:] 的索引,因此需要加 1 来对应原始的 order
        order = order[indx + 1]  #indx是一个列表,表示啥,表示比如说,indx=[0,5],那就是order只保留序列0,5的数据,意识是大于这个阈值的就不会再这个循环中出现
        print("order:",order)
    # 打印最终保留的检测框的索引