# Sugestões — Classificação de Imagens

Gerado em 08-08-2026 a partir da análise do `golden_imagens.csv` (160 entradas).

---

## 1. Correção aplicada

**Digest `5b45cd4c773f6e13`** — reclassificado de `recorrente` para `frequente`.

- Imagem: desenho técnico cotado de pista de ensaio (573×144px)
- PDFs: RTAC002603 (p.20), RTAC002611 (p.18), RTAC002948 (p.11)
- Causa: na 3ª ocorrência (RTAC002948), o `texto_vizinho` capturou o cabeçalho institucional da página junto com a legenda da figura:
  ```
  "Figura 2 - Pista de Ensaio com Simulador de Pista / Serviço Público Federal
  MINISTÉRIO DA ECONOMIA INSTITUTO NACIONAL DE METROLOGIA, QUALIDADE E TECNOLOGIA - INMETRO"
  ```
- O `_classificar` concatena texto das 5 primeiras ocorrências (linha 266 de `pdf_images.py`), e o regex `_TEXTO_INSTITUCIONAL` casou "MINISTÉRIO" no texto agregado.

---

## 2. Estatísticas da amostra revisada

| Classificação | Quantidade | n_documentos | Descrição |
|---|---|---|---|
| `candidata` | 60 | 1-2 | Desenhos técnicos únicos de fabricantes |
| `frequente` | 21 | 3-6 | Desenhos técnicos reutilizados (não institucional) |
| `recorrente` | 19 | 3-94 | Logos, timbres, brasões institucionais |
| `descartada: area pequena` | 34 | 1 | Área < 40.000px² |
| `descartada: minuscula` | 26 | 1 | Menor lado < 100px |

**20 entradas** já tinham rótulos humanos (`label_util`, `label_tipo`, `label_observacao`) do assistente de calibração — foram sincronizados para o CSV.

---

## 3. Diagnóstico: falso positivo no `_classificar`

### O problema

A função `_classificar` (`pdf_images.py:255-269`) funciona assim:

```python
def _classificar(entrada):
    if entrada["n_documentos"] < settings.IMAGE_MAX_DOCS:
        return CLASSIFICACAO_CANDIDATA
    amostra = " ".join(o.get("texto_vizinho", "") for o in entrada["ocorrencias"][:5])
    if _TEXTO_INSTITUCIONAL.search(amostra):
        return CLASSIFICACAO_RECORRENTE
    return CLASSIFICACAO_FREQUENTE
```

O `texto_vizinho` é extraído pela função `texto_vizinho(blocos, bbox)` (linha 97-117), que pega os **2 blocos de texto mais próximos verticalmente** da imagem. Quando a figura está perto do cabeçalho ou rodapé da página, o texto institucional do cabeçalho é capturado junto com a legenda.

No caso do digest `5b45cd4c773f6e13`, as 3 ocorrências têm legenda técnica ("Figura 2 - Pista de Ensaio..."), mas uma delas tem o cabeçalho "Serviço Público Federal / MINISTÉRIO DA ECONOMIA..." fisicamente próximo da imagem no PDF.

### Quando pode acontecer de novo

Qualquer desenho técnico que apareça em 3+ documentos e, em pelo menos um deles, esteja posicionado perto de um cabeçalho institucional, será classificado como `recorrente` mesmo sendo conteúdo técnico útil.

O risco é baixo (apenas 1 ocorrência em 160 na amostra), mas cresce com o tamanho do acervo.

---

## 4. Sugestões de melhoria

### Opção A: Filtrar texto institucional antes de agregar (recomendada)

No `_classificar`, remover linhas que casam `_TEXTO_INSTITUCIONAL` de cada `texto_vizinho` antes de concatenar:

```python
def _classificar(entrada):
    if entrada["n_documentos"] < settings.IMAGE_MAX_DOCS:
        return CLASSIFICACAO_CANDIDATA
    partes = []
    for o in entrada["ocorrencias"][:5]:
        t = o.get("texto_vizinho", "")
        # Remove segmentos institucionais do texto antes de agregar
        t = _TEXTO_INSTITUCIONAL.sub("", t).strip()
        if t:
            partes.append(t)
    amostra = " ".join(partes)
    if _TEXTO_INSTITUCIONAL.search(amostra):
        return CLASSIFICACAO_RECORRENTE
    return CLASSIFICACAO_FREQUENTE
```

**Prós:** Simples, cirúrgico. Remove o ruído institucional do texto sem perder a legenda técnica.
**Contras:** Se a legenda em si contiver "ministério" (ex: "QUADRO ANEXO À PORTARIA INMETRO/DIMEL..." que menciona o ministério no contexto da portaria), perderia o sinal. Mas isso é desejável — a legenda técnica não é um timbre.

### Opção B: Exigir maioria das ocorrências

Só classificar como `recorrente` se a maioria das ocorrências (>= 50%) tiver texto institucional:

```python
def _classificar(entrada):
    if entrada["n_documentos"] < settings.IMAGE_MAX_DOCS:
        return CLASSIFICACAO_CANDIDATA
    ocorrencias = entrada["ocorrencias"][:5]
    com_institucional = sum(
        1 for o in ocorrencias
        if _TEXTO_INSTITUCIONAL.search(o.get("texto_vizinho", ""))
    )
    if com_institucional > len(ocorrencias) / 2:
        return CLASSIFICACAO_RECORRENTE
    return CLASSIFICACAO_FREQUENTE
```

**Prós:** Mais robusto contra um único falso positivo.
**Contras:** Requer pelo menos 3 ocorrências para ter significado estatístico. Para `n_documentos=3`, basta 2 de 3 com texto institucional.

### Opção C: Ajustar a janela de extração do `texto_vizinho`

A função `texto_vizinho` (linha 97-117) pega os 2 blocos mais próximos verticalmente. Uma alternativa seria limitar a distância máxima (ex: 50px) para evitar capturar cabeçalhos distantes:

```python
def texto_vizinho(blocos, bbox):
    if not blocos:
        return ""
    caixa = pymupdf.Rect(bbox)
    MAX_DIST = 50  # pontos

    def distancia(bloco):
        r = pymupdf.Rect(bloco[:4])
        if r.y0 >= caixa.y1:
            return r.y0 - caixa.y1
        if caixa.y0 >= r.y1:
            return caixa.y0 - r.y1
        return 0.0

    proximos = [b for b in sorted(blocos, key=distancia) if distancia(b) <= MAX_DIST][:2]
    texto = " / ".join(" ".join(b[4].split()) for b in proximos)
    return texto[:_MAX_TEXTO_VIZINHO]
```

**Prós:** Ataca a causa raiz — o texto institucional nem seria capturado.
**Contras:** Pode perder legendas legítimas que estejam mais distantes da imagem. Precisa de validação com dados reais para calibrar o `MAX_DIST`.

---

## 5. Recomendação

**Implementar a Opção A** como primeira melhoria — é a mais simples e não afeta a extração do `texto_vizinho` em si. O regex já existe e é testado; a mudança é apenas filtrar antes de agregar.

A Opção C pode ser investigada em paralelo como melhoria de longo prazo na qualidade do `texto_vizinho`, mas requer mais validação.

---

## 6. Observações sobre a amostra

- **Entrada com texto_vizinho vazio** (digest `6bfa4f891df4365b`, PAM000427.pdf p.2): imagem de 1104×1615px sem texto extraível. Classificada corretamente como `candidata` (n_doc=1), mas sem sinal para desambiguação futura.
- **DRESSER/WAYNE**: 3 drawings appear in `frequente` (lines 66, 69, 78) and 1 in `candidata` (line 23, n_doc=2). The candidata may become frequente as more documents are ingested — this is expected behavior.
- **Limiar frequente/recorrente no n_doc=3**: 14 frequente and 4 recorrente entries have n_doc=3. The text-based disambiguation at this boundary is working well — institutional text correctly pushes to recorrente.
