Detecção de objetos pequenos com recorte de imagens em blocos no Ultralytics YOLO, de Python a Rust
Veja quando o recorte em blocos de imagens ajuda o YOLO a detectar objetos pequenos, compare os custos e execute inferência em blocos integrada com Python ou Rust, sem SAHI.
Onuralp Sezer16 min de leitura
Por que um detector que funciona bem em fotos comuns não detecta a maioria das pessoas em uma imagem de drone? Muitas vezes, porque nunca as vê em tamanho real. Com o valor padrão imgsz=640, o Ultralytics YOLO reduz uma imagem de 1920 x 1080 três vezes antes de o modelo analisá-la; assim, um pedestre com 15 pixels de altura acaba com cerca de 5 pixels.
O recorte em blocos de imagens pode preservar esses detalhes de objetos pequenos, executando o modelo em janelas sobrepostas da imagem em resolução total e combinando os resultados. Em um quadro do VisDrone incluído na nossa documentação, o Ultralytics YOLO26s passou de 35 detecções para 161. O custo é mais processamento por quadro: oito entradas de blocos em vez de uma imagem.
Agora, o recorte em blocos está integrado nas duas pontas de uma implantação. O pacote Python tem o argumento tile desde o Ultralytics 8.4.204, lançado em 6 de novembro, e o crate Rust adicionou a flag --tile no Ultralytics Inference 0.0.57, lançado em 9 de novembro. Este guia explica quando o recorte recupera objetos pequenos, quais são os custos e como executá-lo em cada um.
O redimensionamento é o que oculta objetos pequenos#
A detecção de objetos pequenos é difícil por um motivo simples: um objeto só tem os pixels que tem. Um modelo de detecção de objetos aprende formas a partir de poucos pixels por objeto e, quando o quadro inteiro é reduzido para 640 pixels no lado mais comprido, pessoas, veículos e defeitos distantes ficam abaixo do nível que a rede consegue distinguir de texturas e ruído.
Isso fica mais evidente em imagens aéreas, análise de imagens de satélite, câmeras de trânsito e segurança com grande angular e fotos de inspeção em alta resolução. O VisDrone é um benchmark aéreo público muito usado: a documentação descreve objetos que muitas vezes têm apenas algumas dezenas de pixels no quadro e aparecem em grupos densos, com muita oclusão.
O recorte em blocos preserva esses pixels. Com tile definido como o tamanho de entrada do modelo, o modelo vê várias janelas em resolução nativa em vez de processar uma única vez um quadro reduzido. A ideia é o que o artigo sobre SAHI chama de inferência aprimorada por recortes, avaliada pelos autores nos conjuntos de dados aéreos VisDrone e xView.
No guia de recorte em blocos em alta resolução, o YOLO26s, aplicado a um quadro VisDrone de 1920 x 1080 com o limiar de confiança padrão, retorna 35 detecções na imagem inteira com imgsz=640 e 161 com tile=640, incluindo pedestres, ciclistas e carros distantes. O guia mostra as duas imagens lado a lado. Esses números são contagens de previsões, não resultados de uma avaliação com métricas. Os dois números foram gerados com os mesmos pesos; o recorte em blocos também alterou o contexto visto por cada janela.

Um segundo quadro de validação do VisDrone de 1920 x 1080, YOLO26s com a confiança padrão: 8 detecções no quadro inteiro com imgsz=640 e 128 com tile=640. Recorte da estrada, caixas sem rótulos de classe.
O recorte em blocos adiciona uma entrada do modelo por janela#
O guia define o uso de janelas com precisão. As janelas se sobrepõem em 20% por padrão, e a última linha e a última coluna se alinham à borda da imagem, de modo que as janelas nas extremidades podem se sobrepor mais. Uma imagem menor que a janela recebe uma única janela que cobre a imagem inteira.
Assim, é fácil prever o custo. Um quadro de 1920 x 1080 com tile=640 usa oito janelas: quatro na horizontal e duas na vertical. Um quadro de 3840 x 2160 com tile=1280 também usa oito. Aplicando a mesma regra de 20% a um quadro de 3840 x 2160 com tile=640, são oito colunas e quatro linhas, totalizando 32 janelas; portanto, reduzir pela metade o tamanho da janela em um quadro 4K quadruplica as entradas de blocos.

