RELATÓRIO DE PROJETOS 2
INE – DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA
Visão Robótica – Detecção de Movimento
Autor:
Carlos Eduardo Lenz
Orientador: Mauro Roisenberg
Banca Examinadora:
Jorge Muniz Barreto
Jovelino Falqueto
Sumário
Lista de Figuras ...V
Lista de Abreviaturas...VII
Resumo ... VIII
1. Introdução ...1
1.1 Objetivos ... 1
1.2 Motivação ... 2
1.3 Estrutura do Trabalho ... 2
2. Processamento Digital de Imagens ...4
2.1 Etapas... 4
2.2 Ferramentas ... 6
2.2.1 Histograma de Tons-de-Cinza ... 6
2.2.1.1 Contraste Normal ... 7
2.2.1.2 Baixo Contraste... 7
2.2.1.3 Alto Contraste ... 8
2.2.2 Operações Pontuais... 8
2.2.3 Operações Algébricas ... 10
2.2.4 Segmentação ... 10
2.2.4.1 Segmentação de Imagens por Limiarização ... 11
2.2.4.2 Estrutura da Imagem Segmentada ... 13
2.3 Medidas e Classificação... 13
2.3.1 Medidas de tamanho... 14
2.3.2 Medidas de forma ... 14
2.3.3 Classificação ... 15
2.3.3.1 Probabilidades... 15
2.3.3.2 Regra de Decisão ... 15
2.3.3.3 Treinamento ... 15
2.3.3.4 Performance ... 15
3. Robótica...17
3.1 Robô ... 18
3.2 Histórico... 18
3.3 Lego RCX ... 18
3.3.1 Hardware ... 19
3.3.3 LegOS... 21
3.3.3.1 Biblioteca de funções do LegOS ... 22
3.3.3.1.1 Motores ... 22
3.3.3.1.2 Sensor de Luz ... 22
3.3.3.1.3 Sensor de Toque ... 23
3.3.3.1.4 LCD ... 23
3.3.3.1.5 Botões ... 23
3.3.3.1.6 Processos ... 24
3.3.3.2 O Protocolo LNP ... 24
3.3.3.2.1 Integrity Messages ... 25
3.3.3.2.2 Addressing Messages ... 25
3.3.3.2.3 Funções do LegOS para comunicação ... 26
4.1 Captura e Processamento das Imagens ... 28
4.1.1 Classe Região... 28
4.1.2 Classe CBitmapEx ... 28
4.1.3 Classe CFrameGrabber ... 29
4.1.4 Classe CAboutDlg ... 29
4.1.5 Classe CFrameGrabberTestApp... 30
4.1.6 Classe CMainFrame ... 30
4.1.7 Classe CFrameGrabberTestView ... 30
4.1.7.1 Método OnTimer ... 31
4.1.8 Classe CFrameGrabberTestDoc ... 33
4.1.8.1 Método ProcessImage... 33
4.1.8.2 Método Limiarizar... 35
4.1.8.3 Método SeparaRegioes ... 36
4.1.8.4 Método Envia ... 36
4.2 Comunicação ... 37
4.2.1 Classe CComm ... 37
4.2.2 Classe CTower... 38
4.2.3 Classe CLNP... 38
4.2.4 Camada de Transporte... 38
4.3 Controle do Robô ... 42
4.3.1 Processo de Segurança para Permanência do Robô na Arena ... 43
4.3.2 Processo Tratador de Pacotes Recebidos... 44
5. Experimento ...46
5.1 Objetivo... 47
5.2 Robô ... 47
5.3 Interface do Programa ... 47
5.4 Resultados... 49
6. Conclusão ...50
6.1 Sugestões para Trabalhos Futuros ... 50
Referências Bibliográficas ...52
Anexo A – Código Fonte ...53
Lista de Figuras
Figura 2.1 – Imagem em tons de cinza ... 5
Figura 2.2 – Imagem RGB... 5
Figura 2.3 – Imagem com contraste normal ... 7
Figura 2.4 – Histograma do canal verde da imagem 2.3... 7
Figura 2.5 – Imagem com baixo contraste. ... 7
Figura 2.6 – Histograma do canal vermelho da imagem 2.5... 8
Figura 2.7 – Imagem com alto contraste... 8
Figura 2.8 – Histograma do canal azul da imagem 2.7. ... 8
Figura 2.9 – Imagem obtida através de: f(x) = 255 – x ... 9
Figura 2.10 – Imagem limiarizada com limiar “lim = 100” ... 12
Figura 3.1 – RCX... 19
Figura 3.2 – Motor ... 20
Figura 3.3 – Sensores de luz(cor) e toque. ... 20
Figura 3.4 – Torre de comunicação infra-vermelha ... 21
Figura 3.5 – Programa criado pela Lego para desenvolvimento do robô ... 21
Figura 3.6 – Formato das Integrity Messages ... 25
Figura 3.7 – Formato das Addressing Messages ... 25
Figura 4.1 – Visão Geral do sistema. ... 27
Figura 4.2 – Janela Sobre ... 29
Figura 4.3 – Janela Principal com um quadro capturado. ... 30
Figura 4.4 – Método de Suavização ... 32
Figura 4.5 – Reta usada para determinar a direção do robô ... 36
Figura 4.6 – Sucesso... 39
Figura 4.7 – Pacote perdido... 40
Figura 4.8 – ACK perdido. ... 40
Figura 4.9 – Timeout Prematuro. ... 41
Figura 4.10 – Pacote corrompido. ... 41
Figura 4.11 – ACK corrompido... 41
Figura 4.12 – Máquina de estados finitos versão Robô. ... 42
Figura 4.14 – Esquema de funcionamento do programa de controle do robô. ... 43
Figura 5.1 – Arena pronta para o experimento... 46
Figura 5.2 – Menu Controle -> Processador de Imagens. ... 48
Figura 5.3 – Menu Controle -> Cor... 48
Lista de Abreviaturas
ACK
Acknowledgment
PC
Personal
Computer
RGB
Red-Green-Blue
USB
Universal Serial Bus
MIT
Massachusetts Institute of Technology
ROM
Read Only Memory
RAM
Random Access Memory
GCC
GNU Compiler Collection
GNU
GNU's Not Unix
SO
Sistema
Operacional
IEEE
Institute of Electrical and Electronics Engineers
POSIX
Portable Operating System Interface
LCD
Liquid Crystal Display
CPU
Central Processing Unit
LNP
LegOS Networking Protocol
MFC
Microsoft Foundation Classes
OSI
Open Systems Interconnect
Resumo
Este trabalho busca estudar as técnicas de reconhecimento de padrões em
imagens que servem a sistemas de visão robótica. Para tanto as ferramentas de
processamento digital de imagens são apresentadas e implementadas em um programa.
Assim o problema de navegação de robôs autônomos é resolvido através da detecção de
movimento em imagens captadas por uma câmera digital. A comunicação entre o robô e
uma unidade controladora que é responsável pela câmera também é tratada.
A implementação consiste de um sistema completo de visão computacional que
permite o estudo de diferentes aspectos do controle de robôs, como a detecção de alvos
ou de intrusos, a navegação e comunicação com uma unidade de controle.
Palavras-chave: robótica, processamento digital de imagens, reconhecimento de
padrões, visão robótica, navegação de agentes autônomos.
1. Introdução
Nestas últimas décadas a Revolução Industrial tem atingido seu ápice. Após
séculos buscando a construção de sistemas para execução de tarefas mecânicas,
construímos os robôs. Estes não são mais controlados por complexos mecanismos
mecânicos, mas por programas em software ou diretamente em hardware (isto é,
microchips). Assim, substituindo o programa de controle, temos um robô com
capacidades completamente diferentes.
A popularização e crescente capacidade de processamento dos microchips,
aliados a um mercado de trabalho cada vez mais qualificado (principalmente nos países
desenvolvidos) e conseqüentemente avesso à possibilidade de operar máquinas pesadas
manualmente, levaram ao desenvolvimento de robôs para as mais variadas tarefas.
Eventualmente essas tarefas têm ficado cada vez mais complexas e os robôs cada vez
mais sofisticados.
Muitos robôs hoje já são controlados ou navegados com base em imagens, em
vez de usar apenas os mais tradicionais sensores. Principalmente os robôs autônomos
que precisam juntar todas essas informações para navegar pelo seu ambiente e
oferecendo as reações corretas aos estímulos. Isto é, com respostas precisas.
A Visão Computacional emprega várias técnicas, algoritmos e ferramentas
matemáticas para analisar imagens estáticas ou em movimento (isto é, quadros de um
vídeo). Seja para identificar objetos, reconhecer padrões, detectar obstáculos ou resolver
problemas de navegação, entre outros, a Visão Computacional usa os recursos
disponibilizados a partir dos avanços no Processamento Digital de Imagens.
Combinando a Visão Computacional às restrições dos robôs, que contam com
processadores limitados e operam em ambientes desconhecidos ou vastos demais, surge
a Visão Robótica. As informações fornecidas são então processadas junto de outras
vindas de vários tipos sensores para determinar o procedimento do robô, em alguns
casos também se baseando na experiência passada.
1.1 Objetivos
movimento, para isso elas são implementadas em um programa e testadas em um
experimento. Avaliar também a qualidade das respostas do robô, sua navegabilidade na
busca de um alvo quando acontece a identificação de um alvo.
Isto é, foi implementado em PC um programa para detecção de movimento
voltado para a plataforma onde o robô Lego Mindstorms © é operado. Integrando robô e
PC através de transmissão infravermelho, permitindo ao robô seguir com precisão em
direção de qualquer intruso na cena.
Aplicam-se a esse trabalho somente as técnicas de Visão Computacional para a
detecção de movimento, e possivelmente também alguma técnica básica de tratamento
de imagens para auxiliar a análise ou melhorar os resultados.
1.2 Motivação
Com base nessa realidade, a motivação para este trabalho é encontrada na
possibilidade de contribuir e fornecer um auxílio aos alunos e simpatizantes da área de
robótica e visão computacional, fornecendo em linhas gerais um estudo prático sobre o
controle e navegação de robôs usando o método de navegação baseada em visão
robótica.
1.3 Estrutura do Trabalho
O capítulo 2 consiste de relatório da pesquisa feita na área de Processamento
Digital de Imagens, detalhando as principais ferramentas que poderão ser empregadas
na implementação do programa.
A
Robótica é introduzida no capítulo 3, junto com uma descrição do robô Lego
usado na implementação deste trabalho. Outras características importantes como as
ferramentas de desenvolvimento e a câmera também descritas aqui.
Finalmente a proposta de Implementação é detalhada no capítulo 4. As técnicas
de Processamento Digital de Imagens usadas são descritas, junto com os parâmetros
utilizados. As limitações ou características do robô e do sistema de comunicação são
também analisadas e as soluções obtidas apresentadas. Topologia, número de neurônios,
função de transferência, entradas e saídas da rede neural usada no controle do robô
também são justificadas. O sistema como um todo é descrito, junto com a função de
cada módulo.
O Experimento que foi feito para validar o programa é apresentado no capítulo
5. Os resultados obtidos bem como uma avaliação do funcionamento do sistema
também faz parte deste capítulo.
As Conclusões, como resultados práticos, dificuldades encontradas e limitações
da plataforma Lego, ou dos equipamentos usados nos testes encontram-se no capítulo 6.
Sugestões de trabalhos futuros também estão neste capítulo.
2. Processamento Digital de Imagens
Na sua ânsia de registrar os acontecimentos, o homem já criou vários métodos
de capturar imagens. Todas essas técnicas e tecnologias permitiram que surgisse a
captura de imagens através da digitalização, que permitiram armazenar e manipular
imagens no computador.
O Processamento Digital de Imagens pode ser divido em várias etapas:
2.1 Etapas
A digitalização de imagens é justamente o processo de transferir as informações
de cor, forma, etc presentes na imagem para uma forma compreensível para o
computador. Nesse processo a imagem é transformada de um sinal analógico para um
digital (discreto).
A origem dessa imagem pode ser uma cena real captada por uma lente ou um
papel com um desenho (ou foto) que os sensores de um scanner reconhecem. Ou
mesmo uma câmera digital, como neste trabalho.
Exceto para uma possível análise e correção dos mecanismos de digitalização, a
origem da imagem ou método de digitalização não importam mais, a partir do momento
que as informações estão no computador.
No computador a imagem é representada como uma grade de pixels. Pode-se
considerar que os pixels são os menores elementos distinguíveis numa imagem digital,
portanto são às vezes chamados de pontos.
O tamanho dessa grade determina a dimensão da imagem. Por exemplo:
640x480 pixels. A quantidade de pontos que um dispositivo digitalizador pode
reconhecer por polegada é uma característica importante que recebe o nome de
resolução.
Existem várias formas de codificar as cores. Dois formatos muitos populares são
o grayscale, que representa tons de cinza apenas, e o RGB, que representa a cor como
uma combinação de vermelho, verde, e azul. As escalas de cinza usam um número de
bits que varia de acordo com o número de tons de cinza que se deseja representar,
tipicamente até 256. Assim para representar 8 tons são usados 3 bits por ponto.
Tipicamente o 0 (zero) representa o preto e o 255 o branco.
Figura 2.1 – Imagem em tons de cinza
No caso da RGB usam-se 8 bits para representar até 256 valores para cada cor.
Tendo 8 bits de vermelho, 8 bits de azul e 8 bits de verde é possível representar
qualquer cor que um monitor atual pode mostrar. Essa combinação das 3 cores pode
representar até 2 ^ 24 cores e é chamada True Color. O próprio olho humano não
consegue diferenciar muitas das cores mais próximas. Também é usada uma graduação
que representa cada cor por um número real entre 0 e 1.
Figura 2.2 – Imagem RGB
A etapa de Pré-processamento visa corrigir defeitos básicos da imagem, muitas
vezes surgidos durante o processo de aquisição. Durante essa esta etapa pode ser feito
um realce em determinas características da imagem. Também nessa fase defeitos
observados durante a digitalização podem ser corrigidos, como imagens de alto ou
baixo contraste.
A Segmentação é a etapa mais crítica e visa distinguir os elementos da imagem
entre si e do fundo. Permite agrupar pixels contíguos em regiões. Devido à ausência de
um modelo formal, esse processo que tenta imitar o complexo processo cognitivo
realizado pelo cérebro humano, tornando-se basicamente empírico. Mas para corrigir
eventuais falhas desse processo pode existir uma etapa seguinte, de
Pós-processamento.
Com os objetos que compõem a imagem já separados, chega a etapa de
Extração de Atributos, que obtém informações sobres esses objetos, como medidas de
diâmetro, largura, aspecto, e outros. Com esses dados é possível fazer a Classificação e
reconhecimento dos objetos na cena.
2.2 Ferramentas
Embora as técnicas abordadas daqui para frente se refiram a tons-de-cinza, elas
também podem ser aplicadas para imagens coloridas, operando sobre cada cor primária
em separado.
2.2.1 Histograma de Tons-de-Cinza
Entre as operações mais simples sobre imagens digitais está o histograma. Esta
operação pode revelar muita informação sobre uma imagem. Consiste de uma função
mostrando quantas vezes cada tom aparece na imagem. O histograma mostra o
tom-de-cinza no eixo das abscissas enquanto a freqüência de ocorrências está no das ordenadas.
Quando é produzido um histograma, toda a informação espacial é perdida.
Entretanto isso não afeta seus principais usos: detectar quando a digitalização não
encontrou bons resultados, ou indicar que transformações a aplicar na imagem.
Imagens com baixo-contraste são aquelas que onde vários tons não são usados.
Assim a imagem ocupa mais espaço que o necessário. Já o contrário também é ruim,
pois os detalhes são perdidos. Esse problema aparece através de picos nas extremidades
do histograma (0 e 256).
2.2.1.1 Contraste Normal
Figura 2.3 – Imagem com contraste normal
Figura 2.4 – Histograma do canal verde da imagem 2.3.
2.2.1.2 Baixo Contraste
Figura 2.6 – Histograma do canal vermelho da imagem 2.5.
2.2.1.3 Alto Contraste
Figura 2.7 – Imagem com alto contraste.
Figura 2.8 – Histograma do canal azul da imagem 2.7.
2.2.2 Operações Pontuais
Outro tipo de operação simples sobre imagens digitais é a operação pontual.
Diferente do histograma, a operação pontual toma uma imagem como entrada e produz
outra como saída. Ao contrário de outras técnicas usadas mais a diante, nesta operação a
cor de um ponto é apenas dependente da cor do mesmo ponto na imagem original, e não
de outros pontos.
Matematicamente falando a nova imagem B é gerada pela imagem A assim:
B(x,y) = f[A(x,y)]
Assim se a função f é linear:
f(x) = ax + b
Esse caso (quando f é linear) recebe um nome próprio: Operações Lineares
sobre pontos (linear point operations) e merece uma análise especial sobre seus
parâmetros a e b.
a) Quando
a é 1 (um) e b é 0 (zero), a imagem não se altera.
b) O contraste é reduzido quando a é menor que 1 (um) e incrementado quando é
maior.
c) Quando a é 1 (um) e b é diferente de 0 (zero), a imagem inteira é escurecida ou
clareada.
d) Finalmente a negativo inverte (complementa) as cores. O que é claro fica escuro
e vice-versa.
Figura 2.9 – Imagem obtida através de: f(x) = 255 – x
Operações pontuais podem acrescentar contornos à imagem. Ou também
limiarização, que divide a imagem em regiões disjuntas baseado nos tons-de-cinza, o
que permite definir fronteiras ou a construção de máscaras para outras operações. Com a
escolha de uma função f adequada a imagem gerada terá o histograma desejado,
retangular ou gaussiano, ajudando na comparação de imagens digitalizadas de modos
diferentes.
2.2.3 Operações Algébricas
Para juntar 2 imagens existem as operações algébricas, que tomam as imagens
ponto-a-ponto e realizam uma operação matemática básica (adição, subtração,
multiplicação ou divisão por uma constante). Essas operações podem ser combinadas e
a operação pode ser qualquer função com dois argumentos.
A adição de imagens é aplicada freqüentemente em seqüências de imagens com
ruído aleatório, reduzindo o mesmo na imagem resultante. Pode também ser usada para
colar uma imagem sobre a outra.
Para remover um padrão presente na imagem a subtração é usada. Esse padrão
pode ser um padrão de sombreamento no fundo da imagem ou um ruído periódico. A
subtração também é usada para detectar movimento, computando as diferenças entre
imagens da mesma cena, ou no cálculo do gradiente que é usado para detectar bordas.
A operação de multiplicação pode ser usada junto de máscaras para borrar partes
duma imagem deixando intactas as partes de interesse.
2.2.4 Segmentação
Para realizar uma análise no conteúdo de uma imagem, é importante primeiro
segmentá-la, isto é, encontrar suas partes: os objetos da cena. Muitos estudos foram
feitos e existem inúmeras metodologias para fazer a segmentação de imagens, como o
chamado Reconhecimento de Padrões Óticos. Essa estratégia assume que a imagem
contém vários objetos e seu objetivo é encontrá-los, distinguindo entre os vários tipos.
Numa primeira etapa todos os objetos da imagem são encontrados e separados
uns dos outros e do resto da imagem. Em seguida cada objeto é analisado em separado,
e algumas informações são então extraídas. Essas medidas são postas num vetor de
características que é usado pela última etapa, que classifica os objetos entre os diversos
tipos reconhecidos pelo sistema.
O projeto de um sistema de reconhecimento de padrões pode ser dividido em 5
partes:
a) O projeto do localizador de objetos envolve a escolha do algoritmo para a
separação de objetos na cena.
b) A seleção das propriedades que melhor permitirão a posterior classificação
acontece na seleção de características.
c) O estabelecimento do algoritmo de classificação com base na matemática e da
estrutura de classificação ocorre na fase de projeto do classificador.
d) Os parâmetros onde o classificador permite ajustes são corrigidos durante o
treinamento do classificador.
e) Os erros de classificação devem ser determinados, finalizando todo o projeto
com a avaliação de performance.
Definições: A segmentação particiona uma imagem em regiões distintas. Região é um
conjunto de pixels conectados. Nesse todos os pixels são adjacentes ou se tocam. Entre
dois pixels quaisquer num conjunto conectado, existe um caminho conectando ambos.
Existem duas perspectivas para a segmentação de imagens. Numa os pixels são
analisados e agrupados pela cor em regiões (aproximação por regiões). Noutra os
contornos entre as regiões são localizados primeiro (aproximação por contornos).
2.2.4.1 Segmentação de Imagens por Limiarização
Essa técnica de aproximação por regiões é simples e rápida. É útil para cenas
com objetos sólidos sobre um fundo com o qual contrastam. Nela todos os pixels com
tom de cinza igual ou maior ao limiar fazem parte do objeto, mas os outros não. Assim
as bordas são todos o pixels pertencentes à região que tocam pixels fora da região.
Para que a limiarização funcione bem, o objeto deve ter em seu interior um tom
de cinza uniforme, e o fundo também, sendo ambos os níveis diferentes. Se esse não é o
caso, mas ocorre outra propriedade que atende esses requisitos, então essa propriedade
pode ser convertida para tom de cinza para que a técnica seja aplicada.
Figura 2.10 – Imagem limiarizada com limiar “lim = 100”
Limiarização Global: nesse tipo o limiar é mantido constante por toda a imagem.
Limiarização Adaptativa: quando o contraste entre o objeto e o resto da cena varia ao
longo da imagem, uma função que varia lentamente conforme a posição na imagem
pode ser usada como limiar.
Em geral, a variação do valor do limiar pode ter um considerável impacto no
tamanho do objeto, a menos que a imagem tenha margens muito íngremes. Por isso,
para não prejudicar as medidas futuras (baseadas na forma e tamanho do objeto), a
escolha de um método ótimo, ou quase, é importante. Baseando-se num histograma
onde estejam presentes os dois picos que caracterizam o contraste entre o objeto e o
fundo, o ponto de mínimo entre os 2 pontos de máximo é uma boa aproximação para
um valor de limiar.
2.2.4.1.1 Limiarização da Imagem Gradiente
Esta técnica foi criada por Kirsh, e é do tipo “aproximação por contorno”. Nela,
uma limiarização é aplicada sobre a imagem gradiente com um limiar relativamente
baixo. Esse limiar é gradualmente aumentado até que as partes pertencentes ao objeto e
ao fundo se toquem. Nesse momento os pontos de encontro são os contornos. É um
método lento e só funciona se a primeira limiarização não uniu o objeto com o fundo. O
gradiente é uma função que aplicada aos pontos da imagem apresenta valores altos para
áreas com declives íngremes, como as bordas de um objeto.
2.2.4.2 Estrutura da Imagem Segmentada
O método mais simples (mas que desperdiça recursos) consiste em usar uma
nova imagem para guardar os objetos encontrados na imagem original. Os objetos
seriam diferenciados então por uma codificação de cores, uma para cada objeto.
Outra alternativa seria codificar apenas os contornos de cada objeto em
separado, guardando duas coordenadas (x,y) onde o contorno começa e uma série de
códigos de bits indicando qual dos pixels adjacentes é a continuação do contorno.
Os objetos também podem ser codificados por linhas, indicando para cada linha
o início e fim de cada segmento acima do limiar. Essa técnica tem a vantagem de se
encaixar perfeitamente no processamento de uma limiarização e de facilitar a extração
de informações importantes como área, perímetro, comprimento, largura e outras.
2.3 Medidas e Classificação
Para distinguir objetos de tipos diferentes é preciso que as características que
possam diferenciar os mesmos sejam extraídas da imagem segmentada e enviadas ao
classificador. Essas características são uma descrição do objeto que, se bem escolhidas,
podem tornar o processo de classificação mais eficaz.
Obviamente, nem todas as possíveis características são calculadas. Embora esse
processo seja intuitivo, 4 avaliações podem ser feitas para ajudar na escolha das
características que serão implementadas:
1. Distinção: os valores das características avaliadas devem ser significativamente
diferentes entre objetos de tipos diferentes. Ex: se os objetos devem ser
classificados entre grandes e pequenos, o diâmetro pode diferenciá-los.
2. Confiabilidade: os objetos de mesma classe devem ter valores similares. Ex:
diferenciar frutas pela cor pode não ser confiável se elas apresentarem diferenças
na cor dependendo de sua maturação.
3. Independência: não devem ser usadas características que sejam altamente
correlatas.
4. Poucas informações: com muitas características para avaliar torna-se lento o
treinamento do classificador porque sua complexidade cresce exponencialmente.
Poucas informações não correlatas favorecem a performance.
O classificador teve muitas estruturas investigadas, mas muitas decisões são
basicamente uma regra de limiarização. Tendo o projeto do classificador sido feito, com
a escolha de sua estrutura e das características, é o momento de treiná-lo para
determinar os valores dos limiares. Um conjunto de treinamento é usado, os erros são
medidos e os limiares determinados para minimizar tais erros. A performance então
pode ser medida, mas é mais realista que seja usado um conjunto somente para testes.
2.3.1 Medidas de tamanho
Todas as características abaixo estão relacionadas com o tamanho do objeto:
A. Área: número de pixels dentro da imagem e no contorno multiplicado pela área
de um único pixel.
B. Densidade Ótica Integrada: soma dos tons de cinza de todos os pixels dentro
do objeto.
C. Comprimento e Largura: o cálculo desses valores é muito simples, desde que
os objetos não estejam rotacionados, mas também existem cálculos para estes.
D. Perímetro: o número de pixels no contorno do objeto pode sofrer alterações
significativas se a imagem apresenta ruído.
2.3.2 Medidas de forma
Agora as características que estão relacionadas com a forma do objeto:
A. Retangularidade: razão entre a área do objeto e a área do menor retângulo que
poderia contê-lo. Os valores variam na faixa (0,1] e pi/4 é assumido como valor
de objetos circulares.
B. Circularidade: o método mais usado de se avaliar a circularidade é dividindo o
perímetro ao quadrado pela área do objeto, assim valores superiores a 4 pi são
considerados círculos.
C. Perímetro: o número de pixels no contorno do objeto pode sofrer alterações
significativas se a imagem apresenta ruído.
2.3.3 Classificação
Os mecanismos de classificação estão baseados na Estatística e são apresentados
agora.
2.3.3.1 Probabilidades
Conhecendo as amostras, podemos determinar as probabilidades a priori, que
meramente relacionam à chance de um objeto em particular ser de alguma classe, sem
conhecer suas características. Se a probabilidade for relacionada a uma característica do
objeto, então ela é condicional.
Para juntar a as probabilidades a priori, condicionais e as medidas obtidas para
determinado objeto e calcular a probabilidade dele pertencer a determinada classe,
existe o Teorema de Bayes, que é chamada de probabilidade a posteriori.
2.3.3.2 Regra de Decisão
A função de custo é usada para quantificar o risco, e dá o custo de uma
classificação de um objeto de classe A erroneamente classificado B. A regra de decisão
de Bayes define que um objeto deve ser atribuído a uma classe que apresente o mínimo
risco condicionado.
2.3.3.3 Treinamento
Os dados de treinamento do classificador podem já estar classificados por uma
entidade livre de erros ou não, resultado num treinamento supervisionado ou não. Um
tipo de treinamento supervisionado chama-se estimativa de máxima probabilidade.
Ele assume que os parâmetros a serem estimados são desconhecidos, mas fixos. Os
dados de treinamento são considerados com grande chance de representarem
precisamente os dados reais, assim os parâmetros são determinados baseados nisso.
2.3.3.4 Performance
classificador a um conjunto de testes, semelhante ao conjunto de treinamento, mas
diferente dele. As etapas anteriores do processamento digital de imagens são muito
importantes para o resultado final do classificador, porque este é negativamente afetado
por má qualidade nas imagens.
3. Robótica
Conforme dito antes, a robótica tem se desenvolvido muito nos últimos anos e
tem se tornado muito importante para a humanidade.
O
termo
robô foi criado por Karel Capek, um ator e escritor Tcheco. Ele
introduziu esse termo ao mundo em 1921, numa peça chamada: Robôs Universais de
Rossum. A peça, que foi encenada primeiro em Praga, atingiu grande sucesso e como
resultado foi encenada também por toda a Europa e Estados Unidos. A peça trata da
desumanizarão do homem numa sociedade tecnológica.
Apesar de criador do termo, ele não anteviu os meios. Na sua visão os robôs não
seriam construídos de partes mecânicas, mas através de manipulações química. Ele
defendeu sua idéia num ensaio chamado “O autor dos Robôs se defende”, de 1935:
“É com horror, francamente, que ele rejeita toda a responsabilidade pela idéia de
que instrumentos metálicos poderiam algum dia substituir seres humanos, e que pelos
meios de fios metálicos poderia despertar algo como vida, amor, ou rebelião. Ele
poderia considerar sua negra esperança ser ou uma superestimação das máquinas, ou
uma grave ofensa contra a vida” (tradução de Robotics-faq).
Já o termo robótica refere-se ao estudo e uso de robôs. Esse termo foi cunhado
por Isaac Asimov, um escritor e cientista americano que nasceu na Rússia. Em 1942 ele
publicou uma história chamada “Eu, Robô”, onde o termo foi usado pela primeira vez.
Também foi ele que definiu as três leis da robótica (depois ele mesmo acrescentou a lei
zero):
•
Lei Zero: Um robô não pode causar mal à humanidade ou, por omissão,
permitir que a humanidade sofra algum mal, nem permitir que ela própria o faça.
•
Lei Um: Um robô não pode ferir um ser humano ou, por omissão, permitir que
um ser humano sofra algum mal.
•
Lei Dois: Um robô deve obedecer às ordens que lhe sejam dadas por seres
humanos, exceto nos casos que em tais ordens contrariem a Primeira Lei.
•
Lei Três: Um robô deve proteger sua própria existência, desde que tal proteção
não entre em conflito com a Primeira e a Segunda Leis.
3.1 Robô
Classicamente define-se um robô como um “manipulador multifuncional
programável, projetado para mover materiais através de movimentos programados que
realizam um variedade de tarefas”(Robot Institute of America, 1979). Entretanto numa
visão mais atual pode-se dizer que um robô é um: “agente artificial ativo cujo ambiente
é o mundo físico”. Um agente por sua vez pode ser definido como algo que percebe seu
ambiente através de sensores e atua nesse mesmo ambiente através de atuadores
(RUSSEL95). Robôs autônomos são aqueles que alteram seus planos durante a
execução, além de interagir com o ambiente.
3.2 Histórico
Os primeiros robôs industriais surgiram entre os anos 50 e 60. George Devol e
Joe Engelberger desenvolveram os Unimates. Devol patenteou as primeiras máquinas
de transferência de materiais. Já Engelberger fundou uma empresa chamada Unimation
que foi pioneira na comercialização de robôs. Por esse motivo a ele é atribuído o título
de Pai da Robótica (Robotics-faq).
Com o desenvolvimento dos controladores e linguagens, e o aperfeiçoamento de
sensores e motores os robôs se tornaram mais precisos. No começo da década de 80 a
indústria automotiva investiu maciçamente no desenvolvimento da robótica, assim a
maioria das fábricas hoje em paises desenvolvidos é quase completamente
automatizada.
3.3 Lego RCX
O kit de construção de robôs que a Lego comercializa como Lego Mindstorms™
foi produzido através de uma associação entre a fabricante de brinquedos Lego e o
Massachusetts Institute of Technology (MIT) nos EUA.
O MIT recebeu financiamento para suas pesquisas em robótica, aprendizado
infantil e outros tópicos avançados. No MIT foi desenvolvido um robô semelhante ao
que é comercializado pela Lego. Em retribuição aos fundos investidos, a Lego usa as
idéias criadas no MIT nos seus brinquedos. O Lego Mindstorms™ foi lançado em 1999.
Os produtos da linha Mindstorms variam entre 100 e 200 dólares. Há também
uma câmera (vendida separadamente) que permite que imagens sejam captadas para um
computador com porta USB.
3.3.1 Hardware
Um micro controlador Hitachi H8/3292, que é um processador 8 bits e funciona
a 16MHZ, comanda o robô. Ele tem 16 Kbytes de ROM programável, 512 bytes de
RAM interna, 8 registradores de 16bits cada e pode controlar até 3 motores, 3 sensores e
a porta serial de comunicação infravermelha. Os motores e sensores ficam encapsulados
em peças externas que podem ser encaixadas livremente no robô, como é comum nos
brinquedos Lego.
Figura 3.1 – RCX
O RCX é um circuito eletrônico que encapsula o microcontrolador e outras
partes do robô em um revestimento de plástico que permite a montagem de peças Lego
sobre ou sob ele. Ele possui 32Kbytes de RAM, um chip para controle dos motores,
outro para controle da tela. Ele é alimentado por um circuito de pilhas que gera 9V. Há
também botões para a operação do robô, uma interface infra-vermelha, um tela que
permite mostrar uns poucos caracteres e contatos para conectar sensores ou motores.
Figura 3.2 – Motor
Figura 3.3 – Sensores de luz(cor) e toque.
Quando o robô é ligado (pode usar baterias ou um conector AC que vem no kit)
ele executa um driver presente em 16 KiloBytes de memória ROM. Outros 16 Kilobytes
de firmware são transferidos para o microcontrolador. Então o robô passa a aceitar
comandos do PC através da porta de comunicação.
O usuário também pode transferir programas na forma de bytecode, que ocupem
uma área de memória de até 6 Kilobytes, para serem interpretados pelo firmware.
3.3.2 Comunicação
As trocas de informação entre o robô e o PC ocorrem sem fio ligando ambos,
através de raios infravermelhos. Mas entre a base de transmissão e o PC a comunicação
é serial através de um cabo DB9.
Figura 3.4 – Torre de comunicação infra-vermelha
3.3.3 LegOS
É um sistema operacional desenvolvido cooperativamente através da Internet
que pode ser usado para substituir o SO de fábrica, que acompanha o robô. Ele permite
programação em C e C++ junto com uma biblioteca de funções úteis tanto para
programação em geral quando para acessar o hardware presente. Markus L. Noga foi
seu criador e a Lego não participou do seu desenvolvimento.
Figura 3.5 – Programa criado pela Lego para desenvolvimento do robô
Existem outras alternativas com mais recursos que o programa para
desenvolvimento da Lego, entretanto nenhuma oferece tantos benefícios quanto o
LegOS. Seu único inconveniente é a necessidade de carregar o SO para o RCX antes do
programa. No LegOS o desenvolvimento é feito em C ou C++ e o código é compilado
usando o popular compilador GCC. Por isso, o código executado é nativo, e não mais
interpretado como no software original. Benefícios adicionais são o uso de todos os
32Kbytes para variáveis (antes limitadas a 32), a possibilidade de armazenar até 8
programas e o fato de ser um SO multitarefa que escalona os processos
preemptivamente de acordo com as prioridades.
3.3.3.1 Biblioteca de funções do LegOS
Para controle dos motores, sensores, da comunicação, tela, criação de processos,
cálculos matemáticos (inclusive com números de ponto flutuante IEEE float e double) o
LegOS disponibiliza um ampla biblioteca de funções. Existem também outras
funcionalidades de uso geral na biblioteca, apenas para facilitar o desenvolvimento,
como geração de números aleatórios, semáforos POSIX, manipulação de cadeias de
caracteres, etc.
3.3.3.1.1 Motores
A biblioteca <dmotor.h> tem as funções que permitem o controle dos motores
acoplados ao robô. Nas funções abaixo, X deve ser substituído por a, b, ou c, para
indicar o 1
o, 2
oou 3
omotor:
•
enum MotorDirection. É uma enumeração que possui 3 valores: fwd, rev e
brake.
•
motor_X_dir(enum MotorDirection). Para mudar a direção em que o motor
opera: fwd quer dizer pra frente, rev quer dizer pra trás (ré), e brake quer
dizer parar(ou freiar).
•
motor_X_speed(unsigned char). Altera a velocidade do motor. A velocidade
deve estar entre 0 e 255.
3.3.3.1.2 Sensor de Luz
O nível de luminosidade captado pelos sensores é acessado lendo uma constante
que é atualizada pelo SO a cada 0,25 ms. Existem 3 constantes, que são chamadas
LIGHT_1, LIGHT_2 e LIGHT_3 e elas estão disponíveis na biblioteca <dsensor.h>.
Podem ser acoplados até três sensores de luminosidade que correspondem as
constantes citadas, mas eles podem ser acessados de maneira diferente, ativa ou passiva,
e para isso devem ser configurados com uma das funções abaixo (X deve ser substituído
por a, b, ou c para indicar o 1
o, 2
oou 3
osensor):
•
ds_passive(&SENSOR_X). Muda o sensor para modo passivo. Nesse
modo, o sensor apenas capta a luminosidade do ambiente sem interferir.
•
ds_active(&SENSOR_X). Muda o sensor para modo ativo. Assim o
próprio sensor emite luz e capta a luminosidade refletida.
3.3.3.1.3 Sensor de Toque
Acessado através das constantes TOUCH_1, TOUCH_2 e TOUCH_3, que são
atualizadas e operadas como as do sensor de luz e também são acessadas através da
biblioteca <dsensor.h>. Essas variáveis podem assumir 2 valores: 1 quando foi
detectado toque, ou 0 quando não.
3.3.3.1.4 LCD
O RCX possui uma tela que pode ser usadas para mostrar pequenas mensagens.
Assim a depuração de programas fica um pouca mais fácil. As funções abaixo ficam
disponíveis incluindo a biblioteca <dlcd.h>.
•
lcd_int(int). O inteiro é mostrado no LCD.
•
lcd_clear(). Apaga o que foi escrito na tela.
•
cputs(char*). Escreve os primeiros 5 caracteres da string na tela.
3.3.3.1.5 Botões
Os botões também podem ser usados na programação do RCX. Assim pode-se
alternar entre várias opções que alteram o robô durante o funcionamento. Essas funções
estão disponíveis na biblioteca <dbutton.h>.
•
PRESSED(int a, int b). Esta macro retorna verdadeiro se o botão b esta
pressionado. O argumento a deve ser substituído por dbutton(), que
retorna o estado geral dos botões. O argumento b indica qual botão deve
estar pressionado: BUTTON_PROGRAM,
BUTTOM_ONOFF,
BUTTON_RUN, ou BUTTON_VIEW.
•
RELEASE(int a, int b). Esta macro funciona como a anterior, mas retorna
verdadeiro se o botão não está pressionado.
3.3.3.1.6 Processos
Várias funções semelhantes às encontradas no sistema operacional UNIX para
controle de processos estão na biblioteca <unistd.h>.
•
execi(função, argc, argv). Cria um novo processo chamando a função
com os argumentos argc e argv, como se fosse a função main.
•
exit(int). Finaliza o processo atual.
•
yield(). O processo atual libera o CPU para ser usado por outro processo.
•
wait_event(função, int). Chama a função até que ela retorne um valor
diferente de zero. Assim ela trava o processo atual até que um condição
seja satisfeita.
•
sleep(int x). O processo atual é suspenso por x segundos.
•
msleep(int x), Igual a função anterior, mas por apenas x milisegundos.
•
kill(pid_t pid). Força o fim da execução do processo pid.
3.3.3.2 O Protocolo LNP
Para que fosse possível trocar informações com o robô em tempo de execução os
desenvolvedores do LegOS desenvolveram o “LegOS Networking Protocol”. Essa
comunicação é realizada através de infravermelho, usando a porta infravermelha do
RCX e a torre de comunicação infravermelha conectada ao computador. Essa
comunicação pode ocorrer através de dois tipos de mensagens: Integrity Messages e
Addressing Messages.
3.3.3.2.1 Integrity Messages
Essa mensagem é envia da por Broadcast, assim qualquer RCX ou computador
apto vai recebê-la.
Figura 3.6 – Formato das Integrity Messages
O campo F0 é o identificador do pacote, e tem 1 byte. LEN também tem 1 byte e
traz o tamanho do bloco IDATA. IDATA é um bloco de dados com entre 0 e 255 bytes
que leva a mensagem em si. Para checagem de erros o campo CHK contém o checksum
da mensagem. Totalizando a mensagem tem no máximo 258 bytes.
3.3.3.2.2 Addressing Messages
Para mandar mensagens para um RCX específico, as Addressing messages tem
campos para identificar o nó quem envia e a quem é endereçada.
Figura 3.7 – Formato das Addressing Messages
Nesse tipo de mensagem algums campos permanecem iguais aos das Integrity
Messages, tanto em tamanho quanto em função. Os novos campos DEST e SRC são
para os números dos nós destino e o origem, respectivamente, e ambos tem 1 byte. O
campo ADATA é o novo campo de dados em tem o tamanho de IDATA subtraído dos
tamanhos de DEST e SRC, uma Addressing Message pode enviar até 253 bytes de
informação útil.
Num meio de transmissão como o ar, não há como impedir que outros aparelhos
ou qualquer RCX próximo receba o sinal, e assim o LegOS de qualquer que não seja o
do campo DEST ignora a Integrity Message, não a repassando às camadas de aplicação.
3.3.3.2.3 Funções do LegOS para comunicação
O LegOS possui funções para enviar e receber tanto Integrity messages quanto
Addressing Messages. Elas são acessíveis através das bibliotecas <lnp/lnp.h> e
<lnp/lnp-logical.h>. Abaixo seguem as utilizadas neste trabalho:
•
lnp_logical_range(int). Altera a potência do sinal emitido: 0 quando o RCX está
próximo da torre de comunicação; 1 para enviar um sinal forte que permite o
RCX se afastar da torre de comunicação.
•
lnp_integrity_write(const unsigned char* data, const char length). Envia uma
integrity message.
•
lnp_integrity_set_handler(void (*hander)(const unsigned char* data, const char
length). Seta a rotina tratadora das Integrity Messages. Essa rotina é chamada
4. Implementação
O sistema implementado, que permite que o robô seja controlado a partir de
informações obtidas de imagens captadas por uma câmera, tem seu processamento
dividido. Parte dos dados são processados pelo PC ao qual a câmera está conectada, e a
outra parte do processamento é realizada no robô.
Como a comunicação infra-vermelha que ocorre entre PC e RCX não alcança
altas taxas de transmissão, todo o processamento de detecção de objetos sobre a imagem
é realizado no próprio PC. Assim poucos dados são transmitidos entre PC e RCX,
aliviando também a quantidade de cálculos que o processador mais limitado presente no
robô tem de fazer.
Figura 4.1 – Visão Geral do sistema.
As técnicas de Processamento Digital de Imagens usadas são apresentadas no
item 4.1, junto aos parâmetros usados e com as adaptações necessárias para os
experimentos realizados. Cada classe tem sua finalidade exposta e as funções mais
importantes são descritas extensivamente.
O protocolo de comunicação (equivalente à camada de transporte do Modelo de
Referência OSI) é descrito em seguida e as implementações no PC e no robô são
rapidamente vistas no item 4.2.
Finalmente no item 4.3 o programa que controla o robô tem seus mecanismos de
comunicação e controle (tanto sensores como motores) analisados.
4.1 Captura e Processamento das Imagens
Todo esse processo é realizado no PC com as várias tarefas dividas nas classes:
CBitmapEx, CFrameGrabber, CAboutDlg, CMainFrame, CFrameGrabberTestApp,
CFrameGrabberTestDoc, CFrameGrabberTestView e Regiao. O programa foi
desenvolvido em C++ usando a biblioteca para captura de vídeo do SO Windows® e a
biblioteca Microsoft Foundation Classes(MFC) para construir a interface gráfica.
4.1.1 Classe Região
Ao detectar um objeto numa imagem é necessário armazenar seus pontos para
determinar seu tamanho, seu ponto centróide, sua cor ou outras informações que serão
usadas no Classificador (ver 2.3.3.3). Nesse programa os objetos são classificados por
sua cor: o robô apresenta uma cor e seu alvo apresenta outra.
Abaixo estão seus métodos mais importantes:
•
cor(). Retorna a cor do objeto na região (BLUE, GREEN ou RED)
•
cor(COR). Altera a cor do objeto na região.
•
tamanho(). Retorna o tamanho (número de pontos) da região.
•
adiciona(x, y). Acrescenta mais um ponto na região.
•
centroide(). Retorna um par (x,y) com a posição do centróide da região.
4.1.2 Classe CBitmapEx
Essa classe é na verdade apenas uma subclasse de CBitmap, já presente na MFC.
CBitmap por sua vez é um encapsulamento em C++ do modo como os bitmaps são
tratados no Windows.
O principal recurso que a classe CBitmapEx oferece é o método
CreateFromDib(), que copia um Device Independent Bitmap(DIB) para dentro do
objeto. Esse método é importante porque a captura de um quadro através da câmera de
vídeo no windows retorna um DIB.
método BitBlt() para desenhar numa janela ou outra superfície do programa. O método
BitBlt() é usado para desenhar o bitmap na janela principal do programa.
4.1.3 Classe CFrameGrabber
O Windows oferece diversas funções de baixo nível para captura de vídeo
através da biblioteca <vfw.h>. Entretanto usar essas funções é um inconveniente em
programas de alto nível, assim a classe CFrameGrabber existe para permitir uma
interface de alto nível ao programador que deseja capturar vídeo no Windows.
Para obter um quadro basta chamar o método GetDIB(). Um novo quadro está
disponível a cada 20ms, por isso se essa função voltar a ser chamada em um intervalo
de tempo menor, o mesmo quadro será retornado.
Como o Windows aceita que várias câmeras ou outros mecanismos de captura
estejam conectados ao mesmo tempo, o método VideoSourceDialog() permite que o
dispositivo desejado seja escolhido através de uma janela de configuração. Para alterar
os parâmetros com que as imagens serão digitalizadas pela câmera,
VideoFormatDialog() mostra uma janela onde resolução, número de cores, contraste, ou
outros parâmetros podem ser alterados.
4.1.4 Classe CAboutDlg
CAboutDlg apenas mostra a janela “Sobre” do programa:
4.1.5 Classe CFrameGrabberTestApp
O padrão de desenvolvimento de programas chamado de “Modelo – Visão” é
muito difundido atualmente. Nesse padrão há uma separação entre a classe que
armazena as informações e a classe que é responsável por mostrar essas informações ao
usuário. A finalidade desse padrão é aumentar a portabilidade e extensibilidade do
código ao evitar que a lógica da aplicação fique misturada ao código da interface com o
usuário.
Todos programas que usam a biblioteca MFC devem seguir esse padrão. Desta
maneira essa classe herda de CWinApp e apenas deve inicializar as instâncias de
CframeGrabberTestView (Visão), CframeGrabberTestDoc (Modelo) e CMainFrame
(Janela Principal).
4.1.6 Classe CMainFrame
Essa classe é bem simples, somente herda de CFrameWnd e redefine alguns de
seus métodos, justamente os que vão construir a janela principal do programa.
Figura 4.3 – Janela Principal com um quadro capturado.
4.1.7 Classe CFrameGrabberTestView
Seguindo o padrão “Modelo – Visão” da MFC, essa classe herda de CView. Seu
papel nesse padrão é o de Visão, ou seja, sua responsabilidade é redesenhar a janela
toda vez que o Modelo mudou. Também é essa classe que faz a comunicação com a
câmera através de um objeto da classe CFrameGrabber.
O
método
OnDraw() é chamado toda vez que o modelo mudou, ou logo que a
janela é criada. Ele checa se o objeto da classe CFrameGrabber pode ser usado. Se não
for possível ele mostra uma mensagem na janela atestando que não existe um
dispositivo de captura conectado ao computador, ou que ele já está sendo usado por
outro programa.
4.1.7.1 Método OnTimer
A detecção dos movimentos do robô é um processo contínuo, porque o robô ou
seu alvo pode se mover a qualquer instante. Por isso um timer é programado pelo objeto
da classe CFrameGrabberTestView para chamar o método OnTimer() a cada 600ms.
Deste modo os movimentos do robô são continuamente calculados e sua trajetória
corrigida.
1: void CFrameGrabberTestView::OnTimer(UINT nIDEvent) 2: {
3: if(!m_FrameGrabber.GetSafeHwnd()) return;
4: CFrameGrabberTestDoc* pDoc = GetDocument(); 5: ASSERT_VALID(pDoc);
6: LPBITMAPINFO lpBi = m_FrameGrabber.GetDIB();
7: if(suavizar) 8: filtro_suavizar(lpBi); 9: filtro1(lpBi); 10: switch(color) { 11: case GRAY: 12: to_graylevel(lpBi); 13: break; 14: case RED: 15: to_red(lpBi); 16: break; 17: case GREEN: 18: to_green(lpBi); 19: break; 20: case BLUE: 21: to_blue(lpBi); 22: break; 23: default: 24: filtro2(lpBi);
25: break; 26: } 27: if(!pDoc->m_ImageBitmap.GetSafeHandle()) { 28: pDoc->m_ImageBitmap.CreateFromDib(lpBi); 29: InvalidateRect(NULL); 30: } else { 31: pDoc->ProcessImage(lpBi); 32: } 33: }
Esse método controla várias transformações que podem ser feitas na imagem,
algumas que não tem nenhuma relação com o processo de detecção de movimento, mas
permitem analisar a imagem na tela do PC sob vários aspectos. Assim nas linhas 12, 15,
18 e 21 a figura pode ser convertida para tons-de-cinza, ou ter uma componente da cor
(verde, vermelha ou azul) realçada zerando as outras componentes.
Existe a possibilidade de um filtro inicial ser aplicado sobre a imagem para
corrigir falhas no processo de digitalização (linha 9). Embora a função filtro1() não
realize nenhuma operação sobre a imagem, esta chamada de função foi colocada aqui
para permitir que versões posteriores do programa suportem esse recurso. De modo
semelhante a função filtro2() chamada na linha 24 pode ser alterada para realizar
alguma operação importante somente em imagens que permanecerão na codificação
RGB.
No caso de existir ruído nas imagens, causando que alguns pixels tenham valores
muito diferentes dos seus vizinhos o usuário pode escolher por suavizar a imagem.
Assim para cada pixel passa a ter o valor da média do valor antigo do pixel e de seus
oito vizinhos segundo a figura (linha 7 e 8):
Figura 4.4 – Método de Suavização
O programa não processa o 1
oquadro capturado, mas salva num objeto da classe
ProcessImage() da classe CFrameGrabberTestDoc.
4.1.8 Classe CFrameGrabberTestDoc
Essa classe é muito importante, pois no padrão “Modelo - Visão” ela ocupa o
papel de Modelo. Ou seja, ela contém e manipula as informações que serão exibidas por
CFrameGrabberTestView. Um objeto dessa classe também é responsável por calcular a
posição dos objetos na cena e chamar as rotinas que enviarão os dados ao robô. Para
atender as especificações da MFC, ela herda de CDocument.
Um objeto desta classe pode estar em diversos estados: visualizando os quadros
capturados (PROCESSOR_SIMPLE_VIEWER), processando toda cena capturada para
detectar os objetos que estão na cena (PROCESSOR_MOTION_DETECTOR), ou
parado apenas mostrando a última cena que pode pertencer a um dos 2 estados
anteriores (PROCESSOR_PAUSED). O estado atual é armazenado na variável
m_ProcessorMode do objeto.
A última imagem processada é sempre armazenada na variável m_ImageBitmap
do objeto. Desta forma o objeto da classe CFrameGrabberTestView pode usar essa
variável (que é pública) para mostrar a imagem processada na janela.
O
objeto
transporte da classe CTransport é usado para fazer a comunicação com
o RCX. Ele será descrito mais tarde junto da descrição do protocolo e dos mecanismos
de comunicação (item 4.2).
4.1.8.1 Método ProcessImage
Esse é o método mais importante da classe porque ele é o único que é chamado
de fora da classe (do objeto da classe CFrameGrabberTestView). Abaixo seu código e
uma descrição do que cada instrução faz:
1: void CFrameGrabberTestDoc::ProcessImage(LPBITMAPINFO lpBi) 2: {
3: static BOOL bRunNow = FALSE; 4: if(bRunNow || !lpBi) return; 5: bRunNow = TRUE;
6: switch(m_ProcessorMode) {
8: m_ImageBitmap.CreateFromDib(lpBi); 9: UpdateAllViews(NULL);
10: break;
11: case PROCESSOR_MOTION_DETECTOR: 12: if(IMAGEBITS(lpBi)!=24) {
13: AfxMessageBox("Can't run filter: unsupported color resolution!",MB_ICONWARNING); 14: m_ProcessorMode =PROCESSOR_SIMPLE_VIEWER; 15: break; 16: } 17: Limiarizar(lpBi); 18: SeparaRegioes(lpBi); 19: Envia(lpBi); 20: m_ImageBitmap.CreateFromDib(lpBi); 21: UpdateAllViews(NULL); 22: break; 23: } 24: bRunNow = FALSE; 25: }
O método recebe como parâmetro um ponteiro para uma estrutura
BITMAPINFO, que no Windows é a responsável por armazenar todas as informações de
um DIB, seu cabeçalho com informações sobre as cores, resolução, codificação, etc, e
os próprios pixels da imagem (linha 1).
As linhas 8 e 20 copiam o bitmap recebido como argumento pro objeto
m_ImageBitmap, enquanto 9 e 21 manda que todos os objetos com papel de Visão da
aplicação redesenhem suas telas. Assim o método OnDraw() do objeto da classe
CFrameGrabberTestView será chamado para redesenhar a janela, e desta vez usará a
nova imagem salva em m_ImageBitmap.
Como essa aplicação foi desenvolvida para que a detecção de imagem fosse feita
sobre uma imagem RGB de 24 bits, a linha 12 confere se o bitmap capturado é
compatível com essa restrição.
Finalmente a imagem é processada, primeiro através da limiarização expressa na
linha 17, depois as regiões são separadas na 18 e finalmente a trajetória do robô é
calculada e enviada ao RCX na 19.
4.1.8.2 Método Limiarizar
Cada pixel da imagem tem sua componente (Verde, Azul ou Vermelho)
predominante determinada por esse método. Para armazenar essas informações são
usadas três matrizes de valores booleanos. Assim para cada posição (i,j) dessas matrizes
somente uma delas tem valor true.
1: void CFrameGrabberTestDoc::Limiarizar(LPBITMAPINFO lpBi) 2: {
3: int arena_dx = IMAGEWIDTH(lpBi); 4: int arena_dy = IMAGEHEIGHT(lpBi);
5: BYTE * ptr =(BYTE *)IMAGEDATA(lpBi);
6: for(int y=0; y< arena_dy;y++) {
7: for(int x=0, pos = 0; x<arena_dx; x++, pos+=3) {
8: switch(max_rgb(ptr+pos)){
9: case RED:
10: Red[x][y] = true; Green[x][y] = false; Blue[x][y] = false;
11: break;
12: case GREEN:
13: Red[x][y] = false; Green[x][y] = true; Blue[x][y] = false;
14: break;
15: case BLUE:
16: Red[x][y] = false; Green[x][y] = false; Blue[x][y] = true;
17: break;
18: case MRGB:
19: Red[x][y] = false; Green[x][y] = false; Blue[x][y] = false;
20: break; } 21: } 22: ptr += arena_dx*3; 23: } 24: }