在计算机视觉领域,小目标检测一直是个令人头疼的问题。想象一下,你站在高楼俯瞰整条街道,试图找出人群中某个特定的人——这就是典型的小目标检测场景。问题的核心在于,当目标在图像中只占据极少数像素时,传统检测方法往往会失效。
为什么小目标这么难检测?关键在于卷积神经网络的工作原理。模型通过层层卷积聚合像素特征,但小目标的像素信息太少,经过多次下采样后,这些特征几乎消失殆尽。以EfficientDet为例,其在小目标上的平均精度(mAP)仅为12%,而大目标能达到51%,差距高达四倍多。
关键提示:小目标检测的难点不仅在于目标物理尺寸小,更取决于目标在图像中的相对大小。无人机航拍图像中,一辆汽车可能只占几十个像素,这就构成了典型的小目标场景。
当直接使用YOLOv8s-640模型检测海滩场景时,可能连一个人都识别不出来。这时就需要祭出我们的杀手锏——InferenceSlicer。这种方法源自SAHI(Slicing Aided Hyper Inference)思想,其核心是将大图像分割成多个小切片分别检测,再合并结果。
技术实现上主要包含三个关键参数:
slice_wh=(512,512):切片尺寸,越小检测越精细但速度越慢overlap_ratio_wh=(0.4,0.4):切片重叠比例,防止边缘目标被切割overlap_filter_strategy:处理重复检测的策略python复制import supervision as sv
from inference import get_model
import cv2
model = get_model("yolov8s-640")
image = cv2.imread("beach.jpg")
def slicer_callback(slice):
result = model.infer(slice)[0]
return sv.Detections.from_inference(result)
slicer = sv.InferenceSlicer(
callback=slicer_callback,
slice_wh=(512, 512),
overlap_ratio_wh=(0.4, 0.4)
)
detections = slicer(image)
切片检测会带来一个副作用——同一目标可能在多个切片中被重复检测。我们提供了三种处理方案:
对于道路监控场景,NMS可能更适合;而在医学图像分析中,NMM往往能保留更多关键细节。建议通过实验选择最适合的方案:
python复制# 非极大值合并示例
slicer = sv.InferenceSlicer(
overlap_filter_strategy=sv.OverlapFilter.NON_MAX_MERGE,
iou_threshold=0.3 # 重叠度阈值
)
最新版的supervision(v0.21.0+)已支持分割任务。只需将检测模型替换为分割模型(如yolov8s-seg-640),并使用MaskAnnotator进行标注:
python复制model = get_model(model_id="yolov8s-seg-640")
def callback(image_slice):
results = model.infer(image_slice)[0]
return sv.Detections.from_inference(results)
slicer = sv.InferenceSlicer(callback=callback)
detections = slicer(image)
annotated_frame = sv.MaskAnnotator().annotate(
scene=image.copy(),
detections=detections
)
分辨率是小目标检测的生命线。两个关键提升点:
yaml复制# YOLOv4配置示例
[net]
width=1280 # 原640
height=1280 # 原640
警告:分辨率翻倍会使显存占用增加4倍,训练时间大幅延长。建议从640x640开始逐步试验。
在训练阶段使用切片(Tiling)技术,相当于给模型提供了"放大镜"。Roboflow平台支持自动切片预处理,关键参数包括:
重要原则:训练时若使用切片,推理时也必须使用相同参数的切片处理,否则会出现尺度不匹配问题。
针对小目标的特殊增强策略:
python复制transforms.RandomCrop(
size=(512,512),
p=0.5
)
YOLOv5会自动计算最佳锚框,但需注意:
bash复制python train.py --autoanchor
yaml复制anchors:
- [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 切片边缘漏检 | 重叠比例不足 | 增大overlap_ratio_wh至0.3-0.5 |
| 推理速度过慢 | 切片太小/GPU未利用 | 增大slice_wh,设置thread_workers=4 |
| 大目标检测异常 | 切片尺寸过大 | 减小slice_wh,或对大目标单独处理 |
| 训练loss震荡 | 小目标样本不均衡 | 采用过采样或Focal Loss |
当处理4K以上图像时:
python复制slicer = sv.InferenceSlicer(thread_workers=8)
python复制model = get_model("yolov8s-640", trt=True)
python复制for tile in split_large_image(image):
process(tile)
在实际项目中,我们发现结合多尺度检测能进一步提升效果。具体实现是在不同缩放级别(如100%,75%,50%)分别运行切片检测,再融合结果。虽然计算量增大,但在无人机巡检等场景可提升约15%的召回率。
另一个有效策略是背景抑制——通过预训练的分类器识别感兴趣区域,只对这些区域进行精细检测。这种方法在交通监控中能将误检率降低30%。
最后要强调的是,小目标检测不只是技术问题,更是数据问题。我们曾遇到一个案例:通过重新标注让标注员将小目标放大2倍标注(保持原位置),配合适当的训练策略,使检测精度从0.23提升到0.41。这提示我们:有时候,突破瓶颈需要跳出技术思维,从数据标注的源头寻找解决方案。