☰
YOLOv5+SAHI切片与超分协同:小目标检测漏检解决方案
2026/10/7 18:46:41 网站建设 项目流程

简介:基于YOLOv5与SAHI模块的超分辨率及小目标检测演示源码,面向需要在遥感影像、空中航拍、工业质检等场景中识别小尺寸物体的开发者,提供了一套可以在Windows系统和PyCharm集成环境中直接运行的完整工程。压缩包内共有4个文件,包括Python主程序、预训练权重文件、Markdown格式的运行说明文档以及一张示例图片,整体压缩后大小为23.05MB,文件结构清晰,便于逐项对照学习。项目重点展示了将SAHI(尺度感知高分辨率解释模块)与YOLOv5结合使用的技术方案:借助超分辨率放大处理增强小目标的细节表现,再依靠目标检测模型完成精确识别,从而提升小目标检测的准确率。运行说明分别给出了环境依赖配置、数据集组织方式、模型训练与推理脚本的调用思路,涉及Python、PyTorch、CUDA以及sahi、yolov5两个库的版本要求,也提及翻转、裁剪、颜色抖动等数据增强手段,方便用户调整参数并适配自有数据。目前已有503人学习下载,适合希望快速上手小目标检测或进一步研究超分辨率辅助检测技术的读者。

1. 超分和切片,到底谁在解决小目标漏检

拿到这个标题的第一反应,多数人会觉得链路是“先用超分辨率把图变大,再交给YOLOv5检测”。这确实是一条思路,但真正跑过小目标检测的人很快会发现一个反直觉的事实:直接整图超分,小目标往往不会变清晰,反而会被放大成“模糊的大块”,检测器照样漏检。在一个 4K 画幅里占不到几十个像素的物体,超分前后都很难被YOLOv5的默认锚框接住。

真正让这种源码组合能落地的,是SAHI这个模块。它的核心思路不是让图变大,而是把大图切成有重叠的切片,让每个切片里的目标相对尺寸变大,再分别推理、最后合并结果。超分辨率在这里的角色通常是前置增强——尤其对标注质量差、图像偏小的数据集,超分能补细节,但真正提升召回率的往往是切片。适合读这篇的人,是想把yolov5+SAHI跑通、又不想只在论文截图里看效果的那类从业者,包括做遥感目标检测、无人机视角巡检、工业质检小缺陷识别的开发者。下面按我实际会走的路线来讲:先立住切片和超分的分工,再给可复现的最小工程,最后把参数和坑讲透。

2. SAHI切片推理的原理:为什么大图上小目标必然漏检

2.1 漏检的根因在“特征下采样”,不在像素不够多

YOLOv5的主干网络逐级下采样,输入 640×640 的图,经过 8 倍、16 倍、32 倍下采样后,特征图尺寸变成 80×80、40×40、20×20。一个 30×30 像素的目标,在 80×80 的特征图上大概只占据一个点不到的响应区域,网络很难从这种“点状特征”里学出类别判别力。这不是超分能解决的——超分把整张图变大,目标在特征图上的占比不会变,只是把“小模糊块”变成“大模糊块”。

SAHI 的做法是改变目标在输入图中的相对尺寸。把 1280×1280 的图切成四张 640×640 的切片,原先 30×30 的目标在切片里仍然占 30×30,但切片本身的尺寸和训练尺寸一致,等于把一个“微小目标”变成了“正常目标”。这一点是理解整个模块的钥匙。

2.2 切片策略的两个参数:切片高度和重叠率

实际用SAHI跑推理,最常用的两个参数是slice_height和slice_width(切片尺寸),以及overlap_height_ratio、overlap_width_ratio(重叠比例)。切片尺寸直接决定目标相对大小,重叠比例决定目标被切到边界时的还原能力。

我一般会这样设初始值:

  • 训练时输入尺寸是 640,切片尺寸就设 640(或 512,看显存);
  • 重叠比例设 0.2 到 0.3。设 0 会导致目标正好横跨切片边界时被切两半,检测框置信度骤降;
  • 切片尺寸不要小于检测器训练尺寸的一半,否则目标可能会被缩得太小,反而丢失上下文。

这些参数的意义是:切片越小、重叠越高,切出来的块越多,推理总耗时越高,但召回率在临界区间内会明显提升。后面第 5 章的调参表会直接给出对应关系。

2.3 SAHI的输出不是黑匣子:坐标映射逻辑要自己掌握

