您的位置:

NMS非极大值抑制

一、NMS非极大值抑制原理

在目标检测中,通常使用锚点框来检测目标物体的位置,这些锚点框经过神经网络的前向传播后,每个锚点框都会被赋予一个得分,表示该框内是否包含目标物体。这个得分可以看做是置信度值。在一张图像中,由于使用锚点框的数量很多,因此同一个物体可能会被多个框同时检测出来。NMS(non-maximum suppression)非极大值抑制就是一种用于去除重复框的算法。

在具体实现中,非极大值抑制通过以下流程进行:

  1. 选取得分最高的框。这个框被认为是可能包含目标的,保留下来;
  2. 计算剩下的框与这个框的重叠度(overlapping),并删除与其重叠度高于一定阈值的框;
  3. 重复1和2步骤,继续选取得分最高的框并删除与其重叠度较高的框,直到剩下的框都得分较低,或者剩下框的数量较少;
  4. 保留剩下的检测框。

二、NMS非极大值抑制C语言

float iou(float *a, float *b)
{
    float overlap = 0.0f, a_area = 0.0f, b_area = 0.0f;
    float x1 = max(a[0], b[0]), y1 = max(a[1], b[1]);
    float x2 = min(a[2], b[2]), y2 = min(a[3], b[3]);
    overlap = (x2 - x1 > 0 && y2 - y1 > 0) ? (x2 - x1) * (y2 - y1) : 0.0f;
    a_area = (a[2] - a[0]) * (a[3] - a[1]);
    b_area = (b[2] - b[0]) * (b[3] - b[1]);
    return overlap / (a_area + b_area - overlap);
}

void nms_cpu(float *boxes, int boxes_num, int box_size, float overlap, float confidence, int *pick, int *pick_num)
{
    int i, j, pick_idx = 0;
    float score = 0.0f;
    int max_idx = 0;
    float max_score = 0.0f;
    float *pb, *pbmax;
    float iou_val;

    for (i = 0; i < boxes_num; ++i)
    {
        pb = boxes + i * box_size;
        if (pb[4] > max_score)
        {
            max_idx = i;
            max_score = pb[4];
        }
    }
    pbmax = boxes + max_idx * box_size;
    while (max_idx != -1)
    {
        pick[pick_idx++] = max_idx;
        pbmax[4] = -1;
        max_score = 0.0f;
        max_idx = -1;
        for (i = 0; i < boxes_num; ++i)
        {
            if (i == pick[pick_idx - 1])
                continue;
            pb = boxes + i * box_size;
            iou_val = iou(pb, pbmax);
            if (iou_val > overlap)
            {
                for (j = 0, score = 0; j < box_size - 1; ++j)
                {
                    score += pb[j];
                }
                if (score / (box_size - 1) > confidence && score > max_score)
                {
                    max_idx = i;
                    max_score = score;
                }
            }
        }
        if (max_idx != -1)
            pbmax = boxes + max_idx * box_size;
    }
    *pick_num = pick_idx;
}

三、NMS非极大值抑制Python

def nms(dets, thresh):
    """Pure Python NMS baseline."""
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    order = scores.argsort()[::-1]
    keep = []
    while order.size > 0:
        i = 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.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        ovr = inter / (areas[i] + areas[order[1:]] - inter)
        inds = np.where(ovr <= thresh)[0]
        order = order[inds + 1]
    return keep

四、NMS非极大值抑制代码示例

import numpy as np

def nms(dets, thresh):
    """Pure Python NMS baseline."""
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    order = scores.argsort()[::-1]
    keep = []
    while order.size > 0:
        i = 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.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        ovr = inter / (areas[i] + areas[order[1:]] - inter)
        inds = np.where(ovr <= thresh)[0]
        order = order[inds + 1]
    return keep

五、总结

NMS非极大值抑制算法可以有效地去除重复框,提高目标检测的准确率。在实际应用中,可以根据需求采用C语言或Python等多种编程语言来实现NMS算法。