NMS(非极大值抑制)的 Python 实现

news2025/1/23 6:11:57

文章目录

  • 1. NMS的步骤
  • 2. Python代码

非极大值抑制(Non-Maximum Suppression,NMS)是一种在目标检测中常用的技术。

NMS的目的是消除重叠区域中冗余的边界框,并选择最具代表性的目标作为最终结果。通过调整重叠阈值,可以控制NMS的严格程度,从而影响输出的目标数量和召回率。

1. NMS的步骤

实现NMS的步骤如下:

输入:一组候选边界框(通常是由目标检测器生成的),每个边界框都有一个得分值表示其置信度。
按照得分值降序排列所有候选边界框。
选择得分最高的边界框,将其添加到最终的结果列表中,并从候选边界框列表中移除。
计算当前选择的边界框与其他候选边界框的重叠区域(例如,交并比IoU)。
从剩余的候选边界框中移除重叠区域高于一定阈值的边界框。
重复步骤3至步骤5,直到所有候选边界框都被处理完毕。
返回最终的结果边界框列表,这些边界框代表了在重叠区域中最具代表性的目标。

2. Python代码

参考博客:NMS的python实现

code:

import numpy as np
import matplotlib.pyplot as plt


# 自定义数据
# 存储方式: 左下角(x1,y1)坐标,右上角(x2,y2)坐标,置信度 score
Boxes = np.array([[100, 100, 210, 210, 0.72],
                  [250, 250, 400, 400, 0.8],
                  [220, 220, 320, 370, 0.92],
                  [100, 150, 235, 200, 0.79],
                  [230, 240, 355, 350, 0.81],
                  [220, 230, 315, 340, 0.9],
                  [140, 175, 255, 270, 0.95]])


def nms(boxes, iou_thresh):
    # 每个 box 的坐标和置信度
    x1 = boxes[:, 0]
    y1 = boxes[:, 1]
    x2 = boxes[:, 2]
    y2 = boxes[:, 3]
    scores = boxes[:, 4]

    # 每个 box 的面积,areas = [12321. 22801. 15251.  6936. 13986. 10656. 11136.]
    # 需要 +1 的原因:若某个 box 的 x 坐标的像素范围为 [5,10],则共占据 6 个像素,因此 6 = 10-5+1
    areas = (y2 - y1 + 1) * (x2 - x1 + 1)

    # keep_boxes 用于存放执行 NMS 后剩余的 boxes
    keep_boxes = []

    # 取出置信度从大到小排列的索引,其中 scores.argsort() 返回的是数组值从小到大的索引
    # scores = [0.72  0.8  0.92  0.79  0.81  0.9  0.95]
    # index = [  6     2     5    4     1     3    0]
    index = scores.argsort()[::-1]

    while len(index) > 0:
        # 取出置信度最大的 box,将其放入 keep 中,并判断其他 box 是否可以与之合并
        i = index[0]
        keep_boxes.append(i)

        # np.maximum(arr:list, x:int)表示计算arr中每一个元素与常数 x 之间的最大值
        # 如 i=6时,x1[i]=140,x1[index[1:]] = [220. 220. 230. 250. 100. 100.]
        # 则 x11 = [220. 220. 230. 250. 140. 140.]
        x1_overlap = np.maximum(x1[i], x1[index[1:]])
        y1_overlap = np.maximum(y1[i], y1[index[1:]])
        x2_overlap = np.minimum(x2[i], x2[index[1:]])
        y2_overlap = np.minimum(y2[i], y2[index[1:]])

        # 计算重叠部分的面积,若没有不重叠部分则面积为 0
        w = np.maximum(0, x2_overlap - x1_overlap + 1)
        h = np.maximum(0, y2_overlap - y1_overlap + 1)
        overlap_area = w * h

        # 计算 iou(交并比)
        # 第一次 while 循环中,ious = [0.072  0.070  0.031  0.003  0.155  0.119]
        ious = overlap_area / (areas[i] + areas[index[1:]] - overlap_area)

        # 合并重叠度最大的 box,即只保留 iou < iou_thresh 的 box
        # 第一次 while 循环中,np.where(ious <= iou_thresh) = (array([0, 1, 2, 3, 5], dtype=int64),)
        # 因为 np.where(ious <= iou_thresh) 的数据结构是 tuple 里面包含了一个 list,所以要用 [0] 取出 list
        idx = np.where(ious <= iou_thresh)[0]

        # idx + 1 = [1 2 3 4 6]
        # index = index[idx + 1] = [2 5 4 1 0]
        # 这里为什么要将 idx + 1 呢?因为 index 是 ious 的索引,而 ious 是去除掉 index 的第一个元素对应的 box 得到的,
        # 所以 ious 的索引 +1 对应的 box 才是 index 相同索引对应的 index
        # 因为 len(ious)<=len(index),所以 len(index[idx + 1])<=len(index),所以 while 循环中 index 的元素数量越来越少
        index = index[idx + 1]

    return keep_boxes


def plot_bbox(dets, c='k'):
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    plt.plot([x1, x2], [y1, y1], c)
    plt.plot([x1, x1], [y1, y2], c)
    plt.plot([x1, x2], [y2, y2], c)
    plt.plot([x2, x2], [y1, y2], c)
    plt.title("NMS")


if __name__ == '__main__':
    plt.figure(1)
    ax1 = plt.subplot(1, 2, 1)
    ax2 = plt.subplot(1, 2, 2)

    # before nms
    plt.sca(ax1)
    plot_bbox(Boxes, 'g')

    # after nms
    keep_boxes = nms(Boxes, iou_thresh=0.15)
    plt.sca(ax2)
    plot_bbox(Boxes[keep_boxes], 'r')

    # 设置两个子图的坐标范围,防止坐标范围不一致
    ax1.set_xlim([50, 450])
    ax1.set_ylim([50, 450])
    ax2.set_xlim([50, 450])
    ax2.set_ylim([50, 450])
    plt.show()

效果演示:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/966031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

400电话号码怎么开通

开通400电话是企业提供客户服务的重要步骤。下面是一些步骤和注意事项&#xff0c;帮助您顺利开通400电话。 第一步&#xff1a;选择400电话服务提供商 选择一家可靠的400电话服务提供商非常重要。您可以通过搜索引擎、咨询行业内人士或者参考其他企业的经验来选择合适的服务提…

FLASH读写数据

目录 嵌入式 Flash大概了解 数据手册2.3.2章节 结构图f407 等待周期 Flash 控制寄存器解锁 编程/擦除并行位数 擦除 编程&#xff08;写入&#xff09; 工程程序 嵌入式 Flash大概了解 可以从flash区域启动程序&#xff1b;大概是程序区可以在flash&#xff0c;所以是可以…

python调用git出错:ImportError: Failed to initialize: Bad git executable.

报错信息 #报错信息 Traceback (most recent call last): File “”, line 1, in File “C:\Python27\lib\site-packages\git_init_.py”, line 85, in raise ImportError(‘Failed to initialize: {0}’.format(exc)) ImportError: Failed to initialize: Bad git executab…

春秋云镜 CVE-2018-16283

春秋云镜 CVE-2018-16283 WordPress Plugin Wechat Broadcast LFI 靶标介绍 WordPress Plugin Wechat Broadcast LFI 启动场景 漏洞利用 exp # Exploit Title: WordPress Plugin Wechat Broadcast 1.2.0 - Local File Inclusion # Author: Manuel Garcia Cardenas # Date:…

图论-01-图的基本表示-邻接矩阵和邻接表-Java

文章目录 邻接矩阵邻接表邻接表的问题和改进总结 邻接矩阵 import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Scanner;public class AdjMatrix {private int V;private int E;private int[][] adj;// 构造函数&#xff0c;从文…

利用网络流通过拆点判断图的路径存在性问题:abc318_g

https://atcoder.jp/contests/abc318/tasks/abc318_g 对于图上一类路径是否存在问题&#xff0c;可以考虑网络流。 Trick1 路径存在转网络流 题目转化为&#xff1a; 找出两条不交路径 B->A, B->C 对于已经找到的路径&#xff0c;我们不能再走。对于当前我们找到的某条…

Matlab图像处理-幂次变换

幂次变换 如下图所示的幂次变换函数曲线图&#xff1a; 当γ <1时&#xff0c;效果和对数变换相似&#xff0c;放大暗处细节&#xff0c;压缩亮处细节&#xff0c;随着数值减少&#xff0c;效果越强。 当γ >1时&#xff0c;放大亮处细节&#xff0c;压缩暗处细节&…

云备份——配置信息及获取配置信息类模块

一&#xff0c;配置信息 使用文件配置加载一些程序的运行关键信息&#xff0c;如ip&#xff0c;端口等&#xff0c;可以让程序的运行更加灵活 我们需要的配置信息如下 IP地址端口号热点判断时间&#xff0c;也就是非热点文件的时间要求文件下载的URL前缀路径&#xff0c;用于表…

Matlab图像处理-

对数变换 对数变换的一项主要应用是压缩动态范围。一些特别的图像在实际显示中&#xff0c;高灰度值部分较占优势&#xff0c;而低灰度值的可见细节部分丢失。通过计算对数&#xff0c;如10的动态范围会降至14左右[即 ln1013.8]&#xff0c;这样就更易于处理。 对数变换就是压…

Pygame中Trivia游戏解析6-4

3.3.3 显示题目选项 在显示题目选项时&#xff0c;有三种情况&#xff1a;分别是用户还未选择答案时&#xff1b;用户的答案是正确时&#xff1b;用户的答案是错误时。 &#xff08;1&#xff09;用户还未选择答案时 此时&#xff0c;用白色显示四个备选答案&#xff0c;如图…

数据工厂-生成接口通用用例

章节目录&#xff1a; 一、背景介绍二、前置准备三、设计思路四、代码具体实现五、执行效果六、其他说明七、结束语 一、背景介绍 有哪些用例是可以通用且固定的&#xff1f; 针对之前提到的接口用例设计思路&#xff0c;拆分为三个切入点&#xff1a; 举个例子&#xff1a; {…

【原创】H3C三层交换机VLAN路由

网络拓扑图 VLAN 配置 VLAN 100 VLAN 200 [H3C]int vlan 100 ip address 1.1.1.1 255.255.255.0[H3C-Vlan-interface100]int vlan 200 ip address 2.2.2.1 255.255.255.0[H3C]int GigabitEthernet 1/0/1port access vlan 100[H3C]int GigabitEthernet 1/0/2port access vlan 2…

R语言中缺失值的处理

目录 一.寻找缺失值 1.complete.cases() 2.manyNAs 二.缺失值的处理 1.直接删除 2.填补缺失值 一.寻找缺失值 1.complete.cases() #会展现缺失值 algae[!complete.cases(algae),] 2.manyNAs > manyNAs(algae) [1] 62 199 #表示第62条和第199条都有很多缺失值>m…

文本标注技术方案(NLP标注工具)

Doccano doccano 是一个面向人类的开源文本注释工具。它为文本分类、序列标记和序列到序列任务提供注释功能。您可以创建用于情感分析、命名实体识别、文本摘要等的标记数据。只需创建一个项目&#xff0c;上传数据&#xff0c;然后开始注释。您可以在数小时内构建数据集。 支持…

基于springboot跟redis实现的排行榜功能(实战)

概述 前段时间&#xff0c;做了一个世界杯竞猜积分排行榜。对世界杯64场球赛胜负平进行猜测&#xff0c;猜对1分&#xff0c;错误0分&#xff0c;一人一场只能猜一次。 1.展示前一百名列表。 2.展示个人排名(如&#xff1a;张三&#xff0c;您当前的排名106579)。 一.redis so…

wireshark抓包体验

目录 1、使用基础 1.1 数据包筛选 1.2 MAC地址筛选 1.3 端口筛选 1.4 协议筛选 1.5 包长度筛选 1.6 http请求筛选 2.数据包搜索 3.数据包还原 2、例题复现 1、使用基础 1.1 数据包筛选 ip.src 源ip地址 同理可以得到筛选目标地址&#xff1a; ip.dst 目的ip地址 1.2 …

Unity中Shader的渲染排序Tags{“Queue“ = “Transparent“}

文章目录 前言一、在Unity中渲染排序一般是固定的几个层级&#xff0c;透明 和 半透明是以 2500 为 分界点&#xff0c;渲染层级 从 低 到 高二、渲染队列 可以 在 SubShader 或 Pass 中写 前言 Unity中Shader的渲染排序 一、在Unity中渲染排序一般是固定的几个层级&#xff0…

【vue2第十章】data数据与组件间通信

组件化化开发时data写法。 组件化开发中data是一个函数&#xff0c;一个组件的data选项必须是一个函数。需要保证每个组件的实列维护自己的独立的数据。 写法就是&#xff1a; 函数名(){return{属性名:值,属性名:值,属性名:值} }这里不管实列化多少份这个组件&#xff0c;每个…

软件架构Architecture篇卷首语

2023年9月2日&#xff0c;周六晚上 我为什么要开始学习软件架构&#xff1f;我为什么要专门开始这个专栏&#xff1f; 原因如下&#xff1a; Well-structured software is delivered in half the time, at half the cost, with 8x less bugs ——US Air Force study 这句话是我…

2022年06月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:小白鼠再排队2 N只小白鼠(1 < N < 100),每只鼠头上戴着一顶有颜色的帽子。现在称出每只白鼠的重量,要求按照白鼠重量从小到大的顺序输出它们头上帽子的颜色。帽子的颜色用 “red”,“blue”等字符串来表示。不同的小白鼠可…