news 2026/5/31 18:07:30

012、小目标标注总被忽略?SAHI 切片策略与超大图标注的工程化方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
012、小目标标注总被忽略?SAHI 切片策略与超大图标注的工程化方案

012、小目标标注总被忽略?SAHI 切片策略与超大图标注的工程化方案

从一次深夜调试说起

去年做遥感图像检测项目,客户给了一张 2 万像素 × 2 万像素的卫星图,里面密密麻麻的车辆、船只,最小的目标只有 8×8 像素。我直接扔进 YOLOv8 训练,mAP 0.5 勉强到 0.3,小目标 recall 几乎为零。更离谱的是,标注人员告诉我:“那些小点我根本没标,因为看不清,而且标注工具里缩放太麻烦。”

这不是个例。小目标标注被忽略,本质上是两个问题叠加:一是标注工具在大图上操作困难,二是模型在原始分辨率下对小目标感知力不足。SAHI(Slicing Aided Hyper Inference)切片策略,就是专门解决这个痛点的工程化方案。

为什么直接训练大图会失败?

先别急着上切片。你得理解为什么大图直接训练不行。

YOLO 系列在输入尺寸上有限制,通常 640×640 或 1280×1280。你把 2 万像素的图 resize 到 640,小目标直接变成 0.2 像素——模型根本看不见。有人会说“那我用大分辨率输入”,但显存扛不住,batch size 降到 1 都爆显存。

更隐蔽的问题是标注质量。标注员在超大图上标注,缩放比例失调,小目标很容易被漏标、错标。我见过一个项目,标注员把 10 像素的汽车标成了 5 像素的矩形框,因为缩放后鼠标点不准。这种标注噪声,比模型本身的误差更致命。

SAHI 切片策略:把大图拆成小图

SAHI 的核心思想很简单:训练和推理时,把大图切成若干小图,每个小图独立检测,最后合并结果。但这里有几个坑,我踩过之后才明白。

切片参数怎么设?

切片大小和重叠率是关键。切片太小,目标被切碎;切片太大,小目标依然不明显。

我的经验公式:切片大小 = 模型输入尺寸 × 1.5 到 2 倍。比如 YOLOv8 输入 640,切片用 960 或 1280。重叠率至少 30%,否则边界处的目标会被截断。遥感图像我常用 50% 重叠,因为目标分布密集。

代码实现时,注意边界处理。别这样写:

# 错误示范:直接整除切片,边界目标丢失foriinrange(0,img_height,slice_size):forjinrange(0,img_width,slice_size):slice_img=img[i:i+slice_size,j:j+slice_size]

这里踩过坑:当图像尺寸不是切片大小的整数倍时,最后一行/列会丢失。正确做法是计算实际切片数量,确保覆盖全图:

# 正确做法:计算切片数量,处理边界num_slices_y=math.ceil((img_height-overlap)/(slice_size-overlap))num_slices_x=math.ceil((img_width-overlap)/(slice_size-overlap))foriinrange(num_slices_y):forjinrange(num_slices_x):y_start=i*(slice_size-overlap)x_start=j*(slice_size-overlap)# 确保不越界y_end=min(y_start+slice_size,img_height)x_end=min(x_start+slice_size,img_width)# 如果切片尺寸不足,用padding补全ify_end-y_start<slice_sizeorx_end-x_start<slice_size:# 这里用0填充或镜像填充,看场景pass

标注怎么同步切片?

训练时,标注框也要跟着切片。SAHI 官方库提供了切片标注的功能,但有个坑:它默认只保留完全落在切片内的目标。对于跨切片的目标,直接丢弃会导致训练数据丢失。

我的做法是:保留与切片有交集的任何目标,但只取交集部分作为新标注。这样虽然会引入一些截断的目标,但总比丢掉好。推理时再用 NMS 合并。

# 保留跨切片目标,只取交集defslice_annotation(bbox,slice_bbox):x1=max(bbox[0],slice_bbox[0])y1=max(bbox[1],slice_bbox[1])x2=min(bbox[2],slice_bbox[2])y2=min(bbox[3],slice_bbox[3])ifx2>x1andy2>y1:# 转换到切片坐标系return[x1-slice_bbox[0],y1-slice_bbox[1],x2-slice_bbox[0],y2-slice_bbox[1]]returnNone

超大图标注的工程化方案

切片解决了模型训练的问题,但标注环节才是真正的瓶颈。标注员面对 2 万像素的图,效率极低。我试过几种方案,最终选了一个折中。

方案一:先切片再标注

把大图切成 640×640 的小图,让标注员在小图上标注。优点是标注精度高,小目标不会被忽略。缺点是切片数量爆炸,2 万像素的图切成 640 大小,重叠 50%,能切出上千张小图。标注员要标注上千张图,重复劳动多。

方案二:标注大图,训练时切片

标注员在大图上标注,训练时程序自动切片。优点是标注工作量小,一张图标一次。缺点是大图上标注小目标容易漏,而且标注工具在大图上操作卡顿。

方案三:混合策略(推荐)

我最终用的是这个:先在大图上标注大目标(比如建筑、道路),然后自动切片,让标注员在小图上补充标注小目标(车辆、行人)。这样大目标不会漏,小目标也能精确标注。

具体流程:

  1. 标注员在大图上标注面积大于 1000 像素的目标(大目标)
  2. 程序自动将大图切成 640×640 小图,重叠 30%
  3. 标注员在小图上标注面积小于 1000 像素的目标(小目标)
  4. 程序合并标注结果,去重

