VEÍCULO AUTÔNOMO COM VISÃO ROBÓTICAlyceumonline.usf.edu.br/salavirtual/documentos/1879.pdf ·...
Transcript of VEÍCULO AUTÔNOMO COM VISÃO ROBÓTICAlyceumonline.usf.edu.br/salavirtual/documentos/1879.pdf ·...
UNIVERSIDADE SÃO FRANCISCO
Engenharia de Computação
RAFAEL ROBERTO PRADO
VEÍCULO AUTÔNOMO COM VISÃO ROBÓTICA
Itatiba
2010
RAFAEL ROBERTO PRADO – RA 002200700057
VEÍCULO AUTÔNOMO COM VISÃO ROBÓTICA
Monografia apresentada ao Curso de
Engenharia de Computação da
Universidade São Francisco, como requisito
parcial para obtenção do título de Bacharel
em Engenharia de Computação.
Orientador: Prof. Dr. Claudio Kiyoshi
Umezu
Itatiba
2010
Agradecimentos
Dedico esta persistência por cada passo conquistado, por cada novo conhecimento obtido.
Além disso, a minha esposa Vanderléia que me acompanha e me apóia, aos meus pais
Benedito e Helena que sempre me apóiam e a também aos meus amigos por suas
contribuições. Agradeço também as empresas nos quais me deram a oportunidade de exercer
meu trabalho, propriamente de estar fazendo este trabalho sob o apoio de meu orientador e
meu co-orientador Prof. Fábio Andrijauskas e a Deus por me ter guiado a bons caminhos.
RESUMO
No mercado de robótica tem surgido cada vez mais novas aplicações, dos mais diversos
tipos ou finalidade. Os robôs móveis e autônomos devem interagir com o mundo para
alcançar seus objetivos, evitando obstáculos. A navegação em robótica móvel busca a
detecção de obstáculos e de alvos em ambientes dinâmicos e imprevisíveis. Neste processo,
cada ação destaca-se como uma tarefa e cada tarefa compreende em executar a identificação e
a localização do objeto. Visão computacional é a ciência que desenvolve as bases teóricas e
algorítmicas pelas quais informações úteis são automaticamente extraídas de imagens por
meio de computadores. Um dos métodos para a identificação e localização do objeto é o
sistema de visão computacional, capaz de identificar e localizar alvos em ambientes
dinâmicos, trabalhando o uso da segmentação de regiões, baseada em cores, com o apoio da
estereoscopia e de um algoritmo de decisão, como a árvore de decisão. Na árvore de decisão,
cada nó representa uma rede neural responsável por uma tarefa, como passe ou interceptação.
A raiz é um ponto do vetor de centros de cor primária, que representa um pedaço do objeto,
tendo como nós filhos os outros pontos do vetor de centros. Desta forma, o projeto a ser
desenvolvido, busca usar estes conceitos citados anteriormente, compreendendo suas
informações abstratas, analisando as informações pela identificação do alvo e repassando ao
escalonador que deve associar um atributo definido buscando refletir a percepção do veículo
com relação aos obstáculos próximos, ou mesmo ao próprio alvo.
Palavras-chave: robótica. robô. visão. objeto. reconhecimento. detecção. percepção.
estereoscopia. classificação. identificação. localização.
ABSTRACT
In the market for robotics has emerged more and more new applications of all kinds or
purpose. The autonomous and mobile robots must interact with the world to achieve their
goals while avoiding obstacles. The navigation in mobile robotics seeks to detect obstacles
and targets in dynamic and unpredictable environments. In this process, each action stands out
as a task and each task consists in to perform the identification and location of the object.
Computer vision is the science that develops the theoretical and algorithmic by which useful
information is automatically extracted from images by means of computers. A method for the
identification and location of the object using computer vision system capable of identifying
and locating targets in dynamic environments, working to use the segmentation of regions
based on color, with the support of stereoscopy and a decision algorithm as a decision tree. In
the decision tree, each node represents a neural network responsible for a task, such as pass or
interception. The root point is a vector of primary color centers, which represents a piece of
the object, having as nodes the other points of the vector of centers. Thus, the project to be
developed, seeks to use these concepts mentioned previously, understanding its abstract
information, analyzing the information for identifying the target and passing on to the
scheduler which should involve an attribute set trying to reflect the perception of the vehicle
in relation to nearby obstacles, or even the target itself.
Key words: robotics. robot. vision. object recognition. detection. perception. stereopsis.
classification. identification. tracking.
LISTA DE SIGLAS
AAREACT Adaptação Automática da tecnologia confiável de controle
autônomo.
ANSI American National Standards Institute, ou seja, Instituto Nacional
Americano de Padronização.
AR Aprendizado por reforço.
JPG Joint Photographic Group, ou seja, grupo de fotografia comum
MDP Decisão de processo markoviano.
MOSFET Metal Oxide Semiconductor Field Effect Transistor, ou seja,
transistor de efeito de campo de semicondutor de óxido metálico
PNG Portable Network Graphics, ou seja, rede de gráficos portável.
RCM Rabbit Core Module, ou seja, módulo com núcleo Rabbit.
REACT Reliable Autonomous Control Technology, ou seja, tecnologia
confiável de controle autônomo;
RGB Modelo de cor, representando red (vermelho), green (verde) e blue
(azul).
SRAM Static Random Access Memory, ou seja, memória estática de acesso
aleatório.
TCP Transmission Control Protocol, ou seja, protocolo com controle de
transmissão.
USB Universal Serial Bus, ou seja, barramento serial universal
XML Extensible Markup Language, ou seja, linguagem de marcadores
extensível.
LISTA DE FIGURAS
FIGURA 1 - Modelo de comportamentos do veículo autônomo [2] ........................................ 15
FIGURA 2 - Fluxo da política aplicada na navegação ............................................................. 16
FIGURA 3 - Ação e reforço do ambiente [15] ......................................................................... 18
FIGURA 4 - Imagem do objeto (a) e a imagem do fundo do objeto (b) .................................. 20
FIGURA 5 - Imagem da subtração entre imagem fundo e objeto ............................................ 20
FIGURA 6 - Imagem da classificação com brilho ................................................................... 21
FIGURA 7 - Imagem da classificação binarizada .................................................................... 21
FIGURA 8 - Interpolação linear na imagem do objeto e interpolação do vizinho mais próximo
na classificação ......................................................................................................................... 22
FIGURA 9 - Filtro passa-baixa na imagem do objeto .............................................................. 22
FIGURA 10 - Modelo de árvore de decisão sob o classificador do objeto [20] ...................... 23
FIGURA 11 - Método da interpolação de primeira ordem ...................................................... 24
FIGURA 12 - Interpolação de primeira ordem na imagem esquerda (a) e interpolação de
ordem zero na imagem direita (b)............................................................................................. 25
FIGURA 13 - Método da interpolação de primeira ordem ...................................................... 25
FIGURA 14 - Gráfico de amostragem da freqüência da imagem [24] .................................... 26
FIGURA 15 - Filtro passa-baixa na imagem ............................................................................ 26
FIGURA 16 - Imagem da busca do objeto ............................................................................... 27
FIGURA 17 - Interpolação linear na imagem da busca do objeto ........................................... 28
FIGURA 18 - Filtro passa-baixa na imagem da busca do objeto ............................................. 28
FIGURA 19 - Canal de interesse da imagem de busca do objeto ............................................ 29
FIGURA 20 - Binarização do canal de interesse da imagem de busca do objeto .................... 29
FIGURA 21 - Resultado da árvore de decisão sob a imagem da busca do objeto ................... 30
FIGURA 22 - Intersecção do resultado da árvore de decisão e da imagem do canal de
interesse da busca do objeto ..................................................................................................... 30
FIGURA 23 - Inversão da imagem canal de interesse da imagem de busca do objeto ............ 31
FIGURA 24 - Inversão do resultado da árvore de decisão da imagem de busca do objeto ..... 31
FIGURA 25 - Selecionando o objeto na imagem invertida através da área do objeto ............. 31
FIGURA 26 - Selecionando o objeto na imagem de busca do objeto através da referência
obtida na identificação .............................................................................................................. 32
FIGURA 27 - Modelo de visão estéreo simplificado [3] ......................................................... 33
FIGURA 28 - Modelo de cores RGB [6] ................................................................................. 35
FIGURA 29 - Modelo de imagem esquerda e direita ............................................................... 36
FIGURA 30 - Modelo de imagem concatenada ....................................................................... 36
FIGURA 31 - Atributos combinados a comportamentos [1] ................................................... 38
FIGURA 32- Arquitetura embarcada RCM2200 [7] ................................................................ 43
FIGURA 33 - Circuito de acionamento dos motores ............................................................... 44
LISTA DE TABELAS
TABELA 1 - Seqüência “wave drive” do motor de passo [9].................................................. 46
SUMÁRIO
1 INTRODUÇÃO ................................................................................................................ 11 1.1 Objetivo ....................................................................................................................... 12 1.2 Organização do trabalho.............................................................................................. 12
2 COORDENAÇÃO DE COMPORTAMENTOS ........................................................... 14
3 IDENTIFICANDO OS OBJETOS ................................................................................. 19 3.1 Classificação do objeto................................................................................................ 19 3.2 Árvore de decisão ........................................................................................................ 23
3.3 Interpolação linear e por vizinho mais próximo.......................................................... 24 3.4 Filtro passa-baixa ........................................................................................................ 25 3.5 Identificação do objeto ................................................................................................ 26 3.6 Estereoscopia ............................................................................................................... 32
4 MOVIMENTOS DIRIGIDOS A DETECÇÃO DOS OBJETOS ................................ 37
5 A ESTRUTURA DO VEÍCULO .................................................................................... 39 5.1 Aplicações desenvolvidas ........................................................................................... 39
5.1.1 Aplicação de papel agente .................................................................................... 39
5.1.2 Aplicação de papel atuador................................................................................... 43 5.2 Os motores do veículo ................................................................................................. 44 5.3 A mecânica do veículo ................................................................................................ 46
5.4 A alimentação de energia do veículo .......................................................................... 46
6 CONCLUSÃO .................................................................................................................. 48 6.1 Trabalhos futuros......................................................................................................... 48
REFERÊNCIAS BIBLIOGRÁFICAS ................................................................................. 49
APÊNDICES ........................................................................................................................... 51 APÊNDICE A – Código atuador desenvolvido para o microcontrolador ............................ 52 APÊNDICE B – Código agente desenvolvido para o computador portátil .......................... 73 APÊNDICE C – Resultado do desenvolvimento do veículo através das imagens ............. 107
11
1 INTRODUÇÃO
Com o crescimento contínuo do mercado de robótica nos últimos anos, têm surgido
cada vez mais novas aplicações, dos mais diversos tipos ou finalidade. Os robôs móveis e
autônomos devem interagir com o mundo para alcançar seus objetivos, evitando obstáculos.
Normalmente os projetos robóticos têm sido desenvolvidos em centros de pesquisas,
pois cada modelo pode envolver inúmeros conceitos, executando ações e até mesmo tendo
reações durante sua navegação.
A navegação em robótica móvel busca a detecção de obstáculos e de alvos em
ambientes dinâmicos e imprevisíveis. Neste processo, cada ação destaca-se como uma tarefa e
cada tarefa compreende em se executar a identificação e a localização do objeto.
Visão computacional é a ciência que desenvolve as bases teóricas e algorítmicas pelas
quais informações úteis são automaticamente extraídas de imagens por meio de
computadores[21]. Um dos métodos para a identificação e a localização do objeto é o sistema
de visão computacional, capaz de identificar e localizar alvos em ambientes dinâmicos,
trabalhando o uso da segmentação de regiões baseada em cores, com o apoio da estereoscopia
[2].
Assim, o uso da visão computacional busca estender a capacidade da arquitetura reativa
denominada REACT, definida pela atuação reativa do robô autônomo que tem como
responsabilidade de atuar em qualquer ambiente [2].
Evidentemente que a construção de um processo de identificação de objetos, através da
visão robótica não é tão real como o processo de identificação do ser humano. A construção
de uma arquitetura mais robusta requer diversos conceitos à face de identificar detalhes
minuciosos, como ocorre nos processos biométricos determinando um desenvolvimento muito
complexo.
Desta forma, este projeto mostrou que a realidade da visão robótica pode ser
apresentada pelo desenvolvimento de um robô autônomo, compondo um modelo bastante
simples de processos envolvendo o paradigma reativo.
Por sua vez, o paradigma reativo liga estímulos sensoriais em respostas aos motores,
representando o poder de desempenhar sua tarefa em ambientes desconhecidos, ou seja, uma
arquitetura adaptativa e desejável.
12
Contudo, o desenvolvimento do robô autônomo surge da união dos processos, dividindo
os movimentos até cada identificação do objeto, conceituando a cada movimento, um
processamento de uma imagem analisando se contêm qualquer objeto contido em um banco
de imagens. A cada imagem processada, o retorno é um resultado a partir de conceitos
científicos de processamento de imagens, concebidos através de análises comportamentais
visualizadas, construindo uma determinada política, equivalente a análise do ser humano antes
de coletar um determinado objeto.
1.1 Objetivo
O objetivo deste trabalho foi propor um modelo de veículo autônomo utilizando a visão
computacional para prover informações ao módulo de percepção, buscando capacitar
reativamente através da análise das imagens. A cada imagem analisada é criado um endereço
a comportamentos desenvolvendo uma navegação de forma reativa ao ambiente em busca do
objeto conhecido em seu banco de imagens.
Para facilitar o entendimento propôs-se o desenvolvimento de um protótipo utilizando-
se de duas câmeras para aquisição das imagens sob um veículo com o intuito de prover
informações a uma aplicação agente que busca a identificação e localização de um
determinado objeto.
1.2 Organização do trabalho
Este trabalho possui seções organizadas conforme mostram os itens abaixo:
A seção 2 define a coordenação de comportamentos do veículo, mostrando como
ocorre a seleção de políticas de movimentos;
A seção 3 expõe a identificação dos objetos auxiliando a coordenação de
comportamentos;
A seção 4 trata da seleção dos movimentos dirigidos a localização e identificação dos
objetos;
Com o intuito de confirmar a prática, detalhado a estrutura do veículo, a Seção 5
apresenta a prova do conceito;
13
Encerrando-se, a seção 6, expõe a conclusão e os trabalhos que podem ser extraídos
deste projeto.
14
2 COORDENAÇÃO DE COMPORTAMENTOS
A arquitetura que aprende a coordenar comportamentos primitivos codificados se
inspira na idéia do agente aprendiz, modificando seus parâmetros por um elemento
aprendizado. Ela utiliza como base uma arquitetura simples, baseada em comportamento
reativo, codificados por campos potenciais.
O uso do comportamento reativo traz uma camada de aprendizado por reforço
constituindo o elemento aprendizado, supervisionando o desempenho do robô e contribuindo
para sua atuação final.
Este modelo denominado REACT (tecnologias confiáveis de controle autônomo) atua
em diversos ambientes aplicando ações baseadas nos comportamentos primitivos.
Cada ação resulta em uma força sob o robô, codificando cargas repulsivas com os
obstáculos detectados e cargas atrativas com o objetivo. Buscando introduzir um sistema de
visão modificando e aperfeiçoando os módulos de percepção através dos comportamentos
primitivos[2].
Porém, ainda é necessário corrigir as falhas impostas pelo modelo aplicado, que ocorre
quando o robô, em sua navegação, segue por um corredor estreito ou mesmo entra em regiões
de atração indevidas, que fogem de seu objetivo. É necessário colocar o uso da própria
experiência para que o robô possa ser mais autônomo, influenciando sua coordenação através
do modelo AAREACT (Adaptação Automática da REACT) [1].
A coordenação ocorre de forma cooperativa de comportamentos, que por sua vez
implica na sua atuação final, seguindo em frente, dirigindo-se ao alvo ou mesmo evitando
uma colisão. Uma vez que a participação de cada comportamento muda a situação do
ambiente ao seu campo potencial, as variáveis ligadas diretamente ao problema da navegação
correspondem a postura (posição e orientação do veículo autônomo no ambiente) e as leituras
das câmeras.
Os comportamentos primitivos que podem ser usados são detalhados a seguir e
mostrados na FIGURA 1 [1]:
Evitar Colisão (avoidCollision): para este comportamento podem ser usados sensores
como sonares e a visão computacional para percepção de obstáculos, através de
câmeras, codificando obstáculos às cargas repulsivas e avaliando leituras no ambiente
[1].
15
Direcionar ao destino ou ao alvo (moveToGoal): neste caso, através de um agente
externo ou mesmo de um parâmetro interno, o veículo detecta o ponto de atração no
ambiente que é denominado alvo. O parâmetro interno deve ser reconhecido como seu
conjunto de imagens, contido em um conjunto de arquivos, onde a aplicação consulta
e executa o processamento de cada imagem. Sua posição atual é mensurada através
dos módulos perceptivos, como o sistema de visão computacional, primeiramente
detectando posições do robô e do alvo, juntamente através de um odômetro avaliando
à distância percorrida [1].
Seguir em frente (moveAhead): este comportamento preserva a direção imposta no
momento, uma inércia, suavizando o percurso do robô, minimizando as oscilações no
percurso, desde que não seja necessário seguir para outro comportamento conforme o
módulo de codificação [1].
Desta forma, através do componente de supervisão, é identificado o estado s do
ambiente dado por atributos binários, calculados a partir dos sensores do veículo,
complementados por um componente crítico, dado pela codificação que define reforços r que
dependem da atuação do robô. Assim, o elemento aprendizado é desenvolvido pelo algoritmo
de SARSA que determina a atuação para aquele estado correspondendo a um conjunto de
comportamentos da arquitetura.
O algoritmo de SARSA (Sutton e Barto, 1998), baseado no algoritmo Q-Learning, é um
algoritmo de aprendizado por reforço (AR), permitindo que um agente aprenda uma política
de atuação.
avoidColision (-d+S)/T
V(d) =e
= -robô - obstáculo =
1
moveAhead
V(d) =cte
= -robô =1
moveToGoal
V(d) =cte
= -robô - alvo (d+S)/T
V(d) =e
= -robô - alvo =1
visão
odômetros
visão
sonares
(V1,1)
(V2,2)
(V3,3)
(VR,R)
FIGURA 1 - Modelo de comportamentos do veículo autônomo [2]
16
A política de atuação ocorre com base na tentativa e erro em um ambiente dinâmico, ou
seja, um ambiente desconhecido, relacionando um estado s a uma ação a ser tomada no
ambiente. De um modo geral, os algoritmos AR têm como papel construir, interagindo com o
ambiente e inspirado em funções previamente definidas, sendo assim caso o ambiente
encontre-se no estado s a medida aplicada é uma ação a [1].
Desta forma, conforme a resultante da ação – mostrada na FIGURA 2 - é aplicada uma
recompensa, explicitando o agente em suas ações boas ou ruins desempenhada por ele e
também exibindo que os estados do ambiente e as possíveis ações são finitamente numeradas
e podem ser identificadas em uma tabela Q.
Agora, formalmente, modela-se em termos markovianos de decisão de processos
(MDPs), para que as decisões satisfaçam as condições de Markov.
As condições a serem satisfeitas determinam que o estado corrente do ambiente resume
o passado de forma compacta, de modo que o futuro não depende dos estados anteriores caso
se conheça o estado corrente. Sendo assim, obtêm-se um MDP que consiste da seguinte forma
[1]:
• é a política, que seleciona no conjunto de ações a para o estado st, sendo que para
valor ação ótima, calculando ótima política por:
*(s) = argmaxQ*(s,a). a
E para valor estado, calculando ótima política por:
*(s) = argmaxV*(s). a
• t é o passo de tempo do episódio;
• st é o estado atual e quando o próximo estado é: st +1;
• at é a ação atual e quando é a ação a ser realizada no próximo estado obtêm-se: at +1;
FIGURA 2 - Fluxo da política aplicada na navegação
=1
Processo
Ação
selecionada
Custo estimado
experiência
acumulada
Sentido
punições
recompensas ação
estado
17
• r(st, at) é o reforço ao realizar uma ação quando em um determinado estado,
compreendendo entre -1 e 1, se o veículo bater ou se aproximar demais obtêm-se -1, caso
contrário, compreende entre 0 e 1, porém, quanto mais distante menor é o reforço, conforme
representado abaixo:
k-1
rt = rt +1 + rt +2 +² rt +3 + … = rt+k k=1
• é a taxa de aprendizado;
• é o fator de desconto temporal para recompensas ou punições, compreendido entre 0
e 1, fato que se recompensa ganha-se 1 e se punição ganha-se 0;
• Um conjunto discreto de Ns, ou seja, finitos estados do ambiente: S = {s1, s2,...,
s[Ns]};
• Um conjunto discreto de Na, ou seja, finitas ações do ambiente: A = {a1, a2,...,
a[Na]};
• Uma função Qt (st, at) para relacionar estado atual s com uma ação a ser tomada,
retornando um valor ação;
• Uma função de probabilidade de transição de estado é P(s’|st, at), que conforme
estado st carrega a ação a e tem origem a um novo estado s’.
Para SARSA o algoritmo ser executado da seguinte forma [15]:
Inicialize Qt(st, at) arbitrariamente
Repita:
Visite o estado st.
Selecione uma ação a de acordo com a regra transição de estados.
Execute a ação at.
Receba o reforço r(st, at) e observe o próximo estado st +1.
Atualize os valores de Qt(st, at) de acordo com a regra de atualização, ou seja,
construa a tabela Q com a iteração do agente com o ambiente:
Qt +1(st, at) Qt (st, at)+ [ r(st, at)+ Qt(st +1, at +1)-Qt(st, at)]
Atualize o estado st st +1.
Até que algum critério de parada seja atingido.
18
Por sua vez, o algoritmo anterior descreve os movimentos expostos – mostrado na
FIGURA 3:
No conjunto de estados e ações ainda são necessários definir seus elementos, para isso
usa-se o conhecimento qualitativo sobre a tarefa do agente para determinar os atributos do
ambiente que correspondem as macro-ações.
Através de cada atributo, obtêm-se informações de forma booleana, caracterizando
condições de operação no ambiente. Desta forma determinam-se alguns atributos binários, os
quais podem ser consultados mediante o papel do algoritmo de AR, que seleciona qual a
macro ação mais adequada para cada estado do ambiente [1].
Os atributos definidos procuram refletir a percepção do veículo com relação aos
obstáculos próximos, ou mesmo ao próprio alvo.
Quando o atributo estiver ativo de forma isolada, pode combinar-se a comportamentos
propositais, ou seja, cada atributo evolui um comportamento primitivo, buscando direcionar a
detecção do objeto.
agente
ambiente
ação at reforço
(ganho)
rt
st +1 rt +1
estado
st
FIGURA 3 - Ação e reforço do ambiente [15]
19
3 IDENTIFICANDO OS OBJETOS
O processo de identificação de objetos contribui na coordenação da navegação, porém o
processo é dependente das respostas de demais sensores, como os controladores de velocidade
e posição. As respostas destes controladores determinam os processos que estão ocorrendo no
ambiente, para que o sensor reconhecido como uma visão artificial possa vir a atuar, quando
solicitado.
A visão artificial envolve a classificação de informações extraídas de uma cena e as
atividades de identificação com base nas informações classificadas através da análise de
imagens [18].
Desta forma, pode-se identificar que uma imagem digital não é interpretada da mesma
forma que um ser humano identifica uma cena, mas a partir de atributos que devem ser
extraídos da imagem, e que estão relacionados entre si. Portanto, num sistema de tratamento
de imagens, se busca capturar alguns atributos da imagem e usar estes elementos para
minimizar o espaço de pesquisa [22].
3.1 Classificação do objeto
No sistema de classificação, a análise de imagens tem por finalidade extrair informação
suficiente para possibilitar a distinção entre regiões de interesse. Esta tarefa apesar de básica,
reveste-se de elevado grau de complexidade, pois tenta reproduzir o sofisticado processo de
classificação e reconhecimento de padrões realizado pela visão humana [18].
O reconhecimento de padrões em imagens emprega as características cor e textura.
Desta forma, a boa quantificação destas características permite a identificação e a
classificação de padrões [18].
A classificação baseada apenas na cor é a forma mais simples. Já a classificação por
textura envolve maior complexidade. Vários métodos para classificação de imagens,
empregando características de textura, têm sido propostos [18].
O método usado nesse trabalho é a árvore de decisão, por não existir um método
genérico ou uma abordagem formal que seja simples para classificação de objetos em
imagens.
20
Assim, os objetos são classificados com cores segmentadas por comparações entre duas
imagens de mesmo tamanho, usando uma imagem do objeto e outra imagem somente do
fundo. A imagem contendo o objeto recebe um ajuste de brilho a fim de realçar o objeto.
A comparação entre a imagem do objeto e a imagem do fundo do objeto sem a presença
do mesmo – mostrado na FIGURA 4, gera uma nova imagem de classificação do objeto
através da subtração destas imagens. A partir da subtração das imagens – mostrado na
FIGURA 5, verifica-se o valor do pixel for equivalente na posição comparada da imagem
subtraída é preto, caso sim, representa na posição comparada com a cor branca da imagem de
classificação, ao contrário, representa na posição comparada com a cor da imagem objeto na
imagem de classificação.
(a) (b)
FIGURA 4 - Imagem do objeto (a) e a imagem do fundo do objeto (b)
FIGURA 5 - Imagem da subtração entre imagem fundo e objeto
21
A subtração e comparação entre a imagem do fundo do objeto e a imagem do objeto não
são suficientes para a geração da imagem de classificação – mostrado na FIGURA 6. Desta
forma, é necessária a retirada de alguns pixels não interessantes, corrigidos através de um
procedimento de binarização sob os três canais, para que o fundo não possa ser confundido
com o objeto, ao ser determinado como uma classe na árvore de decisão.
Apesar da retirada de alguns pixels não interessantes através do procedimento de
binarização – mostrado na FIGURA 7 – é necessário aplicar a interpolação do vizinho mais
próximo à imagem com a classificação do objeto – mostrado na FIGURA 8 - deixando os
pixels mais uniformes.
Na imagem do objeto é necessário aplicar a interpolação linear – mostrado na FIGURA
8 - buscando reduzir o número de cores, através de uma exploração de quatro pixels, deixando
a intensidade linear na vizinhança [17].
FIGURA 6 - Imagem da classificação com brilho
FIGURA 7 - Imagem da classificação binarizada
22
Em seguida, aplica-se um filtro de suavização na imagem do objeto – mostrado na
FIGURA 9. Este filtro passa-baixa tem como objetivo de remover ruídos da imagem e
destacar o objeto.
Após executado os procedimentos sob a imagem de classificação do objeto e a imagem
do objeto, inicia-se a criação de uma árvore de decisão extraindo detalhes da imagem da
classificação do objeto e também da imagem do objeto, relacionando características das
mesmas para determinar se o ponto em questão é o fundo ou o objeto.
Com a árvore de decisão criada e contendo detalhes da classificação do objeto, executa-
se um treinamento, para ser utilizada sob outra imagem e seguir para o processo de
identificação do objeto.
O treinamento da árvore de decisão tem o objetivo de gerar detalhes sob a relação da
imagem de classificação do objeto e a imagem do objeto.
FIGURA 8 - Interpolação linear na imagem do objeto e interpolação do vizinho mais próximo
na classificação
FIGURA 9 - Filtro passa-baixa na imagem do objeto
23
3.2 Árvore de decisão
Árvores de decisão são modelos estatísticos que utilizam um treinamento
supervisionado para a classificação e previsão de dados. Em outras palavras, em sua
construção é utilizado um conjunto de treinamento formado por entradas e saídas. Estas
últimas são as classes [19].
Este modelo utiliza a estratégia de dividir para conquistar: um problema complexo é
decomposto em subproblemas mais simples e recursivamente esta técnica é aplicada a cada
subproblema (Gama, 2004) [19].
As árvores de decisão estão entre os mais populares algoritmos de inferência e tem sido
aplicadas em várias áreas como, por exemplo, diagnóstico médico e risco de crédito (Mitchell,
1997), e deles pode-se extrair regras do tipo “se-então” que são facilmente compreendidas
[19].
A capacidade de discriminação de uma árvore vem da divisão do espaço definido pelos
atributos em subespaços e a cada subespaço é associada uma classe [19].
Na árvore de decisão cada nó representa uma rede neural responsável por uma tarefa,
como passe ou interceptação. Onde a raiz é um ponto do vetor de centros de cor primária, que
representa um pedaço do objeto – mostrado na FIGURA 10, tendo como nós filhos os outros
pontos do vetor de centros. Um nó, ou seja, um ponto do vetor de centros é filho da raiz. Caso
a distância entre esse ponto e o ponto da raiz seja pequeno o suficiente para considerar que
não há espaço entre dois pedaços do objeto [15].
FIGURA 10 - Modelo de árvore de decisão sob o classificador do objeto [20]
24
Portanto, numa árvore de decisão deduz-se que cada nó de decisão contém um teste
para algum atributo, cada ramo descendente corresponde a um possível valor deste atributo
[19].
Os conjuntos de ramos da árvore de decisão são distintos, cada folha está associada a
uma classe e, cada percurso da árvore, da raiz à folha, corresponde uma regra de classificação.
No espaço definido pelos atributos, cada folha corresponde a um hiper-retângulo onde a
interseção destes é vazia e a união é todo o espaço [19].
3.3 Interpolação linear e por vizinho mais próximo
Na interpolação quando as coordenadas de um valor são números fracionais, coloca-se
o problema de como calcular o valor a utilizar. Desta forma, pode-se utilizar de algumas
técnicas de interpolação, como: a interpolação por vizinho mais próximo e interpolação linear
[23].
A interpolação por vizinho mais próximo, também considerado de ordem zero –
mostrado na (b)
FIGURA 12 - Interpolação de primeira ordem na imagem esquerda (a) e interpolação de ordem
zero na imagem direita (b)
, atribui o valor do novo pixel em análise de imagem expandida, ou seja, o valor do
pixel é igual ao valor do seu vizinho mais próximo na imagem original – mostrado na
FIGURA 11, criando o efeito de bloco [17].
Na interpolação linear, ou de primeira ordem – mostrado na FIGURA 12, o novo pixel é
resultado de uma interpolação linear dos quatro pixels mais próximos, obtendo o efeito de
suavização devido a operar em base no filtro de média – mostrado na FIGURA 13,
Imagem original
(x, y)
Imagem original
(x’, y’)
FIGURA 11 - Método da interpolação de primeira ordem
25
considerando duas direções ortogonais da imagem original [17]. Cada interpolação linear se
baseia na distância ponderada desses pontos [5].
O filtro de média, na sua versão mais simples se limita a substituir o valor de um pixel
pela média do seu valor e dos pixels que o rodeiam. Além disso, podem ter núcleos com
coeficientes não uniformes de forma a melhorar o seu desempenho, sem embaçar muito por
dar maior importância ao pixel central [23].
3.4 Filtro passa-baixa
Para reduzir ruído, existem procedimentos que procuram atenuar as variações
localizadas. Esta propriedade é geral nestas transformações que substituem o valor local por
uma média ponderada da vizinhança. Os valores de máximos são naturalmente reduzidos,
FIGURA 13 - Método da interpolação de primeira ordem
(a) (b)
FIGURA 12 - Interpolação de primeira ordem na imagem esquerda (a) e interpolação
de ordem zero na imagem direita (b)
26
uma vez que fazem média com valores menores que eles. O mesmo raciocínio se aplica para
explicar o aumento dos valores de mínimos [24].
Neste caso, a função que elimina as variações de maior freqüência da função f(x) por
h(x) – mostrado na FIGURA 14, se designa como: filtro passa-baixa. É comum utilizarmos
filtros passa-baixa baseados na função de distribuição de Gauss [24].
O filtro passa-baixa – mostrado na FIGURA 15 - consiste na aplicação de operações
elementares à matriz aumentada no sistema, chegando-se assim a uma matriz escalonada,
reduzindo detalhes irrelevantes, pois quanto maior for sua máscara, maior é o borramento,
também conhecido como filtro Gaussiano [16].
3.5 Identificação do objeto
A identificação e extração de objetos de imagens podem possuir problemas que estão
relacionados com a oclusão, onde um objeto pode estar parcialmente escondido atrás de outro
FIGURA 15 - Filtro passa-baixa na imagem
FIGURA 14 - Gráfico de amostragem da freqüência da imagem [24]
f(x)
h(x)
27
objeto, ou dois objetos compondo a mesma imagem. De forma análoga, a perda de
informações ou deformações, pode ser ocasionada por ruídos na imagem devido a condições
anormais de iluminação, defeitos de digitalização, e de resultados ineficientes de algoritmos
de segmentação [22].
As técnicas de reconhecimento de padrões tratam da identificação de partes da imagem
que possuem semelhanças. Uma grande quantidade de ferramentas matemáticas e
computacionais tem sido desenvolvida para permitir que objetos possam ser extraídos e
agrupados em classes específicas de informações. Uma boa representação da forma do objeto
gera facilidades para que ele seja armazenado, transmitido, comparado, reconhecido ou
mesmo entendido. A representação deve ser gerada de acordo com regras simples e precisas.
Geralmente uma forma é descrita em termos de número de componentes, primitivas, e
relacionamentos entre estes componentes [22].
Diversas ferramentas computacionais têm sido exploradas para o pré-processamento,
segmentação de imagens e identificação de objetos.
No processo usado neste trabalho a identificação do objeto ocorreu em uma imagem
qualquer onde se utiliza da árvore de decisão que foi treinada com uma imagem de
classificação do objeto e uma imagem do objeto.
A imagem da busca do objeto – mostrado na FIGURA 16 - também passa por
procedimentos semelhantes, inicialmente recebendo um ajuste de brilho para realçar o objeto,
para que tenha equilíbrio com a árvore de decisão, assim compreendendo as mesmas
características.
Em seguida, a imagem da busca do objeto necessita da aplicação de um filtro de
interpolação linear – mostrado na FIGURA 17 - buscando reduzir o número de cores, através
de uma exploração de quatro pixels, deixando a intensidade linear na vizinhança.
FIGURA 16 - Imagem da busca do objeto
28
Para encerrar a aplicação de filtros é aplicado um filtro de suavização – mostrado na
FIGURA 18 - na imagem da busca do objeto, ou seja, um filtro passa-baixa com o objetivo de
remover ruídos da imagem e destacar os objetos presentes na imagem.
Após executado os procedimentos sob a imagem da busca do objeto é necessário criar
uma imagem usando de apenas um dos canais, considerando que a imagem possua três canais
no modelo RGB, denominando-a como imagem de canal de interesse – mostrado na FIGURA
19.
FIGURA 17 - Interpolação linear na imagem da busca do objeto
FIGURA 18 - Filtro passa-baixa na imagem da busca do objeto
29
Na imagem considerada canal de interesse, são retirados alguns pixels não interessantes,
corrigidos através de um procedimento de binarização – mostrado na FIGURA 20, a fim de
criar uma intersecção com a imagem resultado que é gerada pela compreensão da validação
da árvore de decisão sob a imagem.
Conforme citado anteriormente, ao executar o procedimento de validação da árvore de
decisão criada sob a imagem da busca do objeto é gerado uma imagem de resultado –
mostrado na FIGURA 21.
FIGURA 19 - Canal de interesse da imagem de busca do objeto
FIGURA 20 - Binarização do canal de interesse da imagem de busca do objeto
30
Depois de gerada a imagem de resultado da validação da árvore de decisão é verificada
junto à imagem do canal de interesse se o valor do pixel for equivalente na posição
comparada, removendo um ou mais aglomerados de pixel, não importantes para a busca,
gerando uma imagem resultado da intersecção – mostrado na FIGURA 22.
Caso o valor de pixel seja equivalente para o resultado da intersecção, é representado na
posição comparada com a cor da imagem objeto da imagem de classificação na imagem de
resultado da validação da árvore de decisão. Ao contrário, é representado na posição
comparada com a cor branca na imagem de resultado da validação da árvore de decisão.
A imagem obtida da validação da árvore de decisão após intersecção e a imagem do
canal de interesse tem de ser invertida – mostrado na FIGURA 23 e FIGURA 24, para que
seja visualizado um ou mais aglomerados de pixel equivalentes.
FIGURA 21 - Resultado da árvore de decisão sob a imagem da busca do objeto
FIGURA 22 - Intersecção do resultado da árvore de decisão e da imagem do canal de interesse
da busca do objeto
31
Através das imagens invertidas e contendo os resultados discriminativos do objeto se
pode identificar um ou mais aglomerados de pixel que devem ser filtrados pela área e pelo
centróide aproximado do objeto – mostrado na FIGURA 25, assim identificando o objeto em
questão, caso tenha sido encontrado – mostrado na FIGURA 26.
FIGURA 23 - Inversão da imagem canal de interesse da imagem de busca do objeto
FIGURA 24 - Inversão do resultado da árvore de decisão da imagem de busca do objeto
FIGURA 25 - Selecionando o objeto na imagem invertida através da área do objeto
32
Além disso, o método de identificação do objeto através da visão computacional para
ser capaz de identificar e localizar alvos em ambientes dinâmicos, trabalhando o uso da
segmentação de regiões, baseada em cores, deve buscar o apoio da estereoscopia.
3.6 Estereoscopia
Considerando que os procedimentos de busca do objeto tenham ocorrido sob duas
imagens com o uso de duas câmeras empregadas como olhos artificiais. Com a estereoscopia
quando coletadas duas imagens, estas imagens são concatenadas, recebendo busca de
semelhanças entre os objetos contidos num determinado conjunto.
A busca de semelhanças entre os objetos associa a percepção coletada através das
imagens à profundidade. Em seguida, é usado o deslocamento natural destas imagens
coletadas para medir a profundidade, denominando visão estereoscópica.
A profundidade pode ser detectada também usando apenas um olho, o processo não
ocorre com a mesma velocidade, ou seja, movendo-se a direção do olho em sua horizontal o
objeto mais próximo gera a impressão que ele estava mais rápido do que os objetos distantes,
denominando visão monoscópica [4].
A métrica na percepção de profundidade é conhecida como paralaxe, que resulta da
mudança de dois pontos estacionários, um relativo ao outro, percebida por um observador e
causada pela movimentação dos mesmos.
FIGURA 26 - Selecionando o objeto na imagem de busca do objeto através da referência obtida
na identificação
33
Com a visão estereoscópica, as imagens podem produzir o modelo visual tridimensional
do ambiente, reunindo duas imagens a apenas uma, sendo que nova imagem, passa a ter
características como: profundidade, distância, posição e tamanho.
Em resumo, pode-se dizer que nas imagens estereoscópicas, a quantidade de paralaxe,
ou seja, à distância interocular, que se propõe a distância entre a imagem da esquerda e a
imagem da direita, determinam a distância entre os objetos em relação ao observador [10].
A união das imagens, para compreensão de uma imagem estereoscópica necessita de
grande processamento, para visualizar de forma computacional o modo em que o ser humano
interpreta as imagens distintas coletadas por cada olho.
Quando tirada a foto de nossas retinas, e comparando-as para identificar que elas
também se sobrepõem, resultando na disparidade, obtêm-se a distância horizontal entre os
dois pontos das imagens. Desta forma, ao focalizar algo que está muito perto, medindo a
disparidade, podemos focalizar algo distante como o ambiente e perceber suas distâncias,
concluindo-se que suas distâncias são diferentes [10].
A disparidade no sistema de visão estéreo pode ser identificada pela diferença de
coordenadas dos pontos me e md, correspondendo um ponto M no espaço sob o plano de
imagens das câmeras que compõe o sistema – mostrado na FIGURA 27 [3].
Na visão estereoscópica, três problemas principais são trabalhados: calibração,
correspondência e reconstrução.
FIGURA 27 - Modelo de visão estéreo simplificado [3]
M
me md
md
me
d
34
Na calibração procura-se trabalhar os parâmetros que descrevem o sistema de aquisição
utilizado [3]. A configuração assumida neste modelo simplificado é o uso de duas câmeras
semelhantes e buscando alinhamento entre as câmeras utilizadas.
Através dos parâmetros usados no processo de calibração é possível realizar o
mapeamento de coordenadas da imagem, da câmera e do mundo [3].
O problema de correspondência consiste em determinar qual elemento na imagem
capturada corresponde a um dado elemento na imagem capturada sob outro ponto de vista.
A correspondência busca identificar quais pontos da imagem da esquerda e da direita é
projeção do mesmo ponto na cena tridimensional [3]. Alguns problemas podem ser
identificados como: oclusões, texturas, diferenças de iluminação e distorções projetivas.
Com base na distância entre os atributos associados aos pontos característicos
detectados, ou seja, para cada par correspondido é calculado o valor de disparidade com base
na distância relativa entre a coordenada dos mesmos [3].
Por sua vez, através da reconstrução procura-se recuperar a informação de profundidade
com base nos parâmetros obtidos na etapa de calibração e nos pares obtidos na etapa de
correspondência. Quanto ao que pode ser reconstruído depende do que é conhecido a respeito
da cena e do sistema de visão [3].
No processo de reconstrução é trabalhada a calibração métrica onde inicialmente cada
monocular é calibrado e em seguida executado a calibração da visão estérea.
Cada imagem, para que possa ser processada, requer um modelo matemático adequado.
O termo imagem refere-se à intensidade luminosa bidimensional, denotada por f(x,y), em que
o valor ou amplitude de f nas coordenadas espaciais (x,y) dá a intensidade (ou brilho) da
imagem naquele ponto [6].
Como base da natureza da f(x,y) define-se dois componentes: a quantidade de luz
incidindo sob a cena e a quantidade de luz refletida dos objetos da cena. Estes componentes
são chamados: iluminância e refletância, sendo representadas conforme mostra na seguinte
função: f(x,y) = i(x,y).r(x,y) [6].
A refletância está limitada entre: 0 e 1; e a iluminância compreende em valores maiores
que 0, sendo determinada pela fonte de luz e pela própria refletância das características físicas
dos objetos [6].
O valor de f(x,y) quando representado em uma estrutura matricial denomina-se pixel.
Quando a imagem está sendo representada na forma monocromática, o pixel representa no
nível de escala de cinza. Já em imagens coloridas, o pixel representa uma cor, sendo definida
por um determinado modelo de cores [6].
35
Os modelos de cores são utilizados para especificar cores, os mais comuns são: RGB
(red, green e blue), CMY (cian, magent e yellow), YCrCb e o HSI (hue, saturation, intensity)
[6].
As câmeras deste projeto utilizaram-se do padrão RGB, sendo composto por três
valores: vermelho (red), verde (green) e azul (blue). Assim, qualquer cor pode ser definida em
função destes três componentes [6].
Se for considerado que a intensidade é o grau claro ou escuro de um pixel, no modelo
RGB a intensidade então é dada pelo módulo da distância da origem ao pixel considerado.
Portanto, o menor módulo ou a origem, representa a cor preta e o maior módulo
representa a cor branca. Da mesma forma, o matiz ou a cor é definido pela posição angular do
vetor do pixel em relação aos eixos das cores fundamentais deste modelo: vermelho, verde e
azul – mostrado na FIGURA 28 [6].
Conforme cada uma das imagens – mostrado na FIGURA 29, inicia-se a concatenação
das imagens – mostrada na FIGURA 30 - com base na distância entre os atributos associados
aos pontos característicos detectados, ou seja, onde ocorrer a intersecção das imagens é onde
inicia a sobreposição.
Independente se na região onde os pontos sejam equivalentes tenha ocorrido alguns
pontos não equivalentes a sobreposição ocorrerá, prevalecendo à paralaxe.
FIGURA 28 - Modelo de cores RGB [6]
Verde = ( 0, 1, 0 )
Ciano = ( 0, 1, 1 ) Azul = ( 0, 0, 1 )
Magenta = ( 1, 0, 1 )
Vermelho = ( 1, 0, 0 ) Amarelo = ( 1, 1, 0 )
Branco = ( 1, 1, 1 )
Preto = ( 0, 0, 0 )
36
Alguns fatores como a quantidade de luz refletida dos objetos da cena podem fazer com
que um determinado pixel seja representado por outra cor, representando diferenças entre as
duas imagens.
A busca na imagem concatenada é executada como em qualquer outra imagem,
primeiramente executando os procedimentos detalhados anteriormente, para que exista
compreensão da validação da árvore de decisão, gerando uma imagem resultado com o
propósito de identificar um ou mais aglomerados de pixel que devem ser filtrados pela área e
pelo centróide aproximado do objeto, assim identificando o objeto em questão, caso tenha
sido encontrado.
Intersecção em 2 pixels conforme paralaxe.
Imagem Esquerda Imagem Direita
Imagem Concatenada
FIGURA 29 - Modelo de imagem esquerda e direita
FIGURA 30 - Modelo de imagem concatenada
37
4 MOVIMENTOS DIRIGIDOS A DETECÇÃO DOS OBJETOS
A relação definida pelos movimentos dirigidos a detecção dos objetos dá-se pela
coordenação de comportamentos e a identificação de objetos. A cada imagem reconhecida
através do processo de identificação de objetos, o algoritmo de coordenação busca orientar o
melhor comportamento.
A orientação do melhor comportamento ocorre por via de um escalonador simples,
sendo invocado pelo controle em nível de meta e recebendo a estrutura da tarefa e os critérios
a serem atendidos como entradas. Suas informações são abstratas, pré-analisadas pela
identificação do alvo e repassadas ao escalonador que deve associar um atributo definido
buscando refletir a percepção do veículo com relação aos obstáculos próximos, ou mesmo ao
próprio alvo, determinada como tarefa associada [13].
O agente conhece as situações no contexto específico considerando os critérios a serem
atendidos e um conjunto de parâmetros de escalonamento, determinado como entradas.
Assim, podemos determinar que o escalonamento retorne uma sucessão de ações primitivas
gerando comportamentos propositais [13].
Os comportamentos propositais, também vistos como atributos binários são [1]:
Alvo livre (FreeTarget): quando não existe nenhum obstáculo entre o veículo e o alvo
ou mesmo quando muito distante de alvos ou obstáculos, ou seja, os sonares possuem
suas leituras acima do limiar de avaliação e assim este atributo é ativo[1].
Atrás do alvo (BackTarget): se ativo o sonar traseiro, pode referir-se ao alvo que se
encontra atrás do veículo, desta forma não é possível avaliar se existe um obstáculo
entre o alvo e o veículo[1].
Obstáculo ao lado (SideObstacle): define a existência de um ou mais obstáculos
próximos ao veículo em sua lateral através de sonares laterais[1].
Obstáculo em diagonal (DiagonalObstacle): ativado através de sonares em sua
diagonal quando a presença de obstáculos[1].
Entre obstáculos (MiddleObstacle): determina-se ativo a existência de um obstáculo a
uma distância média, caracterizada por qualquer sonar, porém não implica em
perigo[1].
Caminho estreito (NarrowPath): quando ativo seus sonares laterais, refere-se a um
caminho estreito, ignorando alguns atributos informados (MiddleObstacle,
DiagonalObstacle, SideObstacle, BackTarget e FreeTarget) [1].
38
Obstáculo frontal (FrontalObstacle): definem-se quando o sonar frontal estiver ativo,
detectando a presença de um obstáculo próximo e caracterizando um perigo eminente.
Quando ativo, todos os demais são ignorados e passa a ser tomado uma ação a afastar-
se deste obstáculo[1].
Pode-se visualizar os modelos dos atributos detalhados graficamente – mostrado na
FIGURA 31.
FreeTarget SideObstacle MiddleObstacle
FrontalObstacle DiagonalObstacle BackTarget
NarrowObstacle
FIGURA 31 - Atributos combinados a comportamentos [1]
39
5 A ESTRUTURA DO VEÍCULO
O desenvolvimento do protótipo deste veículo (APÊNDICE C – Resultado do
desenvolvimento do veículo através das imagens) necessitou inúmeras etapas, onde cada uma
se relacionam às outras, sendo necessárias que destas diversas linhas de trabalho fossem
evoluídas de forma paralela para o andamento constante do projeto. Sendo assim estas etapas
foram divididas em:
Seleção das linguagens no qual dão suporte ao desenvolvimento do navegador;
Seleção e aquisição dos componentes físicos (computador portátil, câmeras e outros);
Implementação de software para um microcontrolador com o papel atuador;
Implementação de software com o papel de agente;
Implementação de uma biblioteca para aquisição e processamento de imagens;
Desenvolvimento da mecânica para suportar os componentes físicos deste projeto
(computador portátil, câmeras e outros);
Desenvolvimento do circuito elétrico para acionamento dos motores;
Calibração dos processos de navegação.
5.1 Aplicações desenvolvidas
A necessidade de duas aplicações neste projeto tem-se por sua localização lógica. Uma
aplicação está embarcada no microcontrolador Rabbit, recebendo a coordenação do
comportamento, executando-a, ou seja, tendo o papel de atuador. A outra aplicação está
instalada no computador portátil, fazendo o papel de agente, com a responsabilidade da
análise do comportamento atual, obtendo as imagens, somando-as e decodificando-as.
5.1.1 Aplicação de papel agente
A aplicação agente (APÊNDICE B – Código agente desenvolvido para o computador
portátil) foi executada sob o sistema operacional Windows disponível no computador portátil,
sendo desenvolvida usando ANSI C e C++ devido às necessidades do projeto, podendo
40
também ser portável para o Linux, mas, requerendo uma nova compilação dos códigos fontes
para geração de um novo binário.
Inicialmente esta aplicação foi desenvolvida sob o Linux, sendo ajustada para o
Windows devido à busca de um menor custo para o desenvolvimento do projeto.
O uso do C++ foi para desenvolvimento de uma nova biblioteca para expor funções a
linguagem ANSI C, com a responsabilidade de conceder a classificação e detecção de objetos
com o uso de funcionalidades da biblioteca OpenCv. A classificação dos objetos conhecidos
pela biblioteca ocorre através de imagens armazenadas em um repositório. A biblioteca
desenvolvida em C++ também agrega funções do framework CvBlob com uso da biblioteca
OpenCv, apoiando o processamento das imagens obtidas do cenário atual buscando a
identificação e a localização do conjunto de objetos conhecidos.
Quanto ao uso do ANSI C, foi para desenvolvimento da aplicação principal, agregando
a responsabilidade capturar as imagens das câmeras e geração dos eventos para a aplicação de
papel atuador.
Após a identificação e a localização dos objetos através da biblioteca, obtêm-se um
resultado que define uma determinada ação, que deve ser encaminhada para a aplicação de
papel atuador através do canal de comunicação.
Além disso, o uso do ANSI C é acompanhado pela biblioteca Windows Socket 2,
responsável por estabelecer o canal de comunicação entre a aplicação de papel agente e a
aplicação de papel atuador, para que, ao inicializar a aplicação, seja iniciado um servidor de
comunicação agregado a aplicação sob a porta TCP de número 5150, assim disponibilizando
uma conexão de entrada [12].
Quanto à aquisição da imagem, ocorre através desta aplicação, acionando cada câmera
através da biblioteca OpenCv que utiliza-se das funções disponíveis do framework do
DirectShow disponível no pacote do DirectX. Cada imagem adquirida é repassada para a
biblioteca desenvolvida em C++ para processamento, identificação e a localização dos objetos
conhecidos.
O papel da aplicação agente tem algumas responsabilidades, como:
Armazenamento dos comportamentos executados pelo veículo;
Disponibilizar uma conexão de entrada através da porta Ethernet sob o protocolo TCP
para que o atuador possa enviar consultas do protocolo interno de comunicação e
receber suas informações;
Coordenação do movimento a ser executado pela aplicação com papel de atuador, ou
seja, envio de comando para o atuador;
41
Configuração e aquisição das imagens das duas câmeras agregadas ligadas ao
computador portátil através das portas USB;
Somatória das imagens capturadas das câmeras distintas respeitando a paralaxe,
somente após terem sido decodificadas;
Localização e decodificação dos objetos disponíveis no banco de imagens;
Localização dos objetos decodificados do banco de imagens na imagem somada e
decodificada;
Para a visão computacional implantada na aplicação agente, o grande número de cores
possíveis apresenta-se como um problema para a comparação de imagens, sendo assim,
alguns filtros são aplicados sob cada imagem capturada ou mesmo inserida no banco de
imagens para busca de um objeto.
A aplicação agente, durante sua inicialização, faz uma leitura em seu diretório de
imagens armazenadas no padrão PNG ou JPEG, localizando quais são seus possíveis objetos e
seus respectivos fundos do objeto, assim iniciando uma lista de objetos para possível
classificação da árvore de decisão.
Cada objeto classificado e contido na lista de objetos define um conjunto de atributos,
como algumas leituras iniciais da imagem, sendo apresentadas pelos seguintes atributos:
tamanho da imagem, área, centróide e demais detalhes para identificação do objeto.
A cada movimento dado como estado encerrado ou estado parado, a aplicação agente
executa uma leitura do quadro de imagem disponível em cada uma das câmeras.
O acesso a visão computacional ocorre diretamente na aplicação desenvolvida em ANSI
C através da biblioteca OpenCv, que utiliza-se do framework DirectShow que provê o acesso
a uma imagem de um vídeo ou de um dispositivo de captura de imagens, através de filtros que
podem interceptar dados por via de um gerenciador gráfico toda vez em que um evento é
disparado, da seguinte forma [11]:
Instancia-se um gerenciador gráfico disponível no framework DirectShow.
Filtra-se os dispositivos do tipo entrada de vídeo disponíveis no sistema operacional e
depois seleciona-se um dispositivo conforme o índice informado pela aplicação
agente.
A seleção do dispositivo ocorre inicializando um filtro associado ao dispositivo
enumerado;
42
Além do filtro associado ao dispositivo enumerado, são instanciados mais dois filtros,
um para a fonte da imagem e outro para o processamento da imagem, para ajustes de
cor ou formato;
Os filtros definidos como fonte da imagem e processamento da imagem devem ser
conectados ao gerenciador gráfico;
Cria-se um método coletor de agente de amostras de imagens sendo associado ao
gerenciador gráfico, onde mais de uma imagem é adquirida, mantendo o dispositivo
em constante aquisição de imagens até que o dispositivo seja encerrado;
Em seguida aloca-se um gerenciador de eventos, para relacionar um evento ao
gerenciador gráfico e quando este evento retornar a situação de aquisição como
completa através de um método, a imagem já pode ser lida através de uma cadeia de
bytes, ou seja, um quadro de imagem.
Conforme citado anteriormente, após cada câmera estar configurada numa resolução de
640 pixels de largura por 480 pixels de altura, a aplicação agente executa a leitura das
imagens. Primeiramente, é lido o quadro de imagem da Câmera 0, obtendo a imagem da
esquerda, e em seguida, executa uma leitura na Câmera 1, obtendo a imagem da direita, onde
as duas câmeras devem ser lidas com sucesso, caso contrário, o procedimento é reiniciado.
Porém, entre uma câmera e outra, têm-se uma distância, definida como: paralaxe,
determinando a distância entre as imagens para somá-las e assim, obter a profundidade
desejada em relação ao objeto fundido na mesma.
Para cada par de imagens são executados os procedimentos de identificação de objeto
conforme detalhados anteriormente, para que exista compreensão da validação da árvore de
decisão, assim identificando o objeto em questão, caso tenha sido encontrado.
Os movimentos solicitados são conhecidos entre a aplicação de papel agente e a
aplicação de papel atuador. Desta forma, conforme o movimento desejado pela aplicação
agente, este deve ser enviado para o canal de comunicação com o dispositivo embarcado
somente após ser questionado por um novo movimento.
O canal de comunicação disponível pela aplicação de papel agente através da porta
Ethernet usando de um socket TCP sob a porta de número 5150 tem de respeitar o protocolo
de comunicação conhecido pelo dispositivo embarcado.
O protocolo de comunicação estabelecido entre as aplicações tem como responder qual
o movimento a executar, a data e hora do sistema e o nome do projeto. Os comandos
disponíveis no protocolo como: a data e hora do sistema e o nome do projeto, não tem
43
importância fundamental ao projeto, mas buscam mostrar que o sistema está funcionando
normalmente, ou seja, representando um caminho de teste de forma contínua.
A aplicação de papel agente tem de responder o próximo movimento a executar, caso
exista ou a data e hora do sistema ou nome do projeto, conforme a solicitação da aplicação de
papel atuador. A resposta para a aplicação de papel atuador ocorre pelo mesmo canal de
comunicação, ou seja, pelo canal em que a aplicação agente foi questionada, sem abrir uma
nova conexão.
5.1.2 Aplicação de papel atuador
A aplicação de papel atuador (APÊNDICE A – Código atuador desenvolvido para o
microcontrolador) foi executada sob nenhum sistema operacional, mas utilizando um
firmware desenvolvido no padrão ANSI C.
Sendo instalado em uma arquitetura embarcada da empresa Rabbit Semiconductor,
escolhida pela disponibilidade imediata, pelo baixo consumo de energia e pela disponibilidade
de recursos de hardware e de bibliotecas de software.
A arquitetura embarcada é programável com microcontrolador Rabbit de 22.1 MHz com
256K de memória FLASH e 128K de memória SRAM no modelo RCM2200 – mostrado na
FIGURA 32, onde a mesma disponibiliza diversas funcionalidades como: comunicação por
portas seriais, comunicação por portas paralelas, relógios e comunicação por uma porta
Ethernet [7].
O papel atuador da aplicação define responsabilidades, como:
Execução dos comportamentos solicitados pela aplicação agente;
Estabelecer uma conexão com a aplicação agente através de sua conexão de
entrada sob a porta Ethernet usando de um socket cliente com o protocolo TCP;
FIGURA 32- Arquitetura embarcada RCM2200 [7]
44
Acionamento dos motores de passo de acordo com os comportamentos
solicitados pela aplicação agente;
O canal de comunicação da aplicação de papel atuador inicia-se na porta Ethernet
usando um socket através do acesso de uma porta TCP de número compreendido entre 1024 e
65535, acessando a aplicação de papel agente sob a porta de número 5150 e respeitando o
protocolo conhecido entre ambas as aplicações.
O protocolo de comunicação disponível na aplicação de papel atuador busca questionar
se existe movimento a executar, a data e hora do sistema e o nome do projeto. Depois de
questionado a aplicação de papel agente, a aplicação de papel atuador fica aguardando a
resposta e quando recebê-la, interpreta a informação recebida e executa uma determinada
função.
5.2 Os motores do veículo
Cada motor do veículo utilizado foi do tipo motor de passo unipolar sendo acionado
pela arquitetura embarcada RCM2200 – mostrado na FIGURA 33 - através de um
componente ULN2803 composto por 8 transistores do tipo Darlington. O componente
ULN2803 é alimentado pelo mesmo circuito que alimentara a arquitetura embarcada sendo
capaz de lidar na entrada com uma tensão máxima de 30 V ou uma corrente de 500mA [8].
O papel de cada motor de passo é ser um eletromecânico incremental, onde sua
energização ocorre de maneira seqüencial de cada enrolamento individual, a partir de uma
fonte CC, realizadas por chaves semicondutoras (transistores bipolares ou MOSFETs) [14].
FIGURA 33 - Circuito de acionamento dos motores
ULN2803
1 IN 1 OUT 1 18
2 IN 2 OUT 2 17
3 IN 3 OUT 3 16
4 IN 4 OUT 4 15
5 IN 5 OUT 5 14
6 IN 6 OUT 6 13
7 IN 7 OUT 7 12
8 IN 8 OUT 8 11
9 GND DIODE
CLAMP 10
+12V
B D
A
C
GND
PA0
PA1
PA2
PA3
PA4
PA5
PA6
PA7
A
C
GND
+12V
B D
RC
M2
20
0
+12V
45
O acionamento dos motores através do microcontrolador RCM2200 ocorre por algumas
das portas paralelas disponíveis nesta arquitetura. As portas PA0, PA1, PA2, PA3, PA4, PA5,
PA6 e PA7 do módulo RCM2200 determinam qual é o estado da bobina de acordo com a
necessidade.
O estado de cada bobina de cada motor são comandos enviados por pulsos digitais,
provocando um deslocamento discreto e síncrono com os mesmos (devido ao alinhamento
magnético dos pólos nas estruturas do rotor e estator do motor) denominados "passos" [14].
A cada pulso de alimentação aplicado em uma bobina do estator, o rotor estaciona em
uma posição estável e única, guardando entre um passo e outro a mesma precisão, sem erros
acumulativos [14].
Sendo assim, conforme o dado recebido através do driver, seu sentido pode ocorrer da
forma anti-horário devido aos dados darem a ordem decrescente aos passos, caso contrário, a
orientação do motor é na forma horária.
Além da seqüência, em que as bobinas estão ligadas para provocar a orientação do
motor de passo, pode-se também obter seqüências de bobinas ligadas buscando um torque
maior ou menor.
A operação para ajustar o torque do motor de passo pode ser definida através da
seqüência das bobinas que estão ligadas, compondo uma tabela de possibilidades que pode ser
utilizada, onde três modos podem ser usados.
Estes modos se definem como: modo de seqüência normal, modo de seqüência "wave
drive" e modo de seqüencia de passo médio.
Para o modo de seqüência normal, o motor avança um passo por vez, devido ao fato de
existir sempre pelo menos duas bobinas ligadas por vez e obtêm-se um alto torque de passo e
de retenção, onde o torque é a força exercida sob o rotor do motor, por conseqüência a força
exercida faz o rotor a girar [9].
O modo de seqüência “wave drive” de passo – mostrado na TABELA 1 - é usado com
uma bobina ativada por vez, fornecendo em alguns motores um passo mais suave, mas
gerando um torque e retenção menor que a seqüência normal de passo [9].
Outro modelo é a seqüência de passo médio, ativando as bobinas para que seja
fornecido um impulso igual à metade da passagem do real, ativando a orientação de quando
ligar duas bobinas, no próximo estágio é ligado apenas uma e assim por diante, compondo um
conjunto de 8 movimentos [9].
46
Passo Bobina A Bobina B Bobina C Bobina D Demonstração
1 Ligada Desligada Desligada Desligada
2 Desligada Ligada Desligada Desligada
3 Desligada Desligada Ligada Desligada
4 Desligada Desligada Desligada Ligada
5.3 A mecânica do veículo
A estrutura mecânica, também denominada como chassi do veículo autônomo, sustenta
os componentes do projeto como: um computador portátil, as duas câmeras USB, um circuito
com a arquitetura embarcada RCM2200 e os dois motores de passo fixados de forma paralela
e conectados cada um a uma roda.
Este chassi foi desenvolvido especificamente para suportar os componentes citados
anteriormente, onde suas medidas foram estabelecidas de acordo com a necessidade.
5.4 A alimentação de energia do veículo
A fonte de energia do veículo ocorre através de uma fonte de alimentação de 12 volts
com carga máxima de 1,5 ampères que está sob o chassi, fornecendo energia para os motores
através do componente ULN2803 e outra fonte de alimentação de 5 volts com carga máxima
de 1 ampère, alimentando o circuito da arquitetura embarcada RCM2200.
TABELA 1 - Seqüência “wave drive” do motor de passo [9]
A
B D
C
A
B D
C
A
B D
C
A
B D
C
47
Os demais dispositivos não precisam de qualquer alimentação externa, uma vez que o
computador portátil possui sua própria bateria, alimentando seus dispositivos agregados.
48
6 CONCLUSÃO
Durante o desenvolvimento foi possível identificar quais são as variáveis problemáticas
dos sistemas autônomos e também do sistema de identificação visual, mesmo assim, foi
proposto e desenvolvido um protótipo simplificado, mostrando sua complexidade, onde
poderá ser melhorado através de trabalhos futuros.
A identificação visual desenvolvida limitou-se a detecção de objetos através de fundos
homogêneos e limitando-se aos objetos conhecidos ao conteúdo de sua base de dados. Mesmo
assim, os resultados de detecção de objeto mostraram-se coerentes, selecionado o objeto
desejado.
O uso de ferramentas sem muita precisão ou a reciclagem de componentes eletrônicos
ou mecânicos, retornaram alguns resultados não esperados, vindos do protótipo desenvolvido.
Pode-se observar a dificuldade na escolha de um motor que possuísse maior torque obtendo-
se um problema na navegação do veículo, que é composta pela sua movimentação de acordo
com a localização e distância do objeto.
As teorias aplicadas neste trabalho podem ser empregadas em diversos projetos, tanto
voltado para o modelo de autonomia, onde exista a necessidade de decisão, quanto para o
modelo de identificação visual usando estereoscopia, onde inúmeras aplicações podem ser
desenvolvidas, como: veículos para deficientes visuais, veículos vigilantes e entre outros.
6.1 Trabalhos futuros
Buscando extensões deste trabalho, novos itens podem ser agregados:
Novos filtros de imagem;
Decisão uma coordenação por estatística do ambiente conhecido;
Análise por histograma de cor;
Aviso sonoro ao protótipo quando identificado um objeto;
Otimização do protótipo.
49
REFERÊNCIAS BIBLIOGRÁFICAS
[1] Selvatici, Antonio H. P.; Costa, Anna H. R. Aprendizado da coordenação de comportamentos primitivos para
robôs móveis. Disponível on-line em http://www.lti.pcs.usp.br/publicacoes/SelvaticiCosta05a-SBAI.pdf.
[2] Pacheco, Rafael N.; Costa, Anna H. R. Navegação de robôs móveis utilizando o método de campos
potenciais. Disponível on-line em http://www.lti.pcs.usp.br/robotics/react/html/workcomp2002-react.pdf.
[3] Stivanello, Mauricio E.; Leal, Eduardo S.; Palluat, Nicolas; Stemmer, Marcelo R. Desenvolvimento de uma
biblioteca para sistemas de visão estereoscópica para robótica móvel. Disponível on-line em
http://s2i.das.ufsc.br/s2i3dlib/publicacoes/40944_Induscon2008.pdf.
[4] Leite, Pedro J. S. Openstereo: uma biblioteca para suporte ao desenvolvimento de aplicações estereoscópicas.
Disponível on-line em http://www.cin.ufpe.br/~tg/2006-1/pjsl.pdf.
[5] Embrapa Informática Agropecuária. Fusão espectral de Imagens de Satélite no Espaço de Cores. Disponível
on-line em http://www.cnptia.embrapa.br/files/comtec84.pdf.
[6] Schneider, Marcos R. Sistema de segurança e proteção baseado em visão computacional. Disponível on-line
em http://arquivos.cpgei.ct.utfpr.edu.br/Ano_2007/dissertacoes/Dissertacao_443_2007.pdf.
[7] Rabbit Semiconductor. RCM2200 RabbitCore User's Manual. Disponível on-line em
http://www.rabbit.com/hottag/index.php?ht=/documentation/docs/manuals/RCM2200/UsersManual/RC2200UM
.pdf.
[8] Motorola. Octal High Voltage, High Current Darlington Transistor Arrays. Disponível on-line em
http://elab.ist.utl.pt/rec/Controlo_Experiencias/placa_dsPIC/ULN2803.pdf.
[9] González, Alí M. Construcción de un vehículo todo terreno con control de señales para movimientos básicos.
Disponível on-line em
http://www.uppuebla.edu.mx/Profesores/INFORMATICA/PRODUCCION_CIENTIFICA/ANTONIO/reporteTe
cnico_Ali.pdf.
[10] Momm, Edson. Protótipo de um ambiente de visualização com técnicas de estereoscopia. Disponível on-line
em http://campeche.inf.furb.br/tccs/2001-II/2001-2edsonmommap.pdf.
[11] Wallega. DirectShow Single-Frame Capture Class Without MFC. Disponível on-line em
http://www.codeguru.com/cpp/g-m/multimedia/video/article.php/c9551/.
[12] Microsoft. Windows Sockets 2. Disponível on-line em http://msdn.microsoft.com/en-
us/library/ms740673(v=VS.85).aspx.
[13] Alves, Daniela P. Modelagem de aprendizagem por reforço e controle em nível meta para melhorar a
performance da comunicação em gerência de tráfego aéreo. Disponível on-line em
http://monografias.cic.unb.br/dspace/bitstream/123456789/79/1/Dissertacao_Final.pdf.
[14] Bianchi, Reinaldo A. C. Visão computacional aplicada ao controle de micro robôs. Disponível on-line em
http://www.fei.edu.br/~rbianchi/publications/microrobos-FEI2001.pdf.
[15] Martins, Murilo F. Aprendizado por reforço acelerado por heurísticas aplicado ao domínio do futebol de
robôs. Disponível on-line em http://www.iis.ee.ic.ac.uk/~murilo/papers/martins07mscthesis.pdf.
[16] Tagliaferro, Fatima A. Técnicas de reconhecimento automatizado de padrões baseados em imagens digitais.
Disponível on-line em http://bibdig.poliseducacional.com.br/document/?down=65.
50
[17] Neto, João E. S. B. Processamento de imagens. Disponível on-line em
http://www.lcad.icmc.usp.br/~jbatista/procimg/pre_proc.ppt.
[18] Conci, Aura; Nunes, Éldman de O. Algoritmo genético para classificação temáticade imagens
multiespectrais. Disponível on-line em http://www.ic.uff.br/~aconci/spolmeldman2005.pdf
[19] Silva, Luiza M. O. da. Uma Aplicação de Árvores de Decisão, Redes Neurais e KNN para a Identificação
de Modelos ARMA Não-Sazonais e Sazonais. Disponível on-line em http://www2.dbd.puc-
rio.br/pergamum/tesesabertas/0024879_05_cap_03.pdf
[20] Winn, John. The Layout Consistent Random Field
for detecting and segmenting occluded objects. Disponível on-line em
http://johnwinn.org/Presentations/presentations/LayoutCRF_Expanded.ppt.
[21] Neto, João E. S. B. Visão Computacional e Aplicações. Disponível on-line em
http://www.lcad.icmc.usp.br/~jbatista/procimg/apres_lin.ppt.
[22] Rudek, Marcelo; Coelho, Leandro dos S.; Junior, Osiris C. Visão computacional aplicada a sistemas
produtivos: fundamentos e estudo de caso. Disponível on-line em
http://www.abepro.org.br/biblioteca/ENEGEP2001_TR10_0917.pdf
[23] Fonseca, José M. Acondicionamento da imagem. Disponível on-line em http://www-
ssdp.dee.fct.unl.pt/leec/ss/20042005/documentos/4%20-%20Acondicionamento.pdf
[24] Gattass, Marcelo. Imagem digital. Disponível on-line em http://www.tecgraf.puc-
rio.br/~mgattass/cg/pdf/03_ImagemDigital.pdf
51
APÊNDICES
52
APÊNDICE A – Código atuador desenvolvido para o microcontrolador
/** Descrição da biblioteca ***************************************************/
/** Projeto: Georobo **/
/** Autor: Rafael Roberto Prado **/
/** Nome do fonte: georobo.c Data:27/04/2010 **/
/************************************************************************/
#class auto
#define VERBOSE
#define TCP_CONFIG 1
#define PORTDATA 5150
#define MAX_STREAM_BUFFER 1024
#define NAVEGAR_LARGURA_PASSO 1000
#define NAVEGAR_TEMPO_PASSO 12000
#define NAVEGAR_DIREITA 0x01
#define NAVEGAR_ESQUERDA 0x02
#define NAVEGAR_PROSSEGUIR 0x03
#define NAVEGAR_RETORNAR 0x04
#use "dcrtcp.lib"
#use "connector.lib"
#use "realtime.lib"
struct { char host[20];
char netmask[20];
char nameserver[20];
char gateway[20];
} ipAddress;
//
char defaultIpAddress;
int typeIpAddress;
void* save_data[3];
unsigned int save_lens[3];
CoData initialConfig, startClock, startQuestions, startAction;
int actionState;
char actionData;
void writehostid ();
void inicializaControleMotor();
53
void selecionaMovimentoMotor(char movimento);
////////////////////////////////////////////////////////////////////////
void main()
{
int resSock;
tcp_Socket socket;
char buffer[MAX_STREAM_BUFFER];
int numBytesReceive;
//
actionData = 0;
//
inicializaControleMotor();
// Executa primeira demonstracao do motor
selecionaMovimentoMotor(NAVEGAR_PROSSEGUIR);
// Executa primeira demonstracao do motor
//selecionaMovimentoMotor(NAVEGAR_RETORNAR);
// Executa primeira demonstracao do motor
//selecionaMovimentoMotor(NAVEGAR_DIREITA);
// Executa primeira demonstracao do motor
//selecionaMovimentoMotor(NAVEGAR_ESQUERDA);
//
if ( BitRdPortI( PDDR, 3 ) == 0 )
{
strcpy(ipAddress.host,_PRIMARY_STATIC_IP);
strcpy(ipAddress.netmask,_PRIMARY_NETMASK);
strcpy(ipAddress.nameserver,MY_GATEWAY);
strcpy(ipAddress.gateway,MY_GATEWAY);
defaultIpAddress = 'S';
typeIpAddress = 1;
save_data[0] = &ipAddress;
save_lens[0] = sizeof(ipAddress);
save_data[1] = &defaultIpAddress;
save_lens[1] = sizeof(defaultIpAddress);
save_data[2] = &typeIpAddress;
save_lens[2] = sizeof(typeIpAddress);
writeUserBlockArray(0, save_data, save_lens, 3);
}
//
readUserBlockArray(save_data, save_lens, 4, 0);
//
if ( defaultIpAddress != 'N' )
{ strcpy(ipAddress.host,_PRIMARY_STATIC_IP);
strcpy(ipAddress.netmask,_PRIMARY_NETMASK);
strcpy(ipAddress.nameserver,MY_GATEWAY);
strcpy(ipAddress.gateway,MY_GATEWAY);
defaultIpAddress = 'S';
typeIpAddress = 1;
54
save_data[0] = &ipAddress;
save_lens[0] = sizeof(ipAddress);
save_data[1] = &defaultIpAddress;
save_lens[1] = sizeof(defaultIpAddress);
save_data[2] = &typeIpAddress;
save_lens[2] = sizeof(typeIpAddress);
writeUserBlockArray(0, save_data, save_lens, 3);
}
//
printf( "using ip: %s\n", ipAddress.host );
printf( "using netmask: %s\n", ipAddress.netmask );
printf( "using gateway: %s\n", ipAddress.gateway );
printf( "using nameserver: %s\n", ipAddress.nameserver );
//
printf( "initializing ...\n" );
sock_init();
//
printf( "interface is come down ...\n" );
ifconfig(IF_ETH0, IFS_DOWN, IFS_END);
//
printf( "interface is come up ...\n" );
if ( typeIpAddress == 1 )
{
printf( "interface is static ...\n" );
ifconfig ( IF_ETH0,
IFS_IPADDR, aton(ipAddress.host),
IFS_NETMASK, aton(ipAddress.netmask),
IFS_ROUTER_SET, aton(ipAddress.gateway),
IFS_NAMESERVER_SET, aton(ipAddress.nameserver),
IFS_UP,
IFS_END );
//
}
else
if ( typeIpAddress == 0 )
{
printf( "interface is dynamic ...\n" );
ifconfig ( IF_ETH0,
IFS_DOWN,
IFS_DHCP, 1,
IFS_DHCP_TIMEOUT, 8,
IFS_IPADDR, aton(ipAddress.host),
IFS_NETMASK, aton(ipAddress.netmask),
IFS_DHCP_FALLBACK, 1,
IFS_UP,
IFS_END );
}
printf( "wait for the interface to come up ...\n" );
while (ifpending(IF_DEFAULT) == IF_COMING_UP)
{
55
tcp_tick(NULL);
}
//
printf("initializing communication with server: %s:%d ...\n", ipAddress.gateway,
PORTDATA);
//
resSock = 0;
printf("socket result: %d ...\n", resSock);
//
printf("waiting for connection...\n");
//
while(1)
{
if( resSock == 0 )
{
resSock = tcp_open(&socket,0,inet_addr(ipAddress.gateway),PORTDATA,NULL);
printf("socket result: %d ...\n", resSock);
}
else
{
if (!sock_established(&socket) && sock_bytesready(&socket)==-1)
{
tcp_tick(NULL);
}
else
{
if ( tcp_tick(&socket) )
{
if (sock_bytesready(&socket) >= 0)
{
numBytesReceive = sock_fastread ( &socket,
buffer, sizeof(buffer)-1 );
if( numBytesReceive > 0 )
{
dataSocket( buffer, numBytesReceive );
}
}
}
}
//
costate initialConfig init_on
{
printf("initial config on.\n");
// Consultar nome do projeto
connectorSend( &socket, PROJECTPACKET );
// Executa segunda demonstracao do motor
selecionaMovimentoMotor(NAVEGAR_PROSSEGUIR);
// Gerenciar estados
CoPause (&startClock);
CoResume (&startQuestions);
56
CoPause (&startAction);
}
//
costate startQuestions always_on
{
printf("startquestions on.\n");
//writehostid();
// printf(ipAddress.host);
waitfor ( DelayMs(200) );
// Questionando a hora ao servidor
connectorSend( &socket, DATETIMEPACKET );
waitfor ( DelayMs(100) );
// Iniciando processo de visualizacao da hora
CoResume(&startClock);
waitfor ( DelayMs(150) );
//
if ( actionData == 0 )
{
// Questionando se o servidor possui alguma acao a executar
connectorSend( &socket, HAVEACTIONPACKET );
}
else
{
actionState = 1;
//
CoResume (&startAction);
}
}
//
costate startClock
{
if ( actionState == 0 )
{
// Enquanto nao recebe acao imprime a hora
printingTime();
//
actionState = 1;
waitfor ( DelayMs(150) );
}
else
{
// Inicia processo de execucao de acao
CoResume (&startAction);
}
}
//
costate startAction
{
if ( actionState == 1 )
{
57
CoPause (&startQuestions);
// Verifica acao a ser executada e executa-a
if ( actionData > 0 )
{
printf("executa movimento...\n");
selecionaMovimentoMotor(actionData);
actionData = 0;
}
// Reinicia estado das acoes
actionState = 0;
// Avisa que a acao foi executada, o processo estara aguardando outra acao ser
executada
connectorSend( &socket, ACTIONPACKET );
// Retorna processo de questionamento de acoes
CoResume(&startQuestions);
}
}
}
}
//
if( resSock == 1 )
{
sock_abort(&socket);
}
printf("\nConnection closed...\n");
}
//
void writehostid ()
{
char buffer[ 20 ];
strcpy( ipAddress.host, inet_ntoa ( buffer, gethostid() ) );
save_data[0] = &ipAddress;
save_lens[0] = sizeof(ipAddress);
save_data[1] = &defaultIpAddress;
save_lens[1] = sizeof(defaultIpAddress);
save_data[2] = &typeIpAddress;
save_lens[2] = sizeof(typeIpAddress);
writeUserBlockArray(0, save_data, save_lens, 3);
}
//
void inicializaControleMotor()
{
// Inicializando as portas A
WrPortI ( PADR, &PADRShadow,0x00 );
WrPortI ( SPCR, &SPCRShadow,0x84 );
}
//
void selecionaMovimentoMotor(char movimento)
{
int estMotor1;
58
char senMotor1;
int estMotor2;
char senMotor2;
//
int numRotacao;
int idxTempo;
//
numRotacao = 0;
// iniciando o estado dos motores
estMotor1 = 1;
estMotor2 = 1;
// iniciando o sentido dos motores
senMotor1 = 1;
senMotor2 = 1;
//
if ( movimento == NAVEGAR_DIREITA )
{
// iniciando o estado dos motores
estMotor1 = 1;
estMotor2 = 1;
// iniciando o sentido dos motores
senMotor1 = 2;
senMotor2 = 1;
}
else
if ( movimento == NAVEGAR_ESQUERDA )
{
// iniciando o estado dos motores
estMotor1 = 1;
estMotor2 = 1;
// iniciando o sentido dos motores
senMotor1 = 1;
senMotor2 = 2;
}
else
if ( movimento == NAVEGAR_RETORNAR )
{
// iniciando o estado dos motores
estMotor1 = 1;
estMotor2 = 1;
// iniciando o sentido dos motores
senMotor1 = 2;
senMotor2 = 2;
}
else
if ( movimento == NAVEGAR_PROSSEGUIR )
{
// iniciando o estado dos motores
estMotor1 = 1;
estMotor2 = 1;
59
// iniciando o sentido dos motores
senMotor1 = 1;
senMotor2 = 1;
//
//printf("movimento prosseguir solicitado\n");
}
//
while(numRotacao < NAVEGAR_LARGURA_PASSO)
{
// Atualizando o estado do motor 1
if ( estMotor1 == 0 )
{
BitWrPortI(PADR, &PADRShadow, 0, 0);
BitWrPortI(PADR, &PADRShadow, 0, 1);
BitWrPortI(PADR, &PADRShadow, 0, 2);
BitWrPortI(PADR, &PADRShadow, 0, 3);
//
//printf("motor 1 parado\n");
}
else
if ( estMotor1 == 1 )
{
BitWrPortI(PADR, &PADRShadow, 1, 0); // 1
BitWrPortI(PADR, &PADRShadow, 0, 1); // 0
BitWrPortI(PADR, &PADRShadow, 0, 2); // 0
BitWrPortI(PADR, &PADRShadow, 0, 3); // 0
//
//printf("1000XXXX\n");
//
if ( senMotor1 == 1 )
{
estMotor1 += 1;
}
else
if ( senMotor1 == 2 )
{
estMotor1 = 4;
}
}
else
if ( estMotor1 == 2 )
{
BitWrPortI(PADR, &PADRShadow, 0, 0); // 0
BitWrPortI(PADR, &PADRShadow, 1, 1); // 1
BitWrPortI(PADR, &PADRShadow, 0, 2); // 0
BitWrPortI(PADR, &PADRShadow, 0, 3); // 0
//
//printf("0100XXXX\n");
//
if ( senMotor1 == 1 )
60
{
estMotor1 += 1;
}
else
if ( senMotor1 == 2 )
{
estMotor1 -= 1;
}
}
else
if ( estMotor1 == 3 )
{
BitWrPortI(PADR, &PADRShadow, 0, 0); // 0
BitWrPortI(PADR, &PADRShadow, 0, 1); // 0
BitWrPortI(PADR, &PADRShadow, 1, 2); // 1
BitWrPortI(PADR, &PADRShadow, 0, 3); // 0
//
//printf("0010XXXX\n");
//
if ( senMotor1 == 1 )
{
estMotor1 += 1;
}
else
if ( senMotor1 == 2 )
{
estMotor1 -= 1;
}
}
else
if ( estMotor1 == 4 )
{
BitWrPortI(PADR, &PADRShadow, 0, 0); // 0
BitWrPortI(PADR, &PADRShadow, 0, 1); // 0
BitWrPortI(PADR, &PADRShadow, 0, 2); // 0
BitWrPortI(PADR, &PADRShadow, 1, 3); // 1
//
//printf("0001XXXX\n");
//
if ( senMotor1 == 1 )
{
estMotor1 = 1;
}
else
if ( senMotor1 == 2 )
{
estMotor1 -= 1;
}
}
// Atualizando o estado do motor 2
61
if ( estMotor2 == 0 )
{
BitWrPortI(PADR, &PADRShadow, 0, 4);
BitWrPortI(PADR, &PADRShadow, 0, 5);
BitWrPortI(PADR, &PADRShadow, 0, 6);
BitWrPortI(PADR, &PADRShadow, 0, 7);
//
//printf("motor 2 parado\n");
}
else
if ( estMotor2 == 1 )
{
BitWrPortI(PADR, &PADRShadow, 0, 4); // 1 // 1
BitWrPortI(PADR, &PADRShadow, 0, 5); // 0 // 1
BitWrPortI(PADR, &PADRShadow, 0, 6); // 0 // 0
BitWrPortI(PADR, &PADRShadow, 1, 7); // 0 // 0
//
//printf("XXXX1000\n");
//
if ( senMotor2 == 1 )
{
estMotor2 += 1;
}
else
if ( senMotor2 == 2 )
{
estMotor2 = 4;
}
}
else
if ( estMotor2 == 2 )
{
BitWrPortI(PADR, &PADRShadow, 0, 4); // 0
BitWrPortI(PADR, &PADRShadow, 0, 5); // 1
BitWrPortI(PADR, &PADRShadow, 1, 6); // 0
BitWrPortI(PADR, &PADRShadow, 0, 7); // 0
//
//printf("XXXX0100\n");
//
if ( senMotor2 == 1 )
{
estMotor2 += 1;
}
else
if ( senMotor2 == 2 )
{
estMotor2 -= 1;
}
}
else
62
if ( estMotor2 == 3 )
{
BitWrPortI(PADR, &PADRShadow, 0, 4); // 0 // 0
BitWrPortI(PADR, &PADRShadow, 1, 5); // 0 // 0
BitWrPortI(PADR, &PADRShadow, 0, 6); // 1 // 1
BitWrPortI(PADR, &PADRShadow, 0, 7); // 0 // 1
//
//printf("XXXX0010\n");
//
if ( senMotor2 == 1 )
{
estMotor2 += 1;
}
else
if ( senMotor2 == 2 )
{
estMotor2 -= 1;
}
}
else
if ( estMotor2 == 4 )
{
BitWrPortI(PADR, &PADRShadow, 1, 4); // 0
BitWrPortI(PADR, &PADRShadow, 0, 5); // 0
BitWrPortI(PADR, &PADRShadow, 0, 6); // 0
BitWrPortI(PADR, &PADRShadow, 0, 7); // 1
//
//printf("XXXX0001\n");
//
if ( senMotor2 == 1 )
{
estMotor2 = 1;
}
else
if ( senMotor2 == 2 )
{
estMotor2 -= 1;
}
}
//
for ( idxTempo=1; idxTempo<NAVEGAR_TEMPO_PASSO; idxTempo++)
;;
//
numRotacao++;
}
}
63
/** Descrição da biblioteca ************************************************/
/** Projeto: Georobo **/
/** Autor: Rafael Roberto Prado **/
/** Nome da biblioteca: connector.lib Data:27/04/2010 **/
/**********************************************************************/
#use "dcreth.lib"
#use "realtime.lib"
/*** Beginheader **/
/** Configurações do socket connector **/
#define PORTDATA 5150
#define HEADERPACKET 0x0a
#define ENDPACKET 0x0b
// Define types packet
#define PROJECTPACKET 0x0a
#define MESSAGEPACKET 0x0b
#define ACTIONPACKET 0x0c
#define HAVEACTIONPACKET 0x0d
#define DATETIMEPACKET 0x0e
#define CONFIGETHPACKET 0x0f
/*** Endheader **/
/** Funções **/
/*************************************************************************/
/*** Beginheader connectorSend **/
extern xmem int connectorSend ( tcp_Socket *socketClient, int typePacket );
/*** Endheader **/
debug xmem int connectorSend ( tcp_Socket *socketClient, int typePacket )
{
int result;
char buffer[20];
//
if ( typePacket == DATETIMEPACKET )
{
//printf("consultando data e hora...\n");
buffer[0] = HEADERPACKET ;
buffer[1] = DATETIMEPACKET ;
buffer[2] = ENDPACKET;
sock_mode( socketClient, TCP_MODE_ASCII );
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
//printf("error sending: %s\n", buffer);
result = -1;
}
else
{
result = 0;
64
}
}
else
if ( typePacket == PROJECTPACKET )
{
//printf("consultando nome do projeto...\n");
buffer[0] = HEADERPACKET ;
buffer[1] = PROJECTPACKET ;
buffer[2] = ENDPACKET;
sock_mode( socketClient, TCP_MODE_ASCII );
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
//printf("error sending: %s\n", buffer);
result = -1;
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
else
if ( typePacket == HAVEACTIONPACKET )
{
//printf("consultando acao disponivel...\n");
buffer[0] = HEADERPACKET ;
buffer[1] = HAVEACTIONPACKET ;
buffer[2] = ENDPACKET;
sock_mode( socketClient, TCP_MODE_ASCII );
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
//printf("error sending: %s\n", buffer);
result = -1;
65
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
else
if ( typePacket == ACTIONPACKET )
{
buffer[0] = HEADERPACKET ;
buffer[1] = ACTIONPACKET ;
buffer[2] = ENDPACKET;
sock_mode( socketClient, TCP_MODE_ASCII );
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
if ( sock_write( socketClient, buffer, 3 ) == -1 )
{
//printf("error sending: %s\n", buffer);
result = -1;
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
// printf("%s\n",buffer);
}
66
/*** Beginheader dataSocket **/
extern xmem void dataSocket ( char* buffer, int numBytes );
/*** Endheader **/
debug xmem void dataSocket ( char* buffer, int numBytes )
{
char sProjectName[255];
char sDatetime[20];
char sMessage[1024];
char sActionPacket[10];
//
char sHost[16];
char sNetmask[16];
char sNameserver[16];
//
int idxBufSource;
int idxBufDest;
//
char byteTypeIpAddress;
char byteDefaultIpAddress;
//
idxBufSource = 2;
idxBufDest = 0;
//
if ( buffer[numBytes] == ENDPACKET )
{
printf("error with byte endpacket\n");
//
printf("recebendo dados com tamanho: %d...", numBytes);
}
//
if( buffer[0] == HEADERPACKET && buffer[numBytes-1] == ENDPACKET )
{
if ( buffer[1] == DATETIMEPACKET )
{
while( idxBufSource < numBytes-1 )
{
sDatetime[idxBufDest] = buffer[idxBufSource];
idxBufSource++;
idxBufDest++;
}
//
sDatetime[idxBufDest] = '\0';
//
printf(sDatetime);
printf("\n");
//
writeTime ( sDatetime );
}
else
if ( buffer[1] == PROJECTPACKET )
67
{
while( idxBufSource < numBytes-1 )
{
sProjectName[idxBufDest] = buffer[idxBufSource];
idxBufSource++;
idxBufDest++;
}
//
sProjectName[idxBufDest] = '\0';
printf(sProjectName);
printf("\n");
}
else
if ( buffer[1] == HAVEACTIONPACKET )
{
while( idxBufSource < numBytes-1 )
{
sActionPacket[idxBufDest] = buffer[idxBufSource];
idxBufSource++;
idxBufDest++;
}
//
sActionPacket[idxBufDest] = '\0';
actionData = sActionPacket[0];
//
if ( actionData == NAVEGAR_DIREITA )
{
printf("NAVEGAR_DIREITA:%d", actionData);
}
else
if ( actionData == NAVEGAR_ESQUERDA )
{
printf("NAVEGAR_ESQUERDA:%d", actionData);
}
else
if ( actionData == NAVEGAR_PROSSEGUIR )
{
printf("NAVEGAR_PROSSEGUIR:%d", actionData);
}
else
if ( actionData == NAVEGAR_RETORNAR )
{
printf("NAVEGAR_RETORNAR:%d", actionData);
}
printf("\n");
}
else
if ( buffer[1] == MESSAGEPACKET )
{
while( idxBufSource < numBytes-1 )
68
{
sMessage[idxBufDest] = buffer[idxBufSource];
idxBufSource++;
idxBufDest++;
}
//
sMessage[idxBufDest] = '\0';
printf(sMessage);
}
else
if ( buffer[1] == CONFIGETHPACKET )
{
byteDefaultIpAddress = buffer[2]; // (N) - Não | (S) - Sim
byteTypeIpAddress = buffer[3]; // (0) - DHCP | (1) - Estatico
//
// [N][0][192.168.42.1]
// [N][1][192.168.42.169;][255.255.255.0;][192.168.42.1;]
//
idxBufSource = 4;
//
if ( byteDefaultIpAddress == 'N' )
{
if( byteTypeIpAddress == '0' ) // DHCP
{
// obtendo o nameserver que tambem sera o gateway e o servidor de dados
while( idxBufSource < numBytes )
{
if ( buffer[idxBufSource] != ';' )
{
sNameserver[idxBufDest] = buffer[idxBufSource];
}
else
{
sNameserver[idxBufDest] = '\0';
break;
}
idxBufSource++;
idxBufDest++;
}
//
strcpy(ipAddress.host,"192.168.0.100");
strcpy(ipAddress.netmask,"255.255.255.0");
strcpy(ipAddress.gateway,ipAddress.nameserver);
defaultIpAddress = 'N';
typeIpAddress = 0;
save_data[0] = &ipAddress;
save_lens[0] = sizeof(ipAddress);
save_data[1] = &defaultIpAddress;
save_lens[1] = sizeof(defaultIpAddress);
save_data[2] = &typeIpAddress;
69
save_lens[2] = sizeof(typeIpAddress);
writeUserBlockArray(0, save_data, save_lens, 3);
}
else
if( byteTypeIpAddress == '1' ) // Estatico
{
// obtendo o endereco do host
while( idxBufSource < numBytes )
{
if ( buffer[idxBufSource] != ';' )
{
sHost[idxBufDest] = buffer[idxBufSource];
}
else
{
sHost[idxBufDest] = '\0';
idxBufSource++;
break;
}
idxBufSource++;
idxBufDest++;
}
//
idxBufDest = 0;
// obtendo a mascara do host
while( idxBufSource < numBytes )
{
if ( buffer[idxBufSource] != ';' )
{
sNetmask[idxBufDest] = buffer[idxBufSource];
}
else
{
sNetmask[idxBufDest] = '\0';
idxBufSource++;
break;
}
idxBufSource++;
idxBufDest++;
}
//
idxBufDest = 0;
// obtendo o nameserver que tambem sera o gateway e o servidor de dados
while( idxBufSource < numBytes )
{
if ( buffer[idxBufSource] != ';' )
{
sNameserver[idxBufDest] = buffer[idxBufSource];
}
else
70
{
sNameserver[idxBufDest] = '\0';
idxBufSource++;
break;
}
idxBufSource++;
idxBufDest++;
}
//
strcpy(ipAddress.host,sHost);
strcpy(ipAddress.netmask,sNetmask);
strcpy(ipAddress.nameserver,sNameserver);
strcpy(ipAddress.gateway,ipAddress.nameserver);
defaultIpAddress = 'S';
typeIpAddress = 1;
save_data[0] = &ipAddress;
save_lens[0] = sizeof(ipAddress);
save_data[1] = &defaultIpAddress;
save_lens[1] = sizeof(defaultIpAddress);
save_data[2] = &typeIpAddress;
save_lens[2] = sizeof(typeIpAddress);
writeUserBlockArray(0, save_data, save_lens, 3);
}
}
else
if ( byteDefaultIpAddress == 'S' )
{
strcpy(ipAddress.host,"192.168.0.200");
strcpy(ipAddress.netmask,"255.255.255.0");
strcpy(ipAddress.nameserver,"192.168.0.100");
strcpy(ipAddress.gateway,"192.168.0.100");
defaultIpAddress = 'S';
typeIpAddress = 1;
save_data[0] = &ipAddress;
save_lens[0] = sizeof(ipAddress);
save_data[1] = &defaultIpAddress;
save_lens[1] = sizeof(defaultIpAddress);
save_data[2] = &typeIpAddress;
save_lens[2] = sizeof(typeIpAddress);
writeUserBlockArray(0, save_data, save_lens, 3);
}
//
}
}
}
71
/** Descrição da biblioteca
*************************************************************************/
/** Projeto: Georobo **/
/** Autor: Rafael Roberto Prado **/
/** Nome da biblioteca: realtime.lib Data:27/04/2010 **/
/*************************************************************************/
/** struct time **/
/**------*------*------*------*------*------*------***/
/** sec * min * hour * mday * mon * year * wday ***/
/** 0-59 * 0-59 * 0-23 * 1-31 * 1-12 *80-147* 0-6 ***/
/**------*------*------*------*------*------*------***/
/** **/
/*** Beginheader screen_state, rtc **/
extern root int screen_state;
extern root struct tm rtc;
/*** Endheader **/
root int screen_state;
root struct tm rtc;
/** Funções **/
/*************************************************************************/
/*** Beginheader readTime **/
extern xmem void readTime ();
/*** Endheader **/
xmem debug void readTime ()
{
tm_rd(&rtc);
}
/*** Beginheader writeTime **/
extern xmem void writeTime ( char buffer[] );
/*** Endheader **/
xmem debug void writeTime ( char buffer[] )
{
int idxStrSrc;
int idxStrDest;
// Format time: YYYYMMDDHHMISS
char sYear[5];
char sMon[3];
char sDay[3];
char sHour[3];
char sMin[3];
char sSec[3];
//
printf ( buffer );
printf ( "\n" );
72
//
strncpy(sYear,(char*)(&buffer[0]),4);
sYear[4] = '\0';
strncpy(sMon,(char*)(&buffer[4]),2);
sMon[2] = '\0';
strncpy(sDay,(char*)(&buffer[6]),2);
sDay[2] = '\0';
strncpy(sHour,(char*)(&buffer[8]),2);
sHour[2] = '\0';
strncpy(sMin,(char*)(&buffer[10]),2);
sMin[2] = '\0';
strncpy(sSec,(char*)(&buffer[12]),2);
sSec[2] = '\0';
//
rtc.tm_mday = atoi(sYear);
rtc.tm_mon = atoi(sMon);
rtc.tm_year = (atoi(sYear)-1900);
rtc.tm_wday = 0;
rtc.tm_hour = atoi(sHour);
rtc.tm_min = atoi(sMin);
rtc.tm_sec = atoi(sSec);
tm_wr(&rtc); // write time in struct tm
SEC_TIMER = mktime(&rtc);
}
/*** Beginheader printingTime **/
extern xmem void printingTime ();
/*** Endheader **/
debug xmem void printingTime ()
{
int nYear, nMonth, nDay, nHour, nMin, nSec;
//
readTime();
//
if ( rtc.tm_year != 0 )
{
nDay = rtc.tm_mday;
nMonth = rtc.tm_mon + 1;
nYear = rtc.tm_year + 1900;
nHour = rtc.tm_hour;
nMin = rtc.tm_min;
nSec = rtc.tm_sec;
// exibe a data e hora
printf ( "Data: %02d/%02d/%04d Hora: %02d:%02d:%02d\n", nDay, nMonth,
nYear, nHour, nMin, nSec);
}
}
73
APÊNDICE B – Código agente desenvolvido para o computador portátil
//Arquivo: georobo.c
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <cv.h>
#include <cvaux.h>
#include <cxcore.h>
#include <highgui.h>
#include <conio.h>
#include "network.h"
#include "detectObject.h"
#define NAM_FOLDER_DB "reminder\\"
#define PRE_FILE_DB "obj"
#define PRE_FILE_BACKGROUND "fnd"
#define BASE_STRING_SEARCH "*.jpg"
#define MAX_STRING_SEARCH 255
#define MAX_FILENAME 260
#define MAX_FILEPATH 515
//
#define IMG_PREVIEW_WIDTH 320
#define IMG_PREVIEW_HEIGHT 240
//
#define VISIO_PROCESSA_START 0
#define VISIO_PROCESSA_STOP 1
//
#define ESC_KEY 0x1B
//
#define NUM_LARG_FRAME_STEREO_PARALAXE 20 // 78mm
//
typedef struct ListImageObject
{
TImageObject* start;
TImageObject* end;
int* count;
} TListImageObject;
//
typedef struct _visioStereo
{
CvCapture *captureWebCam0;
CvCapture *captureWebCam1;
IplImage *frameLeft;
IplImage *frameRight;
IplImage *frameStereo;
char staProcessa;
} VISIOSTEREO;
74
DWORD WINAPI CaptureStereoThread(LPVOID lpParam)
{
VISIOSTEREO* visioStereo = (VISIOSTEREO*)lpParam;
//
CvCapture *captureWebCam0 = visioStereo->captureWebCam1;
CvCapture *captureWebCam1 = visioStereo->captureWebCam0;
//
IplImage *frameWebCam0 = NULL;
IplImage *frameWebCam1 = NULL;
//
int numLargFrameStereoTotal = IMG_PREVIEW_WIDTH +
NUM_LARG_FRAME_STEREO_PARALAXE;
int numDistFrameLeftRight = numLargFrameStereoTotal / 2;
int numDistFrameLeft = IMG_PREVIEW_WIDTH - numDistFrameLeftRight;
// inicializando a imagem da visão stereo
IplImage *frameStereo = cvCreateImage(cvSize(numLargFrameStereoTotal, 240), 8,
3); // 368
IplImage *frameRightCrop = cvCreateImage(cvSize(numLargFrameStereoTotal/2, 240),
8, 3); // 368
//
int key = 0;
// inicializa janelas de resultado
cvNamedWindow( "resultWebCam0", CV_WINDOW_AUTOSIZE );
cvMoveWindow ( "resultWebCam0", 10, 50);
//
cvNamedWindow( "resultWebCam1", CV_WINDOW_AUTOSIZE );
cvMoveWindow ( "resultWebCam1", 330, 50);
//
cvNamedWindow( "resultStereo", CV_WINDOW_AUTOSIZE );
cvMoveWindow ( "resultStereo", 650, 50);
//
while( key != 'q' ) {
// consulta a imagem em cada uma das cameras
frameWebCam0 = cvQueryFrame( captureWebCam0 );
frameWebCam1 = cvQueryFrame( captureWebCam1 );
// verifica se as imagens foram capturadas
if( !frameWebCam0 ) break;
if( !frameWebCam1 ) break;
// criando a imagem stereo
frameStereo->origin = frameWebCam0->origin;
// copia a imagem da esquerda
cvSetImageROI(frameStereo, cvRect(0, 0, frameWebCam0->width, frameWebCam0-
>height));
cvCopy(frameWebCam0, frameStereo, 0);
cvResetImageROI(frameStereo);
// copia a imagem da direita
cvSetImageROI(frameWebCam1, cvRect(numDistFrameLeft, 0, frameRightCrop-
>width, frameRightCrop->height)); // 48
cvCopy(frameWebCam1, frameRightCrop, 0);
75
cvResetImageROI(frameWebCam1);
// atualizando a imagem estereo com a imagem da direita
cvSetImageROI(frameStereo, cvRect(numDistFrameLeftRight, 0, frameRightCrop-
>width, frameRightCrop->height));
cvCopy(frameRightCrop, frameStereo, 0);
cvResetImageROI(frameStereo);
//
if ( visioStereo->staProcessa == VISIO_PROCESSA_START )
{
printf("visao stereo processada...\n");
//
cvCopy(frameWebCam0, visioStereo->frameLeft, 0 );
cvCopy(frameWebCam1, visioStereo->frameRight, 0 );
cvCopy(frameStereo, visioStereo->frameStereo, 0 );
//
visioStereo->staProcessa = VISIO_PROCESSA_STOP;
}
// exibe a imagem atual
cvShowImage( "resultWebCam0", frameWebCam0 );
cvShowImage( "resultWebCam1", frameWebCam1 );
cvShowImage( "resultStereo", frameStereo );
// aguarda pressionar uma tecla para sair
key = cvWaitKey( 1 );
}
// encerra as janelas
cvDestroyWindow( "resultWebCam0" );
cvReleaseCapture( &captureWebCam0 );
//
cvDestroyWindow( "resultWebCam1" );
cvReleaseCapture( &captureWebCam1 );
//
cvDestroyWindow( "resultStereo" );
cvReleaseImage( &frameStereo );
}
TListImageObject* inicializaListImageObject();
TImageObject* inicializaImageObject(const char* fileName, char* filePath);
char insereListImageObject(TListImageObject* listImageObject, TImageObject*
imageObject);
void inicializaReminder(TListImageObject* listImageObject);
void inicializaDetalhesReminder(TListImageObject* listImageObject);
int main(int argc, char *argv[])
{
int result = 0;
int lastError = 0;
//
int idxVerifica = 0;
char chrAction = 0x01;
//
76
char chrKeyRead = 0;
// captura estereoscopica
HANDLE _handleCaptureStereoTh;
DWORD _idCaptureStereoTh;
// definindo variaveis das cameras
CvCapture *captureWebCam0;
CvCapture *captureWebCam1;
// estrutura para coleta das imagens da detecção
VISIOSTEREO visioStereo;
// variavel para percorrer os objetos
TImageObject* itrImageObject;
// estrutura para armazenar a lista de objetos
TListImageObject* _listImageObject = inicializaListImageObject();
// estrutura para armazenar o resultado os objetos identificados
TListObjectSearched* _listObjectSearched = NULL;
// imagem para exibir o resultado dos objetos identificados
IplImage* baseResult = NULL;
// lendo os objetos conhecidos
printf("lendo os objetos conhecidos ...\n");
inicializaReminder(_listImageObject);
inicializaDetalhesReminder(_listImageObject);
// percorrendo os objetos para criar a arvore decisao
printf("percorrendo os objetos conhecidos para criar arvore de decisao...\n");
itrImageObject = _listImageObject->start;
while ( itrImageObject != NULL )
{
// criar o classificador do objeto
printf("criando a imagem classificadora do objeto conhecido ...\n");
DetectObjectCreateClassifier ( itrImageObject );
if ( itrImageObject->classifier != NULL )
{
printf("imagem classificadora do objeto criada com sucesso ...\n");
}
// criar a arvore de decisao do objeto
printf("criando a arvore de decisao do objeto conhecido ...\n");
DetectObjectCreateDecisionTree ( itrImageObject );
if ( itrImageObject->dtree != NULL )
{
printf("arvore de decisao do objeto criada com sucesso ...\n");
}
// movimentando para o proximo objeto
itrImageObject = itrImageObject->end;
}
// iniciando o servidor de comunicação com o sw_rabbit
printf("iniciando o servidor de comunicacao ...\n");
startSocket("192.168.0.100", DEFAULT_PORT, TRUE, SERVER_MODE);
// iniciando sistema de visão
printf("iniciando o sistema de visao ...\n");
// initialize camera 0
printf("ativando a camera 0 ...\n");
77
captureWebCam0 = cvCaptureFromCAM( 0 );
// atualiza as propriedades da camera 0
cvSetCaptureProperty(captureWebCam0, CV_CAP_PROP_FRAME_WIDTH, 320 );
cvSetCaptureProperty(captureWebCam0, CV_CAP_PROP_FRAME_HEIGHT, 240 );
cvSetCaptureProperty(captureWebCam0, CV_CAP_PROP_FPS, 15 );
// initi alize camera 1
printf("ativando a camera 1 ...\n");
captureWebCam1 = cvCaptureFromCAM( 1 );
// atualiza as propriedades da camera 1
cvSetCaptureProperty(captureWebCam1, CV_CAP_PROP_FRAME_WIDTH, 320 );
cvSetCaptureProperty(captureWebCam1, CV_CAP_PROP_FRAME_HEIGHT, 240 );
cvSetCaptureProperty(captureWebCam1, CV_CAP_PROP_FPS, 15 );
// Atualizando as variaveis do sistema de visao estereo
visioStereo.captureWebCam0 = captureWebCam0;
visioStereo.captureWebCam1 = captureWebCam1;
visioStereo.frameLeft = NULL;
visioStereo.frameRight = NULL;
visioStereo.frameStereo = NULL;
visioStereo.staProcessa = VISIO_PROCESSA_START;
// inicializando a imagem ser transportada a detecção
int numLargFrameStereoTotal = IMG_PREVIEW_WIDTH +
NUM_LARG_FRAME_STEREO_PARALAXE;
//
visioStereo.frameLeft = cvCreateImage(cvSize(320, 240), 8, 3);
visioStereo.frameRight = cvCreateImage(cvSize(320, 240), 8, 3);
visioStereo.frameStereo = cvCreateImage(cvSize(numLargFrameStereoTotal, 240), 8, 3);
// 368
// valida camera 0
if ( !captureWebCam0 ) {
fprintf( stderr, "Cannot open initialize webcam 0!\n" );
return 1;
}
// valida camera 1
if ( !captureWebCam1 ) {
fprintf( stderr, "Cannot open initialize webcam 1!\n" );
return 1;
}
// iniciando a pre-visualizacao das cameras
printf("executando a pre-visualizacao das cameras ...\n");
_handleCaptureStereoTh = CreateThread(NULL, 0, CaptureStereoThread,
(LPVOID)&visioStereo, 0, &_idCaptureStereoTh);
//
lastError = GetLastError();
//
if ( lastError != 0)
{
printf("CaptureStereoThread() failed: %d\n", lastError );
result = -1;
}
//
78
if ( result == -1 )
{
return result;
}
//
printf("testando os movimentos básicos...\n");
//
/*while( idxVerifica < 8 )
{
if ( _packetAnswerAction == NULL )
{
makeActionPacketToSend(chrAction);
//
chrAction++;
//
idxVerifica++;
}
//
if ( chrAction > 0x04 )
{
chrAction = 0x01;
}
//
sleep(1500);
}*/
//
printf("iniciando procedimento de interacao dos movimentos...\n");
//
while ( chrKeyRead != ESC_KEY )
{
printf("buscando objeto...\n");
if ( visioStereo.staProcessa == VISIO_PROCESSA_STOP &&
visioStereo.frameLeft != NULL &&
visioStereo.frameRight != NULL &&
visioStereo.frameStereo != NULL
)
{
printf("iniciando analise de objeto...\n");
// analisar a imagem coletada para cada objeto conhecido
itrImageObject = _listImageObject->start;
while ( itrImageObject != NULL )
{
//printf("objeto selecionado...\n");
//
//printf("iniciando procedimento de detectar objeto...\n");
//
DetectObjectExecute ( itrImageObject,
visioStereo.frameLeft,
visioStereo.frameRight,
visioStereo.frameStereo,
79
NUM_LARG_FRAME_STEREO_PARALAXE,
0.035F,
&baseResult,
&_listObjectSearched );
// movimentando para o proximo objeto
itrImageObject = itrImageObject->end;
//
visioStereo.staProcessa = VISIO_PROCESSA_START;
//printf("fim procedimento de detectar objeto...\n");
}
}
//
chrKeyRead = cvWaitKey( 1 );
//
sleep(1500);
}
//
printf("fim...\n");
//
return 0;
}
//
TListImageObject* inicializaListImageObject()
{
TListImageObject* result = (TListImageObject*)malloc(sizeof(TListImageObject));
//
result->start = NULL;
result->end = NULL;
result->count = (int*)malloc(sizeof(int));
(*result->count) = 0;
//
return result;
}
//
TImageObject* inicializaImageObject(const char* fileName, char* filePath)
{
TImageObject* result = (TImageObject*)malloc(sizeof(TImageObject));
//
result->name = (char*)malloc(MAX_FILENAME);
result->name_background = (char*)malloc(MAX_FILENAME);
//
strcpy(result->name,fileName);
strcpy(result->name_background,PRE_FILE_BACKGROUND);
strcat(result->name_background,"_");
strcat(result->name_background,result->name+(strlen(PRE_FILE_DB)+1));
//
strcpy(filePath,NAM_FOLDER_DB);
strcat(filePath,result->name);
//
result->object = cvLoadImage(filePath,CV_LOAD_IMAGE_COLOR);
80
//
strcpy(filePath,NAM_FOLDER_DB);
strcat(filePath,result->name_background);
//
result->background = cvLoadImage(filePath,CV_LOAD_IMAGE_COLOR);
//
cvNamedWindow( "objeto", 0 );
cvMoveWindow ( "objeto", 50, 340);
cvResizeWindow( "objeto", result->object->width/3, result->object->height/3 );
cvShowImage( "objeto", result->object );
//
cvWaitKey(1);
//
cvNamedWindow( "fundo", 0 );
cvMoveWindow ( "fundo", 50+(result->background->width/3), 340);
cvResizeWindow( "fundo", result->background->width/3, result->background->height/3 );
cvShowImage( "fundo", result->background );
//
cvWaitKey(1);
//
result->classifier = NULL;
result->dtree = NULL;
//
result->end = NULL;
//
return result;
}
//
char insereListImageObject(TListImageObject* listImageObject, TImageObject*
imageObject)
{
char result = 0;
//
if(listImageObject != NULL && imageObject != NULL)
{
//
if(listImageObject->start == NULL)
{
listImageObject->start = imageObject;
//
listImageObject->end = imageObject;
}
else
{
((TImageObject*)listImageObject->end)->end = imageObject;
//
listImageObject->end = imageObject;
}
//
(*listImageObject->count)++;
81
result = 1;
}
return result;
}
//
void inicializaReminder(TListImageObject* listImageObject)
{
struct _finddata_t cFile;
long hFile;
char* filePath = (char*)malloc(MAX_FILENAME);
TImageObject* imageObject = NULL;
//
char* sSearch = (char*)malloc(MAX_STRING_SEARCH);
//
strcpy(sSearch,NAM_FOLDER_DB);
strcat(sSearch,PRE_FILE_DB);
strcat(sSearch,BASE_STRING_SEARCH);
//
if((hFile = _findfirst(sSearch,&cFile))!= 0 )
{
if(cFile.attrib & _A_ARCH)
{
if ( strcmp( cFile.name, PRE_FILE_DB ) > 0 )
{
imageObject = inicializaImageObject(cFile.name,filePath);
insereListImageObject(listImageObject, imageObject);
}
}
//
while(_findnext(hFile,&cFile) == 0)
{
//
if(cFile.attrib & _A_ARCH)
{
if ( strcmp( cFile.name, PRE_FILE_DB ) > 0 )
{
imageObject = inicializaImageObject(cFile.name,filePath);
insereListImageObject(listImageObject, imageObject);
}
}
//
}
//
_findclose(hFile);
//
}
}
//
void inicializaDetalhesReminder(TListImageObject* listImageObject)
{
82
FILE* fleReminder = fopen("reminder\\reminder.txt","r");
char* buffer;
// variavel para percorrer os objetos
TImageObject* itrImageObject;
TImageObject* imageObject;
//
char* bufferObject;
char* bufferAttrib;
char* bufferValue;
//
int idxBufferPart;
char staBufferObject;
char staBufferAttrib;
char staBufferValue;
//
long szeFile;
long idxSzeFile;
size_t result;
//
if( fleReminder != NULL )
{
printf("aberto arquivo de detalhe dos objetos.\n");
fseek(fleReminder, 0, SEEK_END);
szeFile = ftell(fleReminder);
rewind(fleReminder);
//
buffer = (char*) malloc(sizeof(char)*szeFile);
if (buffer == NULL)
{
printf("erro alocando memoria.\n");
return;
}
//
result = fread( buffer, 1, szeFile, fleReminder);
//
if ( result <= 0 )
{
printf("erro ao ler o arquivo.\n");
return;
}
//
bufferObject = (char*) malloc(sizeof(char)*100);
bufferAttrib = (char*) malloc(sizeof(char)*100);
bufferValue = (char*) malloc(sizeof(char)*100);
//
idxSzeFile = 0;
//
idxBufferPart = 0;
//
staBufferObject = 0;
83
staBufferAttrib = 0;
staBufferValue = 0;
//
while ( idxSzeFile < szeFile )
{
if ( buffer[idxSzeFile] == 0x0a ||
buffer[idxSzeFile] == 0x0d
)
{
printf("buscando no detalhe de novo objeto ...\n");
idxBufferPart = 0;
staBufferObject = 0;
staBufferAttrib = 0;
staBufferValue = 0;
}
else
if ( staBufferObject == 0 )
{
if ( buffer[idxSzeFile] == ':' )
{
bufferObject[idxBufferPart] = '\0';
idxBufferPart = 0;
staBufferObject = 1;
//
imageObject = NULL;
// identificando o objeto
printf("percorrendo os objetos conhecidos como %s...\n", bufferObject);
itrImageObject = listImageObject->start;
while ( itrImageObject != NULL )
{
if ( strcmp( itrImageObject->name, bufferObject ) > 0 )
{
printf("o objeto conhecido: %s encontrado...\n", itrImageObject->name);
imageObject = itrImageObject;
break;
}
// movimentando para o proximo objeto
itrImageObject = itrImageObject->end;
}
}
else
{
bufferObject[idxBufferPart] = buffer[idxSzeFile];
idxBufferPart++;
}
}
else
if ( staBufferAttrib == 0 )
{
if ( buffer[idxSzeFile] == '=' )
84
{
bufferAttrib[idxBufferPart] = '\0';
idxBufferPart = 0;
staBufferAttrib = 1;
// identificando o nome do atributo do objeto
printf("atributo do objeto conhecidos como %s...\n", bufferAttrib);
}
else
{
bufferAttrib[idxBufferPart] = buffer[idxSzeFile];
idxBufferPart++;
}
}
else
if ( staBufferValue == 0 )
{
if ( buffer[idxSzeFile] == ';' )
{
bufferValue[idxBufferPart] = '\0';
idxBufferPart = 0;
staBufferValue = 1;
// identificando o nome do atributo do objeto
printf("valor do atributo do objeto coletado foi %s...\n", bufferValue);
}
else
{
bufferValue[idxBufferPart] = buffer[idxSzeFile];
idxBufferPart++;
}
}
//
if ( staBufferObject &&
staBufferAttrib &&
staBufferValue &&
imageObject != NULL )
{
if ( strcmp( bufferAttrib, "area" ) == 0 )
{
imageObject->area = (double*)malloc(sizeof(double));
*imageObject->area = atof(bufferValue);
//
printf("atualizado %s do objeto %s com valor: %f \n", bufferAttrib, bufferObject,
*imageObject->area );
//
staBufferAttrib = 0;
staBufferValue = 0;
}
else
if ( strcmp( bufferAttrib, "distance" ) == 0 )
{
85
imageObject->distance = (double*)malloc(sizeof(double));
*imageObject->distance = atof(bufferValue);
//
printf("atualizado %s do objeto %s com valor: %f \n", bufferAttrib, bufferObject,
*imageObject->distance );
//
staBufferAttrib = 0;
staBufferValue = 0;
}
}
//
idxSzeFile++;
}
//
fclose(fleReminder);
//
free(buffer);
}
else
{
printf("erro abrindo arquivo de detalhe dos objetos.\n");
}
}
//Arquivo: network.h
#ifndef NETWORK_H
#define NETWORK_H
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DEFAULT_PORT 5150
#define DEFAULT_BUFFER 4096
#define SERVER_MODE 0
#define CLIENT_MODE 1
#define SEND_MODE 0
#define RECEIVE_MODE 1
// Define first byte and last byte
#define HEADERPACKET 0x0a
#define ENDPACKET 0x0b
// Define types packet
#define PROJECTPACKET 0x0a
86
#define MESSAGEPACKET 0x0b
#define ACTIONPACKET 0x0c
#define HAVEACTIONPACKET 0x0d
#define DATETIMEPACKET 0x0e
#define NAVEGAR_DIREITA 0x01
#define NAVEGAR_ESQUERDA 0x02
#define NAVEGAR_PROSSEGUIR 0x03
#define NAVEGAR_RETORNAR 0x04
#define PROJECT_NAME "GeoRobo System Detection"
#define PROJECT_NAME_SIZE 24
struct Packet_ {
char* stream;
int length;
char type;
void* next;
};
typedef struct Packet_ Packet;
Packet* _packetAnswerAction;
Packet* _packetAnswer;
Packet* _packetReceive;
WSADATA _wsaData;
SOCKET _socketListen;
SOCKET _socketClient;
int _numAddrSize;
HANDLE _handleThread;
DWORD _idThread;
// Server
HANDLE _handleServerSocketTh;
DWORD _idServerSocketTh;
//
HANDLE _handleClientSocketTh;
DWORD _idClientSocketTh;
// Client
HANDLE _handleClientRecvSocketTh;
DWORD _idClientRecvSocketTh;
//
HANDLE _handleClientSendSocketTh;
DWORD _idClientSendSocketTh;
//
struct sockaddr_in _serverSockAddr;
struct hostent* _serverHostEntry;
//
struct sockaddr_in _clientSockAddr;
//
87
int _staSocketMode; // Can be SERVER_MODE or CLIENT_MODE
//
int _serverPort; // DEFAULT_PORT - Port to listen for clients on
BOOL _staSelectInterf; // FALSE - Listen on the specified interface
BOOL _staRecvOnly; // FALSE - Receive data only; don't echo back
BOOL _staEndClientSocketThread; // FALSE - Receive data only; don't echo back
BOOL _staEndServerSocketThread; // FALSE - Receive data only; don't echo back
char _ipServerAddress[128]; // - Interface to listen for clients on
/**/
void setIpServerAddress(const char* ipServerAddress);
/**/
DWORD WINAPI ClientSocketThread(LPVOID lpParam);
/**/
DWORD WINAPI ClientRecvSocketThread(LPVOID lpParam);
/**/
DWORD WINAPI ClientSendSocketThread(LPVOID lpParam);
/**/
DWORD WINAPI ServerSocketThread(LPVOID lpParam);
/**/
int initializeSocket(const char* ipServerAddress,
int numServerPort,
BOOL staSelectInterf,
int staSocketMode
);
/**/
int startSocket(const char* ipServerAddress,
int numServerPort,
BOOL staSelectInterf,
int staSocketMode);
/**/
int answerBuffer(const char* strBuffer,
int numLengthBuffer,
int staSocketMode);
/**/
int validateBuffer( const char* strBuffer,
int numLengthBuffer,
int staSocketMode );
/**/
int makePacket(char modePacket,
const char* stream,
int numLengthStream,
char typePacket);
/**/
int makeShortPacketToSend(char typePacket);
/**/
int makePacketDateTime();
/**/
int makeActionPacketToSend(char moveAction);
/**/
#endif /** NETWORK_H **/
88
//Arquivo: network.c
#include "network.h"
/*
* # Metodo construtor
*/
/*
* # Propriedades
*/
void setIpServerAddress(const char* ipServerAddress)
{
strcpy(_ipServerAddress,ipServerAddress);
}
/*
* # Métodos
*/
DWORD WINAPI ClientSocketThread(LPVOID lpParam)
{
SOCKET socketClient = (SOCKET)lpParam;
char strBytesBuffer[DEFAULT_BUFFER];
int sizeBytesReturn;
int sizeBytes;
int idxByteBuffer;
int idxByteStream;
printf("client thread started...\n");
while( !_staEndClientSocketThread && socketClient != NULL)
{
memset(strBytesBuffer,'\0',DEFAULT_BUFFER);
// Perform a blocking recv() call
sizeBytesReturn = recv(socketClient, strBytesBuffer, DEFAULT_BUFFER, 0);
//
if (sizeBytesReturn == SOCKET_ERROR)
{
printf("recv() failed: %d\n", WSAGetLastError());
socketClient = NULL;
_staEndClientSocketThread = TRUE;
break;
}
//
if ( sizeBytesReturn > 0 )
{
strBytesBuffer[sizeBytesReturn] = '\0';
//printf("RECV:: '%s'\n", strBytesBuffer);
//
validateBuffer( strBytesBuffer, sizeBytesReturn, _staSocketMode );
}
while( _packetAnswer != NULL )
{
//-printf("make a answer packet...\n");
// Start packet + packet bytes + End Packet
sizeBytes = 3;
sizeBytes += _packetAnswer->length;
// Packets
strBytesBuffer[0] = HEADERPACKET;
strBytesBuffer[1] = _packetAnswer->type;
89
//
idxByteBuffer = 2;
idxByteStream = 0;
//
if (idxByteStream < _packetAnswer->length)
{
//-printf("put data in answer packet...\n");
}
//
while(idxByteStream < _packetAnswer->length)
{
strBytesBuffer[idxByteBuffer] = _packetAnswer->stream[idxByteStream];
//
idxByteBuffer++;
idxByteStream++;
}
//
strBytesBuffer[idxByteBuffer] = ENDPACKET;
//
idxByteBuffer = 0;
//
//-printf("bytes to send: %d...\n", sizeBytes);
// Make sure we write all the data
while(idxByteBuffer < sizeBytes)
{
sizeBytesReturn = send(socketClient, &strBytesBuffer[idxByteBuffer], sizeBytes, 0);
if (sizeBytesReturn == 0)
{
//-printf("packet send...\n");
break;
}
else if (sizeBytesReturn == SOCKET_ERROR)
{
printf("send() failed: %d\n", WSAGetLastError());
socketClient = NULL;
_staEndClientSocketThread = TRUE;
break;
}
sizeBytes -= sizeBytesReturn;
idxByteBuffer += sizeBytesReturn;
}
//
if( _packetAnswer->next != NULL )
{
_packetAnswer = (Packet*)_packetAnswer->next;
}
else
{
_packetAnswer = NULL;
}
}
}
//
_staEndClientSocketThread = FALSE;
return 0;
}
//
DWORD WINAPI ClientRecvSocketThread(LPVOID lpParam)
{
SOCKET socketClient = (SOCKET)lpParam;
90
char strBytesBuffer[DEFAULT_BUFFER];
int sizeBytesReturn;
int sizeBytes;
int idxByteBuffer;
int idxByteStream;
printf("client recv thread started...\n");
while( !_staEndClientSocketThread )
{
memset(strBytesBuffer,'\0',DEFAULT_BUFFER);
// Perform a blocking recv() call
sizeBytesReturn = recv(socketClient, strBytesBuffer, DEFAULT_BUFFER, 0);
//
if (sizeBytesReturn == SOCKET_ERROR)
{
//printf("recv() failed: %d\n", WSAGetLastError());
}
else
if ( sizeBytesReturn > 0 )
{
strBytesBuffer[sizeBytesReturn] = '\0';
//printf("RECV: '%s'\n", strBytesBuffer);
//
validateBuffer( strBytesBuffer, sizeBytesReturn, _staSocketMode );
}
}
return 0;
}
//
DWORD WINAPI ClientSendSocketThread(LPVOID lpParam)
{
SOCKET socketClient = (SOCKET)lpParam;
char strBytesBuffer[DEFAULT_BUFFER];
int sizeBytesReturn;
int sizeBytes;
int idxByteBuffer;
int idxByteStream;
printf("client send thread started...\n");
while( !_staEndClientSocketThread )
{
while( _packetAnswer != NULL )
{
//-printf("make a answer packet...\n");
// Start packet + packet bytes + End Packet
sizeBytes = 3;
sizeBytes += _packetAnswer->length;
// Packets
strBytesBuffer[0] = HEADERPACKET;
strBytesBuffer[1] = _packetAnswer->type;
//
idxByteBuffer = 2;
idxByteStream = 0;
//
if (idxByteStream < _packetAnswer->length)
{
//-printf("put data in answer packet...\n");
}
//
while(idxByteStream < _packetAnswer->length)
91
{
strBytesBuffer[idxByteBuffer] = _packetAnswer->stream[idxByteStream];
//
idxByteBuffer++;
idxByteStream++;
}
//
strBytesBuffer[idxByteBuffer] = ENDPACKET;
//
idxByteBuffer = 0;
//
printf("bytes to send: %d...\n", sizeBytes);
// Make sure we write all the data
while(idxByteBuffer < sizeBytes)
{
sizeBytesReturn = send(socketClient, &strBytesBuffer[idxByteBuffer], sizeBytes, 0);
if (sizeBytesReturn == 0)
{
break;
}
else if (sizeBytesReturn == SOCKET_ERROR)
{
printf("send() failed: %d\n", WSAGetLastError());
socketClient = NULL;
_staEndClientSocketThread = TRUE;
break;
}
sizeBytes -= sizeBytesReturn;
idxByteBuffer += sizeBytesReturn;
}
//
if( _packetAnswer->next != NULL )
{
_packetAnswer = (Packet*)_packetAnswer->next;
}
else
{
_packetAnswer = NULL;
}
}
}
return 0;
}
//
DWORD WINAPI ServerSocketThread(LPVOID lpParam)
{
//
printf("server thread started...\n");
//
while( !_staEndServerSocketThread )
{
_numAddrSize = sizeof(_clientSockAddr);
_socketClient = accept(_socketListen, (struct sockaddr *)&_clientSockAddr, &_numAddrSize);
if (_socketClient == INVALID_SOCKET)
{
printf("accept() failed: %d\n", WSAGetLastError());
}
else
{
92
printf("Accepted client: %s:%d\n",inet_ntoa(_clientSockAddr.sin_addr),
ntohs(_clientSockAddr.sin_port));
//
_handleThread = CreateThread(NULL, 0, ClientSocketThread, (LPVOID)_socketClient, 0, &_idThread);
//
if (_handleThread == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
}
}
}
}
//
int initializeSocket(const char* ipServerAddress,
int numServerPort,
BOOL staSelectInterf,
int staSocketMode)
{
// Initialize Winsock
// load version 2.0
int result = WSAStartup(MAKEWORD(2,2), &_wsaData);
if (result != 0)
{
printf("WSAStartup failed: %d\n", result);
return result;
}
//
if ( _serverPort == -1 )
{
_serverPort = DEFAULT_PORT;
}
else
{
_serverPort = numServerPort;
}
//
if( staSelectInterf )
{
_staSelectInterf = staSelectInterf;
strcpy(_ipServerAddress,ipServerAddress);
}
//
_packetAnswer = NULL;
_packetReceive = NULL;
//
_staSocketMode = staSocketMode;
//
if ( staSocketMode == SERVER_MODE )
{
// create a socket listen
_socketListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (_socketListen == SOCKET_ERROR)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
// Select the local interface and bind to it
if (_staSelectInterf)
{
_serverSockAddr.sin_addr.s_addr = inet_addr(_ipServerAddress);
93
}
else
{
_serverSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
_serverSockAddr.sin_family = AF_INET;
_serverSockAddr.sin_port = htons(_serverPort);
//
if (bind(_socketListen, (struct sockaddr*)&_serverSockAddr, sizeof(_serverSockAddr)) ==
SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
return 1;
}
//
result = listen(_socketListen, 8);
}
else
{
// Create socket stream to connect server
_socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (_socketClient == INVALID_SOCKET)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
//
_serverSockAddr.sin_family = AF_INET;
_serverSockAddr.sin_port = htons(_serverPort);
_serverSockAddr.sin_addr.s_addr = inet_addr(_ipServerAddress);
//
if (_serverSockAddr.sin_addr.s_addr == INADDR_NONE)
{
_serverHostEntry = gethostbyname(_ipServerAddress);
if (_serverHostEntry == NULL)
{
printf("Unable to resolve server: %s\n", _ipServerAddress);
return 1;
}
CopyMemory(&_serverSockAddr.sin_addr,
_serverHostEntry->h_addr_list[0],
_serverHostEntry->h_length);
//
}
if (connect(_socketClient,
(struct sockaddr *)&_serverSockAddr,
sizeof(_serverSockAddr)) == SOCKET_ERROR )
{
printf("connect() failed: %d\n", WSAGetLastError());
return 1;
}
}
//
return result;
}
//
int startSocket(const char* ipServerAddress,
int numServerPort,
94
BOOL staSelectInterf,
int staSocketMode)
{
int result = initializeSocket(ipServerAddress, numServerPort, staSelectInterf, staSocketMode);
//
_packetAnswerAction = NULL;
//
if ( result == 0 )
{
printf("connected...\n", GetLastError());
if( staSocketMode == SERVER_MODE )
{
_staEndServerSocketThread = FALSE;
//
_handleServerSocketTh = CreateThread(NULL, 0, ServerSocketThread, NULL, 0,
&_idServerSocketTh);
//
if (_handleServerSocketTh == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
result = -1;
}
}
else
{
_staEndClientSocketThread = FALSE;
//
_handleClientSendSocketTh = CreateThread(NULL, 0, ClientSendSocketThread,
(LPVOID)_socketClient, 0, &_idClientSocketTh);
//
if (_handleClientSendSocketTh == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
result = -1;
}
//
_handleClientRecvSocketTh = CreateThread(NULL, 0, ClientRecvSocketThread,
(LPVOID)_socketClient, 0, &_idClientSocketTh);
//
if (_handleClientRecvSocketTh == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
result = -1;
}
}
}
return result;
}
//
int validateBuffer( const char* strBuffer,
int numLengthBuffer,
int staSocketMode )
{
//
if ( numLengthBuffer <= 2 )
{
printf("numLengthBuffer minor or equals 2...\n");
}
if ( strBuffer[0] != HEADERPACKET )
{
95
printf("byte 0 isnt header [%s]...\n",strBuffer);
}
if ( strBuffer[numLengthBuffer-1] != ENDPACKET )
{
printf("end byte isnt endpacket [%s][%c]...\n",strBuffer,strBuffer[numLengthBuffer-1]);
}
//
if ( numLengthBuffer > 2 &&
strBuffer[0] == HEADERPACKET &&
strBuffer[numLengthBuffer-1] == ENDPACKET
)
{
if ( staSocketMode == SERVER_MODE )
{
//-printf("now is server mode...\n");
if( strBuffer[1] == PROJECTPACKET )
{
//-printf("make a project packet to answer...\n");
return makePacket(SEND_MODE, PROJECT_NAME, PROJECT_NAME_SIZE,
PROJECTPACKET);
}
else
if( strBuffer[1] == MESSAGEPACKET )
{
//-printf("make a message packet to answer...\n");
// no answer, identify answer return to algoritm detection
makePacket(RECEIVE_MODE, strBuffer, numLengthBuffer, MESSAGEPACKET);
}
else
if( strBuffer[1] == HAVEACTIONPACKET )
{
// if ask by any action, return to algoritm detection
if ( _packetAnswerAction != NULL )
{
//-printf("make a action packet to answer...\n");
makePacket(SEND_MODE, _packetAnswerAction->stream, _packetAnswerAction->length,
HAVEACTIONPACKET);
//
_packetAnswerAction = _packetAnswerAction->next;
}
}
else
if( strBuffer[1] == DATETIMEPACKET )
{
//-printf("make a datetime packet to answer...\n");
// answer date time
makePacketDateTime();
}
}
else
if ( staSocketMode == CLIENT_MODE )
{
//-printf("now is client mode...\n");
if( strBuffer[1] == PROJECTPACKET )
{
//-printf("make a project packet to print...\n");
// print project name
makePacket(RECEIVE_MODE, strBuffer, numLengthBuffer, PROJECTPACKET);
}
else
96
if( strBuffer[1] == HAVEACTIONPACKET )
{
//-printf("make a action packet to print...\n");
// select action, execute and answer action with a haveactionpacket
// size message: 1
makePacket(RECEIVE_MODE, strBuffer, numLengthBuffer, HAVEACTIONPACKET);
}
else
if( strBuffer[1] == DATETIMEPACKET )
{
//-printf("make a datetime packet to print...\n");
// print date time
// packet entry: yyyymmddhh24miss
// size message: 14
makePacket(RECEIVE_MODE, strBuffer, numLengthBuffer, DATETIMEPACKET);
}
}
return 1;
}
else
{
return -1;
}
}
//
int makePacket( char modePacket,
const char* stream,
int numLengthStream,
char typePacket )
{
int idxStream = 0;
char* streamPacket = NULL;
//
Packet* newPacket = (Packet*)malloc(sizeof(Packet));
//
if( numLengthStream > 0 )
{
//printf("make a new packet with data ...\n");
//
if ( modePacket == RECEIVE_MODE )
{
numLengthStream -= 1;
idxStream = 2;
}
//
newPacket->stream = (char*)malloc(numLengthStream*sizeof(char));
streamPacket = newPacket->stream;
//
while(idxStream<numLengthStream)
{
*streamPacket = stream[idxStream];
//
streamPacket++;
idxStream++;
}
}
else
{
//-printf("make a new packet no data...\n");
newPacket->stream = NULL;
97
}
//
newPacket->length = numLengthStream;
newPacket->type = typePacket;
newPacket->next = NULL;
//
if ( modePacket == SEND_MODE )
{
//-printf("put packet to send...\n");
//
if ( typePacket != ACTIONPACKET )
{
if( _packetAnswer != NULL )
{
_packetAnswer->next = newPacket;
}
else
{
_packetAnswer = newPacket;
}
}
else
{
if( _packetAnswerAction != NULL )
{
_packetAnswerAction->next = newPacket;
}
else
{
_packetAnswerAction = newPacket;
}
}
}
else
{
//-printf("put packet to receive...\n");
//
if( _packetReceive != NULL )
{
_packetReceive->next = newPacket;
}
else
{
_packetReceive = newPacket;
}
}
//
return numLengthStream;
}
//
int makeShortPacketToSend(char typePacket)
{
//
return makePacket( SEND_MODE, "", 0, typePacket );
}
//
int makePacketDateTime()
{
struct tm *localTime;
time_t timeValue;
98
timeValue = time(NULL);
localTime = localtime(&timeValue);
//
Packet* newPacket = (Packet*)malloc(sizeof(Packet));
//
newPacket->stream = (char*)malloc(14*sizeof(char));
//
snprintf(newPacket->stream,
14,
"%04d%02d%02d%02d%02d%02d",
localTime->tm_year+1900,
localTime->tm_mon,
localTime->tm_mday,
localTime->tm_hour,
localTime->tm_min,
localTime->tm_sec);
//
newPacket->length = 14;
newPacket->type = DATETIMEPACKET;
newPacket->next = NULL;
//
if( _packetAnswer != NULL )
{
_packetAnswer->next = newPacket;
}
else
{
_packetAnswer = newPacket;
}
//
}
//
int makeActionPacketToSend(char moveAction)
{
char* bufferAction = (char*)malloc(2*sizeof(char));
bufferAction[0] = moveAction;
bufferAction[1] = '\0';
return makePacket( SEND_MODE, bufferAction, 1, ACTIONPACKET );
}
//Arquivo: detectObject.c
#ifndef DETECTOBJECT_H
#define DETECTOBJECT_H
#ifdef __cplusplus
#include <cv.h>
#include <highgui.h>
#include <ml.h>
#include <cvblob.h>
using namespace cvb;
#define ADJUST_NUMBER_CLASS 1
#define PIXEL_SIZE 0.10307
#define ERROR_TAXA_AREA 0.5
#define PI 3.1413
enum {FUNDO, OBJETO, NUM_CLASSES};
99
int get_type(CvScalar sc)
{
double *px = sc.val;
return px[0] == 255 && px[1] == 255 && px[2] == 255 ? FUNDO : OBJETO;
}
const static CvScalar class_colors[] = {
{{1*255, 1*255, 1*255, 0}}, // FUNDO
{{0*255, 1*255, 0*255, 0}} // OBJETO
};
CvScalar get_px(int type)
{
if (type == FUNDO) return cvScalar(255, 255, 255);
else if (type == OBJETO) return cvScalar(0, 255, 0);
}
extern "C"
{
#endif
typedef struct ImageObject
{
char* name;
char* name_background;
IplImage* object;
IplImage* background;
IplImage* classifier;
void* dtree;
double* distance;
double* area;
struct ImageObject* end;
} TImageObject;
//
typedef struct ObjectSearched
{
double minx;
double miny;
double maxx;
double maxy;
double area;
double centroidx;
double centroidy;
double distance;
struct ObjectSearched* end;
} TObjectSearched;
//
typedef struct ListObjectSearched
{
TObjectSearched* start;
TObjectSearched* end;
int* count;
} TListObjectSearched;
void DetectObjectCreateClassifier ( TImageObject* imageObject );
void DetectObjectCreateDecisionTree ( TImageObject* imageObject );
void DetectObjectExecute ( TImageObject* imageObject,
IplImage* imageLeft,
IplImage* imageRight,
100
IplImage* scene,
double numParalaxe,
double numDistFocal,
IplImage** baseResult,
TListObjectSearched** listObjectSearched );
TListObjectSearched* inicializaListObjectSearched();
TObjectSearched* inicializaObjectSearched( double minx, double miny,
double maxx, double maxy,
double area,
double centroidx, double centroidy,
double distance
);
char insereListObjectSearched ( TListObjectSearched* listObjectSearched,
TObjectSearched* ObjectSearched );
#ifdef __cplusplus
};
#endif
#endif /** DETECTOBJECT_H **/
//Arquivo: detectObject.cpp
#include "detectObject.h"
/*
* # Construtor
*/
/*
* # Propriedades
*/
/*
* # Métodos
*/
void DetectObjectCreateClassifier( TImageObject* imageObject )
{
int x = 0, y = 0;
// criando a imagem classificadora
imageObject->classifier = cvCreateImage(cvGetSize(imageObject->object), 8, 3);
// criando a imagem para subtracao do objeto ao fundo
IplImage* subclassifier = cvCreateImage(cvGetSize(imageObject->object), 8, 3);
// adicionando brilho a imagem do objeto (exemplo: * melhor condicao de visualizacao para heineken
aluminum)
cvAddS(imageObject->object, cvScalar(50,50,50), imageObject->object);
// subtraindo a imagem do objeto e a imagem do fundo atribuindo a subtracao do classificador
cvSub(imageObject->background, imageObject->object, subclassifier, NULL);
// obtendo a imagem classificadora
for( int idxSize=0;
idxSize < imageObject->background->height*imageObject->background->width*imageObject-
>background->nChannels;
idxSize += imageObject->background->nChannels )
{
x = (idxSize+1)%(imageObject->background->height*imageObject->background->nChannels);
y = (idxSize+1)/(imageObject->background->height*imageObject->background->nChannels);
//
if( *(subclassifier->imageData+idxSize ) != 0 &&
101
*(subclassifier->imageData+idxSize+1) != 0 &&
*(subclassifier->imageData+idxSize+2) != 0
)
{
*(imageObject->classifier->imageData+idxSize ) = *(imageObject->object->imageData+idxSize );
*(imageObject->classifier->imageData+idxSize+1) = *(imageObject->object->imageData+idxSize+1);
*(imageObject->classifier->imageData+idxSize+2) = *(imageObject->object->imageData+idxSize+2);
}
else
{
*(imageObject->classifier->imageData+idxSize ) = 255;
*(imageObject->classifier->imageData+idxSize+1) = 255;
*(imageObject->classifier->imageData+idxSize+2) = 255;
}
}
/** ajustando a imagem classificadora *************************************/
// removendo detalhes nao interessantes da imagem classificadora
cvThreshold(imageObject->classifier,imageObject->classifier,140,255,CV_THRESH_BINARY);
// obtendo o tamanho da imagem
CvSize size = {imageObject->object->width, imageObject->object->height};
// criando nova imagem para aplicar interpolacao tanto na imagem do objeto
// quanto na imagem do objeto
IplImage *s_object = cvCreateImage(size, imageObject->object->depth , imageObject->object-
>nChannels);
IplImage *s_classifier = cvCreateImage(size, imageObject->classifier->depth, imageObject->classifier-
>nChannels);
cvResize(imageObject->object , s_object , CV_INTER_LINEAR);
cvResize(imageObject->classifier, s_classifier, CV_INTER_NN);
cvReleaseImage(&imageObject->object);
cvReleaseImage(&imageObject->classifier);
// atualizando a imagem do objeto e imagem classifcadora
imageObject->object = s_object;
imageObject->classifier = s_classifier;
// aplicando filtro passa-baixa - filtro gaussiano
cvSmooth(imageObject->object, imageObject->object, CV_BLUR, 11, 11, 0, 0);
}
//
void DetectObjectCreateDecisionTree ( TImageObject* imageObject )
{
int out_rows = imageObject->object->height * imageObject->object->width;
CvMat *data = cvCreateMat(out_rows, NUM_CLASSES+ADJUST_NUMBER_CLASS, CV_32F);
CvMat *missing = cvCreateMat(out_rows, NUM_CLASSES+ADJUST_NUMBER_CLASS,
CV_8U);
CvMat *responses = cvCreateMat(out_rows, 1, CV_32F);
int row, col;
// carregando a arvore de decisao com pedacos da imagem
for (row = 0; row < imageObject->object->height; row++)
{
for (col = 0; col < imageObject->object->width; col++)
{
int out_row = row*imageObject->object->width + col;
//
CvScalar object_px = cvGet2D(imageObject->object , row, col);
CvScalar classifier_px = cvGet2D(imageObject->classifier, row, col);
//
cvSet2D(data, out_row, 0, cvScalar(object_px.val[0]));
cvSet2D(data, out_row, 1, cvScalar(object_px.val[1]));
cvSet2D(data, out_row, 2, cvScalar(object_px.val[2]));
cvSet2D(missing, out_row, 0, cvScalar(0)); // No missing data
cvSet2D(missing, out_row, 1, cvScalar(0)); // No missing data
102
cvSet2D(missing, out_row, 2, cvScalar(0)); // No missing data
// identificando se fundo ou objeto
int type = get_type(classifier_px);
//
cvSet2D(responses, out_row, 0, cvScalar(type));
}
}
//
CvMat* var_type = cvCreateMat(data->cols+1, 1, CV_8U);
cvSet(var_type, cvScalarAll(CV_VAR_NUMERICAL));
cvSet2D(var_type, data->cols, 0, cvScalarAll(CV_VAR_CATEGORICAL));
// definindo prioridades de pesquisa
float priors[] = {5, 10}; // fundo, objeto
// criando a arvore de decisao
CvDTree *dtree = new CvDTree;
// treinando a arvore de decisao
dtree->train( data,
CV_ROW_SAMPLE,
responses,
0,
0,
var_type,
missing,
CvDTreeParams( 17, // Max depth
10, // min sample count
0, // regression accuracy: N/A here
false, // compute surrogate split , as we have missing data
5, // max number of categories (use sub-optimal algorithm for
larger numbers)
10, // the number of cross-validation folds
false, // use 1SE rule => smaller tree
true, // throw away the pruned tree branches
priors // the array of priors , the bigger p_weight, the more attention
)
);
// retornando a arvore criada
imageObject->dtree = dtree;
}
void DetectObjectExecute ( TImageObject* imageObject,
IplImage* imageLeft,
IplImage* imageRight,
IplImage* scene,
double numParalaxe,
double numDistFocal,
IplImage** baseResult,
TListObjectSearched** listObjectSearched )
{
// Trabalhando com a imagem SCENE ------------------------------------------
CvDTree *dtree = (CvDTree*) imageObject->dtree;
// ajustando a imagem onde será pesquisado o objeto
cvAddS(scene, cvScalar(50,50,50), scene);
cvResize(scene, scene, CV_INTER_LINEAR);
// aplicando filtro passa-baixa - filtro gaussiano
cvSmooth(scene, scene, CV_BLUR, 11, 11, 0, 0);
// selecionando um canal de interesse
IplImage* sceneGreen = cvCreateImage(cvGetSize(scene), 8, 1);
cvCvtPixToPlane(scene, 0, 0, sceneGreen, 0);
// ajustando a imagem do canal de interesse
cvThreshold(sceneGreen, sceneGreen, 140, 255, CV_THRESH_BINARY);
103
// aplicando a arvore sob a cena para obter o resultado
*baseResult = cvCloneImage(scene);
CvMat *dataoutput = cvCreateMat(scene->height, NUM_CLASSES+ADJUST_NUMBER_CLASS,
CV_8U);
CvMat *dataimage = cvCreateMat(1, NUM_CLASSES+ADJUST_NUMBER_CLASS, CV_32F);
int correct = 0, wrong = 0, p_total = 0;
int row, col;
for (row = 0; row < scene->height; row++)
{
for (col = 0; col < scene->width; col++)
{
int out_row = row*scene->width + col;
//
CvMat *sample = cvCreateMat(1, NUM_CLASSES+ADJUST_NUMBER_CLASS,
CV_32F);
CvScalar scene_px = cvGet2D(scene, row, col);
cvSet2D(sample, 0, 0, cvScalar(scene_px.val[0]));
cvSet2D(sample, 0, 1, cvScalar(scene_px.val[1]));
cvSet2D(sample, 0, 2, cvScalar(scene_px.val[2]));
double predicted_val = dtree->predict(sample, NULL)->value;
//
cvSet2D(*baseResult, row, col, get_px(predicted_val));
}
}
//
// removendo os objetos que não são interessantes
int numSizeDesloc;
int x, y;
//
for( int idxSize=0;
idxSize < sceneGreen->height*sceneGreen->width*sceneGreen->nChannels;
idxSize += sceneGreen->nChannels )
{
// identificando o numero de deslocamento da imagem de um canal
// para a imagem de tres canais
numSizeDesloc = idxSize * scene->nChannels;
//
x = (idxSize+1)%(sceneGreen->height*sceneGreen->nChannels);
y = (idxSize+1)/(sceneGreen->height*sceneGreen->nChannels);
if( *(sceneGreen->imageData+idxSize ) == 0 )
{
*((*baseResult)->imageData+numSizeDesloc ) = *((*baseResult)->imageData+numSizeDesloc );
*((*baseResult)->imageData+numSizeDesloc+1) = *((*baseResult)->imageData+numSizeDesloc+1);
*((*baseResult)->imageData+numSizeDesloc+2) = *((*baseResult)->imageData+numSizeDesloc+2);
}
else
{
*((*baseResult)->imageData+numSizeDesloc ) = 255;
*((*baseResult)->imageData+numSizeDesloc+1) = 255;
*((*baseResult)->imageData+numSizeDesloc+2) = 255;
}
}
CvBlobs blobsOutput;
// ajustando a imagem para localizar o objeto sob o resultado da arvore
IplImage *sceneLabel = cvCreateImage(cvGetSize(scene), IPL_DEPTH_LABEL, 1);
IplImage *baseResultGreen = cvCreateImage(cvGetSize(scene), 8, 1);
IplImage *baseScene = cvCreateImage(cvGetSize(scene), 8, 1);
104
cvCvtColor( *baseResult, baseResultGreen, CV_BGR2GRAY );
cvNot( sceneGreen, sceneGreen );
cvNot( *baseResult, *baseResult );
// localizando os objetos
unsigned int result = cvLabel(sceneGreen, sceneLabel, blobsOutput);
//
if ( result > 0 )
{
printf("aglomerados de pixel: %d\n", result );
}
double numDistance = 0;
double numAreaMin = 0;
double numAreaMax = 0;
// iniciando a lista de objetos localizados
if ( *listObjectSearched == NULL )
{
printf("lista de objetos encontrados foi iniciada...\n");
printf("numParalaxe: %f, numDistFocal: %f\n", numParalaxe, numDistFocal );
*listObjectSearched = inicializaListObjectSearched();
}
//
cvNamedWindow( "resultScene", CV_WINDOW_AUTOSIZE );
cvMoveWindow ( "resultScene", 650, 300);
//cvShowImage( "resultScene", scene );
//
//
TObjectSearched* objectSearched = NULL;
//
(*listObjectSearched)->start = NULL;
(*listObjectSearched)->end = NULL;
*((*listObjectSearched)->count) = 0;
//
for (CvBlobs::const_iterator it=blobsOutput.begin(); it!=blobsOutput.end(); ++it)
{
// localizando a distancia dos pixels aglomerados baseado em:
numDistance = ( sceneLabel->height - it->second->miny ) / PIXEL_SIZE / 1000;
//
numAreaMin = (( *imageObject->area * numDistance ) / ( *imageObject->distance ));
numAreaMax = numAreaMin * ( 1.0F + ERROR_TAXA_AREA);
numAreaMin = numAreaMin * ( 1.0F - ERROR_TAXA_AREA);
//
if ( it->second->area >= numAreaMin &&
it->second->area <= numAreaMax )
{
cout << "Blob #" << it->second->label << ": height=" << sceneLabel->height << ": width=" <<
sceneLabel->width << ": Minx=" << it->second->minx << ": Miny=" << it->second->miny << ": Maxx=" << it-
>second->maxx << ": Maxy=" << it->second->maxy << ": Area=" << it->second->area << ", Centroid=(" << it-
>second->centroid.x << ", " << it->second->centroid.y << "), estimate distance[m] " << numDistance << endl;
//
cout << "Objeto encontrado..." << endl;
//
objectSearched = inicializaObjectSearched( it->second->minx, it->second->miny,
it->second->maxx, it->second->maxy,
it->second->area,
it->second->centroid.x, it->second->centroid.y,
0
);
105
//
insereListObjectSearched( *listObjectSearched, objectSearched );
//
CvContourPolygon *polygon = cvConvertChainCodesToPolygon(&(*it).second->contour);
CvContourPolygon *sPolygon = cvSimplifyPolygon(polygon, 10.);
CvContourPolygon *cPolygon = cvPolygonContourConvexHull(sPolygon);
//
cvRenderContourPolygon(cPolygon, *baseResult, CV_RGB(0, 255, 0));
cvRenderContourPolygon(cPolygon, scene, CV_RGB(0, 255, 0));
//
delete cPolygon;
delete sPolygon;
delete polygon;
}
else
{
cout << "Blob #" << it->second->label << " min area: " << numAreaMin << " max area: " <<
numAreaMax << ": AreaR=" << it->second->area << " estimate distance[m] " << numDistance << endl;
cout << "Blob #" << it->second->label << ": height=" << sceneLabel->height << ": width=" <<
sceneLabel->width << ": Minx=" << it->second->minx << ": Miny=" << it->second->miny << ": Maxx=" << it-
>second->maxx << ": Maxy=" << it->second->maxy << ": Area=" << it->second->area << ", Centroid=(" << it-
>second->centroid.x << ", " << it->second->centroid.y << "), estimate distance[m] " << numDistance << endl;
//
}
}
//
cvShowImage( "resultScene", scene );
cvWaitKey(1);
}
//
TListObjectSearched* inicializaListObjectSearched()
{
TListObjectSearched* result = (TListObjectSearched*)malloc(sizeof(TListObjectSearched));
//
result->start = NULL;
result->end = NULL;
result->count = (int*)malloc(sizeof(int));
(*result->count) = 0;
//
return result;
}
//
TObjectSearched* inicializaObjectSearched( double minx, double miny,
double maxx, double maxy,
double area,
double centroidx, double centroidy,
double distance
)
{
TObjectSearched* result = (TObjectSearched*)malloc(sizeof(TObjectSearched));
//
result->minx = minx;
result->miny = miny;
result->maxx = maxx;
result->maxy = maxy;
result->area = area;
result->centroidx = centroidx;
result->centroidy = centroidy;
result->distance = distance;
result->end = NULL;
106
//
return result;
}
//
char insereListObjectSearched( TListObjectSearched* listObjectSearched,
TObjectSearched* ObjectSearched )
{
char result = 0;
//
if(listObjectSearched != NULL && ObjectSearched != NULL)
{
//
if(listObjectSearched->start == NULL)
{
listObjectSearched->start = ObjectSearched;
//
listObjectSearched->end = ObjectSearched;
}
else
{
((TObjectSearched*)listObjectSearched->end)->end = ObjectSearched;
//
listObjectSearched->end = ObjectSearched;
}
//
(*listObjectSearched->count)++;
result = 1;
}
return result;
}
//
107
APÊNDICE C – Resultado do desenvolvimento do veículo através das
imagens
Imagem da frente do veículo.
Imagem superior do veículo exibindo sua lateral.
108
Imagem exibindo a detecção da garrafa verde diposta entre os objetos.
Imagem exibindo a detecção da garrafa verde diposta entre os objetos com foco na tela do computador portátil.
109
Imagem exibindo a detecção da garrafa verde diposta à direita dos objetos com foco no objeto e na tela do
computador portátil.