使用 Ultralytics YOLO 进行图像切片小目标检测:从 Python 到 Rust
了解图像切片何时有助于 YOLO 检测小目标、比较其成本,以及如何在 Python 或 Rust 中运行内置切片推理,无需使用 SAHI。
Onuralp Sezer11 分钟阅读
为什么一个在普通照片上表现良好的检测器,却会漏掉无人机画面中的大多数人?通常是因为它从未以完整尺寸看到这些人。在默认的 imgsz=640 下,Ultralytics YOLO 会在模型查看画面之前将 1920 x 1080 的画面缩小三倍,因此一个 15 像素高的行人最终只有约 5 像素高。
图像切片可以保留这些小目标细节:在全分辨率图像的重叠窗口上运行模型,然后合并结果。在文档中的一张 VisDrone 画面上,Ultralytics YOLO26s 的检测数从 35 个增加到了 161 个。代价是每帧需要更多计算:该帧要输入 8 个切片,而不是一张图像。
切片现在已内置于部署的两端。自 11 月 6 日发布的 Ultralytics 8.4.204 起,Python 包就支持 tile 参数;Rust crate 则在 11 月 9 日发布的 Ultralytics Inference 0.0.57 中新增了 --tile 标志。本指南介绍切片何时能找回小目标、需要付出什么代价,以及如何在两者中运行切片推理。
缩放会隐藏小目标#
小目标检测之所以困难,原因很简单:一个物体所拥有的像素数量是有限的。目标检测模型需要从每个物体寥寥几个像素中学习形状;当整幅画面最长边缩小到 640 像素时,远处的人、车辆和缺陷就会变得过小,网络难以将它们与纹理和噪声区分开来。
在航拍图像、卫星图像分析、广角交通和安防摄像头画面,以及高分辨率检测照片中,这个问题最为明显。VisDrone 是广泛使用的公开航拍基准数据集:其文档描述的物体在画面中通常只有几十个像素大小,并且密集成群、严重遮挡。
切片能保留这些像素。将 tile 设为模型输入尺寸后,模型会以原生分辨率查看多个窗口,而不是对缩小后的画面进行一次推理。这一思路正是 SAHI 论文所称的切片辅助超推理;论文作者在 VisDrone 和 xView 航拍数据集上对其进行了评估。
在高分辨率切片指南中,YOLO26s 对一张 1920 x 1080 的 VisDrone 画面进行推理,在默认置信度阈值下,整张图像在 imgsz=640 时返回 35 个检测结果,在 tile=640 时返回 161 个,其中包括远处的行人、骑行者和汽车。指南并列展示了两张图像。这些是预测数量,不是经过评分的评估结果。两组数量使用的是同一组权重;切片还改变了每个窗口所能看到的上下文。

第二张 1920 x 1080 的 VisDrone 验证画面,YOLO26s 使用默认置信度:整幅画面在 imgsz=640 时检测到 8 个目标,tile=640 时检测到 128 个。图中显示道路裁剪区域,边界框未标注类别。
每个窗口都会增加一次模型输入#
指南对窗口划分进行了精确定义。窗口之间的基础重叠率为 20%,最后一行和一列会与图像边界对齐,因此边缘窗口的重叠率可能更高。小于窗口尺寸的图像只会生成一个覆盖整幅图像的窗口。
这样一来,成本很容易预测。tile=640 下的一帧 1920 x 1080 画面会运行 8 个窗口,横向 4 个、纵向 2 个。tile=1280 下的一帧 3840 x 2160 画面也会运行 8 个窗口。对于一帧 3840 x 2160 的画面,按相同的 20% 规则设置 tile=640,会得到 8 列、4 行,共 32 个窗口。因此,在 4K 画面上将窗口尺寸减半,会使切片输入数量增加到原来的 4 倍。

