軟NMS詳解

一、演算法介紹

軟 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-tw/n/368237.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
YZGEU的頭像YZGEU
上一篇 2025-04-12 01:13
下一篇 2025-04-12 01:13

相關推薦

  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁碟中。在執行sync之前,所有的文件系統更新將不會立即寫入磁碟,而是先緩存在內存…

    編程 2025-04-25
  • 神經網路代碼詳解

    神經網路作為一種人工智慧技術,被廣泛應用於語音識別、圖像識別、自然語言處理等領域。而神經網路的模型編寫,離不開代碼。本文將從多個方面詳細闡述神經網路模型編寫的代碼技術。 一、神經網…

    編程 2025-04-25
  • nginx與apache應用開發詳解

    一、概述 nginx和apache都是常見的web伺服器。nginx是一個高性能的反向代理web伺服器,將負載均衡和緩存集成在了一起,可以動靜分離。apache是一個可擴展的web…

    編程 2025-04-25
  • Python輸入輸出詳解

    一、文件讀寫 Python中文件的讀寫操作是必不可少的基本技能之一。讀寫文件分別使用open()函數中的’r’和’w’參數,讀取文件…

    編程 2025-04-25
  • 詳解eclipse設置

    一、安裝與基礎設置 1、下載eclipse並進行安裝。 2、打開eclipse,選擇對應的工作空間路徑。 File -> Switch Workspace -> [選擇…

    編程 2025-04-25
  • C語言貪吃蛇詳解

    一、數據結構和演算法 C語言貪吃蛇主要運用了以下數據結構和演算法: 1. 鏈表 typedef struct body { int x; int y; struct body *nex…

    編程 2025-04-25
  • Java BigDecimal 精度詳解

    一、基礎概念 Java BigDecimal 是一個用於高精度計算的類。普通的 double 或 float 類型只能精確表示有限的數字,而對於需要高精度計算的場景,BigDeci…

    編程 2025-04-25
  • git config user.name的詳解

    一、為什麼要使用git config user.name? git是一個非常流行的分散式版本控制系統,很多程序員都會用到它。在使用git commit提交代碼時,需要記錄commi…

    編程 2025-04-25
  • Python安裝OS庫詳解

    一、OS簡介 OS庫是Python標準庫的一部分,它提供了跨平台的操作系統功能,使得Python可以進行文件操作、進程管理、環境變數讀取等系統級操作。 OS庫中包含了大量的文件和目…

    編程 2025-04-25
  • Linux修改文件名命令詳解

    在Linux系統中,修改文件名是一個很常見的操作。Linux提供了多種方式來修改文件名,這篇文章將介紹Linux修改文件名的詳細操作。 一、mv命令 mv命令是Linux下的常用命…

    編程 2025-04-25

發表回復

登錄後才能評論