切片推理的最后一步,是把每个切片上的检测框坐标换算回原图坐标。SAHI 内部处理的方式是记录每个切片在原图的偏移量(offset_x, offset_y),检测框在切片上的坐标加上偏移,再按重叠区域做 NMS 合并。

这里有一个常见的“黑匣子”误区:直接使用默认配置跑出的检测框,看起来在原图上是准确的,但如果你自己写数据增强、自己切图、然后只调SAHI的坐标转换函数,很容易把偏移方向和缩放比搞反。所以我建议第一次跑通时,先在一张图上可视化“原始框、切片框、合并框”三个结果,确认坐标链路没问题,再放心跑批。把这一点想清楚,后面改代码才不会翻车。

3. 跑通yolov5+SAHI的最小工程:目录结构、推理脚本与超分前处理

3.1 源码的典型目录结构和运行前提

这类演示源码通常会把三块东西放进一个压缩包:yolov5 工程本体(或裁剪过的推理部分)、SAHI 模块及其依赖、超分前处理脚本。你解压后先按下面结构核对,缺什么补什么:

project/ ├── yolov5/ │ ├── models/hub/yolov5s.pt │ └── detect.py ├── sahi/ │ └── predict.py ├── sr/ │ ├── esrgan.py │ └── weights/RealESRGAN_x4.pth ├── runs/demo/ ├── data/input/ # 待测大图 └── requirements.txt

建议先用pip install -r requirements.txt装依赖。特别注意 SAHI 和 torch 的版本匹配,我遇到最坑的一次是 torch 版本太新,SAHI 依赖的旧版torchvision.ops.nms接口报错。遇到这种问题,优先看 SAHI 的 setup.py 声明的版本范围,而不是盲目升依赖。

3.2 用SAHI快速跑一张测试大图

第一步先不接超分,直接跑原始SAHI推理,确定检测基线。核心命令如下(bash 环境):

python yolov5/detect.py \ --weights yolov5/models/hub/yolov5s.pt \ --source data/input/aerial_0429.jpg \ --img 640 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --save-txt

这条命令的含义:用官方预训练权重直接对一张大图做推理。--img 640指把输入图缩放成 640 宽;--conf-thres是置信度阈值;--save-txt会输出每个框的类别和归一化坐标。跑完后大概率发现小目标的conf普遍低于 0.2,说明“直接整图推理”路线对小目标基本失效。这一步是给后面的SAHI做对照用的,建议保留输出文件。

3.3 替换成SAHI切片推理脚本

常见做法是在sahi/predict.py里封装一个predict_with_slices函数,下面是一个可复现的简化版本:

from sahi.model import Yolov5DetectionModel from sahi.predict import get_sliced_prediction detection_model = Yolov5DetectionModel( model_path="yolov5/models/hub/yolov5s.pt", confidence_threshold=0.3, image_size=640, device="cuda:0", ) result = get_sliced_prediction( image="data/input/aerial_0429.jpg", detection_model=detection_model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2, ) result.export_visuals(export_dir="runs/demo/")

逻辑说明:get_sliced_prediction会先把原图按 640×640 切块,相邻块重叠 20% 防止目标被切断,每块单独走 YOLOv5 推理,最后把检测框坐标映射回原图,再做一次全局 NMS 合并。所以调用时你不需要自己写坐标换算,但要确认image_size=640和切片尺寸一致——不一致会导致切片被二次缩放,目标相对尺寸反而回退到整图推理时的大小。

3.4 超分辨率前处理怎么插进链路

如果源码里带了超分模块,位置通常是在“切片之前、整图放大之后”。为什么不先切片再逐块超分?因为逐切片超分会有重叠区域的重建不一致问题,拼接处容易出现边缘伪影,反而干扰检测。我一般这样设计流程:先用 Real-ESRGAN 或类似模型把整张图放大两倍,再做切片。放大系数不要贪大,2 到 3 倍足够,四倍会让推理耗时翻好几倍。插入方式如下:

python sr/esrgan.py --input data/input/aerial_0429.jpg --scale 2 --output data/input/aerial_0429_sr2x.jpg python sahi/predict.py --image data/input/aerial_0429_sr2x.jpg --slice-size 640 --overlap 0.2

注意:如果超分把图从 1280 放大到 2560,切片尺寸仍然是 640,切片数量会大约是原来的 4 倍(假设参数不变),显存占用和推理耗时都会显著上升。所以“超分 + 切片”不是无脑叠加,后面第 5 章会给一组合适的搭配参数。

