一、NMS非极大值抑制原理
在目标检测中,通常使用锚点框来检测目标物体的位置,这些锚点框经过神经网络的前向传播后,每个锚点框都会被赋予一个得分,表示该框内是否包含目标物体。这个得分可以看做是置信度值。在一张图像中,由于使用锚点框的数量很多,因此同一个物体可能会被多个框同时检测出来。NMS(non-maximum suppression)非极大值抑制就是一种用于去除重复框的算法。
在具体实现中,非极大值抑制通过以下流程进行:
- 选取得分最高的框。这个框被认为是可能包含目标的,保留下来;
- 计算剩下的框与这个框的重叠度(overlapping),并删除与其重叠度高于一定阈值的框;
- 重复1和2步骤,继续选取得分最高的框并删除与其重叠度较高的框,直到剩下的框都得分较低,或者剩下框的数量较少;
- 保留剩下的检测框。
二、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算法。