As oito janelas usadas por tile=640 em um quadro de 1920 x 1080: as colunas começam em x = 0, 512, 1024 e 1280; as linhas, em y = 0 e 440. As faixas sombreadas são vistas por mais de uma janela.
O processamento em lotes altera como essas entradas chegam ao modelo. Em Python, batch define quantas janelas são processadas juntas pelo modelo em uma chamada de inferência; o crate Rust faz o mesmo com --batch em uma exportação com lote dinâmico. O processamento em lotes pode aumentar a taxa de transferência, mas meça a latência no seu hardware; nosso guia sobre inferência em lotes com o Ultralytics YOLO explica por quê.
Veja como o recorte em blocos se compara a outras formas de dar mais pixels aos objetos pequenos:
| Abordagem | Entradas do modelo para um quadro de 1920 x 1080 | O que o modelo vê | Ideal quando |
|---|---|---|---|
Imagem inteira, imgsz=640 | 1 | Quadro reduzido 3 vezes | Os objetos continuam claramente visíveis após o redimensionamento |
Imagem inteira, imgsz=1280 | 1, com cerca de 4 vezes o custo computacional de 640 | Quadro reduzido 1,5 vez | A memória e a latência permitem uma entrada maior |
tile=True com imgsz=640 | 8 | Janelas de 640 pixels em resolução nativa | Imagens várias vezes maiores que a entrada do modelo |
tile=400 com imgsz=640 | Mais de 8 | Janelas ampliadas para 640 | Objetos com apenas alguns pixels de largura, mesmo em resolução nativa |
Cada bloco é uma entrada de tamanho normal para o modelo, então o recorte em blocos lida com imagens muito grandes sem aumentar imgsz. Saídas no tamanho da fonte, como máscaras e mapas de profundidade, ainda exigem memória proporcional à imagem original, e max_det limita o número de máscaras de instância mantidas.
Quando o recorte em blocos ajuda e quando atrapalha#
O recorte em blocos ajuda quando os objetos são pequenos em relação ao quadro e o quadro é muito maior que a entrada do modelo. Imagens de drones e satélites, tráfego visto de cima, multidões, prateleiras de lojas fotografadas em grande angular e imagens de inspeção visual de placas ou painéis inteiros são bons casos de uso.
Ele atrapalha quando os objetos são grandes. Uma janela só vê parte de um caminhão que ocupa metade do quadro, e o guia é claro quanto a isso: objetos maiores que a sobreposição ainda podem ser divididos, porque nenhuma janela os vê por inteiro, e a combinação não une fragmentos separados. O recorte também remove o contexto global, o que afeta principalmente a classificação e a profundidade, pois as saídas dos blocos podem não coincidir ao longo da imagem.
Janelas menores trazem mais uma compensação. Ampliar uma janela de 400 pixels para 640 ajuda com objetos que têm apenas alguns pixels de largura, mas também amplia a desordem do fundo, o que pode gerar falsos positivos. Compare dois ou três tamanhos de bloco no seu próprio conjunto de validação e acompanhe a precisão e também a revocação.
Como os blocos são combinados em um único resultado#
Cada janela gera suas próprias previsões nas coordenadas da janela. O recorte em blocos as mapeia de volta para a imagem de origem e retorna um objeto Results por imagem original, então o código subsequente que lê result.boxes continua funcionando sem alterações.
A sobreposição significa que um objeto perto de uma junção pode ser detectado duas vezes. Na detecção, as duplicatas são suprimidas com supressão não máxima, usando as configurações iou, agnostic_nms e max_det; por isso, nosso guia sobre ajuste do limiar de IoU do NMS se aplica diretamente à saída em blocos. Uma caixa cortada pela borda de uma janela é descartada quando outra janela vê o objeto sem cortes nas bordas e uma caixa mantida o cobre; assim, na junção, fica a previsão mais completa. Uma caixa cortada sem correspondência melhor é mantida.

