nms--非极大值抑制

nms(non maximum suppression) 非极大值抑制算法在检测任务中是非常常用的,而且检测结果中不可避免出现在同一个目标位置处产生多个候选框;因此nms的作用是剔除掉检测结果中重合率(IOU)大于给定阈值(threshold)的候选框最终期望达到在一个目标位置处只保留一个最优检测结果。

算法原理

方法的输入参数由两部分组成:dets 所有候选区域,包含每一个检测框的左上和右下角位置坐标以及置信度;thresh阈值

我们首先根据每个候选框的置信度进行一个由大到小的排序,置信度最高的排在第一位;

循环开始,首先取置信度最高候选框, 将其加入到最终返回值列表中,然后计算其和剩下所有候选框区域的交并比iou,剔除掉和当前候选区域计算结果中iou>thresh的候选框, 对剩下的候选区域继续执行上述的循环直到整个数组为空。

nms.py

import numpy as np
# 输入: dets为候选框; thresh为iou阈值
# 返回值 keep
def nms(dets, thresh):
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, -1]
    order = np.argsort(scores)[::-1] # 排序后的索引,由大到小
    areas = (x2-x1) * (y2-y1)
    # print(areas)

    # 最后保留的结果
    keep = []
    while order.size > 0:
        i = order[0] # 取出置信度最高的窗口
        keep.append(i)
        # 计算窗口i 和其他所有窗口 交叠部分面积
        xx1 = np.maximum(x1[i], x1[order[1:]])
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])

        w = np.maximum(0.0, xx2 - xx1)
        h = np.maximum(0.0, yy2 - yy1)
        inter = w * h

        # 计算交并比iou
        ovr = inter / ( areas[i] + areas[order[1:] ] - inter )
        print(ovr)
        # inds 为 所有与窗口i的iou值小于threshold值的索引
        # np.where返回值为tuple,*[0]才为真正想要的数据
        inds = np.where(ovr <= thresh)[0]
        print("IOU合并 ", i, order[np.where(ovr > thresh)[0]+1])
        # 因为窗口i代表自身,inds + 1即可对应于order中那些不满足条件的窗口索引位置
        order = order[inds + 1]

    return dets[keep]

测试部分

模拟给出了几组候选框信息,对其执行非极大值抑制操作,最终剩下3组候选框。
test.py

import cv2 as cv
import numpy as np
import nms
boxes = [[200, 200, 400, 400, 0.99],
         [220, 220, 420, 420, 0.9],
         [100, 100, 150, 150, 0.82],
         [200, 240, 400, 440, 0.5],
         [150, 250, 300, 400, 0.88]]
boxes = np.array(boxes)
overlap = 0.6 # 阈值
pick = nms.nms(boxes, overlap)
print(pick)

###
canvas = np.zeros((500, 500, 3), dtype='uint8')
color = (0, 255, 255)
for box in boxes:
    x1, y1, x2, y2, _ = map(int, box)
    cv.rectangle(canvas, (x1, y1), (x2, y2), color, 5)
color = (255, 0, 255)
for box in pick:
    # print(box)
    x1, y1, x2, y2, _ = map(int, box)
    cv.rectangle(canvas, (x1, y1), (x2, y2), color, 2)
cv.imwrite("result.png", canvas)
cv.imshow('nms', canvas)
cv.waitKey()

结果和分析:

5个黄色框是最初出入的所有候选区域,经过nms算法之后,只保留了3个粉红色框部分,剔除掉的2个黄色候选框是因为和200, 200, 400, 400, 0.99 这个候选框计算的IOU结果大于了给定的阈值

使用OpenCV进行可视化,左上角坐标为(0,0),最终结果如图
这里写图片描述

参考:
https://blog.csdn.net/hongxingabc/article/details/78996407
https://www.cnblogs.com/king-lps/p/8040458.html

猜你喜欢

转载自blog.csdn.net/u010472607/article/details/81317065
今日推荐