Redes Neurais: Do reconhecimento de caracteres para o reconhecimento de ruas

Neste texto assumo que o leitor tem conhecimentos básicos teóricos de redes neurais artificiais – apesar de eu mesmo ainda estar aprendendo algumas coisas básicas… XD

A ideia é, partindo daqui:

7775

(Exemplo do Matlab para reconhecimento de caracteres)

…chegar aqui:

reconhecimento de rua

(um trabalho da USP de São Carlos. só tenho a imagem salva aqui, mas eu procuro a referência se for do interesse de alguém nos comentários)

A primeira ideia, na verdade, era simplesmente ler o conteúdo desse segundo trabalho, da USP de São Carlos, e tentar reproduzir (pra depois melhorar). Mas ao começar a leitura me deparei com um material extenso, e que envolve muito processamento de imagem, o qual eu não tenho um conhecimento razoável a respeito, e uma tal segmentação em bloco, que não está fácil encontrar um bom material explicando. Isso somado a falta de tempo (MALDITOS CRÉDITOS OBRIGATÓRIOS!), me levou ao experimento que segue, de tentar pegar o exercício de reconhecimento de caracteres feito na matéria de Computação Neural, e tentar adaptar (pior que eu odeio adaptar… maldita fata de tempo…) para reconhecer ao menos o padrão da rua (se é reta, ou curva para esquerda, ou curva para direita).

E, se estou com tão pouco tempo, por que estou gastando tempo escrevendo ao invés de focar no trabalho? Porque o trabalho estava confuso e desmotivante, e as coisas ficam mais simples e claras quando explicamos pra alguém :)

Talvez a própria monografia devesse servir a esse propósito: eu escrevo os resultados e dificuldades, entendo melhor, e prossigo com o projeto. Mas não. Durante a escrita da monografia existe a preocupação com a formalidade, com “o que meu orientador vai pensar disso”, etc. Já em um texto no blog eu tenho muito mais liberdade, posso focar nos problemas do projeto, e, depois, posso pensar em pegar partes desse texto e deixar “bonitinho” pra por na monografia… :)

Analisando a situação

O primeiro problema é que o trabalho de reconhecimento de caracteres foi feito utilizando o tamanho do pixel. E o reconhecimento de ruas provavelmente seria feito em tons de cinza (mais de 50). Ou ainda em tons de todas as cores possíveis…

O ideal, talvez, olhando a foto do trabalho de São Carlos, seria listar todos os tons de asfalto possíveis, e com esses tons identificar o asfalto (a rua). Já se a rua não for asfaltada é um outro problema… XD Uma coisa por vez.

Eu já comecei algum estudo sobre identificar tonalidades nas fotos, mas gostaria de tentar uma abordagem apenas e diretamente com as redes neurais, sem precisar fazer qualquer tipo de processamento de imagem (pelos motivos já explicados).

Seguindo essa linha, e pelos exercícios que fiz com a Rede Hopfield, é possível que essa rede, treinada com algumas fotos (de rua reta e curva), consiga identificar algum padrão. Ou, como foi feito com no trabalho de reconhecimento de caracteres, a Rede MLP poderia ser a mais útil. Mas, se possível, não quero gastar tempo testando as duas, então vou para o aparentemente mais indicado: Hopfield.

Hopfield

Hopfield, pelo pouco que aprendi, parece ser a mais indicada para reconhecer padrões de imagens. Entretanto, infelizmente ainda não consegui rodar uma rede Hopfield no Matlab, apenas no software iSNS. Sim, existem os tutoriais, tudo se pode aprender… Mas se houver a opção por algo que eu já conheça, dado o tempo escasso, acho melhor ir por ela :)

(pausa para testes)

E, fazendo os testes no iSNS, no qual eu já tenho alguma familiaridade, me deparei com um sério problema de não conseguir treinar a rede com uma imagem preexistente colorida. O único modo no qual consigo inserir imagens e treinar a rede é com a “Hopfield picture”, que é uma opção em que você define as dimensões da imagem, e clica nos pixels (gigantes) para trocar a cor entre preto e branco. Até consigo importar as fotos da rua, mas não consigo inserir no treino da rede.

Eu gastaria mais tempo nisso, por acreditar que é a rede mais indicada, mas como o tempo continua escasso, e como estou mais familiarizado com a Rede MLP, vou voltar a ela.

MLP – agora vai, adaptando o reconhecimento de caracteres

(se em algum momento eu escrever MPL, foi engano meu, o Movimento Passe Livre não tem parte nesse trabalho, sorry)

No trabalho de reconhecimento de caracteres, feito com Rede MLP no Matlab, as “fotos” dos caracteres eram, na verdade, matrizes de bytes que foram geradas no próprio Matlab. Então, acredito que a forma de começar um teste similar com as fotos das ruas seria tentar importar as fotos para o Matlab transformando as informações das cores dos pixels em matriz de bytes.

Ler a imagem no Matlab foi fácil, só usar a função imread, que, no caso de uma imagem colorida, retorna uma matriz MxNx3. Para minha imagem de 960×720 gerou uma matrix de 720x960x3, imagino que esse 3 seja devido ao RGB (uma matriz para o vermelho, uma para o verde e uma para o azul). Para matar essa curiosidade, pensei em simplesmente imprimir as imagens separadamente:

imshow(img) % mostra a imagem normal (colorida)
imshow(img(:,:,1)) % mostra a imagem 1
imshow(img(:,:,2)) % mostra a imagem 2
imshow(img(:,:,3)) % mostra a imagem 3

Mas as três imagens se mostraram a mesma: a original em preto e branco. Vou perguntar no Stackexchange pra tentar descobrir o porquê.

Update: Responderam lá, as 3 imagens são sim o RGB, mas em tons de cinza. A primeira representa os tons vermelhos, em tons de cinza, a segunda os tons verdes e a terceira os azuis.

Agora,  seguindo o exemplo do reconhecimento de caracteres, criamos a rede neural com os comandos:

setdemorandstream(pi);
net1 = feedforwardnet(25);

Esse ‘setdemorandstream‘ evita que a saída da rede neural tenha a leve variância que as redes neurais normalmente têm, usado apenas para fins de tutorial. Não vou usar.

Já o feedforwardnet é o comando que efetivamente cria a rede (aqui com 25 neurônios ocultos).

O treino da rede neural é feito com os comandos a seguir:

net1.divideFcn = '';
net1 = train(net1,X,T);

Não estou encontrando uma boa explicação sobre o que é o divideFcn, a ajuda do Matlab diz:

This property defines the data division function to be used when the network is trained using a supervised algorithm, such as backpropagation.

As opções são:

divideblock – Partition indices into three sets using blocks of indices.
divideind   – Partition indices into three sets using specified indices.
divideint   – Partition indices into three sets using interleaved indices.
dividerand  – Partition indices into three sets using random indices.
dividetrain – Partition indices into training set only

Se você não entende inglês, relaxa, está no mesmo barco que eu, que apesar de entender inglês não entendi nada da explicação acima (por isso não vou fazer uma tradução meia boca e te confundir ainda mais). Talvez essa “função de divisão” seja algo básico em redes neurais, mas que eu ainda não estudei a respeito, ou não com esse nome. Eu volto a isso depois, se for algo realmente necessário.

Na segunda linha:

net1 = train(net1,X,T);

X representa a matriz, e T representa a matriz identidade. X é a imagem que eu importei, e agora vou fazer uma pausa pra procurar como crio a matriz identidade dela no matlab.

update: muito depois deste ponto, eu descobri que não precisa ser matriz identidade, apenas uma matriz com o mesmo número de colunas, representando as saídas para cada coluna de entrada.

(…)

Voltei! Encontrei a função eye, na qual se passa um número, e é retornada a função identidade com aquele número sendo a quantidade de linhas e colunas, o que me lembrou que a matriz identidade só é possível em uma matriz quadrada. Ou seja, ficou complicado trabalhar com minha imagem 960×720. Então, para fins de teste, vou truncar minha imagem para 720×720, cortando as bordas:

img720 = img(:,121:840,:);
size(img720)
ans =
   720   720     3

Agora podemos ter a matriz identidade:

T = eye(720);

E treinar a rede ‘net1’:

net1 = train(net1,img720,T);

Enquanto a rede treina eu pondero: “estou treinando uma rede neural com uma única imagem?…” Bom, é só pra começar a entender, depois eu penso nisso… XD

E temos o erro:

Inputs X is not two-dimensional

A imagem RGB é uma matriz tridimensional (uma dimensão para cada uma das 3 cores). Então, vamos trabalhar com a imagem em tons de cinza… Estou com esperança de chegar em algum resultado ainda hoje… :)

imgGray = rgb2gray(img2);

Ruflem os tambores…

E o resultado:

Out of memory.

Tenho 2.8 GB de memória livre… Acho que estou fazendo algo errado… :/

No dia seguinte…

Ok, parece que uma matriz 720×720 é um tanto exagerado para treinar rede, então vamos tentar diminuir a resolução da imagem (para isso usei o imagemagick, no Ubuntu).

Primeiro, fiz o teste em uma resolução ridiculamente baixa de 9×7, para confirmar que resolveria. E o resultado foi…

sucesso1

sucesso2

sucesso3

SUCESSO!

Primeiro passo dado! Claro, longe de ser algum resultado… estou treinando uma rede neural usando uma única imagem de 9×7… XD Mas foi o primeiro passo para entender o processo, agora posso seguir adiante :D

Quanto mais baixa a resolução, melhor a velocidade da rede neural, porém menos informação para a rede ter bons resultados. Vou supor que, em uma imagem onde eu consigo ver com certa facilidade a rua, a rede neural também deveria conseguir. Com isso, me parece um bom tamanho de resolução 48×36, 5% do tamanho original, como essa:

new-rua1

Esticando para fins de ilustração:

rua1-48x36-ampliado

Original:

rua1

Agora, para deixar a coisa mais séria, vamos lembrar de como funciona o exemplo de reconhecimento de caracteres: a rede é treinada com matrizes onde cada coluna representa uma letra do alfabeto. Ou seja, cada coluna da matriz X representa uma informação de entrada, e cada coluna da matriz T representa o resultado esperado.

Então, vou pegar as fotos que tirei das ruas, converter cada uma em uma coluna da matriz, e indicar (na matriz de saída, T) quais colunas/imagens representam ruas curvas para esquerda, ou curvas para direita (vou ignorar ruas retas em um primeiro momento pra facilitar).

E como virá um monte de código fonte e gráficos a seguir, estou movendo o conteúdo a partir daqui para uma nova postagem, essa já ficou comprida o bastante… :)

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s