非极大值抑制算法
非極大值抑制算法
簡介
非極大值抑制算法(Non-Maximum Suppression,NMS),首次在論文 Efficient non-maximum suppression 被提出,多年之后被廣泛用于目標(biāo)檢測領(lǐng)域,用于消除多余的檢測框。
NMS 介紹
目標(biāo)檢測算法(主流的有 RCNN 系、YOLO 系、SSD 等)在進(jìn)行目標(biāo)檢測任務(wù)時(shí),可能對同一目標(biāo)有多次預(yù)測得到不同的檢測框,NMS 算法則可以確保對每個(gè)對象只得到一個(gè)檢測,簡單來說就是“消除冗余檢測”。
IOU
交并比(Intersection over Union,IOU)是目標(biāo)檢測領(lǐng)域常用的一個(gè)指標(biāo),用于衡量兩個(gè)邊界框的重疊程度,顧名思義利用兩個(gè)邊界框的交集面積除以兩個(gè)邊界框的并集面積即可。當(dāng) IOU 為 0 的時(shí)候表示無重疊,為 1 的時(shí)候表示完全重疊,在 0 到 1 之間的數(shù)值表示重疊程度。
NMS 算法流程
NMS 的工作流程如下,其實(shí)非常簡單粗暴:
上圖中,顯然,左側(cè)目標(biāo)只保留0.95的置信度的檢測結(jié)果,右側(cè)目標(biāo)只保留0.9的檢測結(jié)果。
此外,還有一個(gè)問題就是當(dāng)目標(biāo)為很多類別時(shí)(上圖只有一個(gè)行人類別),按照吳恩達(dá)的思路這里應(yīng)該不引入其他變量,簡單來說就是一個(gè)類別一個(gè)類別地進(jìn)行NMS。
代碼實(shí)現(xiàn)
利用Python實(shí)現(xiàn)NMS是非常簡單的,有興趣可以查看Fast R-CNN的實(shí)現(xiàn)源碼,下文代碼參考其完成(代碼中沒有進(jìn)行第一步的按置信度過濾)。
import numpy as np import cv2from draw_bbox import draw_boxdef nms(bboxes, scores, iou_thresh):""":param bboxes: 檢測框列表:param scores: 置信度列表:param iou_thresh: IOU閾值:return:"""x1 = bboxes[:, 0]y1 = bboxes[:, 1]x2 = bboxes[:, 2]y2 = bboxes[:, 3]areas = (y2 - y1) * (x2 - x1)# 結(jié)果列表result = []index = scores.argsort()[::-1] # 對檢測框按照置信度進(jìn)行從高到低的排序,并獲取索引# 下面的操作為了安全,都是對索引處理while index.size > 0:# 當(dāng)檢測框不為空一直循環(huán)i = index[0]result.append(i) # 將置信度最高的加入結(jié)果列表# 計(jì)算其他邊界框與該邊界框的IOUx11 = np.maximum(x1[i], x1[index[1:]])y11 = np.maximum(y1[i], y1[index[1:]])x22 = np.minimum(x2[i], x2[index[1:]])y22 = np.minimum(y2[i], y2[index[1:]])w = np.maximum(0, x22 - x11 + 1)h = np.maximum(0, y22 - y11 + 1)overlaps = w * hious = overlaps / (areas[i] + areas[index[1:]] - overlaps)# 只保留滿足IOU閾值的索引idx = np.where(ious <= iou_thresh)[0]index = index[idx + 1] # 處理剩余的邊框bboxes, scores = bboxes[result], scores[result]return bboxes, scoresif __name__ == '__main__':raw_img = cv2.imread('test.png')# 這里為了編碼方便,將檢測的結(jié)果直接作為變量bboxes = [[183, 625, 269, 865], [197, 603, 296, 853], [190, 579, 295, 864], [537, 507, 618, 713], [535, 523, 606, 687]]confidences = [0.7, 0.9, 0.95, 0.9, 0.6]# 未經(jīng)過nms的原始檢測結(jié)果img = raw_img.copy()for x, y in zip(bboxes, confidences):img = draw_box(img, x, y)cv2.imwrite("../assets/raw_img.png", img)# 進(jìn)行nms處理bboxes, scores = nms(np.array(bboxes), np.array(confidences), 0.5)img = raw_img.copy()for x, y in zip(list(bboxes), list(scores)):img = draw_box(img, x, y)cv2.imwrite("../assets/img_nms.png", img)在上一節(jié)的檢測結(jié)果基礎(chǔ)上進(jìn)行NMS后的檢測結(jié)果如下圖,可以看到,成功過濾掉很多冗余的檢測。
補(bǔ)充說明
本文主要講解并實(shí)現(xiàn)了目標(biāo)檢測算法中常用的NMS算法,該算法對檢測結(jié)果進(jìn)行篩選上有著姣好的效果,本文理論部分參考吳恩達(dá)的深度學(xué)習(xí)課程,設(shè)計(jì)的源碼可以在我的Github找到,歡迎star或者fork。
總結(jié)
- 上一篇: WRN详述
- 下一篇: Zotero参考文献管理