# SANMS **Repository Path**: tommycloud/SANMS ## Basic Information - **Project Name**: SANMS - **Description**: 【Github镜像】Structure-aware post-NMS refinement resolving geometric containment for visual retrieval. - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-05 - **Last Updated**: 2026-09-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: Computer-vision, nms, object-detection, post-processing, visual-retrieval ## README

SANMS: 面向视觉检索中主体检测的结构感知后NMS精修

Python 3.8+ License: Apache License: Apache

[English](./README.md) | 简体中文 SANMS(Structure-Aware Non-Maximum Suppression)是一个 **NMS 后精修模块**,专为 **以图搜图中的主体检测** 设计。它解决了一个 IoU 类 NMS 无法检测的几何包含盲区:当检测器对同一物体同时输出宽松裁剪框(有利于检索)和紧凑裁剪框(不利于检索但置信度更高)时,由于两者的 IoU 低于抑制阈值,NMS 会保留错误的框。 **SANMS 不是 NMS 的替代品。** 它在任何 NMS 变体(Greedy、Soft、DIoU、Matrix)之后作为轻量精修步骤使用,仅依赖一个超参数(alpha,面积比例门控)。 --- ## 目录 - [快速开始](#快速开始) - [算法概述](#算法概述) - [安装](#安装) - [项目结构](#项目结构) - [使用方法](#使用方法) - [实验](#实验) - [论文](#论文) - [引用](#引用) - [许可证](#许可证) --- ## 快速开始 ```bash # 克隆仓库 git clone https://github.com/TommysLee/SANMS.git cd SANMS # 安装核心依赖(仅需 numpy + scipy) pip install -r requirements.txt # 运行示例(无需数据集) python examples/quickstart.py # 运行单元测试 python -m pytest tests/ -v ``` **最小代码示例:** ```python import numpy as np from sanms import greedy_nms, sanms # 模拟检测器输出:包含框 + 被包含框 boxes = np.array([[50, 50, 250, 250], [90, 90, 160, 160]]) scores = np.array([0.65, 0.92]) # 步骤1:标准 NMS(因 IoU 低,无法抑制被包含框) nms_boxes, nms_scores = greedy_nms(boxes, scores, iou_thresh=0.5) # 步骤2:SANMS 精修(检测几何包含关系,抑制内部框) final_boxes, final_scores = sanms(nms_boxes, nms_scores, alpha=0.75) ``` --- ## 算法概述 SANMS 解决 IoU 类 NMS 的一个盲区:**几何包含关系**。 当检测器对同一物体同时输出宽松框(包含框)和紧凑框(被包含框)时,两者的 IoU 可能低至 0.3,远低于典型 NMS 抑制阈值(0.45-0.5)。NMS 因此保留两个框。被包含框通常置信度更高,会被选为最终检测结果,产生过度紧凑的裁剪区域,损害下游检索质量。 ``` Container box (loose crop, score=0.65) Contained box (tight crop, score=0.92) ┌──────────────────────────────┐ ┌──────────────────────────────┐ │ │ │ ┌──────────┐ │ │ │ │ │ │ │ │ │ │ │ IoU≈0.3 │ │ │ │ │ │ │ │ │ │ │ └──────────┘ │ └──────────────────────────────┘ └──────────────────────────────┘ IoU < 0.5: NMS keeps both is_contained = True: SANMS fixes this ``` **SANMS 算法(3 步):** 1. **排序**:按面积降序排列(最大框优先处理) 2. **包含检测**:对每个框,通过直接坐标比较(非 IoU)检查是否被已保留的框几何包含 3. **面积比例门控**:若被包含且 `area(内框)/area(外框) < alpha`,则抑制内框,并将其分数继承给外框(分数继承机制) **核心特性:** - **免训练**:无需学习参数 - **单一超参数**:`alpha`(面积比例门控,默认 0.75) - **后 NMS**:在任何 NMS 变体之后应用 - **最坏 O(N^2),平均 O(N)** - **运行时**:仅为 Soft-NMS 的 10-15% --- ## 安装 ```bash # 方式一:从源码安装(推荐,含实验代码) git clone https://github.com/TommysLee/SANMS.git cd SANMS pip install -r requirements.txt # 核心:numpy, scipy pip install -r requirements-optional.txt # 可选:torch, faiss, PIL, pycocotools # 方式二:pip 安装(仅包) pip install git+https://github.com/TommysLee/SANMS.git # 方式三:开发模式 pip install -e ".[all]" ``` ### 依赖说明 | 包 | 必需 | 用途 | |---|------|------| | numpy | 是 | 核心数组运算 | | scipy | 是 | 数值工具 | | torch | 否 | ResNet-50 特征提取(完整流程) | | faiss-cpu | 否 | 快速近邻搜索 | | Pillow | 否 | 图像加载 | | pycocotools | 否 | COCO 格式评测 | 核心算法和合成实验仅需 numpy + scipy。torch/faiss/PIL 仅在完整检索流程中使用,为可选依赖。 --- ## 项目结构 ``` SANMS/ |-- sanms/ # 核心 Python 包 | |-- __init__.py # 公共 API 导出 | |-- sanms.py # SANMS 算法(核心贡献) | |-- box_ops.py # IoU、DIoU、包含检测、框投票 | |-- nms_baselines.py # Greedy NMS、Soft-NMS、DIoU-NMS、Matrix NMS | |-- metrics.py # COCO mAP、Recall@K、Oxford mAP、Top-1、ECE | |-- feature_extractor.py # ResNet-50 特征提取(可选) | `-- retriever.py # 基于 Faiss 的检索引擎(可选) |-- experiments/ # 实验脚本 | |-- pipeline.py # 端到端流程编排 | |-- run_all.py # 复现全部表格(合成数据) | |-- run_runtime.py # 运行时基准测试(Table 12) | `-- results/ # 预计算结果 | |-- all_results_v2.json # Tables 1-11, 13 数据 | `-- runtime_with_std.json # Table 12 数据(100次试验) |-- tests/ | `-- test_sanms.py # 25 个单元测试(无外部依赖) |-- examples/ | `-- quickstart.py # 最小示例(仅需 numpy) |-- paper/ | |-- SANMS Resolving Geometric Containment in Non-Maximum Suppression for Visual Retrieval_en.pdf # 论文(英文) |-- pyproject.toml # 现代打包配置 |-- setup.py # 向后兼容 setup |-- requirements.txt # 核心依赖 |-- requirements-optional.txt # 可选依赖 |-- LICENSE `-- .gitignore ``` --- ## 使用方法 ### 运行示例 ```bash python examples/quickstart.py ``` ### 运行单元测试 ```bash python -m pytest tests/ -v # 或直接运行: python tests/test_sanms.py ``` ### 复现实验 所有实验使用受控合成数据,建模包含场景。无需外部数据集。 ```bash # 复现 Tables 1-11, 13(约 2-5 分钟) python -m experiments.run_all # 复现 Table 12: 运行时基准(约 2 分钟) python -m experiments.run_runtime ``` 结果保存到 `experiments/results/`。 ### 在你的代码中使用 ```python import numpy as np from sanms import greedy_nms, soft_nms, diou_nms, matrix_nms, sanms # 检测器输出 boxes = np.array([...], dtype=np.float64) # (N, 4): [x1, y1, x2, y2] scores = np.array([...], dtype=np.float64) # (N,) # 步骤1:运行任意 NMS 变体 nms_boxes, nms_scores = greedy_nms(boxes, scores, iou_thresh=0.5) # 步骤2:应用 SANMS 精修 final_boxes, final_scores = sanms(nms_boxes, nms_scores, alpha=0.75) ``` --- ## 实验 ### 预计算结果 预计算实验结果已包含在 `experiments/results/` 中: | 文件 | 内容 | 对应表格 | |------|------|----------| | `all_results_v2.json` | COCO mAP、Recall@K、Oxford mAP、Top-1、ECE、消融 | Tables 1-11, 13 | | `runtime_with_std.json` | 运行时(mean +/- std, 100次试验) | Table 12 | ### 运行时基准 在 Intel Core i7-8550U 上测量(每组 100 次试验): | 方法 | N=50 | N=100 | N=300 | |------|------|-------|-------| | Greedy NMS | 3.4 +/- 1.0 ms | 6.3 +/- 1.7 ms | 15.5 +/- 2.7 ms | | Soft-NMS | 6.6 +/- 1.7 ms | 16.6 +/- 6.9 ms | 79.2 +/- 14.2 ms | | DIoU-NMS | 6.5 +/- 1.9 ms | 12.9 +/- 2.6 ms | 30.0 +/- 4.6 ms | | Matrix NMS | 0.5 +/- 0.2 ms | 1.6 +/- 0.5 ms | 9.7 +/- 1.9 ms | | Box Voting | 4.3 +/- 2.1 ms | 7.8 +/- 1.7 ms | 21.9 +/- 4.2 ms | | **SANMS** | **0.9 +/- 0.3 ms** | **2.4 +/- 0.7 ms** | **10.8 +/- 1.9 ms** | SANMS 仅增加 Soft-NMS 10-15% 的开销。 --- ## API 参考 ### `sanms.sanms(boxes, scores, alpha=0.75, eps=1e-3, sort_criterion="area")` 核心 SANMS 算法。 **参数:** - `boxes`: (N, 4) numpy 数组,格式 [x1, y1, x2, y2] - `scores`: (N,) numpy 数组,置信度分数 - `alpha`: float,面积比例门控(默认 0.75)。当被包含框面积/外框面积 < alpha 时被抑制。 - `eps`: float,几何容差(像素,默认 1e-3) - `sort_criterion`: str,排序方式。可选 `"area"`、`"diagonal"`、`"perimeter"`、`"confidence"`(默认 `"area"`) **返回:** `(kept_boxes, kept_scores)`,按置信度降序排列。 ### NMS 基线 - `greedy_nms(boxes, scores, iou_thresh=0.5)` - `soft_nms(boxes, scores, sigma=0.5, mode="gaussian")` - `diou_nms(boxes, scores, diou_thresh=0.5)` - `matrix_nms(boxes, scores, iou_thresh=0.5, sigma=0.5)` ### 框操作 - `compute_area(boxes)` -> 面积数组 - `compute_iou(boxes_a, boxes_b)` -> IoU 矩阵 - `compute_diou(boxes_a, boxes_b)` -> DIoU 矩阵 - `is_contained(box_inner, box_outer, eps)` -> bool - `box_voting(boxes, scores, iou_thresh)` -> (投票框, 投票分数) ### 评测指标 - `coco_map(...)` -> {mAP, AP50, AP75, per_class} - `recall_at_k(...)` -> {R@1, R@10, R@100} - `oxford_map(...)` -> mAP - `top1_accuracy(...)` -> Top-1 准确率 - `expected_calibration_error(...)` -> ECE --- ## 论文 完整论文包含在 [`paper/`](paper/) 目录中: - **英文版**:`SANMS Resolving Geometric Containment in Non-Maximum Suppression for Visual Retrieval_en.pdf` ### 核心发现 - SANMS 通过抑制 NMS 遗漏的几何包含框来提升检测 mAP - 改进可迁移到检索任务:应用 SANMS 后 Recall@K 和 Top-1 准确率均有提升 - SANMS 仅有单一超参数(alpha=0.75),且在较宽范围内鲁棒 - 算法免训练,计算开销极低(Soft-NMS 的 10-15%) ### 局限性 本仓库中的实验使用受控合成数据,建模包含场景。在真实基准(MS COCO、Stanford Online Products、Oxford Buildings)上的验证仍是后续工作。 --- ## 引用 如在研究中使用本代码,请引用: ```bibtex @misc{sanms2026, author = {Li Zongjin}, title = {SANMS: Structure-Aware Post-NMS Refinement for Subject Detection in Visual Retrieval}, year = {2026}, url = {https://github.com/TommysLee/SANMS}, orcid = {0009-0009-9121-0268} } ``` --- ## 许可证 [Apache-2.0](LICENSE) ## 作者 **Li Zongjin** - ORCID: [0009-0009-9121-0268](https://orcid.org/0009-0009-9121-0268) - Email: li_zongjin@alumni.hust.edu.cn - GitHub: [TommysLee](https://github.com/TommysLee)