一、算法介绍
软 NMS (Non-Maximum Suppression,非极大值抑制)是一种目标检测算法,它可以在减少重复框的同时保证准确率。传统的 NMS 算法会选择最高分值的框,但在多目标检测中,它可能会选择重叠较多的框。软 NMS 是通过计算 IoU(Intersection over Union,交并比)的方式来调整框的得分值,减少重叠框的选择。
下面是一个简单的软 NMS 算法实现:
def soft_nms(dets, sigma=0.5, Nt=0.3, threshold=0.001, method='linear'): """ @param dets:(numpy.array) 要检测的目标框,(x1,y1,x2,y2,score)、score表示得分 @param sigma:(float) 常量为卷积核的方差σ。 @param Nt: IoU阈值,小于此阈值的框被过滤。 @param threshold: score阈值,当score小于这个阈值时就不会再被考虑。 @param method: 下降函数的类型,可选择 'linear' 或 'gaussian'
二、软 NMS 的具体实现
1、算法思路
软 NMS 的核心思路就是对所有框按照得分从大到小排序,然后依次处理每个框,计算其与后面框的 IoU 值,并按照下降函数(如线性函数或者高斯函数)的方法对其得分进行调整,最后筛选出得分高于阈值并且没有被过滤掉的框。
具体细节如下:
def soft_nms(dets, sigma=0.5, Nt=0.3, threshold=0.001, method='linear'): """ @param dets:(numpy.array) 要检测的目标框,(x1,y1,x2,y2,score)、score表示得分 @param sigma:(float) 常量为卷积核的方差σ。 @param Nt: IoU阈值,小于此阈值的框被过滤。 @param threshold: score阈值,当score小于这个阈值时就不会再被考虑。 @param method: 下降函数的类型,可选择 'linear' 或 'gaussian' """ N = dets.shape[0] pos = 0 maxscore = 0 maxpos = 0 tmp = 0 if N == 0: return [] if sigma < 0.001: sigma = 0.001 for i in range(N): # 找出得分最大的框 maxscore = dets[i, 4] maxpos = i # if we have one box to cluster dets[i, 4] = 0 # 遍历所有剩余的 box,计算它和当前 box 的 IoU 值 pos = i + 1 while pos < N: if dets[pos, 4] > threshold: # 计算框的 IoU 值 xx1 = np.maximum(dets[i, 0], dets[pos, 0]) yy1 = np.maximum(dets[i, 1], dets[pos, 1]) xx2 = np.minimum(dets[i, 2], dets[pos, 2]) yy2 = np.minimum(dets[i, 3], dets[pos, 3]) w = np.maximum(0.0, xx2 - xx1) h = np.maximum(0.0, yy2 - yy1) o = w * h / ((dets[i, 2] - dets[i, 0]) * (dets[i, 3] - dets[i, 1]) + (dets[pos, 2] - dets[pos, 0]) * (dets[pos, 3] - dets[pos, 1]) - w * h) # 对得分进行调整 if method == 'linear': if o > Nt: weight = 1 - o else: weight = 1 elif method == 'gaussian': weight = np.exp(-(o * o) / sigma) dets[pos, 4] = weight * dets[pos, 4] # 如果得分小于阈值,就把它和最后一个框位置互换,然后将 N 减 1,剔除最后一个得分低的框 if dets[pos, 4] < threshold: tmp = dets[pos] dets[pos] = dets[N - 1] dets[N - 1] = tmp N = N - 1 pos = pos - 1 pos = pos + 1 # 将得分最大的框交换到前面 if maxpos != i: tmp = dets[i] dets[i] = dets[maxpos] dets[maxpos] = tmp # 最后筛选出得分高于阈值并且没有被过滤掉的框 keep = [i for i in range(N) if dets[i, 4] > threshold] return keep
2、下降函数的选择
软 NMS 中下降函数的选择影响着得分的调整过程。一般有两种下降函数可供选择:线性函数(linear)和高斯函数(gaussian)。
线性函数调整基于 IoU 值的得分,其计算公式如下:
if o > Nt: weight = 1 - o else: weight = 1
其中,o 是 IoU 值,Nt 是 IoU 阈值,weight 是调整得分后的值。如果 IoU 值大于阈值 Nt,则使用线性函数进行调整;否则不进行调整,保持原来的得分。
高斯函数调整基于框之间距离的指数函数,其计算公式如下:
weight = np.exp(-(o * o) / sigma)
其中,sigma 是常量,是卷积核的方差。sigma 越大,框之间的距离越远,得分越低。
三、使用示例
下面是一个使用软 NMS 进行目标检测的示例:
import cv2 import numpy as np # 加载模型及其配置文件 net = cv2.dnn.readNetFromDarknet("yolov3.cfg", "yolov3.weights") classes = open("coco.names").read().strip().split("\n") layer_names = net.getLayerNames() output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()] # 加载图片,并进行目标检测 img = cv2.imread("object.jpg") img = cv2.resize(img, None, fx=0.4, fy=0.4) height, width, channels = img.shape blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False) net.setInput(blob) outs = net.forward(output_layers) class_ids = [] confidences = [] boxes = [] for out in outs: for detection in out: scores = detection[5:] class_id = np.argmax(scores) confidence = scores[class_id] if confidence > 0.5: center_x = int(detection[0] * width) center_y = int(detection[1] * height) w = int(detection[2] * width) h = int(detection[3] * height) x = center_x - w // 2 y = center_y - h // 2 boxes.append([x, y, w, h]) confidences.append(float(confidence)) class_ids.append(class_id) # 进行非极大值抑制,使用软 NMS indices = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4) for i in indices: i = i[0] box = boxes[i] x = box[0] y = box[1] w = box[2] h = box[3] label = str(classes[class_ids[i]]) confidence = confidences[i] color = (0, 255, 0) cv2.rectangle(img, (x, y), (x + w, y + h), color, 2) cv2.putText(img, label + " " + str(round(confidence, 2)), (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) cv2.imshow("Image", img) cv2.waitKey(0) cv2.destroyAllWindows()
四、小结
软 NMS 是一种目标检测算法,应用广泛。在处理重复的检测框时,传统的 NMS 算法可能会将得分较低的框筛选出来,导致准确率降低。而软 NMS 可以通过计算 IoU 值来调整框的得分,以减少重复框的选择,同时保证准确率。此外,软 NMS 中下降函数的选择也影响着得分的调整过程。在实际应用中,需要根据具体需求进行选择和调整。