非极大值抑制算法(NMS)的python实现

文章目录

*
前言
1. NMS概述
2. 绘制候选框
3. NMS代码实现
4. 完整代码
结束语

前言

本篇博客主要是介绍非极大值抑制 NMS算法的 python实现,并根据实例检测实现效果。

非极大值抑制算法(NMS)的python实现

; 1. NMS概述

非极大值抑制 (Non-Maximum Supression, NMS),顾名思义,就是抑制非极大值,在目标检测领域中经常使用到,主要是用来对候选框进行去重处理。
NMS算法的大致流程如下:
(1) 根据概率分数 score对候选框进行排序
(2) 选择概率分数最大的 bbox,记录这个 bbox到输出列表中,并删除和这个选框 IoU大于一定阈值的 bbox
(3) 继续选择概率分数最大的边框,并添加到输出列表中,重复上处过程直至没有候选框为止。

2. 绘制候选框

以上述迪迦奥特曼为例,我们首先提供三个候选框,并在候选框的基础之上生成其他的候选框,实现代码如下:

import cv2
import numpy as np
import copy

seed = 10001
np.random.seed(seed)

bounding_boxes = [
        [545, 125, 765, 440],
        [890, 100, 1115, 430],
        [1275, 170, 1490, 490]
    ]

confidence_score = [0.95, 0.98, 0.96]

num_anchor = 10
anchors = copy.deepcopy(bounding_boxes)
scores = copy.deepcopy(confidence_score)

if __name__ == '__main__':
    img = cv2.imread('dijia.png')

    for i in range(num_anchor):
        index = np.random.randint(0, 3)
        offset = np.random.randint(-50, 50, size=4)
        score = np.random.uniform(0.5, 0.9)
        anchors.append(list(bounding_boxes[index] - offset))
        scores.append(round(score, 2))

    for i in range(len(scores)):
        cv2.rectangle(img, pt1=tuple(anchors[i][:2]), pt2=tuple(anchors[i][2:]), color=(0, 255, 0), thickness=2)
        cv2.putText(img, text=str(scores[i]), org=tuple(anchors[i][:2]), fontFace=cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
                    fontScale=1, color=(255, 0, 255), thickness=2)
    cv2.imshow('dijia', img)
    cv2.waitKey()
    cv2.imwrite('dijia1.png', img)

代码运行结果如下:

非极大值抑制算法(NMS)的python实现

3. NMS代码实现

在实现 NMS算法之前先看一下 IoU是如何计算的:
IoU就是我们常说的交并比 (Intersection over Union, IoU),顾名思义,就是交集与并集的比值,反映的是两个物体间的重合程度。计算公式如下:I o U = A ∩ B A ∪ B IoU = \frac{A \cap B} {A \cup B}I o U =A ∪B A ∩B ​

非极大值抑制算法(NMS)的python实现

根据上图所示, IoU 就等于左边灰色面积与右边灰色面积的比值。
下面来看一下 NMS算法的具体实现:

def nms(bboxes, scores, threshold=0.5):
    x1 = bboxes[:, 0]
    y1 = bboxes[:, 1]
    x2 = bboxes[:, 2]
    y2 = bboxes[:, 3]

    areas = (x2 - x1) * (y2 - y1)

    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]

        keep.append(i)

        if order.size == 1:
            break

        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))
        h = np.maximum(0.0, (yy2 - yy1))
        inter = w * h

        iou = inter / (areas[i] + areas[order[1:]] - inter)

        ids = np.where(iou  threshold)[0]

        order = order[ids + 1]

    return keep

4. 完整代码

import cv2
import numpy as np
import copy

seed = 10001
np.random.seed(seed)

bounding_boxes = [
        [545, 125, 765, 440],
        [890, 100, 1115, 430],
        [1275, 170, 1490, 490]
    ]

confidence_score = [0.95, 0.98, 0.96]

num_anchor = 10
anchors = copy.deepcopy(bounding_boxes)
scores = copy.deepcopy(confidence_score)

def nms(bboxes, scores, threshold=0.5):
    x1 = bboxes[:, 0]
    y1 = bboxes[:, 1]
    x2 = bboxes[:, 2]
    y2 = bboxes[:, 3]

    areas = (x2 - x1) * (y2 - y1)

    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]

        keep.append(i)

        if order.size == 1:
            break

        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))
        h = np.maximum(0.0, (yy2 - yy1))
        inter = w * h

        iou = inter / (areas[i] + areas[order[1:]] - inter)

        ids = np.where(iou  threshold)[0]

        order = order[ids + 1]

    return keep

if __name__ == '__main__':
    img = cv2.imread('dijia.png')

    for i in range(num_anchor):
        index = np.random.randint(0, 3)
        offset = np.random.randint(-50, 50, size=4)
        score = np.random.uniform(0.5, 0.9)
        anchors.append(list(bounding_boxes[index] - offset))
        scores.append(round(score, 2))

    anchors = np.asarray(anchors)
    scores = np.asarray(scores)

    keep = nms(anchors, scores, threshold=0.5)
    proposals = anchors[keep]
    proposals_score = scores[keep]

    for i in range(len(proposals)):
        cv2.rectangle(img, pt1=tuple(proposals[i][:2]), pt2=tuple(proposals[i][2:]), color=(0, 255, 0), thickness=2)
        cv2.putText(img, text=str(proposals_score[i]), org=tuple(proposals[i][:2]), fontFace=cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
                    fontScale=1, color=(255, 0, 255), thickness=2)
    cv2.imshow('dijia', img)
    cv2.waitKey()
    cv2.imwrite('dijia2.png', img)

代码运行如下:

非极大值抑制算法(NMS)的python实现

结束语

NMS的实现代码中可以看到主要是对数组的操作,而这部分可以通过 GPU进行加速处理,比如 PyTochPaddlePaddle等深度学习框架,其目标检测模块中的 NMS算法已经内置实现,可以直接在 GPU上使用。

Original: https://blog.csdn.net/qq_42730750/article/details/126235745
Author: 夏小悠
Title: 非极大值抑制算法(NMS)的python实现

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/629530/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球