# Análise visual local ## Configuração no painel A configuração do Scanner é apresentada na aba **Scanner** do painel CEP em `code/cep-plugin/`. O perfil salvo segue o contrato versionado de `ConfiguracaoVisualDoScanner`; ele define amostragem, faixas, recursos Vision, cenas, continuidade, reenquadramento e interpretação antes de montar os adapters. ## Acesso à timeline do Premiere Quando a análise precisar ler a timeline, a sequência ativa, as faixas ou os clipes do Premiere, use sempre a classe existente `engine.integracoes.premiere.leitura.AcessoAoEditor`. O módulo visual não deve criar chamadas MCP, abrir processos do Premiere ou acessar o bridge diretamente. O acesso deve seguir esta composição: ```python from engine.integracoes.premiere.leitura import AcessoAoEditor, AcessoATimeline from engine.scanner import DescobertaDaTimeline from engine.integracoes.premiere.conversores import ConversorDeTimeline acesso_ao_editor = AcessoAoEditor(AcessoATimeline(cliente_mcp)) descoberta = DescobertaDaTimeline(acesso_ao_editor, ConversorDeTimeline()) ``` Depois, a timeline convertida entra no `ContextoDeAnalise` e o Scanner executa `AnaliseVisualDaTimeline`. A classe de acesso isola o MCP e preserva a separação entre a integração com o Premiere e os analyzers locais. Não duplicar esse acesso em novos adapters ou analyzers. Para testes, injetar um fake de `AcessoAoEditor`/`AcessoATimeline` ou usar uma timeline de domínio pronta. ## Captura para análise visual A análise visual não exporta um frame renderizado pelo Premiere. Para cada clipe de vídeo, o fluxo usa os campos retornados pelo MCP em `get_active_sequence`: 1. `sourceFile` identifica o arquivo original do `projectItem`. 2. `inPoint` e `outPoint` delimitam o trecho usado pelo clipe. 3. O extrator abre `sourceFile` localmente e amostra o primeiro frame do trecho, usando `inPoint` como tempo inicial na origem. 4. Vision/OpenCV/ONNX recebem esse frame persistido, mantendo o timestamp de origem; nenhum frame é exportado da timeline do Premiere. Portanto, `start`/`end` são tempos da timeline e `inPoint`/`outPoint` são tempos do arquivo original. Não misturar esses relógios ao analisar um clipe. O Scanner usa apenas as interfaces em `contratos.py`. As bibliotecas externas ficam em adapters concretos, para que possam ser habilitadas, substituídas ou testadas isoladamente. | Papel | Adapter | | --- | --- | | Extrair frames | `ExtratorDeQuadrosOpenCV` | | Medir qualidade | `AnalisadorDeQualidadeOpenCV` | | Rosto e olhos visíveis | `AnalisadorDeRostosOpenCV` | | Composição e área para legendas | `AnalisadorDeComposicaoOpenCV` | | Tremor/movimento de câmera | `AnalisadorDeTremorOpenCV` | | Continuidade e frame congelado | `AnalisadorDeContinuidadeOpenCV` | | Detectar objetos | `AnalisadorDeObjetosONNX` | | Detectar pose e mãos | `AnalisadorDePoseMediaPipe` | | Reconhecer a mesma pessoa entre tomadas (assinatura facial) | `AnalisadorDeRostosInsightFace` | | OCR e faces macOS | `AnalisadorAppleVision` | | Vision + Apple Intelligence (Swift isolado) | `AnalisadorAppleVisionNativo` | | Similaridade temporal por feature print | `AnalisadorSequenciaAppleVisionNativo` | | Extrair frames para Vision sem OpenCV | `ExtratorDeQuadrosFFmpeg` | | Detectar cenas | `DetectorDeCenasPySceneDetect` | `AnalisadorDeObjetosONNX` exige dois adapters específicos do modelo: `preparar(imagem, entradas)` e `decodificar(saidas, quadro)`. Isso mantém os detalhes de cada arquivo ONNX fora do Scanner e permite trocar de modelo sem alterar a interface do domínio. `AnalisadorDePoseMediaPipe` recebe caminhos explícitos para os arquivos `.task` de pose e mãos. Os modelos ficam em `/Volumes/Merongo/SISTEMAS/MODELOSIA/mediapipe/` e não são acoplados ao pacote Python. Ele executa em subprocesso: falhas nativas do MediaPipe são contidas e retornam como indisponibilidade do adapter, sem encerrar o processo do Scanner. `AnalisadorDeRostosOpenCV` usa os arquivos locais `haarcascade_frontalface_default.xml` e `haarcascade_eye.xml`. Quando a distribuição do OpenCV não os incluir, forneça `diretorio_de_modelos` apontando para a pasta que os contém. Ele entra automaticamente no detector local (`criar_detector_visual_local`) quando `"faces"` está em `recursos_vision` (padrão do perfil). `AnalisadorDeRostosInsightFace` resolve o que nem o OpenCV nem o Apple Vision fazem: reconhecer que o rosto de um clipe é a mesma pessoa de outro clipe. Ele devolve duas evidências por rosto — `rosto` (mesma forma de bounding box dos outros adapters) e `identidade_facial` (com `assinatura_facial`, um vetor de 512 posições, mais `idade_aproximada`/`genero_aparente` quando o modelo os estimar). Aceita tanto o frame decodificado em `quadro.imagem` (pipeline OpenCV) quanto um frame persistido em `quadro.caminho` (pipeline Apple Vision/FFmpeg), lendo o PNG com OpenCV nesse segundo caso. Por ser mais pesado (baixa o modelo `buffalo_l` na primeira execução), só entra nos detectores locais e no detector Apple Vision quando `perfil.identidade_facial=True` — desligado por padrão. `AnalisadorAppleVisionNativo` é a opção Apple recomendada. Seu runner Swift executa faces/landmarks, qualidade facial, pessoas, pose, mãos, OCR, classificação e estética de forma independente. A interpretação editorial pelo `FoundationModels` só é criada a partir dessas evidências e é salva em separado. Falhas nativas por recurso viram `diagnostico_apple_vision`, sem derrubar o Scanner nem descartar os fatos que funcionaram. Além de rostos, pessoas, pose, mãos, OCR, categorias e estética, o runner Apple retorna códigos/QR, horizonte, retângulos, densidade de contornos, ocupação da máscara de pessoas e similaridade visual entre frames. Os valores são fatos normalizados; descrição, contexto e ação devem ser derivados depois, a partir dessas evidências temporizadas. ## Montagem ```python from engine.integracoes.visual import ( AnalisadorDeQualidadeOpenCV, AnalisadorDeRostosOpenCV, AnalisadorDeComposicaoOpenCV, AnalisadorDeTremorOpenCV, AnalisadorDeContinuidadeOpenCV, DetectorDeCenasPySceneDetect, ExtratorDeQuadrosOpenCV, ) from engine.scanner.visual import DetectorDeCenas detector = DetectorDeCenas( ExtratorDeQuadrosOpenCV(intervalo_em_segundos=1.0, diretorio_de_cache=".frames"), analisadores_de_frame=[ AnalisadorDeQualidadeOpenCV(), AnalisadorDeRostosOpenCV(), AnalisadorDeComposicaoOpenCV(), ], analisadores_de_sequencia=[ AnalisadorDeTremorOpenCV(), AnalisadorDeContinuidadeOpenCV(), ], detectores_de_intervalo=[DetectorDeCenasPySceneDetect()], ) ``` Depois, passe esse `DetectorDeCenas` para `AnaliseVisualDaTimeline` ao montar o `PipelineDoScanner`. Para o caminho local padrão, a montagem pode ser reduzida a: ```python from engine.scanner import AnaliseVisualDaTimeline, PipelineDoScanner, criar_detector_visual_local pipeline = PipelineDoScanner([AnaliseVisualDaTimeline(criar_detector_visual_local())]) contexto = pipeline.executar(contexto) ``` O resultado fica em `contexto.caracteristicas_visuais` (por clipe), `contexto.cenas_visuais` (cenas com observações) e `contexto.avisos`. Quando OpenCV/FFmpeg ou outro adapter opcional não estiver disponível, o clipe é marcado com `disponivel=False` e os demais continuam sendo processados. ## Montagem recomendada para Apple Vision ```python from engine.scanner import AnaliseVisualDaTimeline, PipelineDoScanner, criar_detector_apple_vision pipeline = PipelineDoScanner([ AnaliseVisualDaTimeline(criar_detector_apple_vision(intervalo_em_segundos=1.0)), ]) ``` Esse detector extrai PNGs do arquivo original com FFmpeg, usando o intervalo `inPoint`/`outPoint` do clipe, e não exporta imagens renderizadas pelo Premiere. Ele também recua a amostra no fim de vídeos muito curtos quando não há um frame decodificável exatamente no timestamp solicitado. Os analyzers de sequência não tentam concluir a intenção de uma pessoa. Eles retornam indícios temporais (`possivel_tremor`, `possivel_descontinuidade` e `possivel_frame_congelado`) para que a camada editorial decida como tratá-los.