reconhecimento de padrões em tempo real utilizando a
TRANSCRIPT
Reconhecimento de Padrões em Tempo Real Utilizando a
Biblioteca OpenCV
João Paulo Silva do Monte Lima1
Daliton da Silva1
Veronica Teichrieb1
Judith Kelner1
Resumo: Reconhecimento de padrões em tempo real é uma tarefa crucial em
várias áreas, tais como Realidade Aumentada, Robótica e Interação Homem
Computador. A biblioteca OpenCV é uma solução open source para visão
computacional que provê várias funcionalidades adequadas para esse tipo de
aplicação. A implementação do OpenCV contém várias otimizações que
favorecem uma boa performance. Ela também provê funcionalidades simples
de usar (out of the box) para interface com o usuário, carregamento de imagens
e captura de vídeo. O objetivo deste minicurso é mostrar o potencial do
OpenCV para reconhecimento de padrões com restrições de tempo real. Serão
apresentadas as principais funções de processamento de imagem presentes no
OpenCV que podem ser usadas em sistemas de reconhecimento de padrões,
em tempo real. Os algoritmos implementados serão explicados, juntamente
com informações sobre como eles podem ser utilizados e sua aplicabilidade a
1 Grupo de Pesquisa em Realidade Virtual e Multimídia, Centro de Informática, UFPE, Av.
Professor Moraes Rego S/N, Prédio da Positiva, 1º Andar, Cidade Universitária, Recife, Pernambuco,
CEP 50670-901 {jpsml, ds2, vt, jk @cin.ufpe.br}
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
2 RITA Volume XXXX Número X 20XX
problemas reais. Exemplos de aplicações também serão apresentadas de forma
a ilustrar o uso das funcionalidades de visão computacional descritas.
Abstract: Real-time pattern recognition is a crucial task of systems applied
to several fields, such as Augmented Reality, Robotics and Human Computer
Interaction. The OpenCV library is an open source solution for computer
vision that provides many features suitable for this kind of applications.
OpenCV implementation contains many optimizations that favor a good
processing performance. It also provides out of the box functionalities for user
interface, image loading and video capture. The goal of this tutorial is to show
OpenCV’s potential for pattern recognition with real-time constraints. A
number of image processing functions featured by OpenCV that can be used in
real-time pattern recognition systems will be enumerated. The implemented
algorithms will be explained, along with information of how they can be
utilized and their applicability to real life problems. Example applications will
also be presented in order to illustrate the use of the described computer vision
features.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 3
1 Introdução
O OpenCV é uma biblioteca open source para processamento de imagens offline e em
tempo real. Ela pode ser utilizada em diversas e diferentes áreas, como em interação homem-
máquina (Human-Computer Interaction, HCI), identificação de objetos, segmentação e
reconhecimento, reconhecimento de faces, reconhecimento de gestos, rastreamento de
movimentos, ego motion, compreensão de movimentos e Structure from Motion (SfM), e
robótica móvel. A Tabela 1 apresenta uma descrição mais detalhada das funções suportadas
pelo OpenCV. A biblioteca é desenvolvida pela Intel, e está em desenvolvimento desde
2001, com a primeira versão liberada em outubro de 2006. Existem versões do OpenCV
tanto para o sistema operacional Windows quanto para o Linux.
Tabela 1. Principais funções do OpenCV
Funçaõ Descrição
Manipulação de imagens Alocação, desalocação, cópia, modificação, conversão
IO de vídeo e imagem Input e output baseado em arquivo e câmera
Manipulação de matrizes e
vetores e retinas de álgebra
linear
Produto, solução, single value decomposition (SVD)
Diversas estruturas de dados
dinâmicas
Listas, filas, pilhas, árvores, grafos
Processamento de imagens
básico
Fitragem, detecção de bordas, detecção de cantos,
interpolação e amostragem, conversão de cor, operações
morfológicas, histogramas, pirâmides de imagens.
Análise estrutural Componentes conexos, processamento de contornos,
transformação de distância, momento diverso, casamento
de templates, aproximação poligonal, montagem de linha,
montagem de elipse, triangularização de Delaunay
Calibração de câmera Busca, rastreamento e calibração de padrões, calibração,
estimação de matrizes fundamentais, estimação
homográfica, correspondência estéreo.
Análise de movimentos Fluxo óptico, segmentação de movimentos, rastreamento
Reconhecimento de objetos. Métodos-eigen, Hidden Markov Models (HMM)
GUI básica Exibição de vídeo e imagens, tratamento de entrada do
teclado e do mouse, barras de rolagens
Labeling de imagens Linha, cônica, polígono, texto, desenho de texto
O código do OpenCV encontra-se disponível para download e é aberto para modificações,
desde que as cláusulas da licença sejam obedecidas. O OpenCV foi escrito em C/C++, e
provê suporte para desenvolvedores que utilizam o Microsoft Visual Studio, Eclipse Project
e C++ Builder (quando utilizando Windows) e make files (quando utilizando Linux).
OpenCV pode ser dividido em quatro módulos: cv, cvaux, cxcore e highgui. O módulo cv
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
4 RITA Volume XXXX Número X 20XX
contém as funções padrões podendo ser considerado o coração da biblioteca. O módulo
cvaux, como o nome sugere, implementa funções que suportam o uso do OpenCV. O módulo
cxcore é responsável pelas estruturas de dados e operações de álgebra linear. Por fim, o
módulo highgui provê suporte para funções de GUI, como a exibição de janela contendo
imagens capturadas pela webcam, por exemplo.
1.1 Motivação
Reconhecimento de padrões em tempo real representa uma importante tarefa de
aplicações em diversas áreas, como realidade aumentada, robótica e HCI. OpenCV provê
funcionalidades para construção de interfaces com o usuário, leitura de imagens e captura de
vídeo, por exemplo. A biblioteca OpenCV é uma solução de código aberto para visão
computacional que provê funcionalidades adequadas para aplicações dos tipos listados
anteriormente. A biblioteca foi definida para prover uma interface de programação simples,
podendo ser facilmente integrada em outros projetos que já existam.
Um importante problema envolvendo o reconhecimento de padrões é o pesado
processamento exigido por esse tipo de tarefa. Por causa disto, o OpenCV contém
otimizações que resultam em bom desempenho para as suas aplicações. Como o OpenCV é
implementado pela Intel, ele contém otimizações especificamente desenvolvidas para os
processadores da Intel.
A Intel tem realizado investimentos de larga escala no desenvolvimento do OpenCV. Seus
pesquisadores se dedicam ao desenvolvimento de novas funcionalidades para o OpenCV,
que são incorporadas a biblioteca a cada nova versão distribuída. Como exemplo, pode-se
citar a função cvGoodFeaturesToTrack, baseada no trabalho de Carlo Tomasi [1].
1.2 Licença
A licença do OpenCV permite a modificação e a livre distribuição do seu código fonte e
binários, desde que certas condições sejam observadas. Entre essas condições, as seguintes
são relevantes:
- O código fonte e os binários distribuídos devem conter todas as informações listadas na
licença original do OpenCV;
- O nome da Intel ou qualquer uma de suas marcas não podem ser utilizados para
promover o uso de aplicações que utilizem OpenCV sem a prévia autorização.
1.3 Instalação
O OpenCV pode ser instalado através de um wizard, disponível em
http://sourceforge.net/projects/opencvlibrary/, ou pode ser adquirido diretamente do CVS. As
instruções para o uso do CVS estão disponíveis em
http://sourceforge.net/cvs/?group_id=22870. Em ambos os casos podem ser copiados o
código fonte e os binários.
Na sequência, a instalação passo a passo do OpenCV é descrita. A Figura 1 mostra a tela
que aparece na instalação do OpenCV. Clicando no botão “Next”, a licença de usuário é
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 5
exibida. Para aceitar os termos listados, o usuário deve clicar na opção “I accept the
agreement” e clicar no botão next novamente. As três telas seguintes do processo de
instalação exibem as configurações de instalação padrões. A Figura 1 ilustra a primeira
dessas telas. Depois de confirmar todas as opções, o OpenCV é copiado para o disco rígido e
estará pronto para o uso.
Figura 1. A primeira tela da instalação do OpenCV.
Para recompilar o código do OpenCV utilizando o Microsoft Visual Studio, é necessário
abrir o arquivo “opencv.sln”, localizado dentro da pasta “_make”. Desta forma todo o
ambiente de desenvolvimento é configurado para a correta compilação do código. Na
sequência, o usuário clica em “Build Solution”, do menu “Build”, como ilustrado na Figura
2. Cada módulo do OpenCV é compilado em duas Iink libraries (.dll e .lib). Elas integram o
OpenCV com projetos desenvolvidos pelo usuário.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
6 RITA Volume XXXX Número X 20XX
Figura 2. Compilando o código fonte do OpenCV.
1.4 Documentação
O OpenCV possui uma documentação completa, muitos fóruns e grupos de discussão,
resultando em um suporte eficiente para os usuários da biblioteca. A aplicação de instalação
automaticamente copia uma série de documentos de suporte ao usuário. Dentre estes
documentos, o “opencvman_old.pdf” merece uma atenção especial, este é o manual de
referência da biblioteca. Neste documento pode ser encontrada a descrição em detalhes das
funções do OpenCV e códigos de exemplos. O manual também explica conceitos gerais
referentes ao OpenCV, como a definição de tipos de dados específicos e guias de
implementação utilizados e processamento de imagens. O grupo de discussão sobre OpenCV
está disponível em http://tech.groups.yahoo.com/group/OpenCV. A documentação também
está disponível na instalação do OpenCV como um arquivo HTML, que é uma versão mais
simples porém mais freqüentemente atualizada do manual.
Quando o usuário se registra (o registro no grupo de discussão é grátis) ele pode acessar
uma extensa base de dados envolvendo questões práticas. O usuário tem a possibilidade de
postar suas questões que não podem ser resolvidas utilizando a documentação existente.
Existe uma grande chance de que a questão seja resolvida, pois a comunidade do OpenCV
possui um grande número de membros ativos.
2 Funcionalidades
Este capítulo explica um conjunto de funções do OpenCV relativas a vários passos do
pipeline de processamento de imagens. As funções relativas a pré-processamento,
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 7
segmentação, representação e reconhecimento são inseridas em um contexto e sua utilização
é explicada.
2.1 Realce de imagens e seleção de características
O principal objetivo do realce de imagens é processar uma imagem de forma que o
resultado seja mais adequado do que a imagem original para um conjunto de aplicações
específicas.
Existem basicamente duas abordagens para o realce de imagens: métodos do domínio
espacial e métodos do domínio de freqüência. O termo domínio espacial se refere ao próprio
plano de imagem, e abordagens nesta categoria são baseadas na manipulação direta de pixels
de uma imagem. Técnicas do domínio de freqüência são baseadas em modificar a
transformada de Fourier de uma imagem. A biblioteca OpenCV trata somente um
subconjunto de técnicas do domínio espacial.
Além disso, neste capítulo algumas funções relacionadas a seleção de características (por
exemplo, arestas e cantos) são apresentadas.
Suavização. Filtros de suavização são usados para borramento e redução de ruído. O
borramento é usado em etapas de pré-processamento, tais como remoção de pequenos
detalhes de uma imagem. Além disso, a redução de ruído pode ser feita através de um
borramento usando um filtro linear e através de uma filtragem não-linear. Um exemplo de
uso do borramento é mostrado na Figura 3.
Figura 3. Imagem original (esquerda), um kernel uniforme (centro) e um kernel Gaussiano (direita).
Na biblioteca OpenCV, existe uma função relativa a filtragem de suavização chamada
cvSmooth, e como a operação de suavização nada mais é que uma convolução com uma
matriz específica, é possível usar a função cvFilter2D.
Ambas as funções são explicadas abaixo.
void cvSmooth( const CvArr* src, CvArr* dst,
int smoothtype,int param1, int param2,
double param3 );
O argumento src é a imagem de origem, dst é a imagem de destino, smoothtype é o
tipo da suavização que pode ser aplicada (todos os tipos estão listados na Tabela 2).
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
8 RITA Volume XXXX Número X 20XX
Tabela 2. Tipos de suavização do OpenCV.
Tipo de suavização Descrição
CV_BLUR_NO_SCALE Somatório em uma vizinhança de pixels param1×param2
CV_BLUR Somatório em uma vizinhança de pixels
param1×param2 com subseqüente escala
por 1/(param1×param2)
CV_GAUSSIAN Convolução da imagem com um kernel
Gaussiano param1×param2
CV_MEDIAN Mediana de uma vizinhança de pixels
param1×param1 (ou seja, a vizinhança é
quadrada)
CV_BILATERAL Aplicação de um filtro 3x3 bilateral com cor
sigma=param1 e espaço sigma=param2,
como descrito em [2]
Quando o smoothtype Gaussiano é usado, param3 indica o sigma da Gaussiana (isto
é, o desvio padrão). E se ele for zero, ele é calculado a partir do tamanho do kernel, usando a
fórmula:
8.03.0*)12/(nsigma ,
onde sigma é param1 ou param2, dependendo da orientação do kernel (horizontal ou
vertical).
Outra função relacionada com convoluções é cvFilter2D, que é uma função que
convolui qualquer kernel linear com uma imagem, e sua assinatura é:
void cvFilter2D( const CvArr* src, CvArr* dst,
const CvMat* kernel, CvPoint anchor);
onde src é a imagem de origem, dst é a imagem de destino e kernel é o kernel de
convolução, uma matriz de ponto flutuante mono-canal. O anchor indica a posição relativa
de um ponto filtrado com o kernel, a única preocupação é que o ponto da âncora deve estar
dentro do kernel. O valor padrão especial (-1,-1) significa que ele está no centro do kernel.
Detecção de arestas. As técnicas de detecção de arestas são inerentemente fáceis de
implementar e possuem uma complexidade computacional baixa. Como um exemplo de
aplicação de detecção de arestas para rastreamento, o RAPiD [3] é comumente citado, e pode
ser visto na Figura 4.
Este capítulo apresenta todas as funções relativas a detecção de arestas do OpenCV. Os
operadores de Sobel, de Canny e Laplaciano são apresentados.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 9
Figura 4. Alguns pontos são amostrados ao longo das arestas do modelo (esquerda), estes pontos são
utilizados para inferir a pose (centro). Oclusões podem ser tratadas de uma forma robusta (direita).
Operador de Sobel. O operador de Sobel realiza uma medida do gradiente espacial 2D de
uma imagem e enfatiza regiões de alto gradiente espacial que correspondem a arestas.
Tipicamente ele é usado para encontrar a magnitude absoluta aproximada do gradiente em
cada ponto de uma imagem em tons de cinza de entrada. Um exemplo de uso do operador de
Sobel é ilustrado na Figura 5.
Figura 5. Imagem em tons de cinza (esquerda), imagem do gradiente x de Sobel (centro) e imagem do
gradiente y de Sobel (direita).
Pelo menos na teoria, o operador consiste em um par de máscaras de convolução 3x3
como as mostradas na Figura 6. Uma máscara é simplesmente a outra após sofrer uma
rotação de 90°.
Figura 6. Máscaras de convolução de Sobel.
Estas máscaras são designadas para responder maximamente a arestas verticais e
horizontais com relação à grade de pixels, uma máscara para cada uma das duas orientações
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
10 RITA Volume XXXX Número X 20XX
perpendiculares. As máscaras podem ser aplicadas independentemente na imagem de entrada
para produzir medidas separadas da componente do gradiente em cada orientação (chamadas
Gx e Gy ). Elas podem ser combinadas para encontrar a magnitude absoluta do gradiente
em cada ponto e a orientação desse gradiente. A magnitude do gradiente é dada por:
x yG G G,
embora tipicamente uma magnitude aproximada pode ser computada rapidamente usando:
x yG G G
Na biblioteca OpenCV, o operador de Sobel é implementado através da função
cvSobel, e sua assinatura é:
void cvSobel( const CvArr* src, CvArr* dst, int xorder,
int yorder, int aperture_size );
O argumento src é a imagem de origem, dst é a imagem de destino, xorder é a ordem
da derivada x , yorder é a ordem da derivada no eixo y . O parâmetro aperture_size
é o tamanho do kernel de Sobel estendido, ele precisa ser 1, 3, 5 ou 7. Em todos os casos,
exceto quando ele é 1, um kernel aperture_size x aperture_size será usado para
calcular a derivada. Existe também um valor especial para aperture_size CV_SCHARR
que corresponde ao filtro 3x3 de Scharr [4].
Operador Laplaciano. O Laplaciano é uma medida isotrópica 2D da derivada segunda
espacial de uma imagem. O Laplaciano de uma imagem destaca regiões de rápida mudança
de intensidade e portanto é comumente usado para detecção de arestas.
O Laplaciano é freqüentemente aplicado em uma imagem que foi primeiramente
suavizada com um filtro Gaussiano aproximado de forma a reduzir sua sensibilidade a ruído,
e por isso as duas variantes serão descritas em conjunto neste texto. O operador normalmente
toma uma única imagem em tons de cinza como entrada e produz outra imagem em tons de
cinza como saída.
O Laplaciano ),( yxL de uma imagem com valores de intensidade de pixel ),( yxI é
dado por: 2 2
2 2( , )
I IL x y
x y
Este operador pode ser aproximado por um filtro de convolução. Visto que a imagem de
entrada é representada por um conjunto de pixels discretos, é necessário encontrar um kernel
de convolução discreta que possa aproximar as derivadas segundas na definição do
Laplaciano. Dois kernels pequenos comumente utilizados são mostrados na Figura 7.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 11
Figura 7. Duas aproximações discretas do filtro Laplaciano comumente usadas.
A função do OpenCV que implementa o Laplaciano de uma imagem é cvLaplace, e
sua assinatura é:
void cvLaplace( const CvArr* src, CvArr* dst,
int aperture_size );
O argumento src é a imagem de entrada, dst é a imagem resultante, e
aperture_size é o mesmo argumento usado no operador de Sobel.
Operador de Canny. O operador de Canny foi projetado para ser um detector de arestas
ótimo (de acordo com critérios particulares, isto é, existem outros detectores que também
afirmam ser ótimos de acordo com critérios ligeiramente diferentes). Ele usa como entrada
uma imagem em tons de cinza e produz como saída uma imagem mostrando as posições das
descontinuidades de intensidade rastreadas. Um exemplo do operador de Canny é a Figura 8.
Como pode ser visto nesta figura, as arestas da imagem foram destacadas.
Figura 8. Imagem crua (esquerda), imagem resultante (direita).
O operador de Canny funciona como um processo multi-estágio. Primeiramente, a
imagem é suavizada usando convolução Gaussiana. Então, uma derivada primeira 2D
simples é aplicada à imagem suavizada para destacar regiões da imagem com derivadas
primeiras espaciais altas. Arestas dão origem a picos na imagem da magnitude do gradiente.
O algoritmo então rastreia ao longo do topo desses picos e seta para zero todos os pixels que
não estão no topo dos picos, de forma a gerar linhas finas na saída, um processo conhecido
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
12 RITA Volume XXXX Número X 20XX
como supressão de não-máximos. O processo de rastreamento utiliza uma histerese
controlada por dois limiares: 1T e 2T , com 1T > 2T . O processo de rastreamento só pode
começar em um ponto de pico maior que 1T . O rastreamento então continua em ambas as
direções a partir desse ponto até que a altura do pico fique abaixo de 2T . Esta histerese ajuda
a garantir que arestas com ruído não sejam quebradas em múltiplos fragmentos.
O operador de Canny é implementado no OpenCV através da função cvCanny e sua
assinatura é a seguinte:
void cvCanny( const CvArr* image, CvArr* edges,
double threshold1, double threshold2,
int aperture_size );
O argumento image é a imagem de entrada, edges é a imagem que irá guardar os
resultados, threshold1 e threshold2 são os dois limiares usados nesse operador,
aperture_size é o parâmetro de abertura, assim como no operador de Sobel.
Detecção de cantos. Uma das abordagens da literatura de visão computacional para
extrair certos tipos de características de uma imagem é a detecção de cantos, ou mais
genericamente detecção de pontos de interesse. A Figura 9 mostra uma aplicação de
realidade aumentada sem marcadores baseada em pontos de interesse [5] que é capaz de
rastrear, por exemplo, a posição e orientação de um computador usando alguns pontos de
interesse. E como pode ser notado na Figura 9 acima e à direita, a maioria dos pontos de
interesse estão localizados ao redor de cantos. Na Figura 9 abaixo e à esquerda, é possível
ver que o algoritmo é robusto a rotação e translação, uma vez que a posição da placa é
rastreada corretamente.
Alguns usos da detecção de características incluem detecção de movimento, mosaicos de
imagens, colagem de imagens panorâmicas, modelagem 3D e reconhecimento de objetos.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 13
Figura 9. Inicialmente, o aramado é casado com o computador (acima, à esquerda), oito pontos são
rastreados (acima, à direita) e finalmente a placa no computador é rastreada (abaixo, à esquerda e à
direita).
Na biblioteca OpenCV, existem três maneiras de detectar pontos de interesse: (1)
diretamente calculando autovetores e autovalores, (2) através do operador de Harris e (3)
usando a função Good Features to Track. As alternativas (1) e (2) se preocupam em detectar
cantos na imagem, e embora a (3) seja baseada na (2), a classe de características que o
algoritmo é capaz de tratar abrange mais elementos do que apenas cantos.
Autovetores e autovalores. A maioria dos algoritmos de detecção de características são
baseados no cálculo de autovalores e autovetores, e esta operação é implementada no
OpenCV através de duas funções, cvCornerEigenValsAndVects e
cvCornerMinEigenVal. Ambas as funções são relativas à matriz de covariação das
derivadas em torno de certo pixel. A matriz de covariação é da forma: 2
2
dI dI dI
dx dx dyC
dI dI dI
dx dy dy
,
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
14 RITA Volume XXXX Número X 20XX
onde ),( yxI é a intensidade do pixel nas coordenadas ),( yx .
A função cvCornerEigenValsAndVects calcula tanto os autovalores como os
autovetores da matriz de covariação e cvCornerMinEigenVal apenas calcula e guarda
os autovalores desta.
A assinatura de cvCornerEigenValsAndVects é:
void cvCornerEigenValsAndVecs( const CvArr* image,
CvArr* eigenvv,
int block_size,
int aperture_size );
O argumento image é a imagem de entrada, eigenvv é uma imagem que guarda os
resultados e precisa ser seis vezes mais larga que image, block_size é o tamanho da
vizinhança e aperture_size é o parâmetro de abertura como no operador de Sobel.
A assinatura da função cvCornerMinEigenVal é:
void cvCornerMinEigenVal ( const CvArr* image,
CvArr* eigenval, int block_size,
int aperture_size );
Os parâmetros desta função são os mesmos da cvCornerEigenValsAndVecs, com
exceção de eigenval, porque esta função apenas calcula e guarda os menores autovalores
associados com os pixels. Isso significa que cada autovalor é do mesmo tamanho de image,
ao contrário da função cvCornerEigenValsAndVecs que é seis vezes maior, além de
calcular e guardar tanto os autovalores como os autovetores.
Detector de cantos de Harris. O detector de cantos de Harris computa a matriz de
momento com média local a partir dos gradientes da imagem, e então combina os
autovalores da matriz de momento para computar a “força” do canto, da qual valores
máximos indicam as posições dos cantos.
Esse detector também é baseado na matriz de covariação. A chave desta equação está em
examinar seus autovalores. Quando a matriz possui dois autovalores altos, isto corresponde a
duas direções principais diferentes no gradiente da imagem subjacente. Isto é calculado
rapidamente e eficientemente com uma simples equação para a resposta do canto que é
guardada para cada pixel da imagem: 2det( ) *( ( ))R C k trace C ,
onde k é um parâmetro ajustável que determina o quão “aresta-fóbica” a resposta do
algoritmo é.
O resultado da aplicação do algoritmo em uma imagem pode ser visto na Figura 10. Na
figura da direita, é possível ver algumas regiões brancas, relativas a máximas locais que
indicam que uma região é um canto. Deve-se notar que o detector de cantos de Harris é
capaz de encontrar arestas também, como pode ser visto nas regiões cinza escuro da Figura
10.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 15
Figura 10. Imagens em tons de cinza (esquerda), o resultado da aplicação do detector de cantos de
Harris (direita).
A assinatura da função é mostrada abaixo:
void cvCornerHarris( const CvArr* image,
CvArr* harris_response,
int block_size,
int aperture_size, double k );
O argumento image é a imagem de entrada, harris_response é a imagem que
guardará o resultado do detector de Harris. O parâmetro block_size é responsável pelo
tamanho da vizinhança, como discutido para autovetores e autovalores. O
aperture_size é o mesmo do operador de Sobel. Finalmente, k é o parâmetro ajustável.
Good Features to Track. O trabalho de Shi e Tomasi [1] em rastreamento de
características é implementado no OpenCV através da função
cvGoodFeaturesToTrack. Ele é fortemente baseado no operador de detecção de cantos
de Harris. A idéia básica do algoritmo é monitorar a qualidade das características da imagem
durante o rastreamento usando uma medida de dissimilaridade da característica que
quantifica a mudança de aparência de uma determinada característica entre o primeiro
quadro e o quadro atual. Abaixo, na Figura 11, as características encontradas na imagem da
esquerda são realçadas e mostradas na imagem de direita.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
16 RITA Volume XXXX Número X 20XX
Figura 11. O primeiro quadro da sequência (esquerda), as características selecionadas de acordo com o
critério estabelecido (direita).
Existem algumas precauções relativas a esta função. Uma delas é a necessidade de se ter
duas imagens temporárias de ponto flutuante de 32 bits do mesmo tamanho da imagem de
entrada. Em aplicações onde a memória é um recurso escasso, alguns problemas podem
aparecer quando essa função é usada.
A assinatura da função é mostrada abaixo:
void cvGoodFeaturesToTrack( const CvArr* image,
CvArr* eig_image,
CvArr* temp_image,
CvPoint2D32f* corners,
int* corner_count,
double quality_level,
double min_distance,
const CvArr* mask,
int block_size,
int use_harris,
double k );
O argumento image é a imagem mono-canal de entrada, eig_image e temp_image
são imagens temporárias de ponto flutuante de 32 bits do mesmo tamanho da imagem de
entrada. O parâmetro corners é uma estrutura previamente alocada para comportar os
cantos detectados, corner_count é simplesmente o número de cantos detectados. O
parâmetro quality_level é um número indicando a qualidade mínima aceitável dos
cantos da imagem, min_distance é a distância euclidiana mínima entre os cantos. O
parâmetro mask é a região de interesse, se um ponteiro para NULL é passado, a imagem
inteira é usada. O parâmetro block_size é o mesmo da função do detector de cantos de
Harris. Ao usar esta função, é possível decidir por usar o detector de cantos de Harris setando
use_harris para qualquer valor diferente de zero. Por fim, k é o parâmetro livre do
operador de Harris.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 17
2.2 Segmentação
A tarefa de analisar uma imagem de forma a distinguir elementos específicos é chamada
segmentação. Os sub-capítulos a seguir explicam algumas técnicas usadas para atingir esse
objetivo.
Limiarização. Esta técnica consiste em separar os objetos de interesse do fundo da
imagem. Isto é comumente feito com imagens em tons de cinza, mas pode também ser
aplicado a outros formatos, como imagens coloridas. Uma prática comum quando se quer
limiarizar imagens coloridas é considerar a soma das componentes de cor para cada pixel.
A limiarização é feita estimando intervalos de nível que determinam os pixels que
pertencem ao fundo da imagem e a objetos de interesse. Como pode ser visto na Figura 12
(esquerda), quando existe apenas um objeto para segmentar em uma imagem ),( yxf , um
limiar T é especificado e dois intervalos de nível são definidos: Tyxf ),( e
Tyxf ),( . Esta operação é chamada limiarização mono-nível e o resultado é uma
imagem binária que distingue os pixels que pertencem a cada intervalo de nível. Na
limiarização multi-nível, existem n objetos para segmentar, requerendo o uso de diferentes
limiares 1T , …, nT , como mostrado na Figura 12 (direita). O resultado desta operação é uma
imagem em tons de cinza com n níveis distintos.
Figura 12. Limiarização mono-nível (esquerda) e multi-nível (direita)
A operação de limiarização pode também ser classificada como global ou local. Na
limiarização global, os mesmos limiares kT são usados para todos os pixels da imagem. Na
limiarização local, os limiares kT dependem de propriedades locais dos pixels, tais como o
nível médio de sua vizinhança. A limiarização global é mais adequada a imagens onde os
objetos possuem uma iluminação constante. A Figura 13 mostra um exemplo onde um objeto
com iluminação constante é corretamente segmentado usando limiarização global, enquanto
que os resultados obtidos com a limiarização local não são satisfatórios. A limiarização local
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
18 RITA Volume XXXX Número X 20XX
é mais indicada para casos onde a iluminação dos objetos é variável, visto que ela leva em
consideração características locais da imagem. Na Figura 14, a limiarização local segmenta
mais pixels dos objetos do que a limiarização global, devido à natureza variável da
iluminação dos objetos.
Figura 13. Imagem de entrada onde o objeto possui uma iluminação constante (esquerda), resultado da
limiarização global (centro) e resultado da limiarização local (direita).
Figura 14. Imagem de entrada onde os objetos possuem uma iluminação variável (esquerda), resultado
da limiarização global (centro) e resultado da limiarização local (direita).
Muitos algoritmos de processamento de imagens usados em aplicações de tempo real não
manipulam imagens coloridas. Como resultado, a imagem original tem de ser convertida
para um formato mais adequado, tal como o binário. É aí que a limiarização entra. Um
exemplo de uso da limiarização no reconhecimento de padrões em tempo real aparece no
rastreamento de marcadores feito pela biblioteca de realidade aumentada ARToolKit [6]. As
imagens coloridas capturadas pela câmera são analisadas de forma a segmentar os pixels
escuros relativos a marcadores do fundo da imagem. Uma limiarização mono-nível global é
aplicada à imagem de entrada, com o limiar T sendo especificado pelo usuário. Um valor
comum para T é 150. Considerando um pixel colorido ),,( ppp bgr da imagem de entrada,
se Tbgr ppp 3 , então o pixel é classificado como um pixel de marcador, caso
contrário é classificado como pixel de fundo. A Figura 15 mostra os resultados obtidos pelo
ARToolKit ao limiarizar um quadro de entrada.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 19
Figura 15. Limiarização global usada no ARToolKit: imagem colorida de origem (esquerda) e
resultado da limiarização global (direita).
O OpenCV implementa uma limiarização mono-nível e oferece tanto uma limiarização
global como uma local para imagens em tons de cinza. A limiarização global é implementada
pela função cvThreshold, que possui a seguinte assinatura:
void cvThreshold ( const CvArr* src, CvArr* dst,
double threshold, double max_value,
int threshold_type );
O argumento src é a imagem em tons de cinza a ser limiarizada. O argumento dst é
onde a imagem binária resultante será guardada. O limiar global T é especificado pelo
argumento threshold. O argumento max_value é o nível que será usado para distinguir
os pixels do objeto dos pixels do background. O argumento threshold_type determina
qual função será usada na operação de limiarização. Os cinco tipos de limiarização
disponíveis e suas respectivas funções são apresentados na Tabela 3, e sua representação
visual é ilustrada na Figura 16.
Tabela 3. Tipos de limiarização do OpenCV e suas funções.
Tipo de limiarização Função
CV_THRESH_BINARY contrário caso ,0
),( se,max_value),(
thresholdyxsrcyxdst
CV_THRESH_BINARY_INV contrário caso ,max_value
),( se,0),(
thresholdyxsrcyxdst
CV_THRESH_TRUNC contrário caso ),,(
),( se,),(
yxsrc
thresholdyxsrcthresholdyxdst
CV_THRESH_TOZERO contrário caso ,0
),( se),,(),(
thresholdyxsrcyxsrcyxdst
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
20 RITA Volume XXXX Número X 20XX
CV_THRESH_TOZERO_INV contrário caso ),,(
),( se,0),(
yxsrc
thresholdyxsrcyxdst
Figura 16. Representação visual dos tipos de limiarização do OpenCV.
A limiarização local é implementada pela função cvAdaptiveThreshold, que tem a
seguinte assinatura:
void cvAdaptiveThreshold( const CvArr* src, CvArr* dst,
double max_value,
int adaptive_method,
int threshold_type, int block_size,
double param1 );
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 21
Os argumentos src, dst, max_value e threshold_type são os mesmos de
cvThreshold. Os únicos tipos de limiarização local disponíveis são
CV_THRESH_BINARY e CV_THRESH_BINARY_INV. O limiar T é computado para cada
pixel da imagem de entrada. O argumento adaptive_method determina como T é
calculado. Se ele é CV_ADAPTIVE_THRESH_MEAN_C, então T é a media da vizinhança
de pixels block_size x block_size subtraída por param1. Se ele é
CV_ADAPTIVE_THRESH_GAUSSIAN_C, então T é a soma ponderada Gaussiana da
vizinhança de pixels block_size x block_size subtraída por param1. Isso significa
que pixels mais próximos terão uma influência maior no resultado do que os mais distantes.
Detecção de linhas. Para detectar linhas retas em uma imagem, o primeiro passo é
realizar uma operação de realce de arestas na imagem de entrada. Daí, um limiar é aplicado
ao resultado. A saída binária desta operação pode ser usada para a detecção de linhas.
Algumas técnicas de rastreamento 3D sem marcadores se baseiam na detecção de
segmentos de linha na imagem Erro! Fonte de referência não encontrada.. Um modelo
aramado do objeto a ser rastreado é projetado na imagem usando uma estimativa de pose da
câmera. A projeção e as linhas da imagem são comparadas para calcular a pose atual da
câmera. A Figura 17 ilustra o processo.
Figura 17. Linhas detectadas na imagem (esquerda) e pose estimada do carro (direita).
O operador usado para realizar detecção de linhas é a transformada de Hough. A idéia por
trás da transformada de Hough é diminuir a complexidade computacional da detecção de
linhas usando uma representação de linhas no espaço de parâmetro ao invés de no plano xy .
Considerando um ponto ),( ii yx no plano xy , existe uma infinidade de linhas que passam
por ele. Essas linhas têm a forma baxy ii . Rearranjando a equação em termos dos
parâmetros a e b , a equação resultante é ii yaxb . Isto é equivalente a uma linha no
espaço de parâmetros. Considerando outro ponto ),( jj yx , o conjunto de linhas que passa
por ele é representado no espaço de parâmetros por jj yaxb . A intersecção das linhas
no espaço de parâmetro no ponto )','( ba determina os parâmetros da linha que passa por
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
22 RITA Volume XXXX Número X 20XX
ambos os pontos no ),( ii yx e ),( jj yx no plano xy . A Figura 18 mostra gráficos que
ilustram esta idéia.
Figura 18. Representação da linha no plano xy (esquerda) e no espaço de parâmetros (direita).
Na representação usada pelo algoritmo, cada eixo do espaço de parâmetros é subdividido
em intervalos de tamanho igual, como mostra a Figura 19, gerando células chamadas
acumuladores. Cada acumulador ),( ba no espaço de parâmetros representa uma linha no
plano xy .
O primeiro passo do algoritmo é atribuir zero a todos os acumuladores. Depois, a imagem
de entrada é escaneada à procura de pontos de aresta. Para cada ponto ),( ii yx , os
parâmetros ),( ba de todas as linhas que passam por ele são avaliados usando todos os
valores permitidos pela subdivisão da equação yxab . O acumulador correspondente
para cada par de parâmetros é incrementado. Depois que todos os pontos de aresta são
tratados, os valores nos acumuladores serão o número de pontos de aresta contidos na linha
correspondente. Um limiar pode então ser aplicado para selecionar as linhas com o maior
número de pontos.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 23
Figura 19. Acumuladores no espaço de parâmetros.
O tempo de execução da transformada de Hough pode ser reduzido sem perda
significativa na qualidade dos resultados usando uma abordagem probabilística [8]. Ao invés
de se utilizar todos os pontos de aresta, apenas uma fração aleatória desses pontos é
considerada.
A detecção de linhas é feita pela função do OpenCV cvHoughLines2:
CvSeq* cvHoughLines2( CvArr* image, void* line_storage,
int method, double rho, double theta,
int threshold, double param1,
double param2 );
O argumento image é a imagem binária de onde as linhas serão adquiridas. O argumento
line_storage é um recipiente para os dados das linhas detectadas. A variante da
transformada de Hough a ser utilizada é especificada pelo argumento method. A Tabela 4
apresenta os métodos da transformada de Hough disponíveis. Os argumentos rho e theta
são a resolução da distância e do ângulo, respectivamente. O argumento threshold
determina o número mínimo de pontos necessários para uma linha. Os argumentos param1
e param2 são apenas usados se method é CV_HOUGH_PROBABILISTIC ou
CV_HOUGH_MULTI_SCALE. Na transformada de Hough probabilística, param1 é o
tamanho mínimo da linha e param2 é a distância máxima entre segmentos pertencentes a
uma mesma linha que não causa sua união. Na transformada de Hough multi-escala,
param1 é o divisor para rho e param2 é o divisor para theta.
Tabela 4. Métodos da transformada de Hough do OpenCV.
Método da transformada de Hough Descrição
CV_HOUGH_STANDARD Transformada de Hough clássica. Retorna
todas as linhas detectadas. Cada linha é
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
24 RITA Volume XXXX Número X 20XX
representada pela distância para a origem
( ) e pelo ângulo entre o eixo x e a
normal da linha ( )
CV_HOUGH_PROBABILISTIC
Transformada de Hough probabilística.
Retorna todos os segmentos de linha
detectados. Cada segmento é representado
pelos seus pontos de início e fim
CV_HOUGH_MULTI_SCALE
Variante multi-escala da transformada de
Hough clássica. Retorna todas as linhas
detectadas da mesma maneira que CV_HOUGH_STANDARD
Detecção de contornos. Após aplicar um operador de realce de imagens para detecção de
arestas e limiarizar a imagem resultante, os contornos podem ser extraídos a partir da
imagem. Para realizar esta tarefa, dois passos precisam ser contemplados: traçado de
contornos e representação de contornos. No traçado de contornos, os contornos existentes
são seguidos na imagem. Na representação de contornos, os contornos são descritos de uma
forma significativa.
A detecção de contornos é largamente utilizada em soluções de reconhecimento de
padrões em tempo real. No ARToolKit, os contornos relativos aos marcadores presentes no
quadro de entrada precisam ser segmentados para possibilitar o reconhecimento e estimativa
de pose [6]. A Figura 20 ilustra a operação.
Figura 20. Detecção de contornos usada no ARToolKit: imagem colorida de entrada (esquerda), arestas
realçadas (centro) e contornos detectados destacados na imagem (direita).
O OpenCV usa o algoritmo de Suzuki para realizar o traçada de contornos [9]. Nesse
algoritmo, inicialmente o pixel de contorno mais acima e à esquerda é encontrado. Daí, a
vizinhança do primeiro pixel é verificada no sentido horário para encontrar o próximo pixel
do contorno. A partir daí, a busca por outros pixels é feita no sentido anti-horário e termina
quando os primeiros dois pixels do contorno são encontrados novamente.
O OpenCV realiza representação de contornos usando dois tipos diferentes de descrição:
códigos de cadeia e representação poligonal.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 25
Códigos de cadeia consistem numa seqüência de números que determinam a vizinhança
de um pixel de contorno onde o próximo pixel de contorno se encontra. A Figura 21 mostra
os códigos para cada vizinhança (esquerda) e um exemplo de um contorno representado por
um código de cadeia (direita). Pode-se notar que escolher um ponto inicial diferente para o
contorno pode gerar diferentes representações de código de cadeia. Isso pode ser evitado
deslocando os números do código de cadeia de forma que resulte no inteiro de magnitude
mínima.
Figura 21. Códigos de cadeia para cada direção de vizinhança (esquerda) e uma representação de
código de cadeia de um contorno (direita).
A representação poligonal é uma seqüência de vértices que quando ligados simbolizam a
essência do contorno. A Figura 22 exemplifica esse tipo de representação, na qual existe um
compromisso entre a fidelidade do contorno e o overhead de codificação.
Figura 22. Representação poligonal.
O OpenCV provê várias maneiras de organizar os contornos obtidos a partir de uma
imagem. Por exemplo, os contornos podem ser guardados em uma árvore, onde um contorno
1C é pai de um contorno 2C se e somente se 1C contém 2C . A Figura 23 mostra como
contornos aninhados podem ser descritos por uma árvore.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
26 RITA Volume XXXX Número X 20XX
Figura 23. Representação hierárquica de contornos do OpenCV.
A função usada para extrair contornos de uma imagem binária é chamada
cvFindContours e é definida da seguinte forma:
int cvFindContours( CvArr* image, CvMemStorage* storage,
CvSeq** first_contour, int header_size,
int mode, int method, CvPoint offset);
O argumento image é a imagem binária de onde os contornos serão retornados. O
argumento storage é um recipiente de dados dos contornos. O argumento
first_countour é onde um ponteiro para o primeiro contorno detectado estará
disponível após a chamada da função. O argumento header_size é relativo ao tamanho
da estrutura do contorno. O argumento mode determina como os contornos devem ser
organizados. A Tabela 5 apresenta os modos de retorno dos contornos disponíveis e suas
descrições. O argumento method especifica a representação de contorno a ser usada. A
Tabela 6 descreve os métodos de representação disponíveis. O argumento offset é usado
para deslocar os pontos retornados de uma quantidade explícita de pixels. A função retorna o
número de contornos encontrados na imagem.
Tabela 5. Modos de retorno dos contornos do OpenCV.
Modo de retorno Descrição
CV_RETR_EXTERNAL Retorna apenas os contornos externos
extremos
CV_RETR_LIST Retorna todos os contornos numa lista
CV_RETR_CCOMP
Retorna os componentes conexos de uma
imagem (ver Rotulação de componentes
conexos)
CV_RETR_TREE Retorna todos os contornos
hierarquicamente em uma árvore
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 27
Tabela 6. Métodos de representação de contornos do OpenCV.
Método de representação Descrição
CV_CHAIN_CODE Representação de código de cadeia
CV_CHAIN_APPROX_NONE
Representação poligonal onde todos os
pixels de contorno são retornados como
vértices
CV_CHAIN_APPROX_SIMPLE
Representação poligonal onde apenas os
pontos extremos de segmentos
horizontais, verticais e diagonais do
contorno são retornados como vértices
CV_CHAIN_APPROX_TC89_L1 e
CV_CHAIN_APPROX_TC89_KCOS
Duas variantes da representação
poligonal de Teh-Chin [10]. Apenas os
pixels de contorno com curvatura alta
são retornados como vértices
CV_LINK_RUNS
Representação poligonal onde apenas os
pontos extremos de segmentos
horizontais de um contorno são
retornados como vértices
Após extrair os contornos de uma imagem, eles podem ser manipulados de forma a obter
informações tais como área e aproximação poligonal. A área do contorno é calculada usando
a função cvContourArea, descrita a seguir:
double cvContourArea( const CvArr* contour, CvSlice slice);
A área do contorno especificado no argumento contour é retornada pela função. Se
apenas uma secção de interesse do contorno tem de ser considerada no cálculo, ela pode ser
determinada usando o argumento slice.
A aproximação poligonal de um contorno é obtida usando a função cvApproxPoly:
CvSeq* cvApproxPoly( const void* src_seq, int header_size,
CvMemStorage* storage, int method,
double parameter, int parameter2);
O argumento src_seq é o contorno a ser aproximado. Os argumentos header_size e
storage têm a mesma finalidade dos de cvFindContours. O único valor aceito
atualmente para o argumento method é CV_POLY_APPROX_DP, que corresponde ao
algoritmo de aproximação poligonal de Douglas-Peucker [11]. O argumento parameter
determina o valor de tolerância a ser usado no algoritmo. O argumento parameter2
especifica se uma organização hierárquica deve ser organizada ou se o contorno é fechado ou
não.
O algoritmo é baseado na distância entre um vértice e um segmento de aresta e em uma
tolerância . Para começar o algoritmo, dois pontos extremos do polígono são conectados.
Essa conexão define a primeira aresta a ser usada. Depois, a distância entre cada vértice
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
28 RITA Volume XXXX Número X 20XX
remanescente e essa aresta é testada. Se existem distâncias maiores que , então o vértice
com a maior distância da aresta é adicionado à simplificação. O processo continua
recursivamente para cada aresta do passo atual até que todas as distâncias entre os vértices da
linha poligonal original e a simplificação estejam dentro da distância de tolerância. A Figura
24 ilustra o passo-a-passo do algoritmo.
Figura 24. Algoritmo de aproximação poligonal de Douglas-Peucker.
Rotulação de componentes conexos. A rotulação de uma imagem binária diz respeito ao
ato de atribuir um valor único para pixels que pertencem a uma mesma região conexa. Após
limiarizar a imagem de entrada, os pixels vizinhos que pertencem a objetos de interesse são
associados com um rótulo.
O conhecimento dos componentes conexos de uma imagem é bastante útil para o processo
de reconhecimento automatizado. Essa operação é comumente usada em aplicações de
reconhecimento de padrões, em tempo real. A rotulação está presente no pipeline da
biblioteca ARToolKit [6]. Os componentes conexos de uma imagem limiarizada são
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 29
rotulados para identificar regiões relativas a bordas de marcadores e aos padrões internos,
como pode ser visto na Figura 25.
Figura 25. Rotulação de componentes conexos usada no ARToolKit: imagem limiarizada (esquerda) e
resultados da rotulação (direita).
O princípio do algoritmo de rotulação consiste no escaneamento da imagem binária a
partir do pixel localizado mais acima e à esquerda à procura de pixels de objeto. Para cada
pixel de objeto, os seus pixels vizinhos que já foram escaneados são examinados. Existem
três opções para a rotulação de um pixel:
- Se não existem pixels de objeto entre os pixels examinados, um novo rótulo é criado e
atribuído ao pixel atual;
- Se existe um e apenas um pixel de objeto entre os pixels examinados, o rótulo deste
pixel é atribuído ao pixel atual;
- Se existem mais de um pixel de objeto entre os pixels examinados, um dos rótulos é
atribuído ao pixel atual e uma equivalência entre os diferentes rótulos é criada.
Quando todos os pixels de objeto são rotulados, os rótulos equivalentes são agrupados em
classes de equivalência, cada uma com um rótulo único. A imagem é então escaneada
novamente para resolver as equivalências e definir os componentes conexos.
No OpenCV, a rotulação é realizada usando a função cvFindContours com
CV_RETR_CCOMP setado como o argumento mode. Os componentes conexos são
organizados de uma maneira hierárquica. Os contornos externos dos componentes são
colocados no primeiro nível na árvore. Os contornos dos buracos presentes em um
componente são colocados no segundo nível.
2.3 Rastreamento de objetos
A biblioteca OpenCV possui algumas funções para rastreamento de objetos. Este
tutorial abordará três técnicas possíveis de implementação usando estas funções. Casamento
de Modelos (Template Matching) usa um modelo (template) simples para examinar a
imagem, armazenando os resultados. CamShift é um algoritmo adaptativo que tenta
encontrar um objeto baseado na retroprojeção do seu histograma. Fluxo Óptico (Optical
Flow) usa o fluxo de cada pixel para rastrear o objeto. Outras combinações podem ser
realizadas de forma a alcançar resultados diferentes.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
30 RITA Volume XXXX Número X 20XX
Casamento de Modelos. Casamento de Modelos é uma das formas mais simples de
encontrar um objeto em uma imagem. O objetivo desta técnica é examinar todos os pixels de
uma imagem e encontrar todas as instâncias de um objeto específico descrito por um modelo.
Um cenário de uso do Casamento de Modelos para reconhecimento de padrões em
tempo real pode ser encontrado em algumas aplicações de realidade aumentada sem
marcadores, tais como a ilustrada na Figura 26 e descrita em [12]. A diferença entre uma
região da imagem e o modelo de referência é minimizada. Em seguida, os parâmetros de uma
função que mapeia o modelo na imagem alvo são calculados, de forma que o rastreamento
pode ser realizado.
Figura 26. Rastreamento 3D com casamento de modelos – linhas verdes delimitam a imagem do
modelo (esquerda) e cena aumentada (direita).
O OpenCV oferece tal funcionalidade através da função cvMatchTemplate:
void cvMatchTemplate( const CvArr* image, const CvArr* templ,
CvArr* result, int method );
Todos os resultados da comparação são armazenados na variável result, que pode
ser interpretada como uma imagem. A aparência desta imagem estará diretamente
relacionada com o resultado do casamento do modelo com a imagem original: quanto mais
próximo o modelo casado, maior o valor do pixel armazenado, que poderá ser visualizado na
imagem como um pixel claro.
O OpenCV suporta diversos métodos de comparação do modelo com a imagem,
conforme a Tabela 7:
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 31
Tabela 7. Métodos para Casamento de Modelos
Método Descrição
CV_TM_SQDIFF A diferença quadrada entre o modelo e a
imagem
CV_TM_SQDIFF_NORMED A diferença quadrada normalizada
CV_TM_CCORR A correlação cruzada entre modelo e
imagem
CV_TM_CCORR_NORMED A correlação cruzada normalizada
CV_TM_CCOEFF O coeficiente de correlação
CV_TM_CCOEFF_NORMED O coeficiente de correlação normalizado
A Figura 27 mostra o exemplo de um modelo, e a Figura 28 ilustra os resultados
obtidos pelo casamento deste modelo com uma imagem de entrada.
Figura 27. Modelo utilizado pela técnica Casamento de Modelos.
Figura 28. Um exemplo de uso do Casamento de Modelos. A imagem original (cima) e o modelo
resultante (baixo).
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
32 RITA Volume XXXX Número X 20XX
CamShift. CamShift remete a “Continuous Adaptive Mean Shift”, ou seja
“Deslocamento Médio Adaptativo Contínuo”, sendo um algoritmo iterativo [13]. Ele utiliza
o algoritmo de deslocamento médio, que iterage para encontrar o centro de um objeto dada a
imagem da distribuição de probabilidade da sua cor 2D. Então, o algoritmo calcula o
tamanho e a orientação do objeto.
O fluxo de funcionamento do algoritmo é mostrado na Figura 29.
Figura 29. Fluxo de funcionamento do CamShift.
O algoritmo CamShift é descrito, passo a passo, abaixo:
1. Configurar a região de cálculo da distribuição de probabilidade para toda a
imagem.
2. Escolher o local inicial da janela de busca do deslocamento médio 2D.
3. Calcular a distribuição de probabilidade da cor na região 2D centralizada na
janela de busca em uma Region of Interest (ROI) um pouco maior que o
tamanho da janela de deslocamento médio.
4. Executar o algoritmo de deslocamento médio [13] para encontrar o centro da
janela de busca. Armazenar o momento (área ou tamanho) e a posição do
centro.
5. Para o próximo frame de vídeo, centralizar a janela de busca na posição média
armazenada no Passo 4 e configurar o tamanho da janela para uma função do
momento anterior encontrado. Ir para o Passo 3.
A função cvCamShift do OpenCV implementa o algoritmo CamShift:
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 33
int cvCamShift( const CvArr* prob_image, CvRect window,
CvTermCriteria criteria, CvConnectedComp*
comp, CvBox2D* box);
O parâmetro prob_image é a retroprojeção do histograma do objeto, que pode ser
calculada pela função cvCalcBackProject, como mostrado na Figura 30. O parâmetro
window é a janela de busca inicial que o algoritmo utilizará nas iterações. O parâmetro
criteria é usado para informar à aplicação sobre quando ela deve parar a busca. O
usuário pode especificar se o critério é o número de iterações ou um limiar épsilon que
define a similaridade das janelas. O parâmetro comp remete a “Componente Conectado”,
que contém informações sobre a convergência da janela de busca. As coordenadas da janela
podem ser recuperadas chamando comp->rect e a soma de todos os pixels dentro da
janela pode ser obtida pelo campo comp->area. O parâmetro box contém o tamanho e a
orientação do objeto no final da execução do algoritmo. A Figura 31 ilustra um exemplo de
rastreamento de face usando CamShift.
Figura 30. Exemplo da retroprojeção do histograma.
Figura 31. Exemplo de rastreamento com o CamShift.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
34 RITA Volume XXXX Número X 20XX
Fluxo Óptico. Fluxo Óptico é a técnica que mede a velocidade dos pixels de uma
imagem comparando os mesmos com o frame anterior. O deslocamento destes pixels ao
longo do tempo pode ser usado para estimar o movimento da câmera em aplicações como a
ilustrada na Figura 32, que rastreia faces em 3D [14].
Figura 32. Fluxo Óptico usado para rastreamento 3D.
Existem vários algoritmos que implementam Fluxo Óptico, e o OpenCV oferece
quatro deles. Estas implementações são explicadas na seqüência.
Técnica Lucas & Kanade. A tarefa de medir o fluxo óptico é reduzida a um sistema
linear aplicando a equação do fluxo óptico a um grupo de pixels adjacentes e assumindo que
todos eles têm a mesma velocidade [15]. Esta técnica é rápida o suficiente para ser usada em
tempo real porque não processa a imagem toda. A função do OpenCV que implementa esta
técnica é a cvCalcOpticalFlowLK, que é usada em um exemplo descrito na Seção 3.
void cvCalcOpticalFlowLK( const CvArr* prev, const CvArr*
curr, CvSize win_size, CvArr* velx,
CvArr* vely );
Os argumentos prev e curr são os dois frames adjacentes temporários da imagem
usados para calcular a velocidade. O parâmetro win_size é a janela média que funcionará
como base para toda a imagem. Os parâmetros velx e vely são, respectivamente, os
componentes horizontal e vertical do fluxo óptico para cada pixel. Eles têm o mesmo
tamanho das imagens de entrada.
O OpenCV também implementa uma abordagem piramidal do algoritmo Lucas &
Kanade [16]. O algoritmo de rastreamento piramidal procede da seguinte forma.
Primeiramente, o fluxo óptico é calculado em um nível de maior profundidade da pirâmide
mL . Então, o resultado deste cálculo é propagado até o nível mais alto para se obter um valor
inicial (uma tentativa) para o deslocamento dos pixels. Dado este valor inicial, o fluxo óptico
refinado é calculado no nível 0 (a imagem original). A função
cvCalcOpticalFlowPyrLK do OpenCV implementa este algoritmo.
void cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr*
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 35
curr, CvArr* prev_pyr, CvArr*
curr_pyr, const CvPoint2D32f*
prev_features, CvPoint2D32f*
curr_features, int count, CvSize
win_size, int level, char*
status, float* track_error,
CvTermCriteria criteria, int
flags );
Os argumentos prev_pyr e curr_pyr são buffers usados pelo algoritmo para
armazenar as imagens parciais. Os argumentos prev_features e curr_features são
os arrays de pontos a serem rastreados. O primeiro buffer contém os pontos e o segundo
buffer armazenará as novas posições encontradas. O argumento count define o número de
pontos a serem rastreados. O parâmetro win_size define o tamanho da janela de busca
para cada pirâmide, e level o nível piramidal máximo. O parâmetro status é um array
que contém 1 se a característica (feature) foi rastreada com sucesso e o fluxo foi calculado, e
0 em caso contrário. O argumento track_error é um parâmetro opcional que contém
diferenças entre patches ao redor dos pontos originais e deslocados. O parâmetro flags
pode ser configurado para salvar algum tempo de processamento, uma vez que é possível
assumir que um buffer de uma determinada pirâmide já foi calculado. As flags disponíveis
são listadas na Tabela 8.
Tabela 8. Flags do Fluxo Óptico Piramidal
Flag Descrição
CV_LKFLOW_PYR_A_READY A pirâmide para o primeiro frame é pré-
calculada antes da chamada
CV_LKFLOW_PYR_B_READY A pirâmide para o segundo frame é pré-
calculada antes da chamada
CV_LKFLOW_INITIAL_GUESSES
O array curr_features contém as
coordenadas iniciais das características
antes da chamada da função
Técnica Horn & Schunck. Esta função encontra o padrão do fluxo óptico, assumindo
que a velocidade aparente do padrão de brilho varia suavemente, praticamente em toda a
imagem [17].
A técnica de Fluxo Óptico Horn & Schunck é implementada no OpenCV através da
função cvCalcOpticalFlowHS:
void cvCalcOpticalFlowHS( const CvArr* prev, const CvArr*
curr, int use_previous, CvArr* velx,
CvArr* vely, double lambda,
CvTermCriteria criteria );
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
36 RITA Volume XXXX Número X 20XX
O parâmetro use_previous denota usar ou não o cálculo do campo de velocidade
prévia. O campo lambda é chamado multiplicador Lagrangiano (Lagrangian multiplier).
Ele deve ser menor para imagens com ruído e maior para imagens limpas e precisas.
Técnica de Casamento de Blocos (Block Matching). Esta técnica não utiliza
diretamente uma equação de fluxo óptico. Ao invés disso, ela usa uma técnica que lembra
casamento de padrões. Ela usa uma caixa definida dentro da primeira imagem e tenta
encontrar outra caixa de mesmo tamanho na segunda imagem, que seja similar a primeira.
Este algoritmo apresenta um resultado aproximado quando comparado às outras técnicas.
A função cvCalcOpticalFlowBM no OpenCV implementa esta técnica:
void cvCalcOpticalFlowBM( const CvArr* prev, const CvArr*
curr, CvSize block_size, CvSize
shift_size, CvSize max_range, int
use_previous, CvArr* velx, CvArr*
vely );
Os parâmetros block_size e shift_size definem as características do bloco
utilizado. O parâmetro max_range representa o tamanho dos pixels vizinhos ao redor do
bloco que serão examinados.
2.4 Detecção de objetos
A biblioteca OpenCV fornece a funcionalidade de detecção de objetos. Ela usa um
classificador, proposto por Paul Viola [18] e Rainer Lienhart [19], que identifica vários
objetos diferentes.
O processo inicia selecionando algumas centenas de amostras de visões do objeto
desejado, em diversos ângulos e sob diversas condições de iluminação. Este conjunto de
imagens é chamado de amostras positivas. Então, outro conjunto de imagens é escolhido,
contendo imagens arbitrárias não incluindo o objeto desejado. Este conjunto é chamado de
amostras negativas.
Em seguida, ambos os conjuntos são usados para treinar uma cascata de
classificadores ditos “boosted”. A palavra “cascata” no nome do classificador significa que o
classificador resultante consiste de diversos classificadores mais simples que são aplicados
subseqüentemente a uma ROI, até que em alguma etapa o candidato é rejeitado ou todas as
etapas são superadas. A palavra “boosted” significa que os classificadores, a cada etapa da
cascata, são complexos por si só e são formados por classificadores básicos usando uma
entre quatro técnicas de boosting diferentes (voto ponderado). Atualmente, as técnicas
Discrete Adaboost, Real Adaboost, Gentle Adaboost e Logitboost são suportadas [20].
Após o classificador ser treinado, pode ser usado para detectar o objeto em uma ROI.
O classificador é projetado de forma a, redimensionando a ROI, detectar objetos de tamanhos
diferentes.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 37
O OpenCV fornece um projeto completo para detecção de faces, que será detalhado
na Seção 3, implementando o classificador em cascata descrito anteriormente. Este projeto
pode ser facilmente adaptado para qualquer objeto, uma vez que um novo conjunto de
imagens pode ser usado na etapa de treinamento sem modificar muito o código. A Figura 33
mostra uma aplicação de detecção de objetos [21].
Figura 33. Exemplo de detecção de componentes de uma placa mãe.
O OpenCV disponibiliza algumas funções importantes que merecem um
detalhamento para melhor entendimento do conteúdo. A função cvLoad do OpenCV é
usada para importar o arquivo XML gerado durante a etapa de treinamento:
void* cvLoad( const char* filename, CvMemStorage* memstorage,
const char* name, const char** real_name);
O único parâmetro que precisa ser passado para esta função quando carregando uma
cascata é o filename, que deve conter o endereço do arquivo XML.
A função cvHaarDetectObjects retorna uma seqüência de quadrados para cada
objeto detectado:
CvSeq* cvHaarDetectObjects( const CvArr* image,
CvHaarClassifierCascade* cascade,
CvMemStorage* storage,
double scale_factor,
int min_neighbors, int flags,
CvSize min_size);
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
38 RITA Volume XXXX Número X 20XX
O parâmetro image representa a imagem onde os objetos devem ser detectados. A
saída da função cvLoad deve ser passada no parâmetro cascade. Durante a busca,
potenciais retângulos candidatos são armazenados no parâmetro storage. O
scale_factor é o fator de escala aplicado na janela de busca a cada subexame. O
parâmetro min_neighbors funciona agrupando retângulos vizinhos. A única flag
atualmente suportada pelo parâmetro flags é CV_HAAR_DO_CANNY_PRUNNING, que
usa o detector de arestas Canny para rejeitar algumas regiões da imagem que não contém o
objeto procurado. min_size define o tamanho mínimo da janela de detecção.
3 Aplicações de exemplo
A Intel também disponibiliza no pacote padrão do OpenCV alguns exemplos de
código. No subdiretório “samples”, localizado no diretório de instalação, tem códigos fonte
que podem auxiliar um usuário iniciante do OpenCV. Entre estes arquivos, alguns exemplos
merecem um detalhamento maior, levando em consideração sua relevância para detecção de
padrões e o uso de conceitos apresentados previamente neste tutorial. Estes exemplos serão
descritos na seqüência.
3.1 Detecção de quadrados
O exemplo da detecção de quadrados visa encontrar e destacar os quadrados contidos
nas imagens carregadas. Para encontrar os quadrados, o exemplo implementa uma função
que retorna uma seqüência contendo os vértices dos quadrados detectados.
Primeiramente, a seqüência que será usada para guardar o resultado é criada, tornando
possível qualquer futura adição de vértices. Em seguida, alguns filtros são aplicados para
destacar arestas, considerando vários limiares. A cada limiar, a função cvFindContours
separará cada contorno e armazenará os mesmos em um objeto de seqüência. Para cada
contorno, a função cvApproxPoly calcula um polígono aproximado baseado no resultado
de cvFindContours. Se algumas condições forem satisfeitas (tais como ter quatro
vértices e um contorno convexo), o polígono detectado é um retângulo. A Figura 34 ilustra
dois exemplos com os quadrados destacados pelo exemplo.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 39
Figura 34. Exemplo de detecção de quadrados.
3.2 Demo do CamShift
Este exemplo mostra como aplicar a cvCamShift para detectar um padrão em uma
imagem capturada por uma webcam, baseado na informação fornecida por um histograma. O
histograma contém a informação da cor de um padrão, e este demo usa o mesmo para
encontrar uma área na imagem que casa com os dados do histograma.
Para tornar o rastreamento possível, o usuário precisa fornecer como entrada para a
aplicação uma subárea do frame capturado. Esta área é tomada como base para calcular um
histograma de matizes, que servirá como padrão para vasculhar todo o frame procurando por
uma combinação correspondente. Um exemplo de histograma pode ser visto na Figura 35.
Este histograma funciona como uma identidade da cor.
Figura 35. Histograma de matizes da face detectada na Figura 36.
As funções usadas para criar e calcular o histograma são, respectivamente,
cvCreateHist e cvCalcHist.
Para encontrar o padrão em um frame deve-se calcular a retroprojeção do plano de
matizes, usando o histograma. A retroprojeção é uma imagem onde cada posição tem uma
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
40 RITA Volume XXXX Número X 20XX
probabilidade de compor um objeto tal qual o objeto rastreado. Para calcular a imagem
equivalente à retroprojeção da imagem, baseado em um histograma, o usuário precisa
chamar cvCalcBackProjection. O resultado da retroprojeção é ilustrado na Figura 36
(direita). Dado o resultado da retroprojeção, o algoritmo CamShift é aplicado para retornar a
“caixa de rastreamento”, que conterá o retângulo orientado que envolve a área casada. O
algoritmo CamShift é implementado pela função cvCamShift. Um exemplo do CamShift
sendo aplicado a uma face pode ser visto na Figura 36 (esquerda). O algoritmo visa buscar a
maior área com vizinhos conectados, tendo uma alta probabilidade de fazer parte da solução.
Figura 36. CamShift detectando uma face (esquerda) e retroprojeção da imagem (direita).
3.3 O rastreador Kanade Lucas
O Kanade Lucas é um rastreador (tracker) de características (features) popular,
implementado utilizando uma abordagem piramidal que usa fluxo óptico para calcular as
novas posições das características selecionadas. Uma característica pode ser explicada como
um ponto em uma cena praticamente rígida que pode ser casado com outro ponto no próximo
frame, mantendo o valor semântico de estar no mesmo ponto 3D da cena real.
Para gerar algumas características para popular a aplicação e testar o comportamento
do rastreador, uma função chamada cvGoodFeaturesToTrack pode ser usada. Esta
função seleciona os cantos mais fortes na imagem para ser as características que serão
rastreadas pela aplicação. Para refinar a posição dos cantos selecionados,
cvFindCornersSubPix pode ser usada adicionalmente à função apropriada. Um
resultado desta função pode ser visto na Figura 37.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 41
Figura 37. Um frame mostrando as “boas características para rastrear”.
No laço principal, o programa testa se o usuário adicionou manualmente uma nova
característica e também refina a posição deste ponto para casar com o canto mais próximo na
imagem. Isto é necessário porque cantos são mais fáceis de rastrear e calcular o fluxo óptico.
Para calcular a próxima posição das características mostradas no último frame, a
função cvCalcOpticalFlowPyrLK é usada. Esta função implementa o rastreador
Kanade Lucas e precisa de algumas imagens temporárias para aplicar a abordagem
piramidal. Elas atuam como imagens subamostradas que ajudam o algoritmo a rastrear fluxos
ópticos, com movimentos grandes. O resultado desta função é a nova posição dos pontos
fornecidos como parâmetros.
3.4 Detecção de faces
O exemplo de detecção de faces usa o classificador Haar para reconhecer um padrão
de face. O exemplo carrega um classificador Haar pré-treinado e usa o mesmo para detectar
os objetos no frame atual. O classificador Haar usado neste exemplo é o
HaarClassifierCascade, que difere de outros classificadores por usar em cascata múltiplos
classificadores Haar.
Para carregar o classificador o exemplo usa a função cvLoad e o resultado é definido
como sendo do tipo cvHaarClassifierCascade. Este classificador será usado como parâmetro
da função cvHaarDetectObjects. Com esta função, o usuário pode encontrar todas as
regiões que casam com os objetos que a cascata foi treinada. Como valor de retorno a função
cvHaarDetectObjects fornece uma seqüência de retângulos contendo os objetos
casados. Uma instanciação em tempo de execução da detecção de faces é mostrada na Figura
38.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
42 RITA Volume XXXX Número X 20XX
Figura 38. Classificador Haar detectando faces.
4 Considerações finais
Este tutorial apresentou o OpenCV, composto por uma grande quantidade de funções
relacionadas com reconhecimento de padrões. Estas funções são básicas para qualquer
projeto de processamento de imagens que visa detectar um padrão específico ou genérico. As
funções básicas do OpenCV para detecção de padrões são fáceis de usar e seguem uma
estrutura padronizada, compartilhando parâmetros comuns fornecidos pela biblioteca.
Além da simplicidade do framework, o OpenCV traz uma biblioteca para
desenvolvimento de interfaces, que agiliza o período de prototipação de um teste ou
aplicação usando o OpenCV. Esta biblioteca é chamada HighGUI e um exemplo de código é
mostrado no Apêndice, em anexo.
Referências
[1]. J. Shi e C. Tomasi, “Good Features to Track,” Proceedings of the IEEE Conference on
Computer Vision and Pattern Recognition, Washington DC, EUA, 1994.
[2]. C. Tomasi e R. Manduchi. “Bilateral Filtering for Gray and Color Images”,
Proceedings of the International Conference on Computer Vision, Bombay, India, 1998.
[3]. C. Harris. “Tracking with Rigid Objects”. MIT Press, 1992.
[4]. H. Scharr. “Digitale Bildverarbeitung und Papier: Texturanalyse mittels Pyramiden und
Grauwertstatistiken am Beispiel der Papierformation”. Diplomarbeit, Fakultät für Physik
und Astronomie, Ruprecht-Karls-Universität Heidelberg, 1996.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 43
[5]. M. Uenohara e T. Kanade. “Vision-Based Object Registration for Real-Time Image
Overlay”. Journal of Cognitive Neuroscience 3, 71–86, 1991.
[6]. H. Kato e M. Billinghurst. “Marker Tracking and HMD Calibration for a Video-Based
Augmented Reality Conferencing System”, Proceedings of the Workshop on Augmented
Reality, San Francisco, EUA, 1999.
[7]. D. Koller, K. Daniilidis e H. Nagel. “Model-Based Object Tracking in Monocular
Image Sequences of Road Traffic Scenes”. International Journal of Computer Vision
10, 257–281, 1993.
[8]. J. Matas, C. Galambos e J. Kittler. “Progressive Probabilistic Hough Transform”,
Proceedings of the British Machine Vision Conference, Southampton, UK, 1998.
[9]. S. Suzuki e K. Abe. “Topological Structural Analysis of Digital Binary Images by
Border Following”. Graphical Model and Image Processing 30, 32-46, 1985.
[10]. C. The e R. Chin. “On the Detection of Dominant Points on Digital Curves”. IEEE
Transactions on Pattern Analysis and Machine Learning 11, 859-872, 1989.
[11]. D. Douglas e T. Peucker. "Algorithms for the Reduction of the Number of Points
Required to Represent a Digitized Line or its Caricature". The Canadian Cartographer
10, 112-122, 1973.
[12]. Lepetit, V., Lagger, P. e Fua, P. “Randomized Trees for Real-Time Keypoint
Recognition”, Conference on Computer Vision and Pattern Recognition, 2005.
[13]. Bradski, G. “Computer Vision Face Tracking as a Component of a Perceptual User
Interface”, Workshop on Applications of Computer Vision, 1998.
[14]. Basu, S., Essa, I. e Pentland, A. “Motion Regularization for Model-Based Head
Tracking”, International Conference on Pattern Recognition, 1996.
[15]. Lucas, B. e Kanade, T. “An Iterative Image Registration Technique with an Application
to Stereo Vision”, International Joint Conference on Artificial Intelligence, 1981.
[16]. Bouguet, J.-Y. “Pyramidal Implementation of the Lucas Kanade Feature Tracker”, parte
da documentação do OpenCV.
[17]. Horn, B. e Schunck, B. “Determining Optical Flow”. Artificial Intelligence, 17, 185-
203, 1981.
[18]. Viola, P. e Jones, M. “Rapid Object Detection using a Boosted Cascade of Simple
Features”, Conference on Computer Vision and Pattern Recognition, 2001.
[19]. Lienhart, R. e Maydt, J. “An Extended Set of Haar-like Features for Rapid Object
Detection”, International Conference on Image Processing, 2002.
[20]. Freund, Y. e Schapire, R. “A Short Introduction to Boosting”, Journal of Japanese
Society for Artificial Intelligence, 14, 771-780, 1999.
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
44 RITA Volume XXXX Número X 20XX
[21]. Teixeira, J. M., Silva, D., Moura, G., Costa, L. H., Teichrieb, V. e Kelner, J. “miva:
Constructing a Wearable Platform Prototype”, Symposium on Virtual and Augmented
Reality, 2007.
Apêndice
Este apêndice descreve como construir uma interface simples para testar ou prototipar
algumas funcionalidades do OpenCV, usando o framework HighGUI.
O framework HighGUI é disponibilizado com a distribuição padrão do OpenCV e
visa simplificar tarefas básicas, tais como criar e manipular janelas, exibir imagens em
janelas, criar controles para ajustar parâmetros de aplicações e outras funções para manipular
imagens, vídeos e captura de câmera. Funcionalidades como escutar eventos de mouse
também são gerenciadas pelo framework HighGUI.
O trecho de código abaixo mostra o vídeo capturado por uma câmera e implementa
uma função básica que escuta os eventos do mouse.
#include "cv.h"
#include "highgui.h"
#ifdef _EiC
#define WIN32
#endif
//escuta os eventos do mouse
void on_mouse(int event, int x, int y, int flags, void* param)
{
//testar todos os eventos possiveis
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
break;
case CV_EVENT_RBUTTONDOWN:
break;
case CV_EVENT_MBUTTONDOWN:
break;
case CV_EVENT_LBUTTONUP:
break;
case CV_EVENT_RBUTTONUP:
break;
case CV_EVENT_MBUTTONUP:
break;
case CV_EVENT_LBUTTONDBLCLK:
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
RITA Volume XXXX Número X 20XX 45
break;
case CV_EVENT_RBUTTONDBLCLK:
break;
case CV_EVENT_MBUTTONDBLCLK:
break;
default: //CV_EVENT_MOUSEMOVE
}
}
int main( int argc, char** argv )
{
int c = 0;
//Objeto capture usado para captura de video
CvCapture* capture = 0;
//Imagens usadas como buffers na captura de video
IplImage *frame, *frame_copy = 0;
//Captura da camera padrao
capture = cvCaptureFromCAM(-1);
//Cria uma janela chamada "result"
cvNamedWindow( "result", 1 );
//Configura o callback do mouse como sendo a funcao
//descrita antes da main
cvSetMouseCallback( "result", on_mouse, 0 );
if( capture )
{
//laco de captura
for(;;)
{
if( !cvGrabFrame( capture ))
break;
frame = cvRetrieveFrame( capture );
if( !frame )
break;
if( !frame_copy )
frame_copy = cvCreateImage(
cvSize(frame->width,frame->height),
IPL_DEPTH_8U, frame->nChannels );
if( frame->origin == IPL_ORIGIN_TL )
cvCopy( frame, frame_copy, 0 );
else
Reconhecimento de padrões em tempo real utilizando a biblioteca OpenCV
46 RITA Volume XXXX Número X 20XX
cvFlip( frame, frame_copy, 0 );
//Exibe o frame na janela
cvShowImage( "result", frame_copy );
//Testa se o usuario pressionou a tecla ESC
c = cvWaitKey(10);
if( (char)c == 27 )
break;
}
cvReleaseImage( &frame_copy );
cvReleaseCapture( &capture );
}
cvDestroyWindow("result");
return 0;
}