去重逻辑要注意:同一个目标可能出现在多个切片中,用 IoU 阈值 0.5 合并。这里踩过坑:如果阈值设太低,会把相邻的不同目标合并成一个。

推理时的 SAHI 合并策略

训练完模型,推理时也要切片。SAHI 的推理流程:

  1. 将大图切成小图,每个小图独立推理
  2. 每个小图的检测结果转换回原图坐标系
  3. 用 NMS 合并重叠的检测框

NMS 的 IoU 阈值要调低,我通常用 0.3。因为同一个目标可能出现在多个切片中,检测框位置有偏移,阈值太高会保留重复框。

还有一个细节:切片边缘的目标检测置信度通常较低,因为目标被截断。我加了一个后处理:如果检测框距离切片边界小于 10 像素,且置信度低于 0.5,直接丢弃。这能减少大量假阳性。

# 边缘低置信度过滤deffilter_edge_boxes(boxes,scores,slice_bbox,margin=10):filtered_boxes,filtered_scores=[],[]forbox,scoreinzip(boxes,scores):x1,y1,x2,y2=box# 检查是否靠近切片边界if(x1-slice_bbox[0]<marginory1-slice_bbox[1]<marginorslice_bbox[2]-x2<marginorslice_bbox[3]-y2<margin):ifscore<0.5:continuefiltered_boxes.append(box)filtered_scores.append(score)returnfiltered_boxes,filtered_scores

性能优化:别让切片拖慢推理

切片推理的最大问题是速度。一张大图切成 100 张小图,每张都要过模型,推理时间增加 100 倍。我试过几种优化:

  1. 批量推理:把切片组成 batch,一次推理多张。注意 batch size 不要太大,否则显存爆炸。我通常用 4 或 8。

  2. 跳过空白切片:如果切片内没有目标(比如全是天空或水面),直接跳过。可以用简单的像素方差判断,方差小于阈值就跳过。

  3. 多尺度切片:大目标用大切片,小目标用小切片。比如 1280 切片检测大目标,640 切片检测小目标,合并结果。这能减少切片数量。

  4. ONNX 加速:把模型转 ONNX,推理速度提升 30% 以上。YOLOv8 官方支持导出 ONNX,一行代码搞定。

个人经验性建议

  1. 别迷信 SAHI 能解决所有小目标问题。它只是工程手段,模型本身对小目标的感知能力才是根本。如果目标只有 4×4 像素,切片也救不了。考虑超分辨率或特征金字塔改进。

  2. 标注质量比模型更重要。我见过太多项目花大量时间调模型,结果标注数据一塌糊涂。先花一周做标注质量检查,比调一周模型参数有效。

  3. 切片大小不是越大越好。有人觉得切片大能保留更多上下文,但小目标在切片内占比反而更小。我做过实验,640 切片比 1280 切片在小目标 recall 上高 5 个点。

  4. 重叠率 30% 是底线。低于 30%,边界目标丢失严重。高于 50%,计算量翻倍,收益递减。

  5. 标注工具选对能省一半时间。LabelImg 在大图上卡死,用 CVAT 或 Supervisely 的远程标注功能,支持大图缩放和切片标注。别省这个钱。

最后说一句:小目标检测没有银弹。SAHI 切片是工程上的妥协,它让不可能变成可能,但代价是计算量和标注工作量。如果你的项目对实时性要求高,切片推理可能不适用。这时候,考虑模型结构改进,比如 YOLOv8 的 P2 层或 YOLOv6 的 RepVGG 结构,才是正道。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/30 18:11:20

警务机器人核心技术解析:从SLAM导航到多模态交互的工程实践

1. 项目概述&#xff1a;从概念到现实的警务机器人最近几年&#xff0c;如果你在一些大型交通枢纽、商业中心或者特定的大型活动现场留意观察&#xff0c;可能会发现一些造型独特、闪烁着警示灯的机器人正在执勤。它们不是科幻电影里的道具&#xff0c;而是已经投入实际应用的警…

作者头像 李华
网站建设 2026/5/30 9:13:44

AI偏见治理实战:从检测到缓解的全链路解决方案

1. 项目概述&#xff1a;当AI开始“偏心眼”&#xff0c;我们该怎么办&#xff1f;最近几年&#xff0c;AI&#xff08;人工智能&#xff09;这个词火得不行&#xff0c;从帮你写邮件的ChatGPT&#xff0c;到给你推荐下一部剧的Netflix算法&#xff0c;再到决定你能不能拿到贷款…

作者头像 李华
网站建设 2026/5/30 22:00:16

CR2032电池驱动自动变色LED:极简电子制作与电路优化实战

1. 项目概述&#xff1a;当自动变色LED遇上CR2032 如果你手头正好有几颗从废旧设备里拆出来的CR2032纽扣电池&#xff0c;又或者想给某个小物件增加一点无需编程的动态光效&#xff0c;那么这个项目可能就是为你准备的。自动变色LED&#xff0c;也叫七彩慢闪LED&#xff0c;是一…

作者头像 李华
网站建设 2026/5/30 12:40:30

基于Arduino与超声波传感器的交互式LED光雕:从状态机到行为编程

1. 项目概述&#xff1a;当一盏灯有了“脾气” 几年前&#xff0c;我在一个艺术展上看到一件作品&#xff1a;一盏灯&#xff0c;静静地亮着。但当有人靠近时&#xff0c;它却像受惊的小动物一样&#xff0c;光线会“躲”到另一边。那个瞬间&#xff0c;我意识到电子装置可以超…

作者头像 李华