Phase 08 - Lesson 09

Inpainting, Outpainting & Edição de Imagens

Text-to-image cria coisas novas. Inpainting corrige as antigas. Em produção, 70% do trabalho faturável com imagens é edição — trocar um fundo, remover um logotipo, estender a tela, regenerar uma mão. O inpainting é onde a difusão mostra o seu valor.

Tipo: Build Linguagens: Python Pré-requisitos: Phase 8 · 07 (Latent Diffusion), Phase 8 · 08 (ControlNet & LoRA) Tempo: ~75 minutos

O Problema

Um cliente envia uma foto perfeita de um produto, mas com uma placa que chama a atenção no fundo. Você quer apagar a placa e deixar todo o resto idêntico pixel a pixel. Não é possível executar o text-to-image do zero — o resultado terá uma cor diferente, iluminação diferente, ângulo diferente do produto. Você quer regenerar apenas a região mascarada, e quer que a regeneração respeite o contexto ao redor.

Isso é inpainting. Variantes:

  • Inpainting. Regenerar dentro de uma máscara, mantendo os pixels externos.
  • Outpainting. Regenerar fora de uma máscara (ou além da tela), mantendo o interior.
  • Edição de imagens. Regenerar a imagem inteira, mas mantendo a fidelidade semântica ou estrutural com a original (SDEdit, InstructPix2Pix).

Todo pipeline de difusão em 2026 vem com um modo de inpainting. Flux.1-Fill, Stable Diffusion Inpaint, SDXL-Inpaint, DALL-E 3 Edit. Eles funcionam sob o mesmo princípio.

O Conceito

Inpainting: remoção de ruído ciente da máscara com reinjeção que preserva o contexto