Ilustração do tratamento de junções em y = 640 no mesmo quadro. As caixas ciano são cortadas pela borda inferior das janelas da linha superior; as caixas magenta vêm das janelas da linha inferior; o painel à direita mostra a caixa mais completa mantida para cada carro após a combinação.
Cada tarefa do Ultralytics YOLO combina os resultados à sua maneira:
- Detecção, segmentação, pose e OBB restauram caixas, máscaras, pontos-chave ou caixas rotacionadas às coordenadas da imagem de origem e aplicam a seleção de caixas, com NMS rotacionado para OBB.
- Segmentação semântica combina os mapas de classes, escolhendo o bloco mais central onde as janelas se sobrepõem.
- Profundidade combina os mapas de profundidade sobrepostos usando pesos que aumentam em direção ao centro de cada bloco.
- Classificação calcula a média das probabilidades dos blocos.
O pipeline Python também aplica o recorte em blocos às previsões de YOLO-World, YOLOE, RT-DETR e FastSAM. SAM mantém seu próprio pipeline de recortes e não aceita tile.
Inferência em blocos no Python com o argumento tile#
O recorte em blocos requer Ultralytics 8.4.204 ou posterior e não exige pacotes adicionais. No modo de previsão, passe tile=True para usar imgsz como tamanho da janela ou um número inteiro para definir o tamanho da janela separadamente:
from ultralytics import YOLO
model = YOLO("yolo26s.pt")
# Linha de base: uma passagem pelo quadro reduzido para 640 pixels
full = model.predict("intersection.jpg", imgsz=640)
# Em blocos: janelas de 640 pixels em resolução nativa, 8 janelas por lote
tiled = model.predict("intersection.jpg", imgsz=640, tile=640, batch=8)
print(len(full[0].boxes), len(tiled[0].boxes))O mesmo argumento funciona na CLI com yolo predict model=yolo26s.pt source=large-image.tif tile=640 imgsz=640 batch=8. Para vídeo, passe stream=True para limitar o uso de memória. No modo de rastreamento, o rastreador é executado uma vez por quadro sobre as previsões combinadas.
O recorte em blocos não serve apenas para previsões. Quando suas imagens são muito maiores que imgsz, treine e valide com a mesma configuração:
- Treine com blocos usando
model.train(data="aerial.yaml", tile=True, imgsz=640). Os rótulos são recortados para cada janela, as instâncias com menos de 10% da área original da caixa são removidas, e as janelas vazias permanecem como exemplos negativos. - Valide os resultados combinados usando
model.val(data="aerial.yaml", tile=True, imgsz=640). As previsões são combinadas antes de serem avaliadas em relação às anotações originais, então o mAP reflete o que você implantará. - Armazene em cache as imagens de origem grandes usando
cache="ram", pois o treinamento embaralha os blocos e, sem isso, decodificaria a mesma imagem grande muitas vezes. - Compare com uma linha de base usando a imagem inteira na mesma divisão de validação antes de manter o modelo treinado em blocos. Para mais formas de melhorar as métricas em objetos minúsculos, veja nossa lista de verificação de mAP para objetos pequenos.
Treinar com blocos apresenta os objetos ao modelo na escala em que ele os verá durante a previsão em blocos. Nosso guia de conjuntos de dados para detecção com drones percorre todo o ciclo de treinamento, recorte em blocos e avaliação em quadros 4K.
Modelos exportados também podem usar o recorte em blocos. Como o recorte é executado no pipeline de previsão do Python, um modelo exportado para ONNX ou TensorRT mantém seu grafo de entrada normal, e YOLO("yolo26s.onnx").predict(source, tile=640) funciona como de costume, inclusive com tamanhos de lote fixos na exportação e o último lote incompleto.

