
简介基于YOLOv5与SAHI模块的超分辨率及小目标检测演示源码面向需要在遥感影像、空中航拍、工业质检等场景中识别小尺寸物体的开发者提供了一套可以在Windows系统和PyCharm集成环境中直接运行的完整工程。压缩包内共有4个文件包括Python主程序、预训练权重文件、Markdown格式的运行说明文档以及一张示例图片整体压缩后大小为23.05MB文件结构清晰便于逐项对照学习。项目重点展示了将SAHI尺度感知高分辨率解释模块与YOLOv5结合使用的技术方案借助超分辨率放大处理增强小目标的细节表现再依靠目标检测模型完成精确识别从而提升小目标检测的准确率。运行说明分别给出了环境依赖配置、数据集组织方式、模型训练与推理脚本的调用思路涉及Python、PyTorch、CUDA以及sahi、yolov5两个库的版本要求也提及翻转、裁剪、颜色抖动等数据增强手段方便用户调整参数并适配自有数据。目前已有503人学习下载适合希望快速上手小目标检测或进一步研究超分辨率辅助检测技术的读者。1. 超分和切片到底谁在解决小目标漏检拿到这个标题的第一反应多数人会觉得链路是“先用超分辨率把图变大再交给YOLOv5检测”。这确实是一条思路但真正跑过小目标检测的人很快会发现一个反直觉的事实直接整图超分小目标往往不会变清晰反而会被放大成“模糊的大块”检测器照样漏检。在一个 4K 画幅里占不到几十个像素的物体超分前后都很难被YOLOv5的默认锚框接住。真正让这种源码组合能落地的是SAHI这个模块。它的核心思路不是让图变大而是把大图切成有重叠的切片让每个切片里的目标相对尺寸变大再分别推理、最后合并结果。超分辨率在这里的角色通常是前置增强——尤其对标注质量差、图像偏小的数据集超分能补细节但真正提升召回率的往往是切片。适合读这篇的人是想把yolov5SAHI跑通、又不想只在论文截图里看效果的那类从业者包括做遥感目标检测、无人机视角巡检、工业质检小缺陷识别的开发者。下面按我实际会走的路线来讲先立住切片和超分的分工再给可复现的最小工程最后把参数和坑讲透。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. 跑通yolov5SAHI的最小工程目录结构、推理脚本与超分前处理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_pathyolov5/models/hub/yolov5s.pt, confidence_threshold0.3, image_size640, devicecuda:0, ) result get_sliced_prediction( imagedata/input/aerial_0429.jpg, detection_modeldetection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2, ) result.export_visuals(export_dirruns/demo/)逻辑说明get_sliced_prediction会先把原图按 640×640 切块相邻块重叠 20% 防止目标被切断每块单独走 YOLOv5 推理最后把检测框坐标映射回原图再做一次全局 NMS 合并。所以调用时你不需要自己写坐标换算但要确认image_size640和切片尺寸一致——不一致会导致切片被二次缩放目标相对尺寸反而回退到整图推理时的大小。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设的是 640SAHI 会把 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_pathyolov5/models/hub/yolov5s.pt, confidence_threshold0.3, image_size640, devicecuda:0, ) results [] for img_path in glob.glob(data/input/*.jpg): pred get_sliced_prediction( imageimg_path, detection_modelmodel, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.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, indent2)说明box.bbox.to_xyxy()返回的是原图坐标这是批量评估的关键——如果中途自己做了坐标变换这里的值就会错。建议跑五张图就停下检查一次 JSON 里的 bbox 是否真实落在目标上别一次跑完两百张才发现坐标整体偏移。6.2 回归测试用固定阈值判断参数是否改善批量评估需要一个稳定的衡量指标。我自己习惯的做法是在线标注二十张图的“小目标真值框”然后算召回率而非 mAP。因为这类场景中类的数量通常很少一到三类召回率的波动能直接反映切片参数是否有效。以盒中心点距离小于 10 像素作为匹配标准统计“检出的目标数 / 真值目标数”。如果切片尺寸从 640 调到 768 后召回率掉了 5 个点这说明目标尺寸在边缘区间768 反而让切片放不下更多有效上下文。6.3 最后一条经验把超分当成“看运气”的手段把切片当成“确定性”的手段我在多个项目里反复验证过一个结论超分对检测的增益不稳定它在数据模糊时有明显帮助在数据本身清晰时甚至会有副作用但切片推理的增益是稳定的只要遇到小目标它就一定有效。因此我现在的习惯是先跑切片再决定要不要超分而且超分后一定要与没有超分的结果做对比才落地。如果你遵循这个顺序调试成本会少很多。回到标题本身这份源码最大的价值不是“超分辨率”这个名词而是让你直观看到“切片 超分 检测”三者如何协作。花费一个下午把参数跑通、把坐标映射验证清楚你之后换任何检测器不只是YOLOv5都能平移这套方法论。希望这些细节能帮你少走弯路也希望你在自己的数据上跑出比这篇更好的结果。本文还有配套的精品资源点击获取