非极大值抑制(NMS)-Yolov4(二)

非极大值抑制

非极大值抑制也属于后处理一部分,单独说可能会清楚一点,之所以要进行这步操作,原因在于很多时候一个目标存在多个预测框,这时我们需要选出最好的那个作为预测结果。怎么选的过程就是非极大值抑制操作。如下图所示:

非极大值抑制(NMS)-Yolov4(二)_第1张图片

                                                 图1 可爱的小猫

上图中一个目标有三个预测框,所以需要通过非极大值抑制选出最好的那个(黄色框)。需要说明的是,一般情况下,一张图片中可能存在几个类别的目标,每个类别目标可能有多个个体,比如一张图片中可能包含3只猫和2只狗这类更一般的情况。但是一般非极大值抑制每次仅针对一个类别来操作。这里结合代码来说明其具体思路。对于非极大值抑制,我们的输入一般是图像中一类目标(比如猫)的所有预测框和每一个预测框对应的得分以及一个阈值。

def nms(bboxs, scores, threshold):
    x1 = bboxs[:, 0]
    y1 = bboxs[:, 1]
    x2 = bboxs[:, 2]
    y2 = bboxs[:, 3]
    areas = (y2 - y1) * (x2 - x1)  # 每个bbox的面积

    # order为排序后的得分对应的原数组索引值
    _, order = scores.sort(0, descending=True)

    keep = []  # 保存所有结果框的索引值。
    while order.numel() > 0:
        if order.numel() == 1:
            keep.append(order.item())
            break
        else:
            i = order[0].item()
            keep.append(i)

        # 计算最大得分的bboxs[i]与其余各框的IOU
        xx1 = x1[order[1:]].clamp(min=int(x1[i]))
        yy1 = y1[order[1:]].clamp(min=int(y1[i]))
        xx2 = x2[order[1:]].clamp(max=int(x2[i]))
        yy2 = y2[order[1:]].clamp(max=int(y2[i]))
        inter = (yy2 - yy1).clamp(min=0) * (xx2 - xx1).clamp(min=0)
        iou = inter / (areas[i] + areas[order[1:]] - inter)  
        # 如果bboxs长度为N,则iou长度为N-1

        # 保留iou小于阈值的剩余bboxs,.nonzero().squeeze()转化为数字索引,可验证
        idx = (iou <= threshold).nonzero().squeeze()
        if idx.numel() == 0:
            break
        order = order[idx + 1]  
        # idx+1表示对其每个值加一(保证和原来的order中索引一致),并替换原来的order

    return keep

解析:当我们输入需要进行非极大值抑制的所有预测框及其对应的得分和一个阈值后,按如下步骤进行:

第一步:计算所有预测框的面积,areas = (y2 - y1) * (x2 - x1),这是矩阵运算噢。

第二步:根据所有预测框的得分对其进行降序排序, _,order = scores.sort(0, descending=True),order为排序后的得分对应的原数组索引值。

第三步:保留最高得分预测框索引值order[0],计算其和剩余预测框的交集inter,这里也是矩阵运算。

第四步:求得分最高的预测框和其余预测框的交并比IOU。

非极大值抑制(NMS)-Yolov4(二)_第2张图片

                                            图2 IOU示意图

第五步:保留IOU小于阈值的那部分预测框,原因是IOU越大,表明其和最高得分预测框的重合度越大,所以应该去除。

第六步:更新order,order = order[idx + 1],返回第三步,直到IOU小于阈值的那部分预测框数量为零就停止。

通过上面的步骤,我们就可以完成非极大值抑制。同时选出最合适的预测框!

 

接下来结合yolov4再说一下。

接上一节我们得到的三个结果:通过[1,3,13,13,85]变成[1,507,85]、通过[1,3,26,26,85]变成[1,2028,85]、通过[1,3,52,52,85]变成[1,8112,85],这都是维度变化表示噢!对于以上结果我们进行融合后开始非极大值抑制操作,融合代码为:all_prediction= torch.cat((preds,predm,predl),1)

其中preds=[1,507,85],predm=[1,2028,85],predl=[1,8112,85]。

经过非极大值抑制处理后的结果(所有预测框和其对应得分及类别标签)再稍微处理下就可以得到最终的显示效果(这部分看代码就行)。显示效果就是根据上面的结果在图上画出预测框以及对应得分和识别标签。如下所示:

非极大值抑制(NMS)-Yolov4(二)_第3张图片

                                                          图3 识别结果

至此yolov4的结构原理及识别过程完!

接上一篇:https://blog.csdn.net/longing_aa/article/details/113269477

 

你可能感兴趣的:(深度学习,神经网络,pytorch)