DEV Community

Leandro Zanatta
Leandro Zanatta

Posted on AI-assisted

Como anonimizar rostos e placas em imagens com Python (LGPD/GDPR)

Se o seu sistema guarda, compartilha ou publica fotos com pessoas ou carros, ele está tratando dados pessoais. Pela LGPD, rosto e placa identificam alguém (art. 5º, I), e os metadados EXIF ainda guardam a localização GPS de onde a foto foi tirada.

Este tutorial mostra como anonimizar imagens em lote com uma API: localizar rostos e placas, borrar de forma irreversível e remover os metadados. Tudo com curl ou Python, sem treinar modelo e sem GPU.

O que você vai precisar

  • Uma conta gratuita na Apify (o plano gratuito inclui US$ 5 de uso por mês)
  • O token da API, em Settings → API & Integrations
  • Python 3.9+ com apify-client e requests
pip install apify-client requests
export APIFY_TOKEN="seu_token_aqui"
Enter fullscreen mode Exit fullscreen mode

Vamos usar o Image Anonymizer, uma API que detecta rostos e placas (com detector ajustado para placas brasileiras, Mercosul e modelo antigo), aplica o borrão e devolve a imagem sem EXIF.

1. Primeira chamada com curl

O endpoint run-sync-get-dataset-items roda a anonimização e devolve o resultado na mesma resposta. Serve para lotes pequenos, que terminam em até 5 minutos.

curl -X POST \
  "https://api.apify.com/v2/acts/adorable_partial~image-anonymizer/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "imageUrls": ["https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Car_from_Sankt_Gallen.jpg/1280px-Car_from_Sankt_Gallen.jpg"],
    "method": "blur"
  }'
Enter fullscreen mode Exit fullscreen mode

Repare que o token vai no cabeçalho Authorization, não na URL. Assim ele não fica gravado em logs de proxy nem no histórico do terminal de quem vê a URL.

A resposta é uma lista, com um item por imagem:

[
  {
    "sourceUrl": "https://upload.wikimedia.org/.../Car_from_Sankt_Gallen.jpg",
    "outputUrl": "https://api.apify.com/v2/key-value-stores/.../records/anonymized-00001.jpg?signature=...",
    "width": 1280,
    "height": 960,
    "facesBlurred": 0,
    "platesBlurred": 1,
    "metadataRemoved": true,
    "faces": [],
    "plates": [{ "x1": 474, "y1": 717, "x2": 801, "y2": 843, "score": 1.0 }]
  }
]
Enter fullscreen mode Exit fullscreen mode

O outputUrl é a imagem anonimizada. faces e plates trazem as coordenadas de cada região coberta, úteis para auditoria.

2. Lote em Python, baixando as imagens

Para lotes maiores, use o cliente Python. Ele inicia a execução, espera terminar e lê os resultados.

import os
from pathlib import Path

import requests
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

imagens = [
    "https://exemplo.com/fotos/fachada-01.jpg",
    "https://exemplo.com/fotos/evento-02.png",
    # ... centenas de URLs
]

run = client.actor("adorable_partial/image-anonymizer").call(
    run_input={
        "imageUrls": imagens,
        "blurFaces": True,
        "blurPlates": True,
        "method": "blur",           # "blur", "pixelate" ou "solid"
        "detectSmallFaces": True,   # pega rostos pequenos em multidões
        "outputFormat": "jpeg",
    },
    max_total_charge_usd=2,         # teto de gasto desta execução
)

saida = Path("anonimizadas")
saida.mkdir(exist_ok=True)

for i, item in enumerate(client.dataset(run["defaultDatasetId"]).iterate_items(), 1):
    if "error" in item:
        print(f"falhou: {item['sourceUrl']} -> {item['error']}")
        continue
    destino = saida / f"{i:05d}.jpg"
    destino.write_bytes(requests.get(item["outputUrl"], timeout=60).content)
    print(f"{destino}: {item['facesBlurred']} rosto(s), {item['platesBlurred']} placa(s)")
Enter fullscreen mode Exit fullscreen mode

O max_total_charge_usd é um teto de gasto: se o lote ficar mais caro que isso, a API para de processar em vez de passar do limite. Imagens que falham voltam com o campo error e não são cobradas.

3. Opções disponíveis

Campo Padrão O que faz
imageUrls obrigatório Links das imagens (JPEG, PNG, WebP, BMP, TIFF). Aceita links públicos do Google Drive e do Dropbox.
blurFaces true Detecta e cobre rostos.
blurPlates true Detecta e cobre placas de veículos.
method "blur" blur (borrão irreversível), pixelate (mosaico) ou solid (tarja preta).
detectSmallFaces false Faz uma passada extra para rostos pequenos e distantes. Mais lento.
paddingPercent 20 Aumenta cada região detectada para cobrir cabelo, orelhas e moldura da placa.
outputFormat "jpeg" jpeg, png ou webp. O EXIF é sempre removido.
includeDetections true Inclui as coordenadas de rostos e placas no resultado.

4. Imagens que estão no S3 ou em disco

A API recebe URLs, então imagens privadas precisam de um link temporário. No S3, gere URLs pré-assinadas com validade curta:

import boto3

s3 = boto3.client("s3")
chaves = ["vistorias/2026/09/carro-001.jpg", "vistorias/2026/09/carro-002.jpg"]

imagens = [
    s3.generate_presigned_url(
        "get_object",
        Params={"Bucket": "meu-bucket", "Key": chave},
        ExpiresIn=900,  # 15 minutos
    )
    for chave in chaves
]
Enter fullscreen mode Exit fullscreen mode

Depois é só passar a lista imagens para o código da seção 2. O link expira sozinho, e o bucket continua privado.

5. Automatizando o fluxo

Algumas formas de deixar a anonimização rodando sem intervenção:

  • Agendamento: em Schedules, no Console da Apify, a execução roda num horário fixo, por exemplo toda noite.
  • Webhook: configure um webhook para o evento de execução concluída. Seu sistema é avisado quando o lote termina e baixa as imagens.
  • Sem código: há integrações prontas com n8n, Make e Zapier. Um fluxo comum é: foto nova numa pasta do Google Drive → anonimização → imagem salva em outra pasta.

Custos

São US$ 0,005 por imagem anonimizada, mais cerca de US$ 0,005 por execução. Mil imagens custam em torno de US$ 5. Imagens com erro não são cobradas.

Limitações

  • Rostos de perfil acentuado, cobertos ou muito desfocados podem escapar. Em imagens críticas, revise uma amostra ou use "method": "solid".
  • O detector de placas foi ajustado com placas brasileiras. Ele detecta muitas placas de outros países, mas a precisão nelas não foi medida.
  • Crachás, uniformes, tatuagens e fachadas também podem identificar alguém, e não são tratados.
  • Se você guardar a foto original, a cópia borrada pode continuar sendo dado pessoal: o art. 12 da LGPD considera reversível o processo que o próprio controlador consegue desfazer.

Resumo

Com uma chamada de API dá para tirar rostos, placas e localização GPS das imagens antes de armazenar, compartilhar ou publicar. É privacidade desde a concepção (LGPD, art. 46, § 2º) aplicada no código, e reduz o impacto de qualquer vazamento.

Texto informativo, não é orientação jurídica.

Top comments (0)