一、算法介紹
軟 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 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] 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 中下降函數的選擇也影響着得分的調整過程。在實際應用中,需要根據具體需求進行選擇和調整。
原創文章,作者:YZGEU,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/368237.html