Pular para o conteúdo
Higor Lorenzon
← Todos os cases

Serviço de identificação por visão computacional; apps mobile e web em dupla, 2026

Card Finder — a via óbvia não passou no teste

App em React Native e uma versão web que identificam cartas de Pokémon numa foto e devolvem o valor de mercado, ou uma lista de deck pronta para importar. A identificação roda num serviço próprio de visão computacional. O caminho óbvio falhou com fotos reais, e o método e o limiar de aceite que ficaram saíram do teste.

Stack
React Native,Expo,TypeScript,Vite,Python,FastAPI,OpenAPI
Pilares
  • Produto
  • Técnica
Imagem de capa — Card Finder — a via óbvia não passou no teste

O problema

Quem coleciona carta de Pokémon e quer saber quanto tem na mão faz isso carta a carta: digita o nome, escolhe a edição, confere o número, olha o preço. Com trinta cartas em cima da mesa, ninguém faz.

A ideia era tirar uma foto e receber os valores de volta. Depois apareceu um segundo uso: fotografar um deck montado e receber a lista pronta para importar no jogo digital.

O que descobri

Duas coisas, e as duas mudaram o caminho.

Comecei pelo óbvio: comparar imagem por hash perceptual. Ele gera uma assinatura numérica da foto e procura a mais parecida no catálogo, e é barato. Só que compara pixel, e no uso real o pixel é outro: a carta na mesa está impressa em português, o catálogo guarda o render em inglês, e o celular põe brilho no plástico. Testei outros métodos de recuperação lado a lado com ele, nas mesmas fotos, e em parte delas o hash deixava a carta certa longe do topo.

O que passou no teste foi trocar a assinatura por embedding, um vetor que descreve o conteúdo da imagem em vez dos pixels. Aí a tradução, o brilho e o ângulo pesam menos.

A segunda descoberta é do outro lado do mesmo problema: modelo de visão erra com confiança. Ele devolve uma carta que não existe naquela edição, ou acerta o nome e erra o número, e o grau de confiança que ele mesmo reporta continua alto. Num produto que fala de dinheiro, carta inventada é o usuário achando que tem um valor que não tem.

O que construí

Um serviço de identificação próprio, em Python, que roda local, e dois aplicativos em cima dele: um mobile em React Native com Expo e um web em Vite.

  • A foto entra inteira e sai em cartas: o serviço acha cada carta na imagem, recorta e endireita antes de comparar.
  • Acima de um limiar de similaridade o resultado é aceito direto. Abaixo dele o serviço não chuta: marca a carta como incerta e confere o nome e o número impressos antes de decidir.
  • Quando o serviço próprio não responde, o app cai para um modelo externo. Só nesse caso: falha de infraestrutura tem um tipo de erro próprio, e o erro de domínio continua subindo em vez de ser engolido por um fallback genérico.
  • Toda carta reconhecida é conferida numa base pública antes de aparecer na tela, e o preço vem dessa base.
  • Os tipos do serviço são gerados a partir do OpenAPI dele, então mudança de contrato quebra no TypeScript, não em produção.
  • A interface é uma conversa em vez de um formulário. Manda a foto, recebe as cartas.

Resultado

O teste com fotos reais mostrou onde o aceite automático estava errado: cartas erradas passavam do limiar de confiança. Subi o limiar até nenhuma passar, e esses casos voltaram para o caminho da verificação.

A imagem não resolve tudo. Quando a mesma arte aparece em edições diferentes, quem decide é o número impresso na carta.

Os dois fluxos do produto estão implementados: valor de mercado por carta, e lista de deck no formato que o Pokémon TCG Live importa.