在一帧 1920 x 1080 画面上,tile=640 会生成的 8 个窗口:各列的起始 x 坐标为 0、512、1024 和 1280,各行的起始 y 坐标为 0 和 440。阴影区域会被多个窗口看到。
批处理会改变这些输入送入模型的方式。在 Python 中,batch 用于设置每次推理调用中同时通过模型的窗口数量;Rust crate 使用动态批处理导出模型时,也通过 --batch 实现相同功能。批处理可以提升吞吐量,但请在你的硬件上测量延迟;我们的使用 Ultralytics YOLO 进行批量推理指南解释了其中的原因。
下面介绍切片与其他增加小目标像素数的方法相比如何:
| 方式 | 1920 x 1080 画面的模型输入 | 模型看到的内容 | 适用情况 |
|---|---|---|---|
整幅图像,imgsz=640 | 1 | 画面缩小 3 倍 | 缩放后物体仍清晰可见 |
整幅图像,imgsz=1280 | 1 次,计算量约为 640 输入的 4 倍 | 画面缩小 1.5 倍 | 内存和延迟允许使用更大的输入尺寸 |
tile=True 与 imgsz=640 | 8 | 原生分辨率的 640 像素窗口 | 尺寸比模型输入大数倍的图像 |
tile=400 与 imgsz=640 | 超过 8 个 | 放大至 640 像素的窗口 | 即使在原生分辨率下,物体也只有几个像素宽 |
每个切片都是常规尺寸的模型输入,因此切片可以处理超大图像,而无需提高 imgsz。掩码和深度图等与源图像同尺寸的输出仍需要与原始图像成比例的内存;max_det 会限制保留的实例掩码数量。
何时使用切片,何时不该使用#
当物体相对于画面较小,且画面远大于模型输入时,切片很有用。无人机和卫星图像、俯拍交通画面、人群、广角拍摄的零售货架,以及对整块电路板或面板进行视觉检测的图像,都适合使用切片。
当物体较大时,切片反而会带来问题。若一辆卡车占据半幅画面,一个窗口只能看到卡车的一部分;指南对此说得很清楚:大于重叠区域的物体仍可能被切开,因为没有任何窗口能看到物体的完整部分,而且合并操作不会拼接彼此分离的片段。切片还会丢失全局上下文,这对分类和深度任务影响最大,因为不同切片的输出可能无法在整幅图像范围内保持一致。
更小的窗口还带来另一项权衡。将 400 像素的窗口放大到 640 像素,有助于检测只有几像素宽的物体,但也会放大背景杂乱区域,可能导致误报。请在自己的验证集上比较两三种切片尺寸,同时关注精确率和召回率。
切片如何合并回单个结果#
每个窗口都会在窗口坐标系中生成自己的预测结果。切片会将结果映射回源图像,并为每张原始图像返回一个 Results 对象,因此读取 result.boxes 的下游代码无需修改。
重叠意味着接缝附近的物体可能被检测两次。对于检测任务,系统会根据你的 iou、agnostic_nms 和 max_det 设置,使用非极大值抑制去除重复检测结果,因此我们的调整 NMS IoU 阈值指南同样适用于切片输出。如果某个窗口边缘切断了边界框,而另一个窗口看到了未被边缘切断的物体,并且保留的边界框覆盖了它,那么被切断的边界框就会被丢弃,这样接缝处会保留更完整的预测结果。若被切断的边界框没有更好的匹配项,则会予以保留。

示意图展示了同一画面中 y = 640 处的接缝处理。青色框被上排窗口的底边切断,洋红色框来自下排窗口;右侧面板展示了合并后每辆汽车保留的更完整边界框。
Ultralytics YOLO 的每种任务都有自己的合并方式:
- 检测、分割、姿态和 OBB 会将边界框、掩码、关键点或旋转框还原到源图像坐标,并应用边界框筛选;OBB 使用旋转 NMS。
- 语义分割会拼接类别图,在窗口重叠处选择最靠近中心的切片。
- 深度会融合重叠的深度图,越靠近每个切片中心的区域权重越高。
- 分类会对切片概率取平均值。
Python 流水线还支持对 YOLO-World、YOLOE、RT-DETR 和 FastSAM 的预测进行切片。SAM 使用自己的裁剪流水线,不接受 tile。
在 Python 中使用 tile 参数进行切片推理#
切片功能需要 Ultralytics 8.4.204 或更高版本,无需额外安装软件包。在预测模式中,传入 tile=True,即可将 imgsz 用作窗口尺寸;也可以传入整数单独设置窗口尺寸:
from ultralytics import YOLO
model = YOLO("yolo26s.pt")
# 基线:将整幅画面缩小至 640 像素后进行一次推理
full = model.predict("intersection.jpg", imgsz=640)
# 切片:以原生分辨率使用 640 像素窗口,每批处理 8 个窗口
tiled = model.predict("intersection.jpg", imgsz=640, tile=640, batch=8)
print(len(full[0].boxes), len(tiled[0].boxes))在 CLI 中使用 yolo predict model=yolo26s.pt source=large-image.tif tile=640 imgsz=640 batch=8 也能设置相同参数。处理视频时,传入 stream=True 以控制内存用量。在跟踪模式中,跟踪器会在合并后的预测结果上逐帧运行一次。
切片不只适用于预测。当图像远大于 imgsz 时,使用相同设置进行训练和验证:
- 使用切片训练,设置
model.train(data="aerial.yaml", tile=True, imgsz=640)。标签会裁剪到各个窗口中;原始边界框面积剩余不到 10% 的实例会被移除;空窗口则会保留,作为负样本。 - 使用合并结果进行验证,设置
model.val(data="aerial.yaml", tile=True, imgsz=640)。预测结果会先合并,再与原始标注进行评分,因此 mAP能反映实际部署效果。 - 使用
cache="ram"缓存大型源图像,因为训练过程会打乱切片顺序,否则同一张大图可能需要多次解码。 - 在同一验证集上与整图基线进行比较,再决定是否保留切片模型。如需了解提升微小目标得分的其他方法,请参阅我们的小目标 mAP 检查清单。
使用切片训练可以让模型以切片预测时实际会遇到的尺寸学习物体。我们的无人机检测数据集指南以 4K 画面为例,介绍了完整的训练、切片和评估流程。
导出的模型也支持切片。切片在 Python 预测流水线中运行,因此将模型导出为 ONNX 或 TensorRT后,模型仍保留常规输入计算图,YOLO("yolo26s.onnx").predict(source, tile=640) 也照常工作,包括固定的导出批量大小和最后一个不完整批次。