The naive approach (and why it's wrong)

Executar o text-to-image padrão com uma máscara. Em cada etapa de amostragem, substituir a região não mascarada do latente ruidoso pela imagem limpa com difusão direta (forward-diffused). Funciona... mal. Artefatos de borda vazam porque o modelo não tem informação sobre o que está na região mascarada.

O modelo de inpainting adequado

Treinar uma U-Net modificada que recebe 9 canais de entrada em vez de 4:

input = concat([ noisy_latent (4ch), encoded_image (4ch), mask (1ch) ], dim=channel)

Os canais extras são uma cópia da imagem de origem codificada por VAE mais uma máscara de canal único. No momento do treino, você mascara aleatoriamente regiões da imagem e treina o modelo para remover o ruído apenas da região mascarada, enquanto a região não mascarada é fornecida como um sinal de condicionamento limpo. Na inferência, o modelo consegue "ver" o que envolve a região mascarada e produz conclusões coerentes.

SD-Inpaint, SDXL-Inpaint, Flux-Fill utilizam essa entrada de 9 canais (ou similar). Diffusers StableDiffusionInpaintPipeline, FluxFillPipeline.

SDEdit (Meng et al., 2022) — edição livre

Adicionar ruído à imagem de origem até um t intermediário, depois executar a cadeia reversa de t até 0 com um novo prompt. Sem necessidade de retreino. A escolha do t inicial equilibra fidelidade e liberdade criativa:

  • t/T = 0.3 → quase idêntico à origem, pequenas alterações de estilo
  • t/T = 0.6 → edições moderadas, preserva a estrutura geral
  • t/T = 0.9 → gerado a partir de quase puro ruído, preservação mínima da origem

InstructPix2Pix (Brooks et al., 2023)

Ajustar um modelo de difusão em trios de (input_image, instruction, output_image). Na inferência, condicionar tanto na imagem de entrada quanto em uma instrução de texto ("deixe como pôr do sol", "adicione um dragão"). Duas escalas CFG: escala de imagem e escala de texto.

RePaint (Lugmayr et al., 2022)

Manter um modelo de difusão incondicional padrão. A cada etapa reversa, realizar uma nova amostragem — voltar ocasionalmente para um estado com mais ruído e regenerar. Evita artefatos de borda. Usado quando você não tem um modelo de inpainting treinado.

Build It

O arquivo code/main.py implementa um esquema de inpainting didático 1-D em dados de 5 dimensões. Treinamos um DDPM em dados mistos 5-D onde cada amostra consiste em 5 números de ponto flutuante de um dos dois clusters. Na inferência, nós "mascaramos" 2 das 5 dimensões, injetamos a versão ruidosa direta (forward) das três dimensões não mascaradas em cada etapa e regeneramos apenas as dimensões mascaradas.

Passo 1: Dados do DDPM 5-D

def sample_data(rng):
    cluster = rng.choice([0, 1])
    center = [-1.0] * 5 if cluster == 0 else [1.0] * 5
    return [c + rng.gauss(0, 0.2) for c in center], cluster

Passo 2: Treinar o denoiser em todas as 5 dimensões

DDPM padrão. A rede gera uma previsão de ruído 5-D para uma entrada ruidosa 5-D.

Passo 3: Na inferência, processo reverso ciente da máscara

def inpaint_step(x_t, mask, clean_image, alpha_bars, t, rng):
    # replace unmasked dims with a freshly noised version of the clean source
    a_bar = alpha_bars[t]
    for i in range(len(x_t)):
        if not mask[i]:
            x_t[i] = math.sqrt(a_bar) * clean_image[i] + math.sqrt(1 - a_bar) * rng.gauss(0, 1)
    # ...then run the normal reverse step on x_t

Esta é a abordagem ingênua e funciona em dados didáticos 1-D. O inpainting de imagens reais usa a entrada de 9 canais porque a coerência da textura é mais importante.

Passo 4: Outpainting

O outpainting é o inpainting com a máscara invertida: mascara-se a nova tela (que antes não existia) e preenche-se o restante com a original. O objetivo de treino é idêntico.

Armadilhas

  • Costuras (seams). A abordagem ingênua deixa limites visíveis porque as informações de gradiente não fluem através da máscara. Solução: dilatar a máscara em 8-16 pixels ou usar um modelo de inpainting adequado.
  • Vazamento da máscara (mask leakage). Se a região não mascarada da imagem de condicionamento for de baixa qualidade ou ruidosa, ela polui a geração dentro da máscara. Remova o ruído ou desfoque levemente.
  • Interação do CFG com o tamanho da máscara. CFG alto em uma máscara pequena = região saturada. Reduza o CFG para edições pequenas.
  • Queda abrupta de fidelidade no SDEdit (fidelity cliff). Ir de t/T = 0.5 para t/T = 0.6 pode fazer com que a identidade do sujeito seja perdida. Faça varreduras (sweeps) e salve checkpoints.
  • Incompatibilidade de prompt (prompt mismatch). O prompt deve descrever a imagem inteira, não apenas o novo conteúdo. "A cat sitting on a chair" em vez de apenas "a cat".

Use It

Tarefa Pipeline
Remover objeto, máscara pequena SD-Inpaint ou Flux-Fill, prompt padrão
Substituir céu SD-Inpaint + "blue sky at sunset"
Estender tela Modo outpaint do SDXL (suavização/feather de 8px) ou Flux-Fill com máscara de outpaint
Regenerar mão / rosto SD-Inpaint com prompt redescrevendo o sujeito + ControlNet-Openpose
Alterar o estilo de uma região SDEdit em t/T=0.5 na região mascarada
"Make it sunset" InstructPix2Pix ou Flux-Kontext
Substituição de fundo Máscara SAM → SD-Inpaint
Fidelidade ultra-alta Flux-Fill ou GPT-Image (hospedado) para os casos mais difíceis

O SAM (Segment Anything da Meta, 2023) + inpaint por difusão é o pipeline de remoção de fundo em 2026. O SAM 2 (2024) funciona em vídeo.

Ship It

Salve outputs/skill-editing-pipeline.md. A Skill recebe uma imagem original + descrição da edição + máscara opcional (or prompt do SAM) e gera: abordagem de geração de máscara, modelo base, escalas CFG (imagem + texto), SDEdit-t ou modo de inpainting, e um checklist de garantia de qualidade (QA).

Exercícios

  1. Fácil. Em code/main.py, varie a fração de dimensões mascaradas de 0.2 a 0.8. Em qual fração a qualidade do inpaint (resíduo nas dimensões mascaradas) se iguala à geração incondicional?
  2. Médio. Implemente o RePaint: a cada 10ª etapa reversa, volte 5 etapas (adicione ruído) e remova o ruído novamente. Meça se isso reduz o resíduo de borda no limite da máscara.
  3. Difícil. Use os diffusers do Hugging Face para comparar: SD 1.5 Inpaint + ControlNet-Openpose vs Flux.1-Fill em 20 tarefas de regeneração facial. Pontue a aderência à pose e a preservação da identidade separadamente.

Termos-Chave

Termo O que as pessoas dizem O que realmente significa
Inpainting "Preencher o buraco" Regenerar dentro de uma máscara; manter os pixels externos.
Outpainting "Estender a tela" Regenerar fora da tela; manter o interior.
U-Net de 9 canais "Modelo de inpainting adequado" U-Net com noisy | encoded-source | mask como entrada.
SDEdit "Img2img com nível de ruído" Ruído até o tempo t, denoising com novo prompt.
InstructPix2Pix "Edições apenas por texto" Difusão ajustada (fine-tuned) em trios de (imagem, instrução, saída).
RePaint "Sem retreino" Adicionar ruído periodicamente durante o processo reverso para reduzir as costuras (seams).
SAM "Segment Anything" Gerador de máscara por cliques ou caixas de seleção; faz par com inpaint.
Flux-Kontext "Editar com contexto" Variante do Flux que aceita uma imagem de referência + instrução para edições.

Nota de produção: pipelines de edição são sensíveis à latência

Usuários que editam uma imagem esperam tempos de resposta (round trips) inferiores a 5 segundos. Um SDXL-Inpaint de 30 etapas em 1024² leva 3-4 segundos em uma L4, mais a geração de máscara com SAM (200 ms) e codificação/decodificação VAE (500 ms combinados). No contexto de produção, isso é limitado pelo TTFT (Time to First Token) em vez de throughput — lote (batch) de tamanho 1, baixa concorrência, minimize cada etapa:

  • O SAM-H é a parte lenta. O SAM-H em 1024² leva ~200 ms; o SAM-ViT-B leva ~40 ms com pequena perda de qualidade. O SAM 2 (vídeo) adiciona sobrecarga temporal; não o use para edições de imagens únicas.
  • Pule a codificação quando possível. pipe.image_processor.preprocess(img) codifica para latentes. Se você já tiver os latentes da geração anterior (típico em UIs de edição iterativa), passe-os diretamente via latents=... para pular uma codificação VAE.
  • A dilatação da máscara também afeta o throughput. Uma máscara pequena significa que a maior parte da passada direta (forward pass) da U-Net é desperdiçada (os pixels não mascarados são fixados/clamped de qualquer forma). A StableDiffusionInpaintPipeline da biblioteca diffusers executa toda a U-Net de qualquer maneira; apenas as variantes adequadas de inpainting com 9 canais aproveitam a computação mascarada.
  • O Flux-Kontext é a resposta em 2025. Uma única passada direta sobre (source_image, instruction) — sem máscara separada, sem varredura de ruído SDEdit. Em uma H100, ele entrega uma edição em ~1.5 s. A lição de arquitetura: simplifique e unifique as etapas.

Leitura Adicional

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).