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.