Ultralytics Platform 中的 VisDrone 数据集是现成的基准数据集,可用于在标注自己的数据之前测试切片尺寸。
要先用公开数据尝试不同的切片尺寸,请从 Ultralytics Platform 上的 VisDrone 数据集开始。要将切片运行与基线一起跟踪,请从 Platform 训练对话框中复制本地训练命令,将 project 设置为基线所在的 Platform 项目,并添加 tile=True,将切片运行的指标发送到该项目。
在 Rust 中使用新的 --tile 标志进行切片推理#
Ultralytics Inference 是我们的 Rust crate 和 CLI,可通过 ONNX Runtime 运行已导出的 ONNX 模型,并原生运行 OpenVINO IR 模型,无需在推理时使用 Python 运行时。它面向服务器、容器和 CPU、CUDA、TensorRT、CoreML、OpenVINO 及其他执行提供程序上的边缘设备。0.0.57 版本带来了与 Python 相同的切片方案:基础窗口重叠率为 20%,结果映射回源图像,并按类别去除重复结果。

示意图。路边摄像头配有边缘计算机,这类部署场景正是 Rust crate 在无 Python 环境下所面向的目标。
团队在 ONNX Runtime CPU、OpenVINO CPU、GPU 和 NPU、CUDA 及 TensorRT 上,对图像、视频和网络摄像头的切片输出与 Ultralytics Python 进行了核对。检测、分割、语义分割、深度、分类、姿态和 OBB 模型均受支持。
在 CLI 中添加带窗口尺寸的 --tile,或直接传入该参数以使用 --imgsz。模型只需在 Python 中导出一次;推理本身只需 Rust 二进制文件:
# One-time export in Python: a dynamic-batch ONNX model so several windows run per call
pip install -U "ultralytics[export-base]>=8.4.204"
yolo export model=yolo26s.pt format=onnx dynamic=True
# Install the Rust CLI
cargo install ultralytics-inference
# Tiled inference on a large image: 640-pixel windows, 8 per batch
ultralytics-inference predict --model yolo26s.onnx --source aerial.jpg --tile 640 --batch 8作为库使用时,在 InferenceConfig 中设置一次切片,之后每次调用 predict 都会执行切片。with_tile(0) 使用推理尺寸:
use ultralytics_inference::{InferenceConfig, YOLOModel};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = InferenceConfig::new().with_tile(640);
let mut model = YOLOModel::load_with_config("yolo26s.onnx", config)?;
let results = model.predict("aerial.jpg")?;
if let Some(ref boxes) = results[0].boxes {
println!("{} detections", boxes.len());
}
Ok(())
}跨窗口的重复边界框会使用配置的 --iou 进行按类别 NMS 去除;从同一版本起,该值默认为 0.5,与 Ultralytics 的默认预测设置一致。切片默认关闭,因为每个窗口都需要额外输入模型。仅在细节至关重要的场景中启用切片,并在目标设备上测量推理延迟,再选择适合该设备的执行提供程序;我们的 ONNX 与 TensorRT 对比有助于在 NVIDIA 硬件上进行选择,NVIDIA Jetson 指南则介绍了设备端设置。
SAHI 用户可以改用内置 tile 参数#
如果你已经使用 SAHI 库切分图像,内置参数可以在 Ultralytics 中完成相同工作,无需额外软件包或单独的结果格式。我们的 SAHI 集成指南现已弃用,建议改用 tile。
将 SAHI 脚本迁移过来,主要只需修改参数:
| SAHI | 内置切片 |
|---|---|
AutoDetectionModel.from_pretrained(model_type="ultralytics", ...) | YOLO("yolo26s.pt") |
get_sliced_prediction(image, model, slice_height=256, slice_width=256, ...) | model.predict(image, tile=256) |
overlap_height_ratio, overlap_width_ratio | 固定的基础重叠率为 20%,边缘窗口与图像边界对齐 |
SAHI PredictionResult | 标准 Ultralytics Results |
窗口为正方形;重叠和合并遵循上述规则,而非 SAHI 可配置的后处理方式,因此得到的边界框预计会相似,但不会完全相同。切换后,请在验证集上重新检查阈值。
实际差异在于集成方式。tile 使用同一参数即可接入 Ultralytics 的训练、验证、预测和跟踪,返回标准的 Results 对象;Rust crate 也提供相应选项。因此,你在笔记本中验证过的切片尺寸可以直接用于边缘设备上的 Rust 二进制程序。
哪些用户应该启用切片#
如果你使用 Ultralytics YOLO 处理的图像尺寸是模型输入的数倍,并且验证结果显示漏掉了小目标,就应该启用切片:例如无人机和卫星团队、使用广角摄像头的交通和安防集成商,以及拍摄整块电路板、面板或货架的检测团队。Rust 用户无需 Python 运行时,也能在边缘硬件上使用相同的切片方案。
当物体相对于画面较大、较大的 imgsz 已能通过一次推理找回这些物体,或延迟预算无法承受每帧多个切片输入时,请关闭切片。无论哪种情况,都应在相同验证集和相同置信度阈值下比较切片与整图结果,关注召回率、误报和延迟;只有当收益值得额外计算时,才保留切片。
Ultralytics Platform 能让你在同一处完成比较:标注自己的高分辨率图像或从 VisDrone 开始,在云端 GPU 上训练整图基线,再使用更大的 imgsz 训练另一组基线,并从自己的机器向同一项目记录切片运行结果。高分辨率切片指南详细介绍了切片选项,Ultralytics Inference 文档则介绍 Rust 部署。
Python 包和 Rust crate 均采用 AGPL-3.0 许可。如果你要将切片检测用于闭源产品,或部署到交付给客户的边缘设备上,Ultralytics Enterprise License允许你将受许可条款涵盖的 Ultralytics 软件用于商业用途,无需遵守 AGPL-3.0 的源代码披露要求,但须遵循许可条款。
常见问题
图像切片会将大图像拆分成相互重叠的窗口,在每个窗口上运行检测器,然后将边界框合并回原始图像。当窗口尺寸与模型输入尺寸相符时,小目标可以保留整幅图像缩放时会损失的像素。在 Ultralytics YOLO 中,
tile参数会以基础重叠率 20% 执行此操作,并为每张图像返回一个结果。首先检查问题是否出在缩放上:如果物体在
imgsz=640下缩小到只有几像素,请测试更大的imgsz或tile=True。训练时使用与预测时相同的设置,让模型学会识别部署时尺寸的物体,并按尺寸和类别进行验证。切片适用于尺寸比模型输入大数倍的图像。每个窗口都会增加一次模型输入:在
tile=640下,一帧 1920 x 1080 的画面会产生 8 个切片输入,而不是一张图像。使用一次批量调用运行多个切片,并在 Python 中设置batch,或在 Rust 中使用动态批处理导出模型配合--batch,可以提升吞吐量。请在目标硬件上测量延迟。不需要。自 Ultralytics 8.4.204 起,内置的
tile参数无需额外软件包即可处理切片推理,也支持切片训练、验证和跟踪。文档中的 SAHI 指南已弃用,建议改用tile。支持。在 Python 中,导出的模型会保留常规输入计算图,你照常将
tile传给predict即可。在 Rust 中,Ultralytics Inference 0.0.57 为 CLI 新增了--tile,并为InferenceConfig新增了with_tile;团队已在 ONNX Runtime CPU、OpenVINO、CUDA 和 TensorRT 上将其与 Python 进行了核对。先从
tile=True开始,它使用imgsz作为窗口大小。即使在原始分辨率下,目标也只有几像素宽时,可以使用更小的窗口,例如将tile=400与imgsz=640搭配使用;如果目标可能在拼接边界处被截断,则使用更大的窗口。在验证集上比较几种尺寸,同时关注召回率和误报。
作者
评论
提出问题、分享你的结果,或帮助其他人。