O conjunto de dados VisDrone na Ultralytics Platform, um benchmark pronto para testar tamanhos de bloco antes de rotular seus próprios dados.
Para testar primeiro os tamanhos de bloco com dados públicos, comece pelo conjunto de dados VisDrone na Ultralytics Platform. Para acompanhar uma execução em blocos junto à sua linha de base, copie o comando de treinamento local da caixa de diálogo de treinamento da Platform, defina project como o projeto da Platform da sua linha de base e adicione tile=True para transmitir as métricas da execução em blocos para esse projeto.
Inferência em blocos no Rust com a nova flag --tile#
Ultralytics Inference é nosso crate Rust e nossa CLI para executar modelos ONNX exportados pelo ONNX Runtime e modelos OpenVINO IR nativamente, sem ambiente de execução Python durante a inferência. Ele é voltado a servidores, contêineres e dispositivos de borda com CPU, CUDA, TensorRT, CoreML, OpenVINO e outros provedores de execução. A versão 0.0.57 traz a mesma abordagem de recorte em blocos do Python: sobreposição de janela de 20% por padrão, resultados mapeados de volta para a imagem de origem e duplicatas removidas por classe.

Ilustrativo. Uma câmera à beira da estrada com um computador de borda, o tipo de implantação sem Python a que o crate Rust se destina.
A equipe verificou a saída em blocos em comparação com o Ultralytics Python no ONNX Runtime CPU, OpenVINO CPU, GPU e NPU, CUDA e TensorRT, para imagens, vídeo e webcam. Há suporte para modelos de detecção, segmentação, segmentação semântica, profundidade, classificação, pose e OBB.
Na CLI, adicione --tile com um tamanho de janela ou passe a flag sem valor para usar --imgsz. A exportação do modelo é uma etapa única no Python; a inferência em si só precisa do binário 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 8Como biblioteca, configure o recorte em blocos uma vez em InferenceConfig, e todas as chamadas a predict usarão blocos. with_tile(0) usa o tamanho de inferência:
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(())
}As caixas duplicadas entre janelas são removidas com NMS por classe no valor configurado de --iou, que, desde a mesma versão, tem como padrão 0.5, em linha com os valores padrão de previsão do Ultralytics. O recorte em blocos fica desativado por padrão, pois cada janela é mais uma entrada do modelo. Ative-o onde os detalhes forem importantes, meça a latência de inferência no dispositivo de destino e escolha o provedor de execução adequado; nossa comparação entre ONNX e TensorRT ajuda com hardware NVIDIA, e o guia NVIDIA Jetson explica a configuração no dispositivo.
Quem usa SAHI pode mudar para o argumento tile integrado#
Se você já recorta imagens com a biblioteca SAHI, o argumento integrado faz o mesmo trabalho dentro do Ultralytics, sem um segundo pacote nem um formato de resultados separado. Nosso guia de integração do SAHI agora está obsoleto e foi substituído por tile.
Migrar um script SAHI exige, em grande parte, apenas mudar os argumentos:
| SAHI | Recorte em blocos integrado |
|---|---|
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 | Sobreposição fixa de 20% por padrão; janelas nas extremidades alinhadas à borda da imagem |
PredictionResult do SAHI | Results padrão do Ultralytics |
As janelas são quadradas, e a sobreposição e a combinação seguem as regras descritas acima, em vez do pós-processamento configurável do SAHI; portanto, espere caixas semelhantes, mas não idênticas. Ao mudar, confira novamente os limiares em um conjunto de validação.
A diferença prática está na integração. tile se integra ao treinamento, à validação, às previsões e ao rastreamento do Ultralytics com o mesmo argumento, retorna objetos padrão Results e tem uma opção equivalente no crate Rust; assim, um tamanho de bloco validado em um notebook também funciona em um binário Rust na borda.
Quem deve ativar o recorte em blocos#
Ative o recorte em blocos se você executa o Ultralytics YOLO em imagens várias vezes maiores que a entrada do modelo e sua validação mostra que objetos pequenos não são detectados: equipes que trabalham com drones e satélites, integradores de trânsito e segurança com câmeras grande angular e equipes de inspeção que fotografam placas, painéis ou prateleiras inteiros. Quem usa Rust obtém a mesma abordagem de recorte em blocos em hardware de borda, sem ambiente de execução Python.
Deixe-o desativado quando os objetos forem grandes em relação ao quadro, quando um imgsz maior já os recuperar em uma única passagem ou quando o orçamento de latência não puder acomodar várias entradas de blocos por quadro. Em todos os casos, compare os resultados em blocos e da imagem inteira na mesma divisão de validação e com o mesmo limiar de confiança, observando a revocação, os falsos positivos e a latência; mantenha o recorte em blocos somente quando o ganho compensar o processamento adicional.
A Ultralytics Platform reúne essa comparação em um só lugar: rotule suas próprias imagens em alta resolução ou comece pelo VisDrone, treine uma linha de base com imagens inteiras em GPUs na nuvem, treine outra linha de base com um imgsz maior e registre uma execução em blocos da sua própria máquina no mesmo projeto. O guia de recorte em blocos em alta resolução detalha as opções de recorte, e a documentação do Ultralytics Inference explica a implantação em Rust.
Tanto o pacote Python quanto o crate Rust estão disponíveis sob a licença AGPL-3.0. Se você pretende incluir a detecção em blocos em um produto de código fechado ou em um dispositivo de borda que envia aos clientes, uma licença empresarial do Ultralytics permite o uso comercial do software Ultralytics abrangido sem as exigências de divulgação do código-fonte da AGPL-3.0, sujeito aos termos da licença.
Perguntas frequentes
O recorte de imagens em blocos divide uma imagem grande em janelas sobrepostas, executa o detector em cada janela e combina as caixas de volta na imagem original. Quando a janela corresponde ao tamanho de entrada do modelo, os objetos pequenos mantêm os pixels que perderiam se a imagem inteira fosse redimensionada. No Ultralytics YOLO, o argumento
tilefaz isso com uma sobreposição padrão de 20% e retorna um resultado por imagem.Primeiro, verifique se o problema é o redimensionamento: se os objetos ficam com apenas alguns pixels em
imgsz=640, teste umimgszoutile=Truemaior. Treine com a mesma configuração que usará nas previsões, para que o modelo aprenda os objetos na escala em que serão implantados, e valide por tamanho e classe. O recorte em blocos é adequado para imagens várias vezes maiores que a entrada do modelo.Ele adiciona uma entrada do modelo por janela: um quadro de 1920 x 1080 com
tile=640gera oito entradas de blocos em vez de uma imagem. Executar vários blocos em uma única chamada em lote, combatchno Python ou--batchcom uma exportação de lote dinâmico no Rust, pode aumentar a taxa de transferência. Meça a latência no hardware de destino.Não. Desde o Ultralytics 8.4.204, o argumento integrado
tilefaz inferência por recortes sem pacote adicional e também permite recortar em blocos no treinamento, na validação e no rastreamento. O guia do SAHI na nossa documentação está obsoleto e foi substituído portile.Sim. No Python, os modelos exportados mantêm seu grafo de entrada normal, e você passa
tileparapredictcomo de costume. No Rust, o Ultralytics Inference 0.0.57 adiciona--tileà CLI ewith_tileaInferenceConfig; a implementação foi verificada em comparação com Python no ONNX Runtime CPU, OpenVINO, CUDA e TensorRT.Começa com
tile=True, que usaimgszcomo tamanho da janela. Usa uma janela menor, comotile=400comimgsz=640, quando os objetos tiverem apenas alguns pixels de largura mesmo na resolução nativa, e uma janela maior quando houver risco de os objetos serem cortados nas emendas. Compara alguns tamanhos no teu conjunto de validação, observando tanto a revocação quanto os falsos positivos.
Escrito por
Comentários
Faça uma pergunta, compartilhe seus resultados ou ajude alguém.










