NMS,IOU——python实现

NMS代码: 【参考】很详细

import numpy as np
def nms(boxes, overlap_threshold, mode='Union'):  #输入boxes是一个N*5的numpy array,overlap_threshold是阈值
    # if there are no boxes, return an empty list
    if len(boxes) == 0:
        return []

    # if the bounding boxes integers, convert them to floats
    if boxes.dtype.kind == "i":
        boxes = boxes.astype("float")

    # initialize the list of picked indexes
    pick = []

    # grab the coordinates of the bounding boxes
    x1, y1, x2, y2, score = [boxes[:, i] for i in range(5)]

    area = (x2 - x1 + 1) * (y2 - y1 + 1)  #求每个bbox的面积
    idxs = np.argsort(score) #从小到大排列

    while len(idxs) > 0:
        last = len(idxs) - 1  #注意:这句千万要注意,不能写成last = idxs[-1]!!!
        i = idxs[last] #每次都从末尾取值,放入pick中
        pick.append(i)

        #计算前面每个框和当前最大框交集的左上角坐标,右下角坐标,不管有无交集,都可以得到这四个值
        xx1 = np.maximum(x1[i], x1[idxs[:last]])  #拿当前最大的和前面所有的都比较一遍
        yy1 = np.maximum(y1[i], y1[idxs[:last]])
        xx2 = np.minimum(x2[i], x2[idxs[:last]])
        yy2 = np.minimum(y2[i], y2[idxs[:last]])

        # 计算bbox的宽度和高度,如果宽度或高度是负值,用0值代替
        w = np.maximum(0, xx2 - xx1 + 1) #得到的w是一个长度为N的array,其中有一些值为0
        h = np.maximum(0, yy2 - yy1 + 1) #h同理

        inter = w * h  #求每个iou的面积,得到的是一个长度为N的array,没有交集的框,inter为0
        if mode == 'Min': #另一种求重叠的方法,这里没有用到
            overlap = inter / np.minimum(area[i], area[idxs[:last]])
        else:
            overlap = inter / (area[i] + area[idxs[:last]] - inter) #交比并

        # 将idxs中overlap满足阈值的bbox的index删除
        # np.where(overlap > overlap_threshold)[0])得到的是长度为1的tuple的第一个值,是一个array,里面包含的是
        # 满足这个条件的bbox的index,然后使用np.concatenate数组拼接函数,将原来score最大的那个bbox的index和现在
        # 满足条件的bbox的index合并成一个numpy array,
        # 最后使用delete删除掉指定bbox的index,这样idxs中就只剩下那些和之前最大score的bbox的overlap比较小的bbox
        # 的index(重叠度大的那些已经删除了)
        idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlap_threshold)[0])))
    return pick
#-----------------------------------------
boxes = np.array([[10,10,40,80,0.5],[25,30,70,80,0.9],[30,25,65,78,0.8]])
overlap_threshold = 0.5
picks = nms(boxes,overlap_threshold,mode='Union')
print(picks)

【注意】:
这里的np.concatenate()函数,一定要加两个括号,不然会报错。因为函数的定义如下:

    numpy.concatenate((a1, a2, ...), axis=0)

其中a1, a2, … : 需要拼接的矩阵,axis : 沿着某个轴拼接,默认为列方向。如果不加内层括号的话,不知道第二个参数究竟是这里的a2还是axis,所以会报错。


2019.8.28 更新
NMS的简化版代码:【参考】 跟上面的结果是一样的。

def NMS(dets, thresh):
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4] # 每个预测框的置信度

    area = (y2 - y1 + 1) * (x2 - x1 + 1)
    order = scores.argsort()[::-1] # 降序排列,置信度最高的排在最前面

    keep = [] #keep为最后保留的边框
    while len(order) > 0:
        i = order[0] # order[0]是当前分数最大的窗口,肯定保留
        keep.append(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, yy2 - yy1 + 1)
        h = np.maximum(0, xx2 - xx1 + 1)
        inter = w * h
        iou = inter / (area[i] + area[order[1:]] - inter) # 计算其余所有框与当前框的iou
        ids = np.where(iou < thresh)[0]  #inds为所有与窗口i的iou值小于threshold值的窗口的index
        order = order[ids + 1] # idx + 1的原因:iou数组的长度比order数组的长度少1(不包含i),所以inds+1对应到保留的窗口
    return keep

boxes = np.array([[10,10,40,80,0.5],[25,30,70,80,0.9],[30,25,65,78,0.8],[50,50,80,80,0.45]])
res = NMS(boxes, 0.5)
print(res) # [1, 0, 3]
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值