非极大值抑制 NMS 教程资料整理,附Python、C++实现代码

教程推荐,推荐!

Basics of Bounding Boxesicon-default.png?t=O83Ahttps://medium.com/analytics-vidhya/basics-of-bounding-boxes-94e583b5e16cIOU (Intersection over Union)icon-default.png?t=O83Ahttps://medium.com/analytics-vidhya/iou-intersection-over-union-705a39e7acefNon Max Suppression (NMS)icon-default.png?t=O83Ahttps://medium.com/analytics-vidhya/non-max-suppression-nms-6623e6572536

Python版实现代码

代码

快照如下

C++版实现代码

大佬的仓库:

GitHub - developer0hye/Modern-Cpp-NMS: A Modern C++ Implementation of NMS

https://github.com/martinkersner/non-maximum-suppression-cpp/tree/master

我自己写的如下(简单易懂,推荐!)

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

// 边界框结构体定义
struct Box {
    float x1, y1, x2, y2, confidence; // 边界框的四个坐标和置信度
    // 计算边界框的面积
    float area() {
        return abs(x2 - x1) * abs(y2 - y1); // 计算并返回面积
    }
};

// 计算两个边界框之间的IoU (Intersection over Union)
float IOU(Box& a, Box& b);
vector<Box> NMS(vector<Box>& boxes, float threshold); // 声明非极大值抑制函数

int main() {
    vector<Box> boxes; // 存储边界框的向量

    // 添加一些示例边界框数据
    {
        // 向 boxes 中添加多个 Box 实例,包含坐标和置信度(x1,y1,x2,y2,confidence)
        boxes.push_back({ 0.0984375, 0.254167, 0.553125, 0.997222, 0.252669 });
        boxes.push_back({ 0.0820312, 0.275, 0.715625, 0.997222, 0.26813 });
        boxes.push_back({ 0.560938, 0.0694444, 0.878125, 1, 0.28339 });
        boxes.push_back({ 0.09375, 0.273611, 0.528906, 0.997222, 0.295933 });
        boxes.push_back({ 0.560938, 0.0694444, 0.877344, 1, 0.296285 });
        boxes.push_back({ 0.5625, 0.0652778, 0.876562, 1, 0.299446 });
        boxes.push_back({ 0.0921875, 0.270833, 0.528125, 0.997222, 0.302117 });
        boxes.push_back({ 0.0929687, 0.272222, 0.528906, 0.997222, 0.304497 });
        boxes.push_back({ 0.078125, 0.272222, 0.722656, 0.998611, 0.306486 });
        boxes.push_back({ 0.0773437, 0.272222, 0.725, 0.997222, 0.320194 });
        boxes.push_back({ 0.584375, 0.0694444, 0.8875, 0.993056, 0.42026 });
        boxes.push_back({ 0.580469, 0.0541667, 0.879687, 0.998611, 0.429142 });
        boxes.push_back({ 0.582031, 0.0638889, 0.894531, 1, 0.459798 });
        boxes.push_back({ 0.096875, 0.276389, 0.6375, 0.995833, 0.505743 });
        boxes.push_back({ 0.096875, 0.273611, 0.636719, 0.997222, 0.520935 });
        boxes.push_back({ 0.0984375, 0.276389, 0.633594, 0.995833, 0.522453 });
        boxes.push_back({ 0.582812, 0.0680556, 0.892969, 1, 0.548471 });
        boxes.push_back({ 0.582031, 0.0666667, 0.89375, 1, 0.619484 });
        boxes.push_back({ 0.0992187, 0.269444, 0.557813, 1, 0.654754 });
        boxes.push_back({ 0.0976562, 0.269444, 0.557813, 1, 0.664667 });
        boxes.push_back({ 0.0960938, 0.268056, 0.558594, 1, 0.666693 });
        boxes.push_back({ 0.578906, 0.0625, 0.888281, 1, 0.703215 });
        boxes.push_back({ 0.578125, 0.0694444, 0.889063, 1, 0.705285 });
        boxes.push_back({ 0.578906, 0.0694444, 0.888281, 1, 0.713431 });
        boxes.push_back({ 0.5875, 0.0416667, 0.882812, 1, 0.788854 });
        boxes.push_back({ 0.58125, 0.0611111, 0.890625, 1, 0.862154 });
        boxes.push_back({ 0.58125, 0.0666667, 0.891406, 1, 0.87831 });
        boxes.push_back({ 0.580469, 0.0666667, 0.892187, 1, 0.879861 });
        // ... 省略其他边界框添加代码
    }

    // 运行非极大值抑制算法,保留不重叠的边界框
    float threshold = 0.7; // 设置 IoU 阈值
    vector<Box> result = NMS(boxes, threshold); // 获取处理后的边界框

    // 输出保留下来的边界框
    cout << "保留的边界框:" << endl;
    for (Box& box : result) {
        // 输出每个边界框的坐标和置信度
        cout << "x1: " << box.x1 << ", y1: " << box.y1 << ", x2: " << box.x2 << ", y2: " << box.y2 << ", confidence: " << box.confidence << endl;
    }

    return 0; // 主函数结束
}

// 计算两个边界框之间的IoU
float IOU(Box& a, Box& b) {
    // 计算重叠区域的坐标范围
    float x_inter1 = max(a.x1, b.x1); // 取重叠区域的左上角 x 坐标
    float y_inter1 = max(a.y1, b.y1); // 取重叠区域的左上角 y 坐标
    float x_inter2 = min(a.x2, b.x2); // 取重叠区域的右下角 x 坐标
    float y_inter2 = min(a.y2, b.y2); // 取重叠区域的右下角 y 坐标

    // 计算重叠区域的面积
    float intersection_area = abs(x_inter2 - x_inter1) * abs(y_inter2 - y_inter1); // 计算重叠面积

    float area_a = a.area(); // 获取框 a 的面积
    float area_b = b.area(); // 获取框 b 的面积

    // 计算并集区域的面积
    float union_area = area_a + area_b - intersection_area; // 计算并集面积

    // 计算IoU
    return intersection_area / union_area; // 返回 IoU 值
}

// 非极大值抑制函数
vector<Box> NMS(vector<Box>& boxes, float threshold) {
    // 根据置信度排序
    sort(boxes.begin(), boxes.end(), [](Box& a, Box& b) { return a.confidence > b.confidence; }); // 按置信度降序排序

    vector<Box> result; // 存储结果的向量
    for (int i = 0; i < boxes.size(); ++i) {
        bool keep = true; // 初始化为保留该框
        for (int j = 0; j < result.size(); ++j) {
            // 如果当前框与结果框的 IoU 大于阈值,标记为不保留
            if (IOU(boxes[i], result[j]) > threshold) {
                keep = false; // 设为不保留
                break; // 退出内层循环
            }
        }
        if (keep) {
            result.push_back(boxes[i]); // 如果满足条件,添加到结果中
        }
    }
    return result; // 返回处理后的边界框列表
}

运行结果

直观图示(保留项为蓝色)(Python 绘制)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

守正创新哦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值