6.5 Estrutura de Dados

No último post sobre CAPTCHAs nós vimos que a segmentação das imagens (separar uma imagem em várias imagens, uma para cada caractere) é um problema complicado. Definir uma largura fixa ou utilizar outros métodos ad-hoc para segmentar as imagens pode dar bons frutos, mas não é o suficiente para quebrar CAPTCHAs mais complexos, como o da Receita Federal.

Alguns meses atrás, tentamos resolver esse problema de várias formas. Uma delas foi utilizar algoritmos de agrupamento (\(k\)-médias) ou de identificação de conjuntos conectados. Esses algoritmos se mostraram instáveis e não aumentaram muito o poder preditivo. Outra ideia que tentamos foi criar vários critérios de corte fixos e incluir todas as colunas geradas na base de dados. Mas isso deixou nos deixou com uma dimensão muito grande pra tratar, e parecia que os modelos precisavam de muito mais dados pra começarem a funcionar.

Foi aí que o Daniel nos disse que estava trabalhando no pacote do Keras e que existia uma forma de trabalhar com a imagem completa, sem segmentar. A tarefa de segmentação seria “parametrizada” num modelão complexo de deep learning e conseguiríamos resolver o problema sem pré-processamento.

Inicialmente, eu e o Athos ficamos perplexos com a ideia. Foi só quando o Daniel mostrou um modelo que acertava 100% dos CAPTCHAs do TJMG que fomos convencidos, e passamos a chamar esse modelo de “magia negra”.

Vamos discutir como montar a base para fazer a magia negra.

6.5.1 Resposta

Nossa resposta não é mais uma categoria, e sim uma matriz. A matriz tem \(k\) linhas (número de letras em um CAPTCHA) \(p\) colunas (número de valores possíveis de um caractere). O elemento \((i,j)\) vale 1 se na posição \(i\) aparece a letra relativa à posição \(j\).

Assim,

g3kvjg

vira isso: (substituí 0 por '.' para ficar mais fácil de ver)

m <- "imgs/receita/captcha48ec12131bab_g3kvjg.png" %>% 
  read_captcha(ans_in_path = TRUE) %>% 
  first() %>% 
  with(y)
m[m == 0] <- '.'
as_tibble(m) %>% 
  rownames_to_column('posicao')

Isso para uma imagem. Vamos precisar de uma terceira dimensão, que são as “linhas” de nossa resposta (uma para cada CAPTCHA).

Nosso y final é um array de dimensões \(n \times k \times p\). Achou estranho? Estamos só começando!

6.5.2 Explicativas

Uma imagem nada mais é do que uma matriz de pixels. Cada elemento da matriz é um número entre zero e um indicando o quanto de cor há nesse pixel. Assim, zero significa preto (ausência de cor), e um significa branco (todas as cores). Valores intermediários dão escala de cinza. Para representar imagens com cores, é necessária uma terceira dimensão de tamanho 3, indicando os pesos de R (red) G (green) e B (blue), mas não faremos isso.

Assim, nossa base de dados de explicativas é um array de dimensões

\[ n \times h \times w \times 1 \]

em que \(h\) e \(w\) são a altura e a largura da imagem, respectivamente.