4. 避坑:切片推理时最常见的 5 个翻车现场

4.1 切片重叠区域的目标被重复计数

现象:同一个目标在两张相邻切片中都被检出,坐标略有偏移,最终导出结果时计数翻倍。

原因:SAHI 虽然会做全局 NMS,但默认的match_metric是按 IoU 判断是否为同一个目标。重叠率设得太大(比如 0.5)时,同一个目标在两个切片里的框差异也会变大,NMS 无法把它们认为是同一个对象。

解决:重叠率控制在 0.2 到 0.3 之间,且把postprocess_match_threshold从默认值调到 0.5 左右,让合并更激进一些。跑完后按目标的中心点距离再做一次去重,中心距离小于 10 像素的框视为同一个。

4.2 超分后目标反而“糊了”,检测率不升反降

现象:加了超分前处理后,小目标的置信度反而降低,甚至出现大量错框。

原因:超分模型本质上是生成模型,会补出原图不存在的纹理细节。对本来就不清晰的小目标,补出来的“细节”可能是伪影,让检测器学到的特征被干扰。

解决:看检测结果时不要只看置信度,要把超分前后的切片在相同坐标下裁剪出来对比,确认超分确实“补出了结构”而不是“画出了噪声”。如果对比后无明显增益,直接去掉超分,只保留切片。超分在这个链路里是可选增强,不是必选步骤。

4.3 切片尺寸和推理尺寸不一致,特征图被二次缩放

现象:检测框全部乱掉,小目标仍然漏检,但置信度异常高。

原因:get_sliced_prediction里如果切片尺寸设的是 512,而image_size设的是 640,SAHI 会把 512 的切片先缩放成 640 再做推理,等于把目标又缩小了 20%。

解决:让slice_height/slice_width和image_size保持一致。除非你确认自己有充足显存和算力,否则不要试图“切片小一点、推理大一点”来让目标变大——那不是节省,是白耗。

4.4 显存溢出,切片反而比整图更吃显存

现象:整图推理时显存占用 3GB,切片推理时直接 CUDA Out Of Memory。

原因:切片推理不是把大图缩小了才推理,而是每片按 640×640 走完整前向计算,一批处理多张切片时,显存峰值等于 batch 个数的显存占用。我见过有人直接把batch_size设成 32 去跑 4K 图,结果瞬间爆显存。

解决:get_sliced_prediction的batch_size先设 4,显存占用控制在整图推理的 1.5 倍以内。如果还超,就把切片重叠率降到 0.1,同时把超分倍数从 4 降到 2。

4.5 坐标映射在可视化里正常,导出 JSON 却错位

现象:export_visuals画出来的框是准的,但转成 COCO 或 YOLO 格式保存后,坐标对不上原图。

原因:export_visuals用的是从切片坐标加偏移量映射回原图的结果,而导出 JSON 时数据用的是归一化坐标,两者基于的分母不同——前者是原图像素,后者是模型输入尺寸 640。

解决:导出后手动抽查三五张图,把保存的归一化框乘回slice_height,确认结果和可视化框一致。这里没有捷径,坐标链路第一次跑通后最好固化成脚本,减少手算出错的概率。

5. 超参数设置:把超分倍数、切片尺寸、重叠率一次性调明白

5.1 参数优先级和调整顺序

很多人拿到这类源码的第一反应是直接改置信度阈值,但小目标检测的瓶颈往往不在置信度,而在“这个框根本没被检出来”。我调参时遵循这样的顺序:先定切片尺寸(解决漏检),再定重叠率(解决切断),再定超分倍数(解决模糊),最后才动置信度阈值(解决误检)。这个顺序回头改起来最省事。

切片尺寸的决定因素是目标在原始图像中的像素尺寸。假设你要检测的目标在地面采样距离(GSD)下约占 25×25 像素,而训练时输入是 640×640,那么切片尺寸应该让这个目标在切片里保持 25 像素左右——也就是切片越大越好,但不能大过显存。一个土办法:把测试图上目标最大尺寸量出来,用 640 除以它的三分之一,得到的数向下取整到 32 的倍数,就是切片尺寸的合理起点。

超分倍数则要看目标边缘质量。我倾向于先用 2 倍,因为 2 倍超分带来的伪影最少,而 4 倍超分在移动端或低算力设备上要么慢一倍、要么崩显存。超分在整条链路里更像是一个“后悔药”,当你的原图和标注太差时再启用,素材本身清晰时直接跳过它。

5.2 一张参数速查表与对应效果

下面这张表是我在无人机航拍、道路小目标、工业缺陷三种场景下常用的起点参数,可直接抄:

场景切片尺寸重叠率超分倍数备注
无人机航拍车辆6400.22目标约 30~50 像素
道路远距离行人5120.31(不需要)目标约 20 像素,超分易出伪影
工业缺陷检测3200.22目标尺寸极小,切片要更小
遥感船舶检测7680.22大图 4K 以上,显存够可上 768

表中的切片尺寸和重叠率是相互牵连的:尺寸变小,同样一张图切片数量变多,重叠率对总耗时的影响会指数级放大。例如一张 4K 图,切片 640、重叠 0.2 大约是 4×4 共 16 片;重叠升到 0.3 时会在每个方向上多出一片,变成 5×5 共 25 片,耗时增加 50% 以上。所以不要同时把切片尺寸调小、重叠率调高,一次只动一个变量。

5.3 验证参数是否有效的三张可视化图

每次调完参数,我不会只看 mAP 曲线,而是固定一张难度中等的图,导出三张可视化:

  • 第一张是整图直接推理原图的结果,作为基线;
  • 第二张是切片推理原图的结果,看召回率是否提升;
  • 第三张是超分后切片推理的结果,看是否有额外增益。

三张图并排看,能直接分辨出“漏检问题”和“模糊问题”分别在哪个环节被解决。验证耗时通常每轮不超过两分钟,比盯着终端里的指标数字直观得多。

6. 进阶:把SAHI结果转成标准格式、做批量评估的实用脚本

6.1 批量跑图并自动合并结果

进入批量阶段后,建议写一个小脚本,把所有大图的检测结果汇成一个 JSON 文件。只依赖SAHI默认导出功能是不够的——它默认每个图一个输出目录,批量评估时你需要统一合并。下面这段代码能一次搞定:

import json import glob from pathlib import Path from sahi.model import Yolov5DetectionModel from sahi.predict import get_sliced_prediction model = Yolov5DetectionModel( model_path="yolov5/models/hub/yolov5s.pt", confidence_threshold=0.3, image_size=640, device="cuda:0", ) results = [] for img_path in glob.glob("data/input/*.jpg"): pred = get_sliced_prediction( image=img_path, detection_model=model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2, ) for box in pred.object_prediction_list: results.append({ "image": Path(img_path).name, "category": box.category.name, "bbox": [round(v, 2) for v in box.bbox.to_xyxy()], "confidence": round(box.score.value, 4), }) with open("runs/eval/predictions.json", "w") as f: json.dump(results, f, indent=2)

说明:box.bbox.to_xyxy()返回的是原图坐标,这是批量评估的关键——如果中途自己做了坐标变换,这里的值就会错。建议跑五张图就停下检查一次 JSON 里的 bbox 是否真实落在目标上,别一次跑完两百张才发现坐标整体偏移。

6.2 回归测试:用固定阈值判断参数是否改善

批量评估需要一个稳定的衡量指标。我自己习惯的做法是:在线标注二十张图的“小目标真值框”,然后算召回率而非 mAP。因为这类场景中类的数量通常很少(一到三类),召回率的波动能直接反映切片参数是否有效。

以盒中心点距离小于 10 像素作为匹配标准,统计“检出的目标数 / 真值目标数”。如果切片尺寸从 640 调到 768 后,召回率掉了 5 个点,这说明目标尺寸在边缘区间,768 反而让切片放不下更多有效上下文。

6.3 最后一条经验:把超分当成“看运气”的手段,把切片当成“确定性”的手段

我在多个项目里反复验证过一个结论:超分对检测的增益不稳定,它在数据模糊时有明显帮助,在数据本身清晰时甚至会有副作用;但切片推理的增益是稳定的,只要遇到小目标,它就一定有效。因此我现在的习惯是先跑切片,再决定要不要超分,而且超分后一定要与没有超分的结果做对比才落地。如果你遵循这个顺序,调试成本会少很多。回到标题本身:这份源码最大的价值不是“超分辨率”这个名词,而是让你直观看到“切片 + 超分 + 检测”三者如何协作。花费一个下午把参数跑通、把坐标映射验证清楚,你之后换任何检测器(不只是YOLOv5)都能平移这套方法论。希望这些细节能帮你少走弯路,也希望你在自己的数据上跑出比这篇更好的结果。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询