Escolar Documentos
Profissional Documentos
Cultura Documentos
(2.1)
(2.2)
Nas equaes anteriores (2.1 e 2.2) foram introduzidas duas distncias focais diferentes pois
geralmente os pixels so rectangulares e no quadrados. Tambm o centro da cmara no ,
geralmente, sobre o eixo principal, sendo introduzidos dois novos parmetros,
(2.3)
(2.4)
Ento, segundo o modelo da cmara pin-hole, um ponto 3D com coordenadas
mapeado para o ponto
(2.5)
Representando os pontos tridimensionais e os pontos da imagem por vectores de coordenadas
homogneas, pode-se expressar a projeco central como um mapeamento linear entre esses vectores.
Desta forma, a equao (2.5) pode ser escrita como uma multiplicao de matrizes:
(2.6)
Basicamente, como descrito na equao 2.6, este modelo aplica uma matriz de projeco para
transformar as coordenadas 3D dos pontos do objecto (coordenadas do mundo) em coordenadas 2D da
imagem:
=
Por outro lado, para encontrar as coordenadas em relao ao eixo real (3D), sabendo as coordenadas
da imagem (2D), aplica-se o clculo inverso:
=
8
2.2 Processo de calibrao
A calibrao de uma cmara um processo que realizado para que seja possvel obter informaes
(mtricas) 3D a partir de uma imagem 2D capturada pela cmara [8]. Nesse processo obtido um
conjunto de parmetros que nos do essas informaes.
Os referidos parmetros incluem a geometria interna e ptica da cmara (caractersticas intrnsecas), e
a estimativa do posicionamento e da orientao da cmara associada a uma determinada imagem
(caractersticas extrnsecas).
A aquisio desses parmetros pode ser dividida em duas etapas:
- Determinao dos parmetros intrnsecos
- Determinao dos parmetros extrnsecos
Os parmetros intrnsecos descrevem a forma como a cmara cria uma imagem, fornecendo a relao
entre a imagem e a cmara. Consiste em determinar as propriedades intrnsecas da cmara, tais como:
distncia focal , centro da imagem , coeficiente de distoro das lentes e factor de escala. Estes
parmetros so importantes para poder relacionar as coordenadas de um pixel da imagem com as
coordenadas correspondentes do referencial da cmara.
Os parmetros extrnsecos indicam a posio e a orientao da cmara. So definidos como um
conjunto de parmetros que identificam a transformao entre um referencial desconhecido e o
referencial do mundo, ou seja, um referencial conhecido.
Para expressar a correspondncia entre pontos do espao e pontos da imagem conveniente considerar
quatro sistemas de coordenadas de modo a que a transformao da cmara possa ser expressa como a
composta de transformaes simples realizadas entre estes sistemas.
Os sistemas de coordenadas considerados so:
- SCM Sistema de Coordenadas do Mundo :
Sistema tridimensional em que as suas coordenadas descrevem a posio de pontos 3D do
objecto real, coordenadas do mundo real.
- SCC Sistema de Coordenadas da Cmara
Sistema tridimensional com origem no centro ptico da cmara ,ou seja, o orifcio (para o
caso de uma cmara pin-hole), em que as suas coordenadas descrevem a posio do ponto
3D em relao cmara (coordenadas locais da cmara). O plano de projeco o plano de
equao
.
9
- SCI Sistema de Coordenadas da Imagem
Sistema bidimensionalem em que as suas coordenadas descrevem a posio do pondo 2D em
relao ao plano da imagem.
- SCP Sistema de Coordenadas em Pixel
Sistema bidimensional, com coordenadas expressas em pixels, que define a posio de um
ponto da imagem na matriz de pixels.
Para cada imagem (frame) tirada pela cmara podemos descrever a posio do objecto em relao ao
SCC em termos de rotao e translao. O primeiro passo na obteno da posio na
imagem2D, correspondente ao ponto do espao 3D , expressar estas coordenadas
tridimensionais no SCC.
Figura 2.2. 1 Converso do sistema de coordenadas do objecto no sistema da Cmara [1].
A rotao feita em trs dimenses pode ser decomposta numa matriz bidimensional da rotao feita
em torno de cada eixo. Se rodarmos em torno de com os respectivos ngulos o
resultado a matriz R (rotao total) que dada pelo produto das trs matrizes:
, e
;
Ou seja,
(2.7)
10
Assim, sendo
o vector de coordenadas do ponto no SCC,
(2.8)
Em coordenadas Homogneas:
(2.9)
A transformao do SCC para o SCI, em cmaras pin-hole, consiste numa projeco perspectiva. A
projeco perspectiva efectuada por uma cmara pin-hole com distncia focal pode ser escrita como:
(2.10)
Do sistema de coordenadas da imagem (SCI) para o sistema de coordenadas em pixel (SCP):
(2.11)
Os coeficientes da matriz acima representada formam, juntamente com a distncia focal , os
parmetros intrnsecos da cmara. Os significados destes parmetros so os seguintes:
-
(2.12)
Ou ainda,
(2.13)
Como os parmetros ,
12
2.3 Mtodo de Calibrao de Zhang
Para resolver o problema de calibrao da cmara, ou seja, determinar os parmetros intrnsecos e
extrnsecos, foi utilizado o mtodo proposto por Zhang. Este mtodo usa um padro (bidimensional)
que posicionado de diversas formas no espao dando origem a m imagens (conforme ilustrado na
Figura 2.3.1). Em cada uma destas imagens admitimos que h n pontos cujas coordenadas no sistema
de referncia do padro so conhecidas. Admitimos ainda que os parmetros intrnsecos da cmara so
os mesmos em todas as imagens. Somente os parmetros extrnsecos mudam quando o padro
reposicionado.
Figura 2.3. 1 Imagens do chessboard [1].
O facto de termos mais do que uma imagem do padro permite que, no mtodo de Zhang, possamos
ajustar um modelo mais geral de cmara, definido por uma transformao, em coordenadas
homogneas, e que se representa da seguinte forma:
(2.14)
A restrio ao plano de Z = 0 define uma transformao projectiva, ou homografia, entre este plano e o
plano imagem.
Etapas do mtodo de Zhang:
- Primeira etapa - obteno de um conjunto de imagens do padro de calibrao segundo
diferentes orientaes e posies no espao;
13
- Segunda etapa: extraco dos vrtices dos quadrados que constituem o padro de calibrao
em todas as imagens adquiridas;
- Terceira etapa: clculo dos parmetros intrnsecos, extrnsecos e de distoro da cmara
considerada.
2.4 Implementao e resultados
Para a realizao da calibrao foi utilizado um padro de oito vrtices por seis e com 2,9cm de
distncia entre eles (figura 2.4.1). Este padro foi posicionado em vrias formas perante a cmara.
Segue-se um exemplo da aquisio de vrias imagens do padro de calibrao utilizando uma cmara
digital convencional:
Figura 2.4. 1 Imagens do chessboard em diferentes posies.
As seguintes imagens demonstram um exemplo da extraco automtica dos vrtices dos quadrados
do padro de calibrao nas imagens adquiridas, utilizando o algoritmo de Zhang que se encontra
implementado nos exemplos do OpenCV (calibration.cpp):
a) b)
Figura 2.4. 2 a) Imagem da correcta extraco de pontos; b) Incorrecta extraco de pontos.
14
Dos resultados obtidos, podemos retirar os parmetros que nos permitem preencher a matriz de
transformao , assim como a posio e orientao da cmara em relao ao padro de
calibrao usado. Utilizando 5 imagens do padro de calibrao, em que todos os vrtices foram
correctamente detectados, foi realizada a calibrao da cmara, obtendo-se os seguintes parmetros
intrnsecos.
- Distncia focal:
- Ponto principal:
O resultado da realizao da calibrao encontra-se em anexo (ANEXO V) com mais detalhes
relativamente aos parmetros extrnsecos e de distoro da lente.
15
3. Viso do Rob Viso computacional.
O sistema de navegao do rob mvel utilizado baseado num sistema de viso com uma nica
cmara. Este sistema composto por uma srie de algoritmos executados sequncialmente para
cumprir tarefas pr-determinadas de navegao dentro de pista.
Neste captulo so apresentadas algumas tcnicas e conceitos bsicos teis no processamento de
imagens e viso por computador, assim como os algoritmos desenvolvidos para a identificao das
vias. Os algoritmos foram implementados em linguagem C com recurso a funes existentes na
biblioteca OpenCV [1].
3.1 Implementao da funo de Threshold
A funo de threshold usada essencialmente com o objectivo de segmentar
7
a imagem obtida em
tons de cinzentos, numa imagem binria (dois tons - preto e branco). Esta tcnica procura agrupar os
diferentes objectos e regies da imagem conforme o nvel de intensidade luminosa, ou seja, pretende
separar os objectos (vias da estrada) do fundo da imagem (pavimento).
A ideia , dado um valor de threshold , restringir o valor dos pixels a um de dois valores de modo a
obtermos uma imagem binarizada, ou seja:
- Valor 0 binrio (cor preta);
- Valor 1 binrio (cor branca).
(2.15)
7
Em viso computacional, segmentao refere-se ao processo de dividir uma imagem digital em mltiplas regies (conjunto
de pixels) ou objectos, simplificando a representao de uma imagem facilitando a sua anlise.
16
Numa imagem com 256 tons de cinzento, caso , as tonalidades entre 0 e 50
tornam-se informao de fundo da imagem (cor preta) enquanto que os valores superiores a 50
tornam-se informao correspondente aos objectos da imagem.
Desta forma, a definio de um valor de threshold suficiente para dividir a imagem em duas regies:
fundo e objectos, sendo til quando existe um bom contraste entre essas regies.
Existem dois mtodos de Threshold em imagens: o fixo e o adaptativo. Comeou-se por implementar
o mtodo fixo, sendo criado o ficheiro threshold.c (ANEXO III). Neste mtodo fixa-se o valor de
threshold. No OpenCV, este mtodo implementado na funo cvThreshold ().
Um dos problemas de usarmos um valor fixo de threshold em termos de iluminao e contraste, pois
se o objecto e o fundo no tiverem nveis de iluminao distintos, isto , a existncia de um bom
contraste entre ambos, difcil separar o fundo do objecto, tornando-se por vezes impossvel.
O mtodo adaptativo j nos permite resolver melhor esse problema. Nesse mtodo o valor de threshold
uma varivel que depende de valores obtidos da anlise do histograma da imagem, em que se
calcula o valor mdio da intensidade dos pixels de duas regies
relativamente ao
valor de threshold inicial. Assim, temos:
(2.16)
Esta tcnica torna-se til quando existem variaes de iluminao, provocando variaes de contraste.
Foi criado ento o ficheiro threshist.c (ANEXO IV) para reproduzir vdeo em tons de cinzentos, o
respectivo histograma, e utilizao de um threshold dinmico.
17
3.2 Extraco e visualizao do Histograma
O histograma de uma imagem representa, para cada nvel de intensidade, o nmero de pixels desse
nvel, ou seja, o eixo horizontal refere-se intensidade (0 a 255) e o eixo vertical quantidade de
pixels que apresenta essa intensidade.
Figura 3.2. 1 Histograma de uma imagem e escala de cinzentos.
Uma das utilidades de um histograma o realce de imagens a partir da sua equalizao. A equalizao
consiste numa transformao da imagem a partir da resistribuio dos nveis de intensidade luminosa
dos seus pontos, de forma a atingir uma distribuio mais uniforme de uma faixa ou de todas as faixas
do histograma da imagem.
Desta forma, imagens escuras teriam os nveis de intensidades redistribudos gerando um histograma
mais uniforme, ou seja, resulta numa imagem mais clara e ntida, com maior contraste entre o objecto
e o fundo da imagem. O mesmo principio pode ser aplicado a imagens muito claras, realando
caractersticas importantes da imagem.
A extraco e anlise do histograma so relevantes para a escolha do valor de threshold, pois
analisando o histograma de uma imagem em tons de cinza verificamos que os pixels pertencentes ao
objecto (vias da estrada) se encontram mais direita e os pixels referentes ao fundo mais esquerda,
de intensidades predominantemente baixas.
Assim, como referido na seco anterior, atravs da anlise do histograma da imagem, calcula-se a
rea esquerda e direita do valor de threshold para a obteno de um novo valor de threshold
(ANEXO IV).
18
3.3 Mtodo de identificao de uma via
Neste mtodo foi desenvolvido um sistema para identificao de uma via. Este sistema inclui uma
cmara colocada sobre a plataforma do rob de modo a visualizar a via mais direita da pista (Figura
3.3.1).
Figura 3.3. 1 Colocao da cmara no rob.
Desta forma visualiza-se somente a via de interesse para anlise. Essa via ser utilizada como principal
guia para o movimento do rob.
Ao colocarmos o rob na pista ele dever ser posicionado de forma a obter a imagem da via com a
seguinte representao:
Figura 3.3. 2 Imagem original do MI1V.
Ou seja, a parte superior da via dever ficar ao centro da parte superior da imagem, pois necessrio
para o funcionamento correcto do MI1V.
Seguidamente procede-se anlise da imagem. Esta ser convertida para tons de cinzentos (Figura
3.3.3a) para que seja possvel aplicar a funo de threshold adaptativo implementada no OpenCV em
cvAdaptiveThreshold () (Figura 3.3.3b).
19
a) b)
Figura 3.3. 3 a) Imagem em tons de cinzentos: b) Imagem com Threshold adaptativo.
Como a imagem passa a ter dois tons, preto e branco (fundo e objecto, respectivamente), procede-se
ao algoritmo de Canny (implementado no OpenCV em cvCanny()) para retirar os contornos da
imagem adquirida (Figura 3.3.4).
Esse algoritmo essencial neste mtodo, pois atravs dele que se extraem as caractersticas
necessrias para o posterior controlo do rob.
Figura 3.3. 4 - Aplicao do filtro de Canny.
Uma imagem pode ser considerada como uma matriz , em que corresponde resoluo
horizontal da imagem e resoluo vertical. Para anlise foi considerada uma imagem com a
resoluo de 320x240 (pixels).
Figura 3.3. 5 Imagem Vector em anlise.
20
Analisando a imagem da Figura 3.3.4 podemos retirar ento caractersticas (os pontos de interesse).
Isto , percorrendo o vector superior da imagem , analisamos todas as posies desse vector
at serem encontrados pontos brancos, ou seja, com o valor 255, e guardam-se esses valores que
correspondem coordenada , para , do pixel detectado (Figura 3.3.5).
Portanto, encontrada a posio dos pontos de referncia no vector em causa (crculos a branco na
Figura 3.3.6), achada a mdia aritmtica (designado por ponto mdio) das posies encontradas (em
termos de coordenadas em pixel), para que se possa traar a recta final. Essa recta indica a regio
que o rob se encontra (Figura 3.3.6) e traada do ponto mdio at ao centro da imagem (160,120).
a) b) c)
Figura 3.3. 6 Recta final do MI1V: a) Regio 1; b) Regio 2, c) Regio 3.
Foi considerado para anlise um vector com 320 posies, correspondente resoluo horizontal da
imagem. O movimento do rob pode ser definido em quatro regies (ver seco 3.3) e efectuado
perante as seguintes situaes:
- Regio 1: Se o ponto mdio estiver entre 150 e 170 o rob segue em frente;
- Regio 2: Se o ponto mdio for menor que 150 e for maior ou igual que 50 o rob vira para a
direita com velocidade de rotao 1;
- Regio 2: Se o ponto mdio for maior que 170 e for menor ou igual que 270 o rob vira para a
esquerda com velocidade de rotao 1;
- Regio 3: Se o ponto mdio for maior que 270 e for menor que 320 o rob vira para a
esquerda com velocidade de rotao 2;
- Regio 3: Se o ponto mdio for menor que 50 e for maior que 0 o rob vira para a direita com
velocidade de rotao 2;
- Regio 4: Qualquer outro caso o rob pra ( ponto mdio <= 0 e ponto mdio >= 320) .
Considera-se que a velocidade de rotao 1 inferior velocidade de rotao 2. Isto para que, como o
ponto mdio se est a aproximar das margens da imagem, fazer com que o rob vire mais rpido de
forma a colocar o ponto mdio novamente entre os valores aceitveis, ou seja, mais ao centro da parte
superior da imagem.
21
Ao ser detectada a passadeira, e como em ambiente real s existe metade da pista, foi considerado que
o rob pra no instante em que so encontrados mais que dez pontos brancos no vector em anlise.
Figura 3.3. 7 Deteco da passadeira.
3.4 Mtodo de identificao de duas vias
Este mtodo foi desenvolvido com recurso a um vdeo, facultado pelos alunos de mestrado em
robtica avanada, que simula as faixas de rodagem onde o rob se movimenta, como ilustrado na
Figura 3.4.1.
Na aquisio da imagem original foram introduzidas duas barras para ajuste do brilho e do contraste,
pois ajuda a retirar algum rudo para a utilizao da funo de Threshold por forma a posteriormente
se extrair os contornos das vias (baseado no filtro de Canny) e detectar as rectas com a transformada
de Hough (implementada no OpenCV em cvHoughLines2()).
Figura 3.4. 1 Imagem original com ajuste de brilho e contrate MI2V.
Aps o carregamento do vdeo so retiradas vrias imagens (frames) para que a anlise seja feita frame
a frame. De seguida aplicado um procedimento para transformar a imagem a cores em tons de
cinzento, numa escala de oito bits, para que se possa utilizar a funo de threshold. Neste mtodo foi
utilizada a funo de threshold adaptativo (invertido).
22
Figura 3.4. 2 Imagem com Threshold adaptativo MI2V.
Seguidamente, como a imagem j se encontra binarizada, podemos aplicar o filtro de Canny. Com a
filtro de Canny podemos obter os contornos dos objectos existentes (neste caso, das vias).
Figura 3.4. 3 Aplicao da transformada de Canny MI2V.
Para retirar os pontos de interesse dos contornos obtidos necessrio utilizar a transformada de Hough
que, quando aplicada frame em anlise, nos d os pontos de incio e fim de cada recta encontrada.
Neste caso no foram traadas as rectas, mas sim marcados os pontos iniciais e finais das mesmas. Na
figura seguinte so ilustrados esses pontos de interesse.
Figura 3.4. 4 Aplicao da transformada de Hough MI2V.
Cada frame dividida em quatro quadrantes relativamente resoluo da imagem adquirida (Figura
3.4.5):
23
Figura 3.4. 5 Diviso da imagem por quadrantes.
Para cada quadrante analisada a posio de cada ponto encontrado no plano da imagem aplicando o
transformada de Hough, ou seja, so retiradas as coordenadas de cada ponto (em pixels) para que seja
possvel obter a mdia da posio dos pontos em cada quadrante. Essa mdia ser utilizada para traar
a recta que indica a posio e a orientao que o rob deve tomar para seguir o seu caminho.
Ou seja, o ponto superior da recta final ser dado pela soma da posio dos pontos do primeiro e
segundo quadrante, dividida por dois, enquanto o ponto inferior dado pela soma da posio dos
pontos do terceiro e quarto quadrante, dividida tambm por dois. O resultado final ilustrado na figura
seguinte.
Figura 3.4. 6 Resultado final do MI2V.
Aps ser traada a recta final (recta a verde) consegue-se ento determinar os parmetros necessrios
para fazer actuar o rob.
Esses parmetros so o ngulo formado entre a recta final e o eixo horizontal (a branco), e o desvio
dessa mesma recta em relao ao centro da imagem. Com esses parmetros conseguimos que o rob se
mantenha ao centro das vias, como pretendido pelo MI2V.
24
4. Controlo do Rob
Nesta seco apresentada uma introduo ao software ARIA assim como a descrio dos comandos
mais importantes para a utilizao e controlo do rob.
O comportamento do rob baseado somente na classe ArRobot, pois apenas foi implementado em
ambiente real o MI1V (ver seco 3.3), pelo que somente necessrio o rob efectuar movimento para
a frente, de rotao para a esquerda, de rotao para a direita e parar.
4.1 Introduo ao software ARIA
O software ARIA fornecido pelos fabricantes Pioneer, MobileRobots Inc, e pode ser usado para
controlar qualquer um dos seus modelos. essencialmente uma biblioteca para programadores C++
que se destina criao de software de alto nvel para controlar do rob [21].
Contudo necessrio estar familiarizado com o uso de conceitos tpicos de linguagem C++, incluindo
o uso de classes e objectos com uma hierarquia simples, construtores, apontadores e o processo de
compilao do cdigo [4] [5].
O software ARIA inclui muitas ferramentas utis para a programao dos robs. Pode ser acedida em
diferentes nves, desde um simples envio de comandos para o rob atravs da classe ArRobot ou o
desenvolvimento mais de alto nvel como o comportamento do rob atravs de aces (no abordado
neste trabalho).
Atravs da sua infra-estrutura de aces, ARIA fornece um mecanismo poderoso para combinar
comportamentos independentes, de forma a alcanar o controlo de movimentos coordenados e
orientao inteligente.
A classe mais importante do ARIA a classe ArRobot. Esta classe controla o ciclo de comunicao
com o firmware, recebendo e fornecendo acesso os dados sobre o estado do rob, desencadeando as
tarefas pretendidas determinando os comandos a serem enviados para o rob.
25
4.2 Comandos utilizados
A classe ArRobot , para alm de muitas outras classes existentes na biblioteca do ARIA, a classe base
para comunicao e operao do rob, actuando como um gateway de comunicaes cliente-servidor.
ArRobot contem todas as informaes primrias sobre o rob a ser controlado, representando uma
base padro, sem sensores, apenas com os motores como actuadores [19].
Relativamente programao, para que se possa usar a biblioteca do ARIA importante que esta seja
inicializada no nosso programa (cdigo). Para tal usa-se o seguinte comando:
Aria::init ();
Este comando deve de ser inserido no inicio da funo main principal do programa, ou seja, antes de
efectuar qualquer aco ou operao do rob. No final, em vez de se usar o retorno padro para
abandonar o programa, ou seja, return (0); usa-se o seguinte comando:
Aria::exit (0);
Para que se mantenha uma uniformidade entre os programas baseados em ARIA, a biblioteca vem
com um analizador de argumentos padro. Durante a inicializao de um programa (na linha de
comandos da consola, no OpenSUSE), este analizador pode ser usado para garantir que todos os
elementos configurveis de um programa baseado em ARIA (endereo IP do rob, etc) possam ser
transmitidos da mesma forma em qualquer programa ARIA:
ArArgumentParser parser (&argc, argv);
parser.loadDefaultArguments ();
ArArgumentParser::loadDefaultArguments () ir alocar os padres exigidos para se consiga
estabelecer a ligao ao Local Host, isto , ao rob real ou a uma simulao (MobileSim
8
).
Na verdade, para que se estabelea uma ligao ao rob utilizada a classe ArSimpleConnector. Esta
classe pode receber como argumento uma classe ArArgumentParser para inicializar o seu construtor.
ArSimpleConnector connector (&parser);
A ligao ao rob exige um objecto ArRobot, que uma interface para o rob e os seus dispositivos
integrados, gerindo o controlo do rob. Por outras palavras pode entender-se como sendo um rob que
se cria virtualmente com os atributos da classe ArRobot.
ArRobot robot;
8
MobileSim um software para silumao de plataformas mveis MobileRobots/ActivMedia e os seus ambientes.
http://robots.mobilerobots.com/wiki/MobileSim
26
Uma vez estabelecida a ligao, o rob pode ser colocado em modo assncrono, o que garante que, se
a ligao for perdida, o rob vai deixar de operar.
robot.runAsync (true);
Efectuada a ligao, tambm necessrio permitir que os motores do rob possam actuar. Para isso
usa-se o seguinte comando:
robot.enableMotors ();
contudo, antes do rob executar qualquer aco ou operao, deve-se colocar os motores num estado
habilitado e seguro. Isto feito utilizando os mtodos ArRobot::lock() e ArRobot::unlock() na seguinte
ordem;
robot.lock ();
robot.aco a executar;
robot.unlock ();
Relativamente aos comandos utilizados para o controlo do rob, ou seja, para manipular directamente
os motores, usando os mtodos do objecto ArRobot criado (robot), foram os seguintes:
robot.setVel (double vel); Define a velocidade de translao do rob em milmetros/segundo.
robot.setRotVel (double vel); Define a velocidade rotacional do rob em graus/segundo.
robot.stop (); Pra o rob. Define uma velocidade de translao e rotao igual a zero.
Os valores so armazenados e enviados no prximo ciclo do programa.
Quando dada ordem para terminar o programa, pelo utilizador, necessrio enviar comandos para o
rob de modo a interromper e impedir que faa mais processamentos. O comando enviado interrompe
o ciclo de processamento do rob, pois este est a ser executado em modo assncrono:
robot.stopRunning ()
necessrio aguardar que a tarefa que o rob est a executar termine antes de sair do programa, ou
seja, antes de utilizar o mtodo Aria::exit(0) utilizado o seguinte comando:
robot.waitForRunExit ();
Para alm dos comandos e mtodos acima referidos, para utilizao e controlo do rob, foram tambm
usados outros comandos, informativos, da classe ArRobot:
robot.getX (); - Obtm a posio global X do rob;
robot.getY (); - Obtm a posio global Y do rob;
robot.getTh (); - Obtm a posio angular (theta) global do rob;
robot.getVel (); - Obtm a velocidade de translao do rob;
27
robot.getRotVel (); - Obtm a velocidade rotacional do rob;
robot.getBatteryVoltage (); - Obtm a tenso instantnea da bateria.
Em anexo (ANEXO VI), encontra-se disponvel o cdigo fonte onde so usados estes comandos, entre
outros, juntamente com o algoritmo de anlise da imagem adquirida.
4.3 Teste e Resultados
Como descrito no captulo 3, apenas foi testado em ambiente real o mtodo de identificao de uma
via.
Os testes, referentes ao movimento do rob, foram testes realizados de forma a encontrar as
velocidades correctas, de translao e rotao, que o rob deve tomar ao longo do seu percurso.
De acordo com a anlise da imagem adquirida (ver seco 3.3), partindo do principio que o rob est
na posio inicial definida (Regio 1), este inicia o seu percurso com uma velocidade constante de 400
mm/seg (robot.setVel (400)), mantendo sempre essa velocidade durante o percurso efectuado, ou seja,
durante o tempo de execuo.
Segundo o MI1V, assim que o ponto mdio entra na Regio 2, considerado que o rob chega zona
da curva. Foi verificado que a velocidade de rotao necessria para seguir a trajectria correcta era de
8 graus/seg (robot.setRotVel (8)).
Entrando o ponto mdio na Regio 3, o rob encontra-se numa zona crtica da curva, ou seja,
encontra-se na zona em que o raio de curvatura menor (por exemplo, quando se aproxima da zona da
passadeira). Ento, e como o rob mantm a sua velocidade constante, necessita de uma velocidade
rotao superior. Foi definida ento uma velocidade de 30 graus/seg (robot.setRotVel (30)).
Figura 4.3. 1 Regies do movimento do rob.
Todos estes parmetros foram recolhidos de forma a tornar a trajectria do rob o mais estvel
possvel, segundo o mtodo usado. Assim, para velocidades de translao superiores necessrio
velocidades de rotao tambm superiores e vice-versa.
28
5. Concluses e Trabalho futuro
5.1 Concluses
Neste trabalho foi apresentado um mtodo para a calibrao da cmara utilizada no rob. Esse
processo necessrio para que se possa fazer a correspondncia das coordenadas retiradas em pixels
(SCP) com as coordenadas do mundo real (SCM) e vice-versa. A no utilizao da calibrao impede
afirmaes tais como o rob est desviado x metros da via ou o rob encontra-se a uma distncia
de x metros.
No entanto esse processo de calibrao no viria a ser utilizado nos algoritmos de deteco das vias
elaborados, pois o MI1V foi baseado na anlise da imagem atravs das coordenadas em pixels
(posio do ponto mdio) e no na anlise das suas coordenadas reais. O MI2V apenas foi testado com
uso de vdeo.
Em relao utilizao do histograma da imagem este til para a equalizao da imagem quando se
verifica um fraco contraste entre os diferentes objectos e o fundo da imagem. Contudo, neste trabalho
no foi utilizado o histograma da imagem, na parte de processamento, para a elaborao dos mtodos
propostos uma vez que a imagem adquirida era aceitvel em termos de iluminao e contraste.
Relativamente aos dois mtodos apresentados para identificao visual das vias, estes pressupem que
o rob se move sobre um pavimento plano, isento de obstculos e que as vias da estrada onde o rob
se movimenta so predefinidas. Em termos de iluminao do local onde a pista se econtrava, esta era
satisfatria de forma a conseguir um bom contraste na imagem para o seu processamento,
conseguindo-se assim uma boa segmentao na utilizao da funo threshold para posterior uso do
filtro de Canny.
As principais concluses tiradas so:
No mtodo de identificao de uma via:
O algoritmo proposto no se torna muito eficaz no que diz respeito navegao do rob
seguindo uma trajectria totalmente estvel e regular. Pois, segundo o MI1V, o rob opera em
29
somente quatro regies com velocidades rotacionais distintas e pr-definidas, o que faz com
que a trajectria do rob se possa tornar um pouco instvel.
Na fase de anlise da imagem, o algoritmo converte a imagem para tons de cinzentos, aplica a
funo de threshold, aplica o filtro de canny e verifica para todos os pixels do vector da
imagem (frame) em anlise, se branco ou preto, guardando o valor da sua posio caso seja
branco. Apesar do processamento de imagem ser efectuado em toda a matriz de imagem
(320x240), o facto de se estar a analisar somente um nico vector dessa matriz, permite que
este seja um algoritmo rpido, podendo ser executado com velocidades superiores as testadas
na seco 4.3 permitindo uma rpida taxa para aquisio de frames para anlise.
O facto de apenas ser necessrio analisar uma via da estrada torna tambm possvel colocar a
cmara no lado oposto ao estipulado no MI1V, de forma a visualizar a via mais a esquerda, e
executar o percurso no sentido inverso.
No mtodo de identificao de duas vias:
Este algoritmo, em relao ao anteriormente proposto, torna-se mais eficaz uma vez que a fase
de anlise da imagem feita em toda a matriz da imagem. Assim sendo, e passando pela
mesma fase de precessamento da imagem do MI1V (converso para tons de cinzentos, funo
de threshold e o filtro de canny), possvel uma anlise mais pormenorizada utilizando a
transformada de Hough para determinar dos pontos de interesse.
O vdeo utilizado para testes foi simulado assumindo que a cmara se encontra posicionada no
rob de forma a ser possvel visualizar as vias da estrada na frame adquirida (paralela ao
pavimento), pois o algoritmo proposto apenas funciona assumindo que se encontram pontos
nos quatro quadrantes. Ao ser testado o algoritmo proposto em ambiente real verificou-se que
este no era vlido uma vez que no se conseguia visualizar as duas vias devido ao facto de a
cmara estar colocada a uma altura relativamente baixa (sobre o rob).
No MI1V os resultados obtidos relativamente parte de controlo do rob foram satisfatrios, mas com
as suas limitaes.
No entanto, no MI2V, apesar de no serem realizados testes em ambiente real, torna-se mais eficaz,
pois a trajectria do rob ser dada em funo da inclinao da recta final (ngulo) e a distncia (em
mdulo) da mesma em relao ao eixo vertical da imagem. Isto far com que a trajectria do rob se
torne mais estvel.
30
5.2 Trabalho futuro e possveis melhorias
Ao longo do projecto foram encontradas diferentes direes de desenvolvimento e evoluo para o
sistema de identificao visual proposto que seriam interessantes de seguir, mas no poderam ser
tomadas devido aos recursos e ao tempo disponveis no momento.
Com base nos resultados obtidos e continuando o desenvolvimento efectuado, podem ser listadas as
seguintes sugestes para futuros trabalhos e melhorias:
Adaptar o mtodo de identificao de duas vias ao ambiente real utilizando um soporte para a
cmara de forma a tornar possivel visualizar as duas vias, utilizando uma cmara com um
FOV superior (por exemplo a cmara digital PlayStation eye da PlayStation 3).
Utilizar o processo de calibrao para tornar o sistema mais robusto de forma a ser possivel
tomar a correspondencia com o mundo real, utilizando para isso o mtodo de calibrao
proposto por Zhang descrito na seco 2.3.
Por ultimo, possivel ainda realizar diversos melhoramentos na fase de processamento de
imagem com a introduo de filtros para a reduo de rudo que possa existir na imagem e
aprofundar conhecimentos relativamente ao uso da transformada de Hough para a anlise da
imagem.
31
Referncias Bibliogrficas
[1] Bradski, G., Kaebler, A., Learning OpenCV: Computer Vision with OpenCV Library, OReilly,
2008.
[2] Wikipdia, http://pt.wikipedia.org/wiki/Cmara_pinhole, acesso em 20 de Novembro de 2009.
[3] Stroustrup, B., The C++ Programming Language, Second Edition, Addison Wesley Publishing
Company, 1992.
[4] Schildt, H., Teach yourself C++, Second Edition, Osborne McGraw-Hill, 1994.
[5] Gererd, S., C++ math class library, John Wiley & Sons, 1994.
[6] Zhihui, X., Computer Vision, IN-TECH, 2008.
[7] Gaspar, J., Viso para Robtica Mvel: Deteco de Obstculos sobre Pavimento Plano,
Lisboa:[s.n.], 1994.
[8] Azevedo, T., Tavares, J., Vaz, M., Anlise do mtodo de Calibrao de Cmaras Proposto por
Zhang, CLME'2008 - 5 Congresso Luso-Moambicano de Engenharia / 2 Congresso de Engenharia
de Moambique, 2008.
[9] Velho, L. et al, Fotografia 3D, 25 Coloquio Brasileiro de Matemtica IMPA, Rio de Janeiro,
2005.
[10] Cyganek, B., Siebert, J., An Introduction to 3D Computer Vision Techniques and Algorithms,
John Wiley & Sons, 2009.
[11] Hartley, R., Zisserman, A., Multiple View Geometry in Computer Vision, Second Edition,
Cambridge University Press, 2000.
[12] Schmidt, R., Lages, W., Identificao Visual Para Navegao De Robs Mveis Utilizando Um
Controlador Fuzzy Sintonizado Por Otimizao Numrica, Anais do XIII Congresso Brasileiro de
Automtica, CBA 2000, 2000.
[13] Ferriani, V., Ribeiro, C., Deteco de Guias Utilizando Variaes da Transformada de Hough,
Relatrio Final PIBIC/CNPq, Instituto Tecnolgico de Aeronutica, 2005.
32
[14] Pitas, I., Digital image processing algorithms and applications, John Wiley & Sons, 2000.
[15] Ritter, G., Wilson, J., Handbook of computer vision algorithms in image lgebra, CRC Press,
1996.
[16] Karlstroem, A., Estimao de Posio e Quantificao de Erro Utilizando Geometria Equipolar
entre Imagens, So Paulo, 2007.
[17] Stemmer, M. et al, Apostila de sistemas de viso, Florianpolis, 2005.
[18] Sukthankar, R., et al, Panacea: An Active Sensor Controller for the ALVINN Autonomous
Driving System, Carnegie Mellon University, Pittsburgh, 1993.
[19] Aria Reference Manual 1.1.7, http://www-ee.ccny.cuny.edu/www/web/jxiao/P2-Aria-
Reference.pdf, acesso em 20 de Maro de 2010.
[20] MobileRobots - ActiveMedia Robotics., Pioneer 3 Operations Manual with MobileRobots
Exclusive Advanced Robot Control & Operations Software. 2006.
[21] ARIA Overview (HTML), disponvel com a instalao padro de ARIA (ndex.html).
33
ANEXOS
ANEXO I: Instalao do OpenCV no OpenSUSE 11.0
A instalao do OpenCV foi, numa primeira fase, efectuada atravs de pacotes, pois existe um
repositrio (Packman) que inclui a biblioteca OpenCV evitando assim a importao da mesma atravs
de comandos.
Foi ento realizada do seguinte modo:
- Atravs do instalador de software do OpenSUSE foram adicionados os repositrios Packman
repository que contem a biblioteca OpenCV e VideoLan repository que contem os codec's
necessrios para imagem e vdeo, entre os quais o ffmpeg;
- Antes da importao do OpenCV foi necessrio descarregar e instalar os seguintes pacotes:
cmake, gcc-c++, ffmpeg e GTK +2.x;
- Foram ento importados os pacotes do OpenCV contidos no repositrio Packman: opencv,
libopencv2, opencv-debuginfo, opencv-devel e python-opencv (facultativo).
34
ANEXO II: Tutorial de instalao do OpenSUSE 11.3 no Pioneer P3-DX
A utilizao deste tutorial pressupe que exista uma ligao a internet para instalao do OpenSUSE,
assim como uma drive de CDs para uso do software de backup e um disco rgido para o respectivo
armazenamento.
1. Material extra necessrio para instalao:
- Drive CDs:
utilizada para que se possa efectuar o backup do risco rgido do rob utilizando o
software de bakup System Rescue Cd prviamente gravado em cd;
- Disco rgido auxiliar:
utilizado para armazenar a cpia integral do disco rgido do rob;
- Fonte de alimentao PC:
necessria para que se consiga ligar os dispositivos acima referidos alimentao.
2. Instalao dos componentes
2.1 - Drive CDs e disco rgido
Aps a remoo das tampas do rob, conecta-se na slot disponivel o cabo IDE (Fig.A2.1.1a) para
ligar a drive de CDs e utiliza-se o cabo IDE j existente (de cor creme) para a ligao do disco rigido
para backup (Fig.A2.1.1b).
a) b)
Figura A2.1. 1 - a) Coneco do cabo IDE; b) Ligao dos dispositivos.
35
2.2 - Fonte de alimentao
Aps conectados os dispositivos vamos lig-los fonte de alimentao. Uma vez que esta para
funcionar precisa de estar ligada a uma placa-me foi necesrio fazer um curto-circuito entre dois
terminais do conector (Fig.A2.2.1).
Figura A2.2. 1 Conector da fonte de alimentao.
A seguinte figura ilustra a montagem completa dos dispositivos utilizados.
Figura A2.2. 2 Montagem completa
3. Backup do disco
Para efecuar a cpia integral do disco rgido do rob, foi utilizado o system rescue cd (disponvel em
http://www.sysresccd.org/Download) que uma ferramenta para recuperao do sistema em Linux.
Foi ento efectuada a gravao da imagem (ISO) disponibilizada num CD .
Insere-se o CD antes de iniciar o computador para se poder fazer boot do CD, precionando F2 para
tal.
36
O system rescue cd inclui vrias ferramentas para o sistema, das quais se utilizou a que nos permite
fazer uma cpia de um disco rgido para outro. Para isso bastou introduzir o seguinte comando
(Fig.A2.3.1):
> ddrescue -v /dev/sda /dev/sdb
Nota: necessrio confirmar qual o disco a copiar e para onde se vai copiar sendo este
preferencialmente do mesmo tamanho do disco rgido a copiar.
Figura A2.3. 1 Ambiente grfico do system rescue cd.
4. Instalao do OpenSUSE
Efectuar o download de openSUSE-11.3-NET-i586 que se encontra disponvel em
http://download.opensuse.org/distribution/11.3/iso/ para realizar a instalao via internet, pois para
uma boa ligao torna-se mais rpido. Gravar ento a imagem (ISO) para um cd e fazer boot a partir
do mesmo.
Antes de iniciar a instalao mudar a resoluo de ecr para a resoluo que se pretende usar de futuro
(Fig.A2.4.1a) e de seguida iniciar instalao (Fig.A2.4.1b).
Nota: Caso no consiga efectuar a ligao ao servidor pressionar F4 para alterar a fonte.
37
a) b)
Figura A2.4. 1 a) Resoluo de ecr; b) Incio de instalao
Iniciada ento a instalao no esquecer de alterar o teclado para Portugus, deixando o idioma em
Ingls.
No menu seguinte selecionar nova instalao e no usar a configurao automtica.
Figura A2.4. 2 Modo de instalao.
No separador Desktop Selection selecionar o ambiente grfico LXDE (Lightweight X11 Desktop
Environment), pois um ambiente de trabalho que consome menos recursos que o KDE ou GNOME
(Fig.A2.4.3).
38
Figura A2.4. 3 Seleo do ambiente de trabalho.
No separador seguinte ,Disk, selecionar Edit Partition Setup... (Fig.A2.4.4a) para verificar os
discos (Fig.A2.4.4b).
Deveram ser apresentados os seguintes valores:
Device Size FS Type Start End
/dev/sda1 736 Mb Swap 0 2943
/dev/sda2 5.0 Gb Ext4 2944 23423
/dev/sda3 1.91 Gb Ext4 23424 31261
Tabela A2. 1 Detalhes dos discos rgidos.
a) b)
Figura A2.4. 4 a) Editar parties; b) Detalhe do disco.
39
Seguidamente criar novo usurio como ilustrado na figura seguinte (password: linux):
Figura A2.4. 5 Novo utilizador
No separador Instalation Overview selecionar Change e de seguida Booting. Selecionar Boot
Loader Options (Fig.A2.4.6a) para alterar o campo Timeout in Seconds para 3 (Fig.A2.4.6b).
a) b)
Figura A2.4. 6 a) Boot loader settings; b) Boot loader Options.
Seguidamente, no mesmo separador anteriormente referido, selecionar Change e depois Software.
Nesse menu selecionar Details para instalar algum software necessrio (Fig.A2.4.7). Selecionando
ento a opo search (Fig.A2.4.8) instalamos os seguintes pacotes:
- Kdevelop;
- Opencv e opencv-devel;
- cmake;
- gcc++;
- C/C++ Development.
40
Figura A2.4. 7 Seleo de software.
Figura A2.4. 8 Instalao dos pacotes e final da instalao.
Assim terminada a procura do software desejado carregar em accept e de seguida em continue.
Continuando no separador anteriormente referido, selecionar agora Firewall and SSH para dar
permisso ao porto SSH e servio SSH (Fig.A2.4.9).
Figura A2.4. 9 Configurao do servio SSH.
41
Inicia-se ento a instalao.
Figura A2.4. 10 Instalao do software.
Aps a instalao segue-se as configuraes.
No separador Hostname prenche-se os campos como ilustrado na figura seguinte, no esquecendo
de retirar o visto em Change Hostname via DHCP.
Figura A2.4. 11 Hostname e domnio.
No separador seguinte, Network, correr o teste de coneco internet (Fig.A2.4.12).
a) b)
Figura A2.4. 12 a) Teste de coneco; b) Fim de teste.
42
No prximo separador selecionar Run Update (Fig.A2.4.13) finalizando assim a instalao do
OpenSUSE 11.3 (Fig.A2.4.14).
a) b)
Figura A2.4. 13 a) Online Update; b) Download e instalao.
Figura A2.4. 14 Fim da instalao do OpenSUSE.
43
ANEXO III: threshold.c
/*para executar na consola:
>> ./threshold <valor> <maximo valor>
*/
#include "cv.h"
#include "highgui.h"
#include <stdio.h> //Funcoes de linguagem c
#include <stdlib.h> //Funcoes de linguagem c
int main( int argc, char** argv )
{
int i = 1;
int x = atoi(argv[1]); //Valor de threshold
int y = atoi(argv[2]); //Maximo valor
cvNamedWindow ("Video", 0);
CvCapture* capture = cvCreateCameraCapture (0);
if(!capture){
return -1;
}
printf("\n\"ESC\" - Sair\n");
while(1){
IplImage* frame = cvQueryFrame (capture);
if (!frame) break;
IplImage* img_gray = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
cvCvtColor( frame, img_gray, CV_BGR2GRAY );
// cvCvtColor( ) converte imagem a cores para escala de cinzentos
cvThreshold( img_gray, img_gray, x, y, CV_THRESH_BINARY );
// aplicacao da funcao threshold com tipo de threshold binario, ou seja,
// imagem destino = (imagem origem >Threshold ) ?Valor mximo : 0
cvShowImage("Video", img_gray );
char c = cvWaitKey (33);
i++;
if(c==27) break; //(esc - ascii)
}
cvReleaseCapture ( &capture);
cvDestroyWindow( "Video");
return 0;
}
44
Resultados:
a) b)
Figura A3. 1 a) Valor de Threshold 80. Iluminao natural; b) iluminao direccionada.
a) b)
Figura A3. 2 a) Valor de Threshold 150. Iluminao natural; b) iluminao direccionada.
45
ANEXO IV: threshist.c
/*para executar na consola:
>> ./threshist
*/
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <stdlib.h>
#define min(a,b) ( (a)<(b) ? (a) : (b) ) //define mimino de dois valores
#define max(a,b) ( (a)>(b) ? (a) : (b) ) //define maximo de dois valores
//Funcao para encontrar o valor medio das areas de intensidades inferiores e superiores ao valor de threshold
double segment_img(IplImage * img, double T) {
CvScalar z;
unsigned int coluna = img->width;
unsigned int linha = img->height;
unsigned int i, j;
double g1=0, g2=0, valor=0;
int counterg1 = 0, counterg2 = 0;
for (i = 0; i < coluna; i++)
for (j = 0; j < linha; j++) {
z = cvGet2D( img, j, i);
valor = z.val[0];
if (valor >= T ) {
g1 += valor;
counterg1++;
} else {
g2 += valor;
counterg2++;
}
}
return ( (g1/counterg1) + (g2/counterg2));
}
// Funcao para implementacao de threshold dimanico
double thresh_dinamico(IplImage * img) {
CvScalar z;
double minimo, maximo, thresh, thresh_next;
unsigned int coluna = img->width;
unsigned int linha = img->height;
unsigned int i, j;
double done = 0;
z = cvGet2D( img, 0, 0 );
minimo = maximo = z.val[0];
for ( i = 0; i < coluna; i++ )
for ( j = 0; j < linha; j++ ) {
z = cvGet2D( img, j, i);
minimo = min(minimo,z.val[0]);
maximo = max(maximo,z.val[0]);
}
thresh = 0.5*(minimo+maximo);
46
while (!done) {
thresh_next = 0.5*segment_img(img, thresh);
// encontra valor do proximo threshold
done = abs(thresh_next - thresh) < 0.5;
thresh = thresh_next;
}
return thresh;
}
int main( int argc, char** argv )
{
int i, j;
int hdims = 256;
float hranges_arr[] = {0,255};
float* hranges = hranges_arr;
int bin_w = 1;
float maximo_val, minimo_val;
char c;
double val, t;
cvNamedWindow ("Video Gray", 0);
cvNamedWindow ("Video Binary", 0);
cvNamedWindow ("Histogram", 0 );
CvCapture* capture = cvCreateCameraCapture (0);
if(!capture){
printf("\nNo Capture\n\n");
return -1;
}
printf("\n\"ESC\" - Sair\n\n");
IplImage* frame;
IplImage* img_gray;
IplImage* img_bin;
IplImage *histimg = cvCreateImage( cvSize(256,300), 8, 1 ); // 8-bit/ 1 canal por pixel
CvHistogram *hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 );
// Histograma com 1 dimensao do tipo array
CvScalar cor = CV_RGB(255,255,255); // Cor branca
while(1){
frame = cvQueryFrame (capture);
if (!frame) break;
img_gray = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
img_bin = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
cvCvtColor( frame, img_gray, CV_BGR2GRAY );
cvZero( histimg );
//coloca elementos do vector a 0
cvCalcHist( &img_gray, hist, 0, 0 );
// calcula histograma
cvNormalizeHist( hist, 1.0);
// Normaliza o histograma
cvGetMinMaxHistValue( hist, &minimo_val, &maximo_val, 0, 0 );
// encontra indices e valores de minimo e mximo dos bins do histograma
cvConvertScale( hist->bins, hist->bins, maximo_val ? 255. / maximo_val : 0., 0 );
47
bin_w = histimg->width / 256;
for( i = 0; i <256; i++ )
{
cvGetMinMaxHistValue( hist, &minimo_val, &maximo_val, 0, 0 );
// encontra indices e valores de minimo e mximo dos bins do histograma
val = ( cvGetReal1D(hist->bins,i)*histimg->height/maximo_val );
cvRectangle( histimg, cvPoint(i*bin_w,histimg->height), cvPoint((i+1)*bin_w,(int)(histimg->height -
val)),cor, CV_FILLED, 1, 0 );
// desenha as barras do histograma
}//End For
t = thresh_dinamico( img_gray );
cvThreshold( img_gray, img_bin, t, 255, CV_THRESH_BINARY );
cvShowImage("Video Gray", img_gray );
cvShowImage("Video Binary", img_bin );
cvShowImage("Histogram", histimg );
c = cvWaitKey (300);
if(c==27) break; //("esc" - ascii)
}//End While
cvReleaseImage( &img_gray );
cvReleaseImage( &img_bin );
cvReleaseImage( &histimg );
cvReleaseHist ( &hist );
cvReleaseCapture ( &capture);
cvDestroyWindow("Video Gray");
cvDestroyWindow("Video Binary");
cvDestroyWindow("Histogram");
return 0;
}//End Main
48
Resultados:
Figura A4. 1 Valor de Threshold dinmico com fraca iluminao.
Figura A4. 2 Valor de Threshold dinmico com pouca iluminao.
Figura A4. 3 Valor de Threshold dinmico com iluminao.
49
ANEXO V: Resultado da calibrao
Com a realizao da calibrao, utilizando um padro de calibrao com 6 vertices por 8, e com uma
distncia entre eles de 2,9 centimetros, obteve-se o seguinte resultado (neste resultado retira-se os
parmetros descritos nas seces 2.2 e 2.3):
%YAML:1.0
calibration_time: "Qui 17 Dez 2009 11:25:02 WET"
//Numero de imagens retiradas para o processo de calibrao
image_count: 5
//Dimenso da frame capturada
image_width: 160
image_height: 120
//Quantidade de vertices retirados na posio vertical e horizontal
board_width: 6
board_height: 8
// Distncia entre vrtices
square_size: 2.9000000953674316
flags: 0
//Obteno da matriz dos parmetros intrnsecos
camera_matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
//Parmetros intrnsecos
data: [ 151.0492228021207950, 0., 76.3822088193910531, 0.,
151.6216972139991128, 63.5509310734817063, 0., 0., 1. ]
//Obteno dos queficientes de distoro
distortion_coefficients: !!opencv-matrix
rows: 1
cols: 4
dt: d
data: [ -0.5956224170132687, 1.7481555940003135, 0.0117369012853710,
-1.4485431200574083e-03 ]
avg_reprojection_error: 1.6073610504468283
per_view_reprojection_errors: !!opencv-matrix
rows: 1
cols: 5
dt: d
data: [ 0.5391962528228760, 0.6057443618774414, 2.9254736900329590,
3.2581842343012490, 0.7082067131996155 ]
//Obteno dos parmetros extrnsecos (vector rotao e translao) para as 5 frames capturadas
extrinsic_parameters: !!opencv-matrix
rows: 5
cols: 6
dt: f
data: [ 3.10622907, -0.01103038, 0.12557971, -11.16460800, 5.12553787,
29.78573227, -0.02031964, -2.98973441, 0.06476486, 10.66071224,
-8.60595989, 28.92044067, -1.31164584e-03, 2.75725102,
-0.08050375, 9.69400787, -7.44153547, 33.55916977, 0.02832068,
3.04689837, -0.48824352, 10.58997154, -8.64666080, 32.26971054,
50
7.90356286e-03, 3.01666689, 0.37365636, 11.44549847, -9.04483604,
27.86407089 ]
//Descrio dos cantos (vertices) encontrados e usados para a calibrao
image_points: !!opencv-matrix
rows: 1
cols: 240
dt: "2f"
data: [ 21.57544327, 88.69639587, 22.15519142, 74.46207428,
22.39159966, 60.28555298, 22.52618217, 46.41658020, 22.82502556,
32.68410492, 23.23790741, 19.34250450, 36.31382751, 88.61573792,
36.38088989, 74.31353760, 36.49544907, 60.30868912, 36.55658722,
46.46142197, 36.67848969, 32.77919388, 36.95088959, 19.49452400,
50.42252350, 88.39981842, 50.52153397, 74.27995300, 50.47317886,
60.23228455, 50.51266098, 46.47121429, 50.49483871, 32.88315201,
50.54012299, 19.60214233, 64.51478577, 88.30674744, 64.44929504,
74.16114807, 64.44934845, 60.27708054, 64.34678650, 46.53518677,
64.38710785, 33.18721008, 64.18010712, 19.82207680, 78.39717865,
87.99214172, 78.28274536, 74.10897064, 77.83798981, 60.31797409,
77.67213440, 46.59974670, 77.51657104, 33.31914902, 77.48420715,
20.19950294, 92.14296722, 87.72351837, 91.57469177, 73.78565216,
91.47539520, 60.19674683, 91.21553802, 46.60754395, 90.82509613,
33.38061905, 90.51510620, 20.44246864, 105.52169800, 87.49132538,
105.24569702, 73.65924072, 104.59204865, 60.18839264,
104.47409058, 46.62934875, 103.90460968, 33.51981735,
103.63291168, 20.50703049, 118.98424530, 87.33956909,
118.39765930, 73.43827057, 117.77340698, 60.11244583,
117.47349548, 46.64938354, 116.96466064, 33.50217819,
116.55567932, 20.56713867, 128.97341919, 20.63063622,
129.54745483, 34.81664658, 129.89497375, 49.37603378,
130.50497437, 64.04695129, 130.75572205, 78.75939941,
131.46612549, 93.92960358, 114.53469849, 21.56669235,
114.76762390, 35.59261322, 115.41342926, 49.75924683,
115.53320312, 64.34811401, 115.83535767, 78.97812653,
116.29739380, 93.76979065, 100.37824249, 22.45384598,
100.61418915, 36.26230621, 100.70864105, 50.27769852,
101.16661072, 64.53940582, 101.34725952, 79.12358856,
101.53197479, 93.77306366, 86.47757721, 23.26000977, 86.59488678,
36.74244690, 86.67273712, 50.70153809, 86.80688477, 64.79064178,
87.03342438, 79.30004120, 87.05692291, 93.64757538, 72.94007874,
23.89997673, 73.11211395, 37.45384979, 73.09389496, 51.18316269,
73.14536285, 65.14435577, 73.04280090, 79.25325775, 72.93585205,
93.61742401, 59.58543015, 24.59176064, 59.58527756, 37.99052429,
59.56602478, 51.52066040, 59.45576859, 65.27154541, 59.46320724,
79.34270477, 59.29814911, 93.45883942, 47.09764862, 25.54775620,
46.73960876, 38.58440399, 46.35845566, 52.01308823, 46.43052292,
65.52270508, 46.13978958, 79.31656647, 45.74983215, 93.39044189,
33.44626236, 26.12700462, 34.60275650, 39.13238144, 32.48576355,
52.54501343, 33.44001389, 65.61412048, 33.33335495, 79.38373566,
32.61592484, 93.20008850, 112.59777069, 29.54019547, 112.49952698,
42.68335342, 112.56754303, 56.19777298, 112.69506073, 69.52129364,
114.17683411, 83.05636597, 114.54431915, 96.45102692,
112.57182312, 29.54278946, 111.97738647, 42.67565536,
112.07843018, 56.19239426, 112.67853546, 69.52107239,
113.97323608, 83.08310699, 114.45905304, 96.45565796,
101.50469971, 28.71349335, 101.70684814, 42.25146866,
101.34065247, 55.64062881, 101.43914032, 69.48872375,
101.57118225, 83.29402161, 102.33778381, 97.41148376, 83.25320435,
27.17176247, 83.00867462, 41.10808563, 83.14065552, 55.24765015,
83.12245941, 69.53244019, 89.46458435, 83.74886322, 83.43579865,
98.44480896, 69.94771576, 26.01169205, 69.90672302, 40.28789139,
69.73117065, 54.76144791, 69.84693146, 69.43109894, 69.86881256,
51
84.30506134, 70.06008911, 99.24869537, 56.33437729, 24.67664146,
56.03504562, 39.45328903, 55.91140366, 54.34410477, 55.79745865,
69.38834381, 55.85448456, 84.57382965, 55.66686249, 99.96847534,
41.48801041, 23.52204514, 41.46690369, 38.59434509, 41.28130722,
53.83922958, 41.18746948, 69.33825684, 40.89011383, 84.93253326,
40.79147720, 100.76219177, 26.28728676, 22.30418396, 25.80389786,
37.71573257, 25.57279587, 53.43766785, 25.44425583, 69.30434418,
25.38778496, 85.36746979, 24.81701469, 101.55191803, 125.29216003,
31.73820686, 125.24403381, 31.76114655, 126.24182892, 43.33575821,
128.95359802, 63.06774139, 130.88290405, 76.56555176,
133.23722839, 90.88146210, 117.65735626, 31.17439461,
111.80989075, 31.58822060, 112.76120758, 44.53160095,
114.95459747, 63.40968704, 116.64216614, 76.94346619,
118.37249756, 91.36541748, 98.14555359, 31.61387062, 98.13254547,
31.72469330, 99.39671326, 44.95730591, 100.93962097, 63.53279114,
102.18391418, 77.34306335, 103.51257324, 91.71222687, 84.88834381,
31.92614937, 84.91272736, 32.20766830, 85.55043793, 44.21051025,
86.66693115, 63.79961777, 87.59384918, 77.63649750, 88.43180084,
92.20967102, 71.46580505, 31.84549713, 71.46897888, 32.15230179,
71.94979095, 43.76610184, 72.51799774, 63.89209747, 72.76409912,
77.71138763, 73.42046356, 92.49967194, 58.16894150, 24.47778130,
58.05164719, 31.86977768, 57.90837860, 43.76971817, 57.91298676,
63.95322800, 57.98184967, 77.92593384, 57.80279160, 92.63882446,
44.41322327, 26.55235291, 44.41606522, 32.24102783, 43.65969467,
50.91077423, 43.41028976, 64.22763824, 42.84105682, 78.21077728,
42.50139999, 93.08811951, 31.42263222, 23.86544228, 30.58331871,
32.65800476, 29.47257423, 50.89335632, 28.55002022, 64.25836182,
27.74249458, 78.38512421, 26.69224930, 93.32386780, 135.40890503,
17.22026062, 134.02426147, 31.98043633, 132.59872437, 46.46612167,
131.40174866, 60.39638901, 130.07778931, 73.76789093,
129.20297241, 86.96225739, 121.13961029, 16.85395813,
119.76466370, 31.94252014, 118.81401062, 46.48900604,
117.62567139, 60.57686234, 116.74936676, 74.30053711,
115.77299500, 87.52222443, 106.35582733, 16.69334984,
105.56030273, 31.79231644, 104.60562897, 46.57885361,
103.83800507, 60.74651337, 103.16106415, 74.63589478,
102.47494507, 88.16284943, 91.51708984, 16.57758331, 90.78408813,
31.84788132, 90.42549896, 46.69573975, 89.61204529, 61.26783371,
89.36799622, 75.16734314, 88.67022705, 88.59865570, 76.36830902,
16.44038773, 76.03401184, 31.88538551, 75.59289551, 46.95421982,
75.46169281, 61.50686646, 75.27768707, 75.56385803, 74.82732391,
89.34141541, 60.63705444, 16.31904793, 60.60562134, 31.93997765,
60.61705780, 47.20875549, 60.57909775, 61.71610641, 60.67253494,
76.14163208, 60.57510757, 89.76140594, 44.79751968, 16.15568733,
45.30832672, 32.01316071, 45.41616821, 47.35488892, 45.63619232,
62.18765259, 45.94222641, 76.50252533, 46.38366699, 90.46402740,
28.64701080, 16.02121925, 29.39186478, 32.04727554, 29.80850410,
47.56336975, 30.40970802, 62.52282715, 31.03952599, 77.00220490,
31.44651413, 90.97264099 ]
52
ANEXO VI: Mtodo de identificao de uma via
- Fluxograma
INCIO
MI1V
Conecta Rob
Cmara
Detectada?
SIM
NO
FIM
MI1V
Captura Frame
Aplicao da
funo Threshold
Visualizao do
Histograma
Aplicao da
Transformada de
Canny
Convero para a
escala de
cinzentos
Nr. Pixeis
brancos>10?
Actua Rob
Rotao negativa
(Esquerda)
PM < 20
Segue em frente
Rotao positiva
(Direita)
150 < PM < 170
PM > 310
Disconecta Rob
NO
NO
MI1V - Mtodo de identificao de uma via
PM - Ponto mdio retirado da anlise da imagem
PM <= 0
ou
PM >= 320?
SIM
SIM
Fluxograma 1 Mtodo de identificao de uma via
53
- Cdigo
// Exemplo da linha de comandos (para copy-n-paste):
// ./main -b [<Block_size>] -o [<Offset>] [<video.avi>]
// -b <Block_size> # Block_size cvAdaptiveThreshold
// -o <Offset> # Offset cvAdaptiveThreshold
#ifdef _CH_
#pragma package <opencv>
#endif
//Bibliotecas utilizadas
#ifndef _EiC
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include "Aria.h"
#endif
#define WIDTH 320
#define HEIGTH 240
#define MYSPEED 400
//400
#define MYROTVEL1 8
//8 - velocidade rotacao padrao na curva
#define MYROTVEL2 30
//30 velocidade rotacao padrao na zona critica da curva
enum { DETECT = 0, CAPTURA = 1, VIDEO = 2 };
//Funcao para processamento e analiseda imagem
int analisaimagem ( IplImage *org, int bl/*block size*/, int os/*offset*/)
{
int i;
CvScalar sup;
int aux_sup = 0;
int val = 0;
int ct2 = 0;
IplImage *gray = cvCreateImage ( cvGetSize ( org ), IPL_DEPTH_8U, 1 );
IplImage *bin = cvCreateImage ( cvGetSize ( org ), IPL_DEPTH_8U, 1 );
IplImage *view = cvCreateImage ( cvGetSize ( org ), IPL_DEPTH_8U, 3 );
IplImage *view_canny = cvCreateImage ( cvGetSize ( org ), IPL_DEPTH_8U,
1 );
cvCvtColor ( org, gray, CV_RGB2GRAY );
cvAdaptiveThreshold ( gray, bin, 255, CV_ADAPTIVE_THRESH_MEAN_C,
CV_THRESH_BINARY_INV, bl, os );
cvShowImage ("Adaptive Threshold", bin);
cvZero( view );
54
cvZero( view_canny );
cvCanny ( bin, view_canny, 150, 50, 3/*angulo_abertura */);
cvShowImage ("Canny", view_canny);
//cvSmooth (r_bin, r_bin, CV_GAUSSIAN, 9, 9);
//cvErode (r_bin, r_bin, NULL, 1);
//cvDilate (r_bin, r_bin, NULL, 1);
//cvMerge( l_bin, r_bin, NULL, NULL, view);
//cvMax (l_bin, r_bin, view);
cvLine ( view, cvPoint ( 0, view->height/2 ), cvPoint ( view->width,
view->height/2 ), CV_RGB ( 0,255,255 ), 1, CV_AA, 0 );
//Analise do vector superior da imagem para encontrar os pontos brancos
de referencia
for (i = 0; i<view_canny->width ; i++)
{
sup = cvGet2D ( view_canny, 0, i);
if ( sup.val[0] == 255 ) //cor branca
{
cvCircle ( view ,cvPoint ( i , 0 ),2,CV_RGB ( 255,255,255 ),1,4,0
);
aux_sup += i;
//printf("%d\n", aux_sup);
ct2++;
}
}
printf("Contador = %d\n", ct2);
if ( ct2 != 0 && ct2<10)
{
val = aux_sup/(ct2);
cvCircle ( view ,cvPoint ( val , 0 ),2,CV_RGB ( 0,255,255 ),1,4,0
);
aux_sup = 0;
ct2 = 0;
}
else
{
val = 0;
return 0;
}
//Condicao para o caso em que seja detectada a passadeira
if ( ct2 >= 10 )
{
val = 0;
printf("Mais de 10 pontos\n");
}
//Condicao para o caso em que o ponto medio se encontra fora da imagem
if ( val >= WIDTH || val <= 0 )
{
val = 0;
printf("Ponto fora da imagem\n");
}
55
//cvLine ( view, cvPoint ( val_sup, 0 ), cvPoint ( val_inf, view-
>height-1 ), CV_RGB ( 0,255,0 ), 1, CV_AA, 0 );
cvLine ( view, cvPoint ( val, 0 ), cvPoint ( view->width/2, view-
>height/2 ), CV_RGB ( 0,255,0 ), 1, CV_AA, 0 );
printf("Valor = %d\n", val);
//printf("Val Inf = %d\n", val_inf);
cvShowImage ( "Gray Image", gray );
cvShowImage ("Anlise", view);
//Liberta memoria reservada para as imagens
cvReleaseImage ( &view );
cvReleaseImage ( &gray );
cvReleaseImage ( &bin );
cvReleaseImage ( &view_canny );
//retorna o valor da posicao do ponto medio
return val;
}
/*MAIN*/
int main ( int argc, char** argv )
{
CvCapture *capture;
IplImage *frame = 0, *view_org = 0;
char c;
int i;
int modo = DETECT;
int block_size = 3;
double offset = 5;
int val_sup = 0;
int show_hist = 0;
Aria::init();
ArRobot robot;
ArArgumentParser parser(&argc, argv);
parser.loadDefaultArguments();
ArLog::log(ArLog::Terse, "AVISO: este programa nao detecta obstaculos!
Confirme que o robo tem aproximadamente 3 metros de espaco livre em todos
os lados.");
ArSimpleConnector connector(&parser);
//Verifica a coneccao ao robo
if(!connector.connectRobot(&robot))
{
ArLog::log(ArLog::Terse, "Nao conectado ao robo.");
if(parser.checkHelpAndWarnUnparsed())
{
Aria::logOptions();
56
Aria::exit(1);
}
}
if (!Aria::parseArgs())
{
Aria::logOptions();
Aria::shutdown();
return 1;
}
ArLog::log(ArLog::Normal, "simpleMotionCommands: Connected.");
//Inicia o robo em modo assincrono
robot.runAsync(true);
//Desabilita os sonares
robot.disableSonar();
robot.lock();
ArLog::log(ArLog::Normal, "Informacao inicial: Pose=(%.2f,%.2f,%.2f),
Trans. Vel=%.2f, Rot. Vel=%.2f, Bateria=%.2fV",
robot.getX(), robot.getY(), robot.getTh(), robot.getVel(),
robot.getRotVel(), robot.getBatteryVoltage());
robot.unlock();
time_t t;
time ( &t );
printf ( "\n%s", ctime ( &t ) );
for ( i = 1; i < argc; i++ )
{
const char* s = argv[i];
if ( strcmp ( s, "--help" ) == 0 )
{
printf ( "Exemplo da linha de comandos:\n"
"./main -b [<Block_size>] -o [<Offset>]
[<video.avi>]\n\n"
"\t-b <Block_size>\t# Block_size
cvAdaptiveThreshold\n"
"\t-o <Offset>\t# Offset cvAdaptiveThreshold\n\n" );
return 0;
}
if ( strcmp ( s, "-b" ) == 0 )
{
block_size = atoi ( argv[++i] );
//printf("Block size = %d\n", block_size);
}
else if ( strcmp ( s, "-o" ) == 0 )
{
offset = atoi ( argv[++i] );
//printf("Offset = %.f\n", offset);
}
}
capture = cvCreateCameraCapture ( 0 );
cvSetCaptureProperty ( capture, CV_CAP_PROP_FRAME_WIDTH,WIDTH );
cvSetCaptureProperty ( capture, CV_CAP_PROP_FRAME_HEIGHT,HEIGTH );
printf ( "\nMODO CAPTURA\n" );
57
modo = CAPTURA;
if ( !capture ) //se nao for carregado nada o programa e terminado
{
printf ( "Falha na captura da camara\n" );
return -1;
}
//Menu
printf ( "\nOpcoes: \n"
"\tESC - Sair do Programa\n"
"\th - Mostra/Esconde Histograma\n"
"\tp - Pause\n" );
printf ( "\n\t(Press any key to start)\n" );
//Captura frame
frame = cvQueryFrame ( capture );
cvNamedWindow ( "Original", CV_WINDOW_AUTOSIZE );
cvShowImage ( "Original", frame );
c = cvWaitKey ( 0 );
val_sup = analisaimagem (frame, block_size, offset);
//cvNamedWindow ( "Imagem Original", CV_WINDOW_AUTOSIZE );
cvNamedWindow ( "Gray Image", CV_WINDOW_AUTOSIZE );
cvNamedWindow ( "Adaptive Threshold", CV_WINDOW_AUTOSIZE );
cvNamedWindow ( "Anlise", CV_WINDOW_AUTOSIZE );
cvNamedWindow ( "Canny", CV_WINDOW_AUTOSIZE );
//Habilita o funcionamento dos motores
robot.enableMotors();
//while ( 1 )
for (;;)
{
if ( capture )
{
frame = 0;
frame = cvQueryFrame ( capture );// captura da frame
view_org = cvCreateImage ( cvGetSize ( frame ), IPL_DEPTH_8U,
frame->nChannels );
if ( frame->origin == IPL_ORIGIN_BL )
cvFlip ( frame, view_org, 0 );
else
cvCopy ( frame, view_org, 0 );
}
switch ( c )
{
case 'h':
show_hist ^= 1;
58
if ( !show_hist )
{
cvDestroyWindow ( "Histograma" );
}
else
{
cvNamedWindow ( "Histograma", 1 );
}
break;
case 'p':
robot.lock();
robot.stop();
robot.unlock();
printf ( "\nPause\n" );
printf ( "\t(Pressione qualquer tecla para continuar)\n" );
c = cvWaitKey ( 0 );
printf ( "\nContinua\n" );
break;
default:
;
}
if ( show_hist )
{
int i;
int hdims = 256;
float hranges_arr[] = {0,255};
float* hranges = hranges_arr;
int bin_w = 1;
float maximo_val, minimo_val;
int val;
IplImage *histimg = cvCreateImage ( cvSize ( 256,300 ), 8, 1 );
//8-bit/ 1 canal por pixel
IplImage *view_gray = cvCreateImage ( cvGetSize ( view_org ), 8,
1 );
CvHistogram *hist = cvCreateHist ( 1, &hdims, CV_HIST_ARRAY,
&hranges, 1 ); //1 dimenso
CvScalar cor = CV_RGB ( 255,255,255 ); //white
cvCvtColor ( view_org, view_gray, CV_BGR2GRAY );
cvZero ( histimg );//coloca elementos do vector a 0
cvCalcHist ( &view_gray, hist, 0, 0 );
cvNormalizeHist ( hist, 1.0 );//Normalizes histogram by dividing
all bins by sum of the bins, multiplied by <factor>.
//After that sum of histogram bins is equal to <factor>
cvGetMinMaxHistValue ( hist, &minimo_val, &maximo_val, 0, 0 ); //
encontra indices e valores de minimo e mximo dos bins do histograma
cvConvertScale ( hist->bins, hist->bins, maximo_val ? 255. /
maximo_val : 0., 0 );
bin_w = histimg->width / 256;
for ( i = 0; i <256; i++ )
59
{
cvGetMinMaxHistValue ( hist, &minimo_val, &maximo_val, 0, 0 );
// encontra indices e valores de minimo e mximo dos bins do histograma
val = ( cvGetReal1D ( hist->bins,i ) *histimg-
>height/maximo_val );
cvRectangle ( histimg, cvPoint ( i*bin_w,histimg->height ),
cvPoint ( ( i+1 ) *bin_w, ( int ) ( histimg->height - val ) ),cor,
CV_FILLED, 1, 0 );
}//End For
cvShowImage ( "Histograma", histimg );
cvReleaseImage ( &histimg );
}
//Determinacao dos parametros para controlo do robo
val_sup = analisaimagem (view_org, block_size, offset);
printf("val_sup = %d\n", val_sup);
//Controlo do robo
if ( val_sup >= 150 && val_sup <= 170)
{
// Atribui uma velocidade de 400 mm/seg
ArLog::log(ArLog::Normal, "Comando: Segue em frente a 400 mm/s");
robot.lock();
robot.setVel( MYSPEED );
robot.unlock();
}
else
{
//Regiao 2
if (val_sup > 170 && val_sup <= 270)
{
ArLog::log(ArLog::Normal, "Comando: Ajuste negativo");
robot.lock();
robot.setRotVel( -MYROTVEL1 );
//robot.setHeading(-1);
robot.setVel( MYSPEED );
robot.unlock();
}
//Regiao 2
if (val_sup < 150 && val_sup >= 50)
{
ArLog::log(ArLog::Normal, "Comando: Ajuste positivo");
robot.lock();
robot.setRotVel( MYROTVEL1 );
//robot.setHeading(1);
robot.setVel( MYSPEED );
robot.unlock();
}
//Regiao 3
if (val_sup > 270 && val_sup < WIDTH)
{
ArLog::log(ArLog::Normal, "Comando: ajuste critico
negativo");
robot.lock();
robot.setRotVel( -MYROTVEL2 );
//robot.setHeading(-30);
robot.setVel( MYSPEED );
robot.unlock();
}
60
//Regiao 3
if (val_sup < 50 && val_sup > 0)
{
ArLog::log(ArLog::Normal, "Comando: ajuste critico
positivo");
robot.lock();
robot.setRotVel( MYROTVEL2 );
//robot.setHeading(30);
robot.setVel( MYSPEED );
robot.unlock();
}
//Regiao 4
if (val_sup == 0 || val_sup == WIDTH)
{
break;
}
}
c = cvWaitKey ( 15 );
if ( c == 27 )
break;
}
if ( capture )
cvReleaseCapture ( &capture );
cvDestroyAllWindows();
ArLog::log(ArLog::Normal, "Comando: Parar.");
robot.lock();
robot.stop();
robot.unlock();
ArUtil::sleep(1000);
robot.lock();
ArLog::log(ArLog::Normal, "Informacao final: Pose=(%.2f,%.2f,%.2f),
Trans. Vel=%.2f, Rot. Vel=%.2f, Battery=%.2fV",
robot.getX(), robot.getY(), robot.getTh(), robot.getVel(),
robot.getRotVel(), robot.getBatteryVoltage());
robot.unlock();
ArLog::log(ArLog::Normal, "A parar o processamento do robo...");
robot.stopRunning();
//Esperar pelo fim de processamento
robot.waitForRunExit();
//exit
ArLog::log(ArLog::Normal, "Comando: Encerrar.");
//return 0;
Aria::exit(0);
}
#ifdef _EiC
main ( 1,"main.c" );
#endif
61
ANEXO VII: Mtodo de identificao de duas vias
- Fluxograma
INCIO
MI2V
Carrega Video
Video
Detectado?
SIM
NO
FIM
MI2V
Captura Frame
Aplicao da
funo Threshold
Visualizao do
Histograma
Aplicao da
Transformada de
Canny
Convero para a
escala de
cinzentos
Aplicao da
Transformada de
Hough
MI2V - Mtodo de identificao de duas vias
Anlise da
imagem
Determinao dos
parmetros
(ngulo e desvio)
Fluxograma 2 Mtodo de identificao de duas vias
62
- Cdigo
// Exemplo da linha de comandos (para copy-n-paste):
// ./main -b [<Block_size>] -o [<Offset>] [<video.avi>]
// -b <Block_size> # Block_size cvAdaptiveThreshold
// -o <Offset> # Offset cvAdaptiveThreshold
#ifdef _CH_
#pragma package <opencv>
#endif
//Bibliotecas utilizadas
#ifndef _EiC
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#endif
#define ABS(a) (((a) > 0 ? (a) : -(a))
#define min(a,b) ( (a)<(b) ? (a) : (b) )
#define max(a,b) ( (a)>(b) ? (a) : (b) )
#define RADIANS 0.01745
#define DEGREES 57.2958
#define DIM 30
enum { DETECT = 0, CAPTURA = 1, VIDEO = 2 };
//Estrutura que armazena a frame capturada e as respectivas dimensoes.
typedef struct {
CvCapture *capture;
IplImage *frame;
int width;
int height;
} Movie;
//Estrutura que armazena o valor dos pontos em analise e oa parametros
obtidos da analise.
typedef struct {
int eixo;
int eixo1;
int ct1;
int ct2;
int ct3;
int ct4;
double angulo;
double dist;
int nr_pontos;
63
} Buff;
//Variaveis globais
int _brightness = 100;
int _contrast = 100;
uchar lut[256];
CvMat* lut_mat;
IplImage *src_img, *dst_img;
Buff buff_op = {0};
//Funo utilizada para ajuste do brilho e contraste na imagem original
void update_brightcont( int arg)
{
int brightness = _brightness - 100;
int contrast = _contrast - 100;
int i;
if( contrast > 0 )
{
double delta = 127.*contrast/100;
double a = 255./(255. - delta*2);
double b = a*(brightness - delta);
for( i = 0; i < 256; i++ )
{
int v = cvRound(a*i + b);
if( v < 0 )
v = 0;
if( v > 255 )
v = 255;
lut[i] = (uchar)v;
}
}
else
{
double delta = -128.*contrast/100;
double a = (256.-delta*2)/255.;
double b = a*brightness + delta;
for( i = 0; i < 256; i++ )
{
int v = cvRound(a*i + b);
if( v < 0 )
v = 0;
if( v > 255 )
v = 255;
lut[i] = (uchar)v;
}
}
cvLUT( src_img, dst_img, lut_mat );
cvShowImage( "Original", dst_img );
}
//Funcao de processamento e analise da imagem
void TrataImagem( IplImage *img, IplImage *img_h, IplImage *orig)
{
int i=0;
64
int soma1 = 0, soma2 = 0, soma3 = 0, soma4 = 0;
CvPoint* line;
CvMemStorage* storage;
storage = cvCreateMemStorage(0);
cvClearMemStorage( storage );
buff_op.ct1 = 1;
buff_op.ct2 = 1;
buff_op.ct3 = 1;
buff_op.ct4 = 1;
//utilizacao da transformada de Hough
CvSeq* lines = cvHoughLines2( img, storage, CV_HOUGH_PROBABILISTIC, 1,
CV_PI/180, 38 , 35, 10 );
IplImage *final = cvCloneImage( orig );
IplImage *final_h = cvCloneImage( orig );
//printf("\nLines = %d\n", lines->total);
cvZero (final_h); //coloca todos os elementos da matriz de imagem a
zero
for( i = 0; i < lines->total; i++ )
{
line = (CvPoint*)cvGetSeqElem(lines,i);
//Analisa o primeiro e segundo quadrante
if( line->y < img->height/2 )
{
if(line->x < buff_op.eixo )
{
soma1 +=line->x;
buff_op.ct1++;
cvCircle(final_h,cvPoint(line->x, line-
>y),2,CV_RGB(0,255,255),1,4,0 );
}
if(line->x > buff_op.eixo )
{
soma2 +=line->x;
buff_op.ct2++;
cvCircle(final_h,cvPoint(line->x, line-
>y),2,CV_RGB(255,0,255),1,4,0 );
}
}
//Analisa o terceiro e quarto quadrante
if( line->y > img->height/2 )
{
if(line->x < buff_op.eixo1 )
{
soma3 +=line->x;
buff_op.ct3++;
cvCircle(final_h,cvPoint(line->x, line-
>y),2,CV_RGB(0,255,255),1,4,0 );
}
65
if(line->x > buff_op.eixo1 )
{
soma4 +=line->x;
buff_op.ct4++;
cvCircle(final_h,cvPoint(line->x, line-
>y),2,CV_RGB(255,0,255),1,4,0 );
}
}
cvShowImage("Transformada de Hough", final_h );
//cvWaitKey ( 0 );
}
//Determinacao do ponto superior e inferior da recta final
if(buff_op.ct1 > 1 && buff_op.ct2 > 1 && buff_op.ct3 > 1 && buff_op.ct4
> 1)
{
soma1 = soma1/(buff_op.ct1-1);
soma2 = soma2/(buff_op.ct2-1);
soma3 = soma3/(buff_op.ct3-1);
soma4 = soma4/(buff_op.ct4-1);
buff_op.eixo = (soma1 + soma2)/2; // ponto superior
buff_op.eixo1 = (soma3 + soma4)/2; // ponto inferior
printf("Ponto Sup = (%d,%d)\n", buff_op.eixo, img->height/4);
printf("Ponto Inf = (%d,%d)\n", buff_op.eixo1, img->height - img-
>height/4);
cvCircle(final, cvPoint(buff_op.eixo, img->height/4), 2,
CV_RGB(100,200,100), 2, 4, 0 );
cvCircle(final, cvPoint(buff_op.eixo1, img->height/4*3), 2,
CV_RGB(100,200,100), 2, 4, 0 );
cvLine( final, cvPoint(buff_op.eixo, img->height/4), cvPoint(
buff_op.eixo1, img_h->height/4*3 ), CV_RGB(0,255,0), 1, CV_AA, 0 );
}
//Determinacao da recta final - angulo e desvio
//Y=mx+b
if((buff_op.eixo1- buff_op.eixo)!=0)
{
int m = (img->height/4*3 - img->height/4)/(buff_op.eixo1-
buff_op.eixo);
int b = img->height/4 - m * buff_op.eixo;
double angulo = atan( m )*DEGREES*(-1);
if(angulo < 0)
angulo = 180+angulo;
printf("Angulo = %.2f\n", angulo);
buff_op.angulo = angulo;
int intercep = ((img->height/2)-b)/m;
int dist = (img->width/2-intercep)*(-1);
printf("Intercept= %d\n", intercep);
printf("Distancia = %d\n", dist);
double mod_dist = abs( dist );
buff_op.dist = mod_dist;
66
printf("Modulo Distancia = %.2f\n", mod_dist);
cvLine( final, cvPoint( intercep, img->height/2 ), cvPoint( img-
>width/2, img->height/2 ), CV_RGB(102,139,139), 3, CV_AA, 0 );
cvCircle(final, cvPoint(intercep, img->height/2), 2,
CV_RGB(100,0,100), 4, 4, 0 );
}
else
{
cvLine(final, cvPoint( img->width/2, 0 ), cvPoint( img->width/2, img-
>height/2 ), CV_RGB(0,255,255), 3, CV_AA, 0 );
buff_op.angulo = 90.0;
//printf("\nVertical\n");
}
cvLine( final, cvPoint( img->width/2, 0 ), cvPoint( img->width/2,
img_h->height ), CV_RGB(255,255,255), 1, CV_AA, 0 );
cvLine( final, cvPoint( 0, img_h->height/2 ), cvPoint( img->width,
img_h->height/2 ), CV_RGB(255,255,255), 1, CV_AA, 0 );
cvShowImage("Final", final );
cvClearSeq( lines ); //Liberta a memoria utilizada para guardar os
pontos encontrados pela trasnformada de Hough
if( storage )
cvReleaseMemStorage( &storage );
cvReleaseImage( &final );
cvReleaseImage( &final_h );
}
/*MAIN*/
int main( int argc, char** argv )
{
Movie movie;
IplImage *view = 0;
char c;
int i;
const char* video_in = 0;
int modo = DETECT;
int show_hist = 0, ad_thresh = 0;
int block_size = 3;
double offset = 5;
for( i = 1; i < argc; i++ )
{
const char* s = argv[i];
if( strcmp( s, "--help" ) == 0 )
{
printf("Exemplo da linha de comandos:\n"
"./main -b [<Block_size>] -o [<Offset>]
[<video.avi>]\n\n"
"\t-b <Block_size>\t# Block_size cvAdaptiveThreshold\n"
67
"\t-o <Offset>\t# Offset cvAdaptiveThreshold\n\n");
return 0;
}
if( strcmp( s, "-b" ) == 0 )
{
block_size = atoi (argv[++i]);
//printf("Block size = %d\n", block_size);
}
else if( strcmp( s, "-o" ) == 0 )
{
offset = atoi (argv[++i]);
//printf("Offset = %.f\n", offset);
}
else if( s[0] != '-' )
video_in = s;
}
if( video_in )
{
movie.capture = cvCreateFileCapture( video_in ); //carregamento do
video
printf("\nMODO VIDEO\n");
modo = VIDEO;
}
else
{
movie.capture = cvCreateCameraCapture(CV_CAP_ANY);
printf("\nMODO CAPTURA\n");
cvSetCaptureProperty(movie.capture, CV_CAP_PROP_FRAME_WIDTH,320);
cvSetCaptureProperty(movie.capture, CV_CAP_PROP_FRAME_HEIGHT,240);
modo = DETECT;
}
if( !movie.capture ) //se nao for carregado nada o programa e terminado
{
printf("Falha na captura de ficheiro/camara\n");
return -1;
}
time_t t;
time( &t );
printf("\n%s\n", ctime (&t) );
printf( "\nOpcoes: \n"
"\tESC - Sair do Programa\n"
"\th - Mostra/Esconde Histograma\n"
"\tt - Mostra/Esconde Adaptive Threshold\n"
"\tp - Pause\n");
cvNamedWindow( "Transformada de Canny", 0 );
cvNamedWindow( "Transformada de Hough", 0 );
cvNamedWindow( "Original", CV_WINDOW_AUTOSIZE );
cvNamedWindow( "Final", 0 );
// Para brilho e contraste
lut_mat = cvCreateMatHeader( 1, 256, CV_8UC1 );
cvSetData( lut_mat, lut, 0 );
68
buff_op.eixo = 160; // movie.width/2;
buff_op.eixo1 = 140; // movie.width/2;
for(;;)
{
IplImage *view_bin = 0, *view_canny = 0, *view_gray = 0;
int angulo_abertura = 3;
if( (char) c == 80 || c == 112 )// P ou p
{
printf("\nPause\n");
printf("\t(Press any key to continue)\n");
do
{
c = cvWaitKey ( 0 );
}while( c == 80 || c == 112);
printf("\nContinue\n");
}
if( (char) c == 27 )
break;
if( movie.capture )
{
movie.frame = 0;
movie.frame = cvQueryFrame( movie.capture );// captura do frame
view = cvCreateImage( cvGetSize(movie.frame), IPL_DEPTH_8U,
movie.frame->nChannels );
if( movie.frame->origin == IPL_ORIGIN_BL )
cvFlip( movie.frame, view, 0 );
else
cvCopy( movie.frame, view, 0 );
src_img = cvCloneImage(view);
dst_img = cvCloneImage(view);
cvCreateTrackbar("brightness", "Original", &_brightness, 200,
update_brightcont);
cvCreateTrackbar("contrast", "Original", &_contrast, 200,
update_brightcont);
update_brightcont(0);
}
if( modo == DETECT || modo == VIDEO )
{
view_bin = cvCreateImage( cvGetSize(view), IPL_DEPTH_8U, 1 );
view_canny = cvCreateImage( cvGetSize(view), IPL_DEPTH_8U, 1 );
cvCvtColor( dst_img, view_bin, CV_RGB2GRAY );
cvAdaptiveThreshold( view_bin, view_bin, 255,
CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, block_size, offset);
cvCanny( view_bin, view_canny, 150, 50, angulo_abertura );
cvShowImage( "Transformada de Canny", view_canny );
69
if( ad_thresh )
cvShowImage( "Adaptive Threshold", view_bin );
IplImage *img_hough = cvCreateImage( cvGetSize(view),
IPL_DEPTH_8U, 1 );
cvZero(img_hough);
cvCvtColor( dst_img, img_hough, CV_BGR2GRAY );
TrataImagem( view_canny, img_hough, view);
//printf("Angulo buff = %.1f\n", buff_op.angulo);
//printf("Dist buff = %.1f\n", buff_op.dist);
cvReleaseImage( &img_hough );
}
if ( show_hist )
{
int i;
int hdims = 256;
float hranges_arr[] = {0,255};
float* hranges = hranges_arr;
int bin_w = 1;
float maximo_val, minimo_val;
int val;
IplImage *histimg = cvCreateImage( cvSize(256,300), 8, 1 ); //8-
bit/ 1 canal por pixel
view_gray = cvCreateImage( cvGetSize(view), 8, 1 );
CvHistogram *hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY,
&hranges, 1 ); //1 dimenso
CvScalar cor = CV_RGB(255,255,255); //white
cvCvtColor( dst_img, view_gray, CV_BGR2GRAY );
cvZero( histimg );//coloca elementos do vector a 0
cvCalcHist( &view_gray, hist, 0, 0 );
cvNormalizeHist( hist, 1.0);//Normalizes histogram by dividing all
bins by sum of the bins, multiplied by <factor>.
//After that sum of histogram
bins is equal to <factor>
cvGetMinMaxHistValue( hist, &minimo_val, &maximo_val, 0, 0 ); //
encontra indices e valores de minimo e maximo dos bins do histograma
cvConvertScale( hist->bins, hist->bins, maximo_val ? 255. /
maximo_val : 0., 0 );
bin_w = histimg->width / 256;
for( i = 0; i <256; i++ )
{
cvGetMinMaxHistValue( hist, &minimo_val, &maximo_val, 0, 0 );
// encontra indices e valores de minimo e maximo dos bins do histograma
val = ( cvGetReal1D(hist->bins,i)*histimg->height/maximo_val );
cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),
cvPoint((i+1)*bin_w,(int)(histimg->height - val)),cor, CV_FILLED, 1, 0 );
}//End For
70
cvShowImage("Histogram Hough", histimg );
//cvShowImage("Video Gray", view_gray );
cvReleaseImage( &histimg );
}
/*
if ( contors )
{
IplImage *img, *cc_cores; //IplImage - tipo que representa uma
imagem
CvMemStorage *mem;
CvSeq *contornos, *ptr;
CvRect bbox;
img = cvCloneImage( view_gray );
cc_cores = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3);
cvThreshold(img, img, 150, 255, CV_THRESH_BINARY);
//cvAdaptiveThreshold( img, img, 255, CV_ADAPTIVE_THRESH_MEAN_C,
CV_THRESH_BINARY, block_size, offset);
//cvNot(img, img); //inverts the image.
mem = cvCreateMemStorage(0);
cvFindContours(img, mem, &contornos, sizeof(CvContour),
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
for (ptr = contornos; ptr != NULL; ptr = ptr->h_next)
{
//CvScalar color = CV_RGB( rand()&255, rand()&255, rand()&255
);
CvScalar color = CV_RGB( 255,255,111 );
cvDrawContours(cc_cores, ptr, color, CV_RGB(255,213,0), -1,
CV_FILLED, 4, cvPoint(0,0));
}
cvShowImage("Contors", cc_cores);
cvReleaseImage(&img);
}*/
//med_fim=0;
//med_inic=0;
//c = cvWaitKey(capture ? 500 : 1000);
/*if ( modo == VIDEO )
{
printf("\nMODO VIDEO\n");
c = cvWaitKey(capture ? 50 : 500);
}*/
switch( (char) c )
{
case 'h':
show_hist ^= 1;
if( !show_hist )
{
cvDestroyWindow( "Histogram Hough" );
71
//cvDestroyWindow( "Video Gray" );
}
else
{
cvNamedWindow ("Histogram Hough", 1 );
//cvNamedWindow ("Video Gray", CV_WINDOW_AUTOSIZE );
}
break;
case 't':
ad_thresh ^= 1;
if( !ad_thresh )
{
cvDestroyWindow( "Adaptive Threshold" );
}
else
{
cvNamedWindow( "Adaptive Threshold", 0 );
}
break;
/*case 'c':
contors ^= 1;
if( !contors )
{
cvDestroyWindow( "Contors" );
}
else
{
cvNamedWindow ("Contors", CV_WINDOW_AUTOSIZE );
}
break;*/
default:
;
}
if( !view )
break;
cvReleaseImage( &view_canny );
cvReleaseImage( &view_bin );
cvReleaseImage( &view_gray );
c = cvWaitKey ( 30 );
}
if( movie.capture )
cvReleaseCapture( &movie.capture );
cvReleaseImage( &view );
cvDestroyAllWindows();
return 0;
}
#ifdef _EiC
main(1,"main.c");
#endif