VISAO COMPUTACIONAL APLICADA~ A DETECC˘ AO E AO...
Transcript of VISAO COMPUTACIONAL APLICADA~ A DETECC˘ AO E AO...
VISAO COMPUTACIONAL APLICADA A DETECCAO E AO
RECONHECIMENTO FACIAL
Gustavo Martins da Silva Nunes
Projeto de Graduacao apresentado ao Curso
de Engenharia Eletronica e de Computacao
da Escola Politecnica, Universidade Federal
do Rio de Janeiro, como parte dos requisitos
necessarios a obtencao do tıtulo de Enge-
nheiro.
Orientador: Jose Gabriel Rodrıguez Car-
neiro Gomes
Rio de Janeiro
Marco 2016
UNIVERSIDADE FEDERAL DO RIO DE JANEIRO
Escola Politecnica - Departamento de Eletronica e de Computacao
Centro de Tecnologia, bloco H, sala H-217, Cidade Universitaria
Rio de Janeiro - RJ CEP 21949-900
Este exemplar e de propriedade da Universidade Federal do Rio de Janeiro, que
podera incluı-lo em base de dados, armazenar em computador, microfilmar ou adotar
qualquer forma de arquivamento.
E permitida a mencao, reproducao parcial ou integral e a transmissao entre bibli-
otecas deste trabalho, sem modificacao de seu texto, em qualquer meio que esteja
ou venha a ser fixado, para pesquisa academica, comentarios e citacoes, desde que
sem finalidade comercial e que seja feita a referencia bibliografica completa.
Os conceitos expressos neste trabalho sao de responsabilidade do(s) autor(es).
iii
DEDICATORIA
Dedico este trabalho aqueles que estiveram comigo durante todo esse tempo de
faculdade e que acompanharam de perto o seu desenvolvimento. O projeto aqui
exposto e fruto nao so de um ano de trabalho, mas sim de toda uma formacao, que
comecou desde o meu primeiro dia na UFRJ.
iv
AGRADECIMENTO
Primeiramente, gostaria de agradecer a minha famılia, especialmente a minha mae
Ana Lucia, ao meu pai Nelson e a minha irma Luciana, que estiveram sempre ao meu
lado em todos os momentos, me apoiando e me motivando. Sou muito grato a toda
a criacao, atencao, carinho e educacao que sempre me deram, dao e continuarao a
dar, pois, sem essa base, tenho certeza que nao teria sido possıvel chegar onde estou
hoje.
Agradeco, tambem, aqueles que estiveram junto comigo nessa caminhada, sobre-
tudo aos meus amigos Carlos Pedro Vianna Lordelo, Felipe Gonzalez Tubio Ma-
chado, Felipe Rembold Petraglia, Gabriel de Vilhena Torres, Henrique Dias de Ale-
xandria Goncalves, Joao Victor da Fonseca Pinto, Julio de Castro Vargas Fernandes,
Leonardo Oliveira dos Santos, Lucas Daniel Tavares Oliveira, Michel Morais Ferreira,
Pedro Angelo Medeiros Fonini e Pedro Bandeira de Mello Martins, que sempre es-
tiveram presentes tanto nos momentos de divertimento e descontracao (que sempre
rendem boas risadas), quanto nos de seriedade e estudo. Eles nao so me ajuda-
ram nos momentos difıceis, quando achava que nada daria certo, como tambem me
inspiraram e inspiram ate hoje a tentar sempre melhorar e a aprender mais.
Por fim, sou grato aos professores que tive, em especial a dois: a professora
Mariane, que ofereceu minha primeira iniciacao cientıfica, me dando a oportunidade
de trabalhar na area de Processamento de Imagens, ate entao desconhecida por mim,
a qual me despertou tamanho interesse, que culminou na decisao de realizar esse
projeto; e ao professor Jose Gabriel, que aceitou orientar esse trabalho e sempre se
dispos, calmamente e pacientemente, a tirar minhas duvidas e a me acalmar, quando
achava que tudo estava errado.
A todos voces, o meu mais profundo e sincero obrigado.
v
RESUMO
Esse projeto consiste no desenvolvimento de um sistema de deteccao e reconheci-
mento facial, atraves do emprego de tecnicas da area de Visao Computacional. Ele
e composto por 3 modulos, cada um encarregado de uma tarefa distinta. O modulo
de deteccao de faces consiste em uma cascata de classificadores, treinados a partir
de uma tecnica de boosting chamada AdaBoost, responsavel por distinguir faces de
nao faces. Dentre os diversos testes conduzidos para avalia-lo, destaca-se que ele foi
capaz de alcancar taxas de erro de, aproximadamente, 1%. O segundo modulo e um
escaneador, responsavel por localizar uma face presente em uma imagem, aplicando
o detector obtido do modulo anterior. O escaneador apresentou taxas de erro de
50%, sendo um dos principais motivos por esse rendimento o metodo adotado para
se efetuar a localizacao final da face. Por fim, o modulo de reconhecimento analisa
a face extraıda pelo escaneador e a identifica, comparando-o com uma base de faces
ja conhecida por ele. A construcao do reconhecedor utiliza a abordagem conhecida
como Eigenfaces. Atraves da modificacao de alguns parametros desse modulo, os
testes conduzidos resultaram em taxas de erros variando entre, aproximadamente,
3% e 23%.
Palavras-Chave: Reconhecimento Facial, AdaBoost, Eigenfaces, Visao Computa-
cional
vi
ABSTRACT
This project consists in the development of a system capable of detecting and
recognizing faces, using techniques from the Computer Vision field of study. It is
divided into 3 parts, where each one is responsible for a specific task. The facial
detection module consists of a cascade of classifiers, which were trained through
the application of a boosting technique called AdaBoost, and it distinguishes faces
from non-faces. Among the tests conducted to evaluate the detector, it is worth
noting, that it could achieve error rates of, approximately, 1%. The second part is
a scanner, whose task is to locate a face, which is present in an image, by applying
the previously trained detector. The scanner yielded error rates of 50% and one of
the main reasons for this performance was the method used to pinpoint the final
location of the face. Finally, the face recognizer analyzes the face extracted from the
scanner and identifies it, by comparing it to a set that contains well-known faces.
The approach used to build the recognizer is known as Eigenfaces. By modifying
some parameters of this module, the conducted tests yielded error rates ranging
between, approximately, 3% and 23%.
Keywords: Face Recognition, AdaBoost, Eigenfaces, Computer Vision
vii
SIGLAS
UFRJ - Universidade Federal do Rio de Janeiro
AdaBoost - Adaptive Boosting
SVM - Support Vector Machines
PCA - Principal Component Analysis
KNN - K-Nearest-Neighbors
LBP - Local Binary Patterns
CPU - Central Processing Unit
FERET - Face Recognition Technology
viii
Sumario
1 Introducao 1
1.1 Tema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Delimitacao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Justificativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Metodologia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.6 Descricao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2 Fundamentacao Teorica 7
2.1 AdaBoost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Eigenfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.1 PCA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3 Implementacao 20
3.1 Treinamento do Detector . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.1 Ideia Principal . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.2 Estruturacao do codigo . . . . . . . . . . . . . . . . . . . . . . 22
3.2 Escaneamento de Faces em Imagens . . . . . . . . . . . . . . . . . . . 35
3.3 Treinamento do Reconhecedor . . . . . . . . . . . . . . . . . . . . . . 39
4 Resultados 47
4.1 Detector de Faces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.2 Escaneador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.3 Reconhecedor Facial . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
ix
5 Conclusoes 60
5.1 Trabalhos Futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Bibliografia 64
A Bases de Face Utilizadas 66
B Codigo 67
B.1 Treinamento do Detector de Faces . . . . . . . . . . . . . . . . . . . . 67
B.2 Escaneador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
B.3 Reconhecedor Facial . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
x
Lista de Algoritmos
1 Algoritmo de treino AdaBoost . . . . . . . . . . . . . . . . . . . . . . 10
2 Algoritmo do detector . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3 Treino de um Estagio . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4 Algoritmo do Escaneador . . . . . . . . . . . . . . . . . . . . . . . . . 37
5 Treino do Reconhecedor . . . . . . . . . . . . . . . . . . . . . . . . . 40
6 Algoritmo de Reconhecimento . . . . . . . . . . . . . . . . . . . . . . 45
xi
Lista de Figuras
3.1 Topologia da cascata de classificadores que compoe o sistema de de-
teccao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2 Exemplos de amostras positivas de face usadas no treino do classificador 24
3.3 Exemplos de amostras negativas de face usadas no treino do classificador 25
3.4 Diferentes tipos de amostras negativas de cenario usadas no treino do
classificador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.5 Exemplo do calculo da imagem integral . . . . . . . . . . . . . . . . . 28
3.6 Mascaras utilizadas no calculo de features . . . . . . . . . . . . . . . 29
3.7 Possıveis posicionamentos das mascaras na imagem integral . . . . . . 30
3.8 Exemplos de amostras utilizadas de cada uma das classes utilizadas
no treino do reconhecedor . . . . . . . . . . . . . . . . . . . . . . . . 41
3.9 Amostras da Figura 3.8 redimensionadas para a resolucao 30x30 . . . 42
3.10 “Face media” do conjunto de treinamento utilizado . . . . . . . . . . 42
3.11 Eigenfaces escolhidas . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.1 Exemplos de amostras negativas de face . . . . . . . . . . . . . . . . 48
4.2 Exemplos de amostras obtidas pelo escaneador e utilizadas no treino . 50
4.3 Amostras de faces enquadradas, nao obtidas pelo escaneador . . . . . 51
4.4 Exemplo da influencia de diferentes iluminacoes na classificacao do
detector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.5 Exemplo de imagem escaneada . . . . . . . . . . . . . . . . . . . . . 52
4.6 Exemplo de falso positivo, correspondente a face cortada, encontrado
pelo escaneador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
4.7 Classificacoes do detector a cada janela de busca aplicada . . . . . . . 54
4.8 Amostra erroneamente reconhecida . . . . . . . . . . . . . . . . . . . 56
4.9 Grafico das distancias de cada amostra de treino para a da Figura 4.8 56
xii
4.10 Grafico das distancias de cada amostra de treino para a da Figura
4.8, com os 15 vizinhos proximos realcados . . . . . . . . . . . . . . . 57
4.11 Amostra erroneamente reconhecida quando se utiliza muitos vizinhos 58
4.12 Grafico das distancias de cada amostra de treino para a da Figura 4.11 58
4.13 Amostra corretamente reconhecida . . . . . . . . . . . . . . . . . . . 59
4.14 Grafico das distancias de cada amostra de treino para a da Figura 4.13 59
B.1 Fluxograma das funcoes chamadas pelo script mainCascade.m . . . . 67
B.2 Fluxograma das funcoes chamadas pelo script mainScanner.m . . . . 119
B.3 Fluxograma das funcoes chamadas pelo script mainRecognizer.m . . . 132
xiii
Lista de Tabelas
4.1 Resultados do detector . . . . . . . . . . . . . . . . . . . . . . . . . . 49
4.2 Quantidade de amostras classificadas corretamente e erroneamente
pelo detector no Teste 1 . . . . . . . . . . . . . . . . . . . . . . . . . 49
4.3 Quantidade de amostras classificadas corretamente e erroneamente
pelo detector no Teste 2 . . . . . . . . . . . . . . . . . . . . . . . . . 49
4.4 Quantidade de amostras classificadas corretamente e erroneamente
pelo detector no Teste 3 . . . . . . . . . . . . . . . . . . . . . . . . . 50
4.5 Quantidade de amostras classificadas corretamente e erroneamente
pelo detector no Teste 4 . . . . . . . . . . . . . . . . . . . . . . . . . 50
4.6 Resultados do escaneador . . . . . . . . . . . . . . . . . . . . . . . . 52
4.7 Resultados do reconhecedor facial . . . . . . . . . . . . . . . . . . . . 55
xiv
Capıtulo 1
Introducao
1.1 Tema
O trabalho consiste no estudo de algoritmos responsaveis pelo reconhecimento
automatico de faces em uma imagem, atraves do emprego de tecnicas de visao com-
putacional (Computer Vision). Sendo assim, o problema e descobrir quais aborda-
gens tais algoritmos utilizam para fazer com que uma maquina detecte e reconheca
uma face, i.e, que tipos de elementos, presentes na imagem da face de um indivıduo,
permitem caracteriza-la unicamente pelo computador.
1.2 Delimitacao
Dada a abrangencia de situacoes em que uma face aparece em uma imagem,
para delimitar o escopo de atuacao, o presente trabalho se compromete, somente, a
reconhecer faces frontais em imagens, ou seja, aquelas que exibem claramente seus
elementos frontais (olhos, boca, nariz, sobrancelhas e bochechas), nao admitindo,
com isso, faces enquadradas em qualquer outra angulacao (faces em perfil, vistas
de cima ou de baixo, etc). Alem disso, o reconhecimento se limita a uma face por
imagem.
1
1.3 Justificativa
Dados visuais descrevem minuciosamente um fato. A riqueza de detalhes de uma
fotografia, por exemplo, dificilmente conseguiria ser descrita por linguagem escrita
ou oral. Com isso, e possıvel extrair uma grande gama de informacoes de uma
imagem, atraves da aplicacao de tecnicas de processamento adequadas.
Cada imagem e obtida atraves de uma camera e de certas condicoes de filmagem.
A camera possui elementos proprios, tais como lente, capacidade de resolucao, opcao
de iluminacao (“flash”, por exemplo), entre outros. As condicoes de filmagens podem
ser diversas: angulacao e distancia da camera para o objeto, iluminacao do ambiente,
etc. Esses dois fatores definem, portanto, caracterısticas especıficas da imagem.
Nesse sentido, pode-se afirmar que ha uma certa unicidade entre as imagens, visto
que cada uma apresenta propriedades proprias que a distinguem das outras.
Reconhecer pessoas em uma imagem e um tipo de informacao bastante buscado.
Sistemas de vigilancia, por exemplo, captam diversas imagens de cameras de segu-
ranca. Por meio da analise dessas imagens, pode-se desejar saber se uma pessoa
entrou ou saiu de um banco e, caso alguma das imagens registre uma atitude sus-
peita da mesma, identificar essa pessoa. Em redes sociais, a partir da analise de
uma foto, pode-se saber quem sao as pessoas presentes nela e, caso tenham um per-
fil cadastrado, direcionar o usuario para tais perfis, facilitando o estabelecimento de
contato entre as pessoas.
Faces, de um modo geral, apresentam elementos unicos que as diferem de outros
objetos, como um lapis ou uma bola. Porem, ao mesmo tempo em que possuem
caracterısticas comuns, a face de cada indivıduo possui alguma(s) particularidade(s)
capaz(es) de diferencia-la da de outro. Alem disso, a variedade de possibilidades com
as quais uma imagem pode ser obtida torna a identificacao de uma face uma tarefa
desafiadora, ja que certos elementos faciais podem ser realcados ou omitidos.
Esses sao alguns exemplos do porque a area de reconhecimento facial ser tao
importante. Ela surge a partir do interesse (e da dificuldade) de se identificar pessoas
em imagens. Suas diversas aplicacoes incentivam seu constante desenvolvimento.
2
Sob a otica dessas aplicacoes e que se insere e se busca construir o trabalho em
questao.
1.4 Objetivos
O objetivo final desse trabalho consiste em desenvolver um sistema reconhecedor
de faces frontais presentes em imagens. Pode-se subdividir esse objetivo em outros
intermediarios:
• Determinar elementos que melhor caracterizam uma face;
• Identificar a posicao exata em que se localiza a face numa imagem;
• Extrair padroes especıficos de uma face, capazes de distinguı-la de outras
1.5 Metodologia
Inicialmente, sera preciso desenvolver um algoritmo que sera constituıdo por um
classificador, responsavel por detectar faces. O algoritmo de treinamento que sera
utilizado para construir o classificador sera o AdaBoost (ou “Adaptive Boosting”)
[1].
Para poder implementar o AdaBoost, primeiramente, montam-se duas bases de
dados: uma destinada ao treinamento e outra, a validacao do classificador. A mon-
tagem dessas bases consistira na inclusao de amostras positivas e negativas. As
amostras negativas correspondem a imagens que nao representam faces, as quais se
subdividem em elementos de cenario (ceu, arvores, casas, etc), faces descentraliza-
das (ou nao enquadradas) e faces “cortadas”, ou seja, que nao apresentam todos os
elementos frontais necessarios para sua deteccao (olhos, boca, nariz e sobrancelhas);
as amostras positivas correspondem a imagens que exibam uma unica face frontal
de uma determinada pessoa.
3
O classificador sera composto por diversos estagios, cada um treinado pelo algo-
ritmo AdaBoost e utilizando diferentes conjuntos de treinamento [2]. A diferenca
do conjunto de um estagio para o conjunto do estagio anterior e que ele utilizara
amostras negativas que foram incorretamente classificadas como face pelo estagio
anterior. Assim, os estagios subsequentes buscarao por caracterısticas especıficas
dessas amostras negativas, de modo a diferencia-las das positivas.
A eficiencia do detector de faces sera medida atraves da observacao dos dados
estatısticos obtidos de seu desempenho, quando aplicado sobre as amostras que
compoem o conjunto de validacao. Os principais dados monitorados serao as taxas
de falso positivo e negativo (amostras de face classificadas como nao-face e amostras
de nao-face classificadas como face, respectivamente) e a taxa de erro.
A escolha desse metodo para se construir o detector e uma dentre as diversas
possıveis abordagens desenvolvidas no campo de deteccao facial e exploradas em
outros trabalhos. Rowley et al. [3], por exemplo, apresentam em seu trabalho um
sistema de detector facial composto por diversas redes neurais. Em Osuna et al.
[4], e discutida uma outra tecnica de Aprendizado de Maquina, conhecida por SVM
(Support Vector Machines) e uma das aplicacoes apresentadas para tal e no treino
de um sistema de deteccao facial. Em todas as tecnicas aqui citadas (inclusive, a
deste trabalho) constroem o detector de faces utilizando imagens em tons de cinza de
faces. Porem, tambem e possıvel efetuar a deteccao em imagens coloridas, conforme
apresentado por Hsu et al., os quais desenvolveram um metodo de deteccao que faz
uso de tecnicas de compensacao de iluminacao e transformacoes nao-lineares de cor
[5].
Apos essa fase, o algoritmo sera, entao, expandido, de forma a possibilitar que o
detector, previamente construıdo, detecte faces frontais em imagens que as conte-
nham, isto e, em imagens que, alem de faces frontais, contem, tambem, elementos
de cenario. O algoritmo fara uma busca na imagem utilizando diversas sub-janelas,
as quais possuirao diferentes resolucoes, posicionando-as em diversos pontos. O de-
tector, entao, para cada uma das sub-janelas, analisara e classificara como face ou
nao face. Cada uma das sub-janelas classificadas como face possui um parametro
4
associado a ela, retornado pelo detector, e que corresponde a um nıvel de confianca,
segundo o qual a sub-janela em questao representa, de fato, uma face. Mediante
a analise desse parametro, sera escolhida a sub-janela que melhor enquadra e, por-
tanto, localiza a face na imagem.
Para se poder efetuar o reconhecimento, devera ser montada uma base de imagens
de faces, cada uma identificada por um nome, a qual sera usada no treinamento do
reconhecedor. Sobre essas imagens sera aplicada a tecnica denominada Eigenfaces,
cuja ideia e representar cada uma dessas imagens como sendo um ponto em um
“espaco de faces”. Para obter a base desse espaco, o algoritmo utiliza a abordagem
denominada Analise dos Componentes Principais (Principal Component Analysis -
PCA) [6]. O mesmo algoritmo e, entao, aplicado a imagem que se deseja reconhecer,
transformando-a em um ponto no espaco de faces. Para sua identificacao, aplica-
se o algoritmo chamado K-Nearest Neighbor, o qual calcula a distancia do ponto
em questao em relacao a cada um dos pontos obtidos das imagens de treino. As
“K”menores distancias (K sendo um numero ımpar) serao analisadas e a face, sera,
entao, classificada como sendo de uma determinada pessoa se a maior parte das
“K”distancias corresponderem a amostras de uma mesma pessoa. O exito desse
trabalho consistira na taxa de acerto dessas identificacoes.
Assim como na area de deteccao facial, o problema de reconhecimento facial e
amplamente estudado e diversos trabalhos nessa area foram conduzidos, os quais
propoem uma grande gama de diferentes abordagens para solucionar esse problema.
Em Wiskott et al., por exemplo, busca-se representar as faces como grafos de imagens
e a identificacao das pessoas e feita por meio de uma comparacao entre esses grafos
[7]. Ja Ahonen et al. [8] propoem realizar o reconhecimento aplicando um metodo
chamado “Local Binary Patterns (LBP)”, o qual pode ser utilizado para descrever
caracterısticas de textura de uma imagem. Uma abordagem diferente e utilizada por
Wright et al., a qual consiste em aplicar a teoria de representacao esparsa de sinais
(que, no caso, sao imagens de face) para resolver o problema de reconhecimento
[9]. Dada a grande quantidade de sistemas de reconhecimento disponıveis, diversas
comparacoes entre cada sistema sao feitas. Phillips et al. apresentam em seu traba-
lho um programa, conhecido como “FERET”(Face Recognition Technology), o qual
5
nao so fornece uma grande base de imagens de face, que pode ser usada para testar
os diversos sistemas de reconhecimento, como tambem estabelece criterios de teste
para esses sistemas, possibilitando, assim, analisar o desempenho de cada um [10].
1.6 Descricao
Aqui, esta explicada brevemente a estruturacao de capıtulos desse trabalho. O
Capıtulo 2 contem os conhecimentos teoricos que fundamentam as tecnicas aplicadas
nesse projeto. Nele, portanto, sao explicadas as abordagens conhecidas como Ada-
Boost e Eigenfaces. Alem disso, e dada uma breve explicacao sobre PCA, tecnica
utilizada na segunda abordagem. No Capıtulo 3 e explicado como foi feita a imple-
mentacao de todo o sistema de reconhecimento, incluindo as fontes sobre as quais ela
se baseou e todas as decisoes tomadas. Devido a estruturacao do sistema, cada um
dos seus modulos foi separado em secoes distintas, nas quais sao dadas explicacoes
sobre o modulo em questao.
O Capıtulo 4 expoe os resultados do desempenho do sistema. Assim como no
Capıtulo 3, cada modulo do sistema e retratado em uma secao especıfica, em que
estao presentes comentarios e analises mais detalhadas sobre os resultados referentes
ao modulo em questao. O Capıtulo 5 possui as conclusoes sobre o trabalho feito, com
as impressoes do autor acerca dele, levando-se em conta os resultados obtidos. Nesse
capıtulo encontram-se, tambem, sugestoes de trabalhos futuros. No Apendice A
estao listadas as bases de face utilizadas, enquanto que no Apendice B esta exposto,
na ıntegra, o codigo desenvolvido.
6
Capıtulo 2
Fundamentacao Teorica
2.1 AdaBoost
A area conhecida como Aprendizado de Maquina (ou Machine Learning) tem como
objetivo desenvolver uma inteligencia artificial capaz de resolver um determinado
problema. A ideia e “ensinar” a maquina sobre o problema em questao, de modo
que ela gere conhecimento suficiente acerca do mesmo, possibilitando soluciona-lo
de forma automatica. Diversas abordagens de ensinamento foram criadas, dentre
elas uma conhecida como Boosting, a qual foi utilizada nesse projeto e cuja teoria
e apresentada por Schapire [1]. Antes de explicar no que consiste tal abordagem,
serao discutidos alguns conceitos centrais de Aprendizado de Maquina.
Os problemas que a area em questao se propoe a resolver sao de classificacao,
ou seja, categorizar amostras dele em diferentes conjuntos ou classes. Para isso,
dispoe-se de uma fonte de informacoes sobre esse problema, de onde os dados sao
obtidos. Atraves da analise de diversos dados, criam-se regras de classificacao, as
quais diferenciam esses dados em diversas classes. Por meio delas, portanto, a
maquina e capaz de prever automaticamente a que classe pertencem novas amostras,
ou instancias, desse problema, que nunca antes foram analisadas por ela.
O conjunto do qual sao retiradas as amostras que sao expostas a maquina, para
que ela gere tais regras, chama-se conjunto de treinamento. Um outro conjunto, com-
posto por amostras nao usadas no treino, e necessario, para se verificar a qualidade
do classificador treinado, ou seja, sua capacidade de generalizacao do problema, ana-
7
lisando suas taxas de erro. A esse conjunto da-se o nome de conjunto de validacao.
Vale ressaltar que as amostras de ambos os conjuntos devem pertencer a mesma
fonte, isto e, deve haver uma correspondencia, ou semelhanca, entre as amostras de
treino e de teste, pois, caso contrario, o treino torna-se ineficaz e o problema fica
sem solucao.
A ideia por tras da tecnica de Boosting e combinar classificadores simples, cada
um contendo apenas uma regra de classificacao, que sozinhos tem um desempenho
medıocre, mas, quando combinados, alcancam altas taxas de acerto. Tais regras
de classificacao simples, ainda que imprecisas, guardam dentro de si um pouco de
informacao relevante para o problema. Suponha que se deseje criar um classificador
capaz de dizer se um determinado produto vendido nos supermercados esta estra-
gado ou nao. Uma regra simples seria dizer que todos os produtos cuja embalagem
esteja amassada estao estragados. Embora tal classificacao resulte em uma taxa de
erro alta, ainda assim, a utilizacao dela sera melhor do que simplesmente adivinhar
aleatoriamente se tal produto esta ou nao estragado. Assumindo uma distribuicao
uniforme, o erro, para esse caso, seria de 50%, enquanto que utilizando a regra pro-
posta, essa taxa seria um pouco menor, apesar de ainda ser alta. Esse exemplo
ilustra, portanto, a premissa chave, sobre a qual se baseia o Boosting: as regras de
classificacao obtidas do treino apresentam um desempenho um pouco melhor do que
palpites aleatorios.
O treino e repetido diversas vezes, de modo a se extrair, a cada rodada, uma
nova regra de classificacao. Entretanto, caso o treino seja repetido exatamente nos
mesmos moldes, mantendo o mesmo conjunto de treinamento, a mesma regra seria
selecionada em todas as rodadas. Desse modo, para evitar isso, conferem-se pesos a
cada amostra que integra o conjunto de treinamento, conforme mostrado na equacao
(2.1). Nessa equacao, m corresponde ao numero de amostras presentes no conjunto
de treino e T , ao numero total de rodadas executadas. Os demais parametros que
compoem a segunda formula sao explicados mais adiante.
Dt(i) =
1m, t = 1
Dt(i)e−αtyiht(xi)
Zt, t = 2, ..., T
(2.1)
8
Na primeira rodada, o peso dado a cada uma e o mesmo, porem, nas rodadas
subsequentes, amostras corretamente classificadas tem o peso reduzido, enquanto
que amostras incorretamente classificadas recebem um peso maior. Isso faz com que
a regra escolhida na rodada anterior tenha um rendimento excepcionalmente pior
na nova rodada, forcando a maquina a buscar novas regras que resultem em um erro
menor, para a rodada em questao.
O erro da rodada e dado pela soma dos pesos das amostras incorretamente clas-
sificadas. A regra escolhida e aquela que tem o menor erro na rodada. Na Equacao
(2.2), t e o numero da rodada, i e o numero da amostra, ht(xi) e a classificacao
dada pelo classificador para a amostra xi e yi e a classificacao correta da amostra
em questao. De acordo com a premissa chave do Boosting, o erro em cada rodada
sera sempre, no maximo, igual a 12− γ, onde γ e uma constante pequena positiva
(sendo, portanto, menor do que 50%).
εt =∑
i:ht(xi)6=yi
Dt(i) (2.2)
A cada classificador gerado e atribuıdo um peso αt. Ele leva em conta o erro
associado ao classificador e e dado por αt = 12
ln(1−εtεt
) [1]. Por essa formula, nota-se
que quanto menor o erro, maior sera o peso conferido ao classificador, indicando que
ele tem uma importancia maior. Os valores αt sao utilizados tambem na atualizacao
dos pesos de cada amostra para a rodada seguinte, conforme visto na Equacao (2.1).
O fator de modificacao dos pesos (tanto para reducao, quanto para ampliacao) e
e−αt e o valor Zt e um fator necessario para garantir que os novos pesos estarao
normalizados. O erro, em cada rodada, varia de forma distinta, devido ao classifi-
cador selecionado na rodada em questao, indicando, portanto, um valor de γ nao
fixo. Entretanto, ainda assim, o algoritmo adapta os pesos de acordo com esse erro.
Por conta disso, essa tecnica de Boosting recebe o nome de Adaboost (ou Adaptive
Boosting).
O classificador final e entao construıdo por meio de uma combinacao linear dos
classificadores obtidos em cada rodada, em que os pesos dessa combinacao sao os αt
9
calculados. Ele leva em conta, portanto, a classificacao de cada um e as pondera,
de modo que os classificadores mais importantes (com um peso maior) tenham uma
contribuicao maior na decisao final. O Algoritmo 1 resume os principais passos exe-
cutados pelo AdaBoost. A teoria mais aprofundada sobre essa tecnica esta exposta
em Schapire [1].
Algoritmo 1 Algoritmo de treino AdaBoost
1: Dado (xi, yi) o conjunto de treinamento, onde xi e a amostra e yi sua classificacao
correta
2: Inicializa os pesos Dt(i) = 1m
, onde m e o numero de amostras presentes no
conjunto de treinamento
3: for t = 1, ..., T do
4: Colhe diversas regras de classificacao ht
5: Seleciona a regra de classificacao ht que gera o menor erro na rodada, levando-
se em conta os pesos de cada amostra: εt =∑
i:ht(xi)6=yi Dt(i)
6: Calcula o peso do classificador: αt = 12
ln(1−εtεt
)
7: Atualiza os pesos de cada amostra, com base no erro da rodada εt e no peso
do classificador em questao αt: Dt+1(i) = Dt(i)e−αtht(xi)yi
Zt, onde Zt e o fator de
normalizacao para os novos pesos
8: end for
9: Classificacao final: H(x) = sign(∑T
t=1 αtht(x)), onde sign(x) =1, x ≥ 0
−1, x < 0
2.2 Eigenfaces
O campo de reconhecimento facial e bastante estudado ha tempos, sendo sempre
buscadas novas tecnicas capaz de melhora-lo. As faces em imagens sao multidi-
mensionais e cheias de estımulos visuais relevantes, o que torna sua dentificacao
uma tarefa complexa. As primeiras abordagens da area incluem uma analise dos
elementos principais de uma face e a extracao de informacoes acerca deles. Tais
10
elementos englobam distancias entre os cantos dos olhos, os cantos da boca, altura
do nariz, localizacao do centro do queixo, alem de razoes entre tais caracterısticas.
Essas abordagens trazem consigo o problema de reconhecer faces que apresentam
orientacoes distintas, ja que algumas dessas caracterısticas serao modificadas. Alem
disso, algumas delas requeriam o auxılio de uma pessoa, para marcar tais elementos
na imagem, o que dificulta a automacao do processo de reconhecimento.
Procurando nao so resolver esses problemas, como tambem desenvolver um sis-
tema simples, rapido e facil de reconhecimento, foi criada por Turk e Pentland a
abordagem conhecida como Eigenfaces [11]. O foco principal dela e buscar pelos
aspectos mais relevantes de estımulos visuais das imagens de face, os quais real-
mente contribuem para o reconhecimento. Tais aspectos podem nao corresponder
necessariamente a caracterısticas (ou features) consideradas intuitivas, como olhos,
boca e nariz. Essa abordagem se baseia em um princıpio de Teoria da Informacao,
que propoe uma codificacao e decodificacao das imagens atraves do conteudo, da
informacao contida nelas.
Um criterio simples para se extrair informacoes das imagens de face contidas em
um conjunto e computar a variacao entre elas, isto e, como elas se diferem umas
das outras. Obter tal variacao corresponde a calcular os autovetores da matriz
de covariancia do conjunto em questao. As projecoes de uma dada imagem ao
longo desses autovetores sao interpretadas como um conjunto de features que juntas
caracterizam a variacao entre as imagens [11]. Cada face do conjunto contribui de
forma distinta para cada autovetor, fazendo com que o autovetor exiba elementos
dessas faces, sendo por si so uma especie de face. Por conta dessa natureza, tais
autovetores sao chamados de eigenfaces. Com isso, cada face do conjunto pode
ser reconstruıda atraves de uma combinacao linear dessas eigenfaces. Entretanto,
algumas eigenfaces terao, nessa reconstrucao, uma contribuicao maior do que outras,
de modo que usando somente essas que possuem uma relevancia maior e possıvel
obter uma aproximacao bem fiel da face original. A selecao das melhores eigenfaces
e feita por meio da analise dos componentes principais da distribuicao de faces. Essa
analise sera explicada na Secao 2.2.1. As eigenfaces selecionadas constituem a base
do chamado “espaco de faces”, em que cada face do conjunto corresponde a um
11
ponto.
Para se calcular as eigenfaces, primeiramente, as imagens γ1,γ2, ...,γM do con-
junto em questao, de resolucao N ×N , sao transformadas em vetores de dimensao
N2. A partir disso, e calculado o vetor medio dessa distribuicao ψ = 1M
∑Mn=1 γn
e, com isso, se obtem o vetor diferenca entre os do conjunto e o medio, conforme
explıcito na Equacao (2.3).
ηi = γi −ψ i = 1, 2, ...,M (2.3)
Em seguida, e preciso realizar a normalizacao dos desvios-padrao do vetor dife-
renca η. Para isso, calcula-se o vetor de desvio-padrao. Como a media e zero, a
formula para se calcular esse vetor e dada por σ =√
1M
∑Mn=1 ηn
2. Sabendo que
σT = [σ1 σ2 ... σM ] e ηTi = [ηi1 ηi2 ... ηiM ], os vetores φi, correspondentes
as imagens normalizadas em media e desvio-padrao, sao obtidos atraves da Equacao
(2.4).
φTi =
[ηi1σ1
ηi2σ2
...ηiMσM
](2.4)
Monta-se, entao, a matriz A = [φ1 φ2 ... φM ] e calcula-se a matriz de co-
variancia, dada por C = AAT = 1M
∑Mn=1φnφn
T . O objetivo, agora, e calcular o
conjunto dos M autovetores ortonormais dessa matriz que possuem os M maiores
autovalores. A matriz de covariancia, no entanto, tem dimensao N2 × N2, o que
corresponde a N2 autovetores. Para valores tıpicos de dimensoes de imagem, por
exemplo, N = 256, o calculo dessa matriz torna-se computacionalmente inviavel,
devido ao tamanho da variavel que precisaria ser criada. Para contornar esse pro-
blema, calcula-se uma matriz intermediaria L = ATA, de tamanho M ×M . Os
autovetores dessa matriz sao dados pela Equacao (2.5).
ATAvi = µivi i = 1, 2, ...,M (2.5)
12
Pre-multiplicando essa equacao por A obtem-se:
AATAvi = µiAvi i = 1, 2, ...,M (2.6)
No entanto, substituindo Avi por ui e AAT por C, obtem-se a Equacao (2.7),
referente aos M autovetores da matriz de covariancia.
Cui = µiui i = 1, 2, ...,M (2.7)
Essa abordagem permite, portanto, de uma maneira indireta, calcular os autove-
tores da matriz de covariancia, sem ser preciso obter tal matriz. Alem disso, dos
M autovetores calculados, sao escolhidos M ′ para representar o espaco de faces,
baseados nos maiores autovalores, reduzindo, portanto, os calculos executados no
problema da ordem de N2 para M ′ (onde M ′ << N2). Os M ′ autovetores selecio-
nados constituem, entao, o espaco de faces do problema, sobre o qual cada imagem
φ sera projetada. A projecao e dada na Equacao (2.8).
ωk = uTkφ k = 1, 2, ...,M ′ (2.8)
Cada um dos pesos ωk calculados compoe o vetor de pesos ωT = [ω1 ω2 ... ωM ′ ],
os quais sao as representacoes das respectivas imagens no espaco de face, as quais
correspondem a pontos. Um modo simples de descobrir se uma nova imagem corres-
ponde a face de alguma pessoa presente no conjunto utilizado e calcular a distancia
euclidiana entre os pontos correspondentes a tais no espaco de faces.
ε2k = ||(ω −Ωk)||2 (2.9)
13
Na Equacao (2.9), ω sao os pesos obtidos da imagem a ser reconhecida e Ωk
corresponde a media do peso de todas as imagens pertencentes a classe k (ou pessoa
k). A imagem e considerada como sendo da classe que resulta no menor εk, contando
que ε esteja abaixo de um limiar θε. Esse limiar representa a distancia maxima
para a qual se admite que uma imagem pertenca a tal classe. Caso contrario, a
imagem e classificada como desconhecida e pode, opcionalmente, ser usada para se
criar uma nova classe (representando, portanto, uma nova pessoa). Um outro limiar
estabelecido e a distancia a qual a imagem em questao encontra-se do espaco de face.
Caso essa distancia seja maior do que o limiar estabelecido, entao a imagem nao e
considerada como face, nao sendo, portanto, classificada. A distancia da imagem
para o espaco de faces e dada pela Equacao (2.10), onde φf =∑M ′
i=1 ωiui
ε2 = ||(φ− φf )||2 (2.10)
Considerando todos esses limiares, existem quatro casos possıveis para o vetor de
pesos da imagem a ser classificada:
1. Representa um ponto proximo ao espaco de face e a uma classe
2. Representa um ponto proximo ao espaco de face, mas longe de todas as classes
3. Representa um ponto longe do espaco de face, mas perto de uma classe
4. Representa um ponto longe do espaco de face e de todas as classes
O Caso 1 representa a situacao de identificacao da imagem de entrada. O se-
gundo representa uma nova pessoa, a qual nao esteve presente no conjunto original
de imagens, para o qual o reconhecedor foi treinado. O Caso 3 e um exemplo de
falso positivo, no qual uma imagem que nao corresponde a uma face, eventualmente,
localiza-se proximo a alguma imagem de face de alguma pessoa do conjunto original.
O ultimo caso e a apresentacao de uma imagem de nao-face para o reconhecedor.
Nesse caso, nenhuma classificacao e feita, ja que nao corresponde a uma face. O ar-
tigo escrito por Turk e Pentland sugere outros tratamentos que podem ser adotados,
de modo a habilitar a utilizacao da abordagem de Eigenfaces em outras aplicacoes,
14
como deteccao de faces, eliminacao de cenario ou rastreamento do posicionamento
da cabeca. Todos esses podem ser consultados na referencia [11].
2.2.1 PCA
Conforme citado na Secao 2.2, o metodo de selecao das eigenfaces que construirao
o espaco de faces do problema chama-se Analise dos Componentes Principais (Prin-
cipal Components Analysis - PCA). Essa abordagem busca selecionar os vetores que
maximizarao a variancia da projecao dos dados originais sobre eles. A principal
vantagem da PCA e a reducao de dimensionalidade do problema, de modo que e
possıvel reconstruir as amostras originais a partir de suas projecoes com um erro
pequeno, sendo necessario, para isso, somente, utilizar as projecoes ao longo dos
vetores escolhidos. O erro medio quadratico cometido nessa reconstrucao e direta-
mente associado a variancia em cada autovetor, a qual e equivalente ao autovalor
associado a ele. Dessa forma, excluir os autovetores que possuem os menores au-
tovalores resulta em um erro arbitrariamente pequeno. Um resumo da teoria sera
feito a seguir, baseando-se na teoria exposta por Haykin [6]. A demonstracao mais
detalhada e explicada pode ser encontrada nessa referencia.
Suponha um vetor aleatorio de dados x, de dimensao m, cuja media seja igual a
0, ou seja, E[x] = 0. Suponha, tambem, um vetor unitario q, sobre o qual x sera
projetado. A projecao, mostrada na Equacao (2.11), corresponde a uma variavel
aleatoria A, cujas propriedades estatısticas estao diretamente ligadas as de x.
A = qTx (2.11)
A media de A, assim como x, e igual a 0, o que faz com que sua variancia seja
dada pela Equacao (2.12).
15
σ2 = E[A2]− 2(E[x])2
= E[A2]
= E[(qTx)(xTq)]
= qTE[xxT ]q
= qTRq
(2.12)
A matriz R representa a matriz de correlacao da variavel x com ela mesma, a
qual e simetrica, de forma que RT = R. O objetivo e encontrar os vetores q da
Equacao (2.12) que maximizam os valores de σ2. Para isso, define-se, entao, a funcao
Ψ(q) = σ2 = qTRq. Suponha uma pequena perturbacao, representada pelo vetor
δq. Entao:
Ψ(q + δq) = (q + δq)TR(q + δq)
= qTRq + 2(δq)TRq + (δq)TRδq
= qTRq + 2(δq)TRq + (δq)TRδq
= Ψ(q) + 2(δq)TRq
(2.13)
Na Equacao (2.13), desprezou-se o termo (δq)TRδq, que era de segunda ordem.
Por essa equacao, percebe-se que, para se alcancar a aproximacao de primeira ordem,
e preciso que o termo (δq)TRq = 0. Alem disso, a soma do vetor original com a
perturbacao resulta em um vetor que tambem deve possuir modulo unitario, de
modo que:
(q + δq)T (q + δq) = qTq + 2qT δq + δqT δq
= qTq + 2qT δq
= 1
(2.14)
Novamente, desprezou-se o termo de segunda ordem na Equacao (2.14). Alem
disso, como q e um vetor de modulo unitario, entao qTq = 1. Sendo assim, para
que a Equacao (2.14) seja valida, tem-se que qT δq = 0. Igualando isso a condicao
(δq)TRq = 0, chega-se a seguinte equacao:
16
(δq)TRq − λ(δq)Tq = (δq)T (Rq − λq) = 0 (2.15)
A variavel λ, presente na Equacao (2.15), representa uma constante que possui
a mesma unidade de medida dos dados originais, os quais formaram a matriz de
correlacao R. Como os vetores q e δq nao possuem unidades, a introducao dessa
constante e necessaria, como forma de manter a consistencia fısica da equacao.
Uma condicao necessaria e suficiente para que a Equacao (2.15) seja valida e que
Rq − λq = 0 ou:
Rq = λq (2.16)
A partir da Equacao (2.16) e possıvel, entao, obter os vetores (q) que maximizam
a funcao Ψ(q). Essa equacao tambem representa a equacao dos autovalores de uma
matriz, ficando claro que λ e q sao, respectivamente, os autovalores e os autovetores
da matriz R. E possıvel reescrever essa equacao da seguinte forma:
QTRQ = Λ (2.17)
Na Equacao (2.17), a matriz Q = [q1 q2 ... qm] e ortonormal, pois suas
colunas sao os autovetores da matriz R, os quais sao ortonormais, e a matriz Λ =
diag(λ1, λ2, ..., λm) e diagonal, de forma que em sua diagonal principal encontram-
se os autovalores da matriz R. Essa equacao tambem e conhecida como Teorema
Espectral. A Equacao (2.18) corresponde a Equacao (2.17), reescrita termo a termo.
Comparando-a com a Equacao (2.12), observa-se que os autovalores representam a
variancia das projecoes.
qTj Rqk =
λj, k = j
0, k 6= j
(2.18)
17
O sistema (2.19) corresponde as equacoes de analise e sıntese, respectivamente.
O vetor de dados χ (aqui representado pela letra grega “chi”, ou χ) e composto
por amostras observadas (ou seja, realizacoes) das distribuicoes representadas pelo
vetor aleatorio x, enquanto que o vetor a contem o valor das projecoes, tambem
chamadas de componentes principais, dessas amostras nos vetores selecionados.
a = QTχ = [χTq1 χTq2 ... χTqm]T = [a1 a2 ... am]T
χ = Qa =∑m
j=1 ajqj
(2.19)
Suponha que se queira reconstruir o vetor de dados χ utilizando-se um numero
l de autovetores, em que l < m, associados aos l maiores autovalores. O vetor
reconstruıdo e dado pela Equacao (2.20), o qual e uma aproximacao do vetor χ
original.
χ =l∑
j=1
ajqj l < m (2.20)
Por sua vez, o erro cometido por tal aproximacao e dado por:
e = χ− χ =m∑
i=l+1
aiqi (2.21)
A Equacao (2.21) foi obtida substituindo os valores de χ e χ pelas equacoes (2.20)
e de sıntese do sistema (2.19), respectivamente. A variancia total do vetor χ e obtida
substituindo (2.18) em (2.12)
σ2χ =
m∑j=1
σ2j =
m∑j=1
λj (2.22)
De modo similar, a variancia do vetor de aproximacao χ e dada pela Equacao
(2.23).
σ2χ =
l∑j=1
σ2j =
l∑j=1
λj (2.23)
18
Sendo assim, a variancia do vetor de erro e, ou o erro medio quadratico (pois a
media do vetor de erro e 0), e calculado somando-se as variancias dos componentes
restantes, que nao se encontram presentes no vetor χ.
σ2e =
m∑j=l+1
σ2j =
m∑j=l+1
λj (2.24)
Conforme se constata pela Equacao (2.24), quanto menores forem as variancias
dos termos desprezados, o erro medio quadratico tambem sera menor e, com isso,
melhor sera a aproximacao χ. Isso mostra que a aplicacao da reducao de dimensiona-
lidade torna-se possıvel, pois a informacao relevante acerca do problema e mantida,
enquanto que complexidade de sua analise e reduzida.
19
Capıtulo 3
Implementacao
A implementacao do sistema de reconhecimento facial foi divida em 3 modulos
principais: treinamento do detector, sistema de escaneamento de imagens e treina-
mento do reconhecedor. Cada um dos modulos e suas funcoes principais, tal como
as decisoes de implementacao tomadas, serao explicados nesse capıtulo. O codigo,
feito em MATLAB, encontra-se disponıvel, na ıntegra, no Apendice B.
3.1 Treinamento do Detector
3.1.1 Ideia Principal
O primeiro modulo do sistema e responsavel por distinguir faces de nao-faces.
Quando se deseja reconhecer o rosto de uma pessoa em uma imagem, esta contem,
alem da pessoa, elementos de cenario, os quais nao possuem informacao revelante
para o reconhecimento. Dessa forma, a tarefa de reconhecimento torna-se menos
custosa e mais simples, caso se disponibilize ao reconhecedor somente a regiao de
interesse de analise da imagem, que e a face. A construcao desse detector possi-
bilita a localizacao exata dessa regiao de interesse na imagem, o que justifica sua
importancia. A abordagem de treino para o detector, empregada nesse projeto, se-
gue aquela desenvolvida por Viola e Jones [2]. Ela se baseia no seguinte princıpio: o
numero de amostras de nao-face apresentadas ao detector sera muito maior do que o
de amostras de face. Sendo assim, a estrutura de deteccao focara em descartar tudo
o que certamente nao e uma face. Ao fim desse processo, as amostras que sobram
devem corresponder as faces buscadas.
20
Tendo isso em vista, a implementacao sugerida em [2] e a de um sistema de
deteccao composto por diversos estagios cascateados. Cada um desses estagios rece-
bera um grupo de amostras para classificar como face ou nao-face. Somente aquelas
que forem classificadas como face passam adiante na cascata, sendo analisadas pelos
estagios subsequentes, ao passo que as nao-face sao descartadas. E esperado que
as amostras que passam por todos os estagios, ou seja, que nao foram descartadas,
sejam de faces. Cada estagio contem, portanto, um classificador, o qual e treinado
utilizando-se um determinado conjunto de treinamento. O mesmo conjunto, porem,
nao e utilizado para treinar todos os estagios da cascata. O treino de estagios sub-
sequentes apresenta uma particularidade: as amostras negativas (de nao-faces) do
conjunto de treino consistem em amostras, as quais o estagio anterior classificou
como face, embora nao sejam. A ideia e que, conforme se avance na cascata, o pro-
blema de deteccao torna-se mais complexo, ja que nenhum dos estagios anteriores
foi capaz de discernir corretamente entre faces e nao-faces desse conjunto. Sendo
assim, o treino desses estagios visa focar especialmente nesses exemplos, na busca
de informacoes mais especıficas que permitam uma separacao mais confiavel de face
e nao-face. A Figura 3.1 exibe um modelo simplificado da cascata a ser construıda
e seu princıpio de funcionamento.
Figura 3.1: Topologia da cascata de classificadores que compoe o sistema de deteccao
21
3.1.2 Estruturacao do codigo
A implementacao realizada seguiu, portanto, a ideia exposta na Secao 3.1.1. A
funcao principal que rege a construcao do detector chama-se mainCascade.m, apre-
sentada no Apendice B. O Algoritmo 2 traduz os principais passos executados por
essa funcao.
Algoritmo 2 Algoritmo do detector
1: amostras← matriz de 24x24x3000, contendo amostras positivas e negativas;
2: imagem integral ← matriz 24x24x3000, contendo as imagens integrais1 obtidas
de cada uma das amostras;
3: features ← matriz contendo as features de cada amostra, obtidas atraves da
analise das imagens integrais;
4: labels amostras ← vetor 1x3000 contendo as classificacoes corretas de cada
amostra;
5: for i = 1 to numero maximo estagios do
6: estagio ← classificador obtido atraves do treino, utilizando as features cal-
culadas;
7: cascata[i]← estagio (cascata e um vetor que contem cada estagio);
8: features ← nova matriz de features, contendo as das amostras positivas
usadas anteriormente e de amostras negativas classificadas erroneamente pelo
estagio atual;
9: taxa falsos positivos ← taxa de falsos positivos da cascata parcial, obtida
atraves das classificacoes dadas pela cascata parcial as amostras do conjunto de
validacao;
10: if taxa falsos positivos < taxa falsos positivos desejada then
11: Interrompe o loop;
12: end if
13: end for
14: Return cascata;
1Ver detalhes nas Secoes 3.1.2.2 e 3.1.2.3
22
3.1.2.1 Bases de Treino e Validacao
Para a construcao do detector, foi preciso utilizar duas bases distintas, ambas
contendo amostras positivas (ou de face) e negativas (ou de nao-face). A primeira e
a base de treino, a qual e a principal fonte de informacoes fornecida ao detector sobre
o problema em questao. A apresentacao de diferentes exemplos desse problema a
ele tem por objetivo faze-lo extrair caracterısticas especıficas que permitam realizar
a distincao entre face e nao-face, transformando, portanto, essas informacoes em
algum tipo de conhecimento. O segundo e o conjunto de validacao, o qual e usado
para avaliar o desempenho do detector, contendo amostras que nao foram exibidas
a ele durante o treinamento. O desempenho do detector ao classificar as amostras
desse grupo e um indicativo da sua capacidade de generalizacao para o determinado
problema, o que permite concluir, tambem, se o treino foi bem executado ou nao.
Embora nao sejam utilizados diretamente no seu treino, os resultados do desempe-
nho do detector, quando aplicados a este grupo, regem a adicao de mais estagios
a cascata. Caso as estatısticas atinjam limiares pre-definidos, entao, o treino de
novos classificadores, que compoem os estagios da cascata, se encerra e a cascata e
concluıda.
No conjunto de treinamento, a relacao entre amostras positivas e negativas nao e
balanceada. A proporcao escolhida entre positivas e negativas e 1:2 e a explicacao
para essa decisao e porque, no escaneamento de uma imagem em busca da face, sao
geradas muito mais amostras de nao-face do que de face. Esse desbalanceamento
busca, portanto, se aproximar um pouco mais de uma situacao real na qual o detector
sera empregado. Esse conjunto consiste em 3000 amostras, sendo 2000 de nao-face
e 1000 de face. No conjunto de validacao, no entanto, a proporcao entre amostras
positivas e negativas e equilibrada, sendo 1:1, o que nao e um problema, ja que esse
conjunto tem por objetivo apenas avaliar o treino que foi realizado2. Ele e composto
por 200 amostras, com 100 de face e 100 de nao-face. As amostras positivas de
ambos os grupos seguem um padrao: todas as faces sao frontais, permitindo leves
inclinacoes em alguma direcao, porem sempre exibindo os mesmos elementos: boca,
olhos, nariz, sobrancelhas e bochechas. Exemplos desse tipo de amostra encontram-
2 Consideracoes acerca dessa proporcao encontram-se na secao 5.1
23
se na Figura 3.2.
Figura 3.2: Exemplos de amostras positivas de face usadas no treino do classificador
Ja as amostras negativas estao divididas em 2 grupos: os que contem face e os
que contem, apenas, elementos de cenario. As faces pertencentes ao primeiro grupo
nao seguem os padroes impostos as amostras de face para as quais o detector foi
treinado e, portanto, nao devem ser classificadas como tal. Esse grupo se subdivide
em dois: faces descentralizadas e faces cortadas. Este corresponde a amostras nas
quais pelo menos um elemento frontal nao e exibido de forma explıcita, enquanto
que aquele corresponde aquelas nas quais os elementos de cenario compoem uma
porcao consideravel da imagem, contendo, portanto, muitas informacoes que nao
se relacionam com a face. A Figura 3.3 exibe amostras desse tipo. A inclusao
desse grupo tem por objetivo, novamente, se aproximar de uma situacao real de
escaneamento, na qual algumas janelas conterao a face buscada, porem nao de forma
completa, nao sendo, com isso, correto, para esse projeto, classifica-las como face.
O segundo grupo se subdivide em tres conjuntos: cenarios de ambientes fechados,
cidades e paisagens. Com isso, busca-se incluir uma ampla variedade de cenarios,
nos quais e possıvel encontrar uma pessoa. Amostras de ambientes fechados incluem
salas de aula, bibliotecas, cozinhas, quartos, salas de estar e corredores. Paisagens
urbanas ao ar livre, como ruas, pracas, parques e estacionamentos integram o con-
junto de cidades. Por fim, diferentes biomas e cenarios contendo elementos da natu-
24
reza, como praia, montanhas, florestas e campos fazem parte do grupo de paisagens.
Exemplos dos 3 subgrupos sao mostrados na Figura 3.4.
(a) Faces cortadas
(b) Faces descentralizadas
Figura 3.3: Exemplos de amostras negativas de face usadas no treino do classificador
(a) Ambiente fechado (b) Cidade (c) Paisagem
Figura 3.4: Diferentes tipos de amostras negativas de cenario usadas no treino do
classificador
Alem da categorizacao dos diversos tipos de amostras negativas, cada grupo e
subgrupo possui uma cota na porcao de amostras negativas que compoe o conjunto
de treinamento e validacao do detector. Isso foi feito de modo a garantir que o
treino e a validacao do detector sempre apresentarao amostras negativas de cada
um desses tipos. Essa diversidade aumenta a qualidade do treino e do classificador,
uma vez que ele sera capaz de separar faces de nao faces em varios tipos de imagens
diferentes. Para ambos os conjuntos, estabeleceu-se que 80% das amostras negativas
seriam de cenarios, enquanto que 20% seriam de face. Dos 80% de cenario, 50% sao
25
de ambientes fechados, 30% de cidades e 20% de paisagens. Dos 20% de face, uma
metade e de faces cortadas e a outra, de faces descentralizadas.
A cada uma das amostras do conjunto de treino e validacao e associado um
numero, que serve para identificar a que classe essa amostra pertence. Para o
problema de deteccao, existem somente duas classes: faces e nao-faces. Essa iden-
tificacao permite nao so a medicao do desempenho do detector, atraves da com-
paracao das classificacoes esperadas e dadas pelo detector, como tambem orientar o
seu treino, fazendo-o continuar buscando caracterısticas revelantes em imagens ate
que a classificacao seja correta. Nesse projeto, atribuiu-se +1 as faces e -1 as nao
faces. Por conta da utilizacao de amostras categorizadas previamente, diz-se que
esse treinamento e do tipo supervisionado.
3.1.2.2 Pre-processamento das Amostras
A funcao getImages.m se encarrega de ler as imagens e armazena-las em variaveis.
O armazenamento das amostras e todo feito em matrizes de 3 dimensoes, onde as
duas primeiras dimensoes representam a resolucao das amostras e a terceira cor-
responde ao numero da amostra. A resolucao escolhida, a qual e a mesma para
todas as imagens, foi de 24x24, porque essa resolucao inclui informacoes adicionais,
tal como o contorno das bochechas, as quais aumentam a acuracia do classificador
[2]. A utilizacao de resolucoes menores faz com que o detector tenha um desem-
penho pior. Alem de redimensionar as imagens para essa resolucao, essa funcao
tambem converte todas elas para tons de cinza. O motivo disso e tornar a analise
das amostras, em busca de caracterısticas especıficas, pelo detector mais simples e
computacionalmente menos custosa, acelerando, portanto, o tempo de treino.
As imagens de cenario que integram a parte de amostras negativas sao de alta
resolucao. Como qualquer janela que nao contenha uma face e categorizada como
elemento de cenario, e possıvel utilizar uma imagem de alta resolucao desse tipo para
gerar diversas amostras negativas de cenario, diminuindo, portanto, a quantidade
de imagens a serem armazenadas no computador. Essa abordagem consiste em
escolher uma janela de determinada resolucao (menor do que a resolucao da imagem)
e posiciona-la em uma posicao aleatoria da imagem. Essa janela e, entao, extraıda
26
e redimensionada para a resolucao 24x24, consistindo, com isso, em uma amostra
negativa. Sendo assim, cada janela de diferente resolucao e em uma posicao diferente
na imagem resulta em uma nova amostra negativa, deixando claro o motivo pelo
qual muitas amostras negativas sao obtidas de somente uma imagem desse tipo.
Vale ressaltar que nenhuma das amostras passadas ao detector (tanto as de treino,
quanto as de validacao e de teste) foi normalizada em variancia, o que reduziria
os efeitos de diferentes condicoes de iluminacao, presentes em cada amostra. Essa
decisao teve por objetivo verificar como essas diferencas de iluminacao influenciam
na deteccao.
A partir das amostras extraıdas, uma nova representacao delas e gerada, a qual e
chamada imagem integral [2]. A imagem integral tem como principal vantagem re-
duzir o tempo de calculo das features, ou caracterısticas especıficas de cada amostra,
que sera explicado na Subsecao 3.1.2.3. A imagem integral e obtida substituindo
o valor de um determinado pixel da imagem original pela soma de todos aqueles
localizados a esquerda e acima do mesmo. Cada pixel representa, portanto, uma
soma cumulativa. O calculo do valor de cada pixel na imagem integral e mostrado
na Equacao (3.1) e a Figura 3.5 exibe um exemplo de calculo da imagem integral
para uma imagem de 2x2 pixels. No codigo, essa tarefa e realizada na funcao getIn-
tegralImage.m.
ii(x, y) =∑
x′≤x,y′≤y
i(x′, y′) (3.1)
onde:
• ii(x,y) e o valor do pixel localizado nas coordenadas (x,y) da imagem integral;
• i(x’,y’) e o valor do pixel localizado nas coordenadas (x’,y’) da imagem original;
3.1.2.3 Calculo de Features
A funcao getFeatures.m faz uso das imagens integrais de cada amostra para obter
informacoes sobre caracterısticas intrınsecas delas. Essas caracterısticas, tambem
27
(a) Pixels na imagem original (b) Pixels na imagem integral
Figura 3.5: Exemplo do calculo da imagem integral
chamadas de features, sao, na verdade, resultados de operacoes de soma e subtracao
aplicadas aos pixels de uma determinada regiao da amostra. Conforme apresentado
por Viola e Jones [2], existem cinco3 modelos principais de mascaras utilizadas na
extracao de features, exibidas na Figura 3.6. Em cada uma dessas figuras, regioes
de mesma cor sao somadas e e regioes de cores distintas sao subtraıdas. Essas
topologias buscam tirar proveito de caracterısticas comuns de imagens de face. A
feature 3, por exemplo, pode ser utilizada para explorar a caracterıstica de que a
regiao dos olhos tende a ser mais escura do que a do nariz, enquanto que a feature
2 adota a mesma estrategia, porem entre as regioes dos olhos e das bochechas.
Uma feature corresponde a aplicacao de uma determinada mascara, com um ta-
manho especıfico, em uma regiao da imagem. Cada mascara possui um tamanho
mınimo e uma taxa de crescimento proprios. Para exemplificar, a feature quadricu-
lada tem uma resolucao mınima 2x2 e cada aumento de tamanho corresponde a um
acrescimo de 2 pixels em cada dimensao, de modo a manter o formato de operacao
que a mascara deve implementar. Logo, os tamanhos subsequentes seriam 4x4, 6x6,
8x8, e assim por diante, ate alcancar o maior tamanho que nao excede a resolucao
da amostra (no caso, 24x24). Para a feature de tres retangulos verticais, a resolucao
mınima e a taxa de crescimento sao distintos, por conta do modelo que implementa.
Nesse caso, a altura dessa mascara aumenta de pixel em pixel, enquanto que sua
3 Embora a feature 4 nao apareca em [2], ela e uma variante horizontal da feature 3, assim
como a feature 2 tambem e uma variante horizontal da feature 1. E necessario utiliza-la para
se alcancar a quantidade total de features (acima de 160000, conforme [2]) existentes em uma
imagem de resolucao 24x24; caso contrario, serao obtidas menos de 160000 features por imagem
dessa resolucao.
28
(a) Features 1 e 2 (da esquerda para a direita)
(b) Features 3, 4 e 5 (da esquerda para a direita)
Figura 3.6: Mascaras utilizadas no calculo de features
largura cresce a cada 3 pixels, portanto: 1x3, 1x6, 1x9, ... , 2x3, 2x6, 2x9, e assim
por diante. A aplicacao de todos os tipos de mascaras, com todos os tamanhos e em
todas as regioes possıveis em uma amostra de resolucao 24x24 resulta em um total
de 162336 features por amostra.
Como a imagem integral ja representa uma soma cumulativa dos pixels da amos-
tra, nao e necessario utilizar essas mascaras diretamente nas amostras, o que reque-
reria a realizacao de diversas operacoes pela CPU, tornando a execucao do codigo
mais lenta, especialmente para mascaras grandes aplicadas em imagens de alta re-
solucao. Em vez disso, as operacoes de tais mascaras, quando aplicadas na imagem
integral, tornam-se, na verdade, somas e subtracoes de pixels especıficos. A natureza
da imagem integral demanda, no entanto, dois cuidados: nao contar uma regiao de
interesse mais de uma vez e descontar a contribuicao de pixels que correspondem a
regioes nao contidas dentro da mascara. Existem quatro tipos de posicionamentos
possıveis na imagem integral, e cada um requer uma operacao diferente para se obter
o valor correto da feature. A Figura 3.7 exibe os casos para a feature quadriculada.
Os numeros de 1 a 4 sao as regioes de interesse e as letras de A a I representam os
pixels na imagem integral, necessarios para se calcular a feature em questao.
O Caso 1 e o mais simples e direto. Como a feature do exemplo e quadriculada,
basta somar as regioes 1 e 4 e subtrair o resultado da soma das regioes 2 e 3,
29
(a) Caso 1 (b) Caso 2
(c) Caso 3 (d) Caso 4
Figura 3.7: Possıveis posicionamentos das mascaras na imagem integral
conforme mostra a Equacao (3.2). Os coeficientes dessa equacao fazem o ajuste
necessario para que nao se conte uma regiao mais de uma vez, garantindo que, no
fim, o resultado da operacao corresponda, de fato, a (1 + 4)− (2 + 3).
feature = A− 2B − 2D + 4E (3.2)
O Caso 4 e mais complexo, pois, alem de se ter que atentar em nao contar as
regioes de interesse mais de uma vez, e preciso, tambem, descontar a contribuicao
de regioes que nao estao dentro da mascara (nesse caso, as regioes 5, 6, 7, 8 e 9).
A Equacao (3.3) retrata a operacao necessaria para se extrair corretamente o valor
da feature, para esse caso. Os demais, referentes aos outros tipos de mascara e
seus posicionamentos, podem ser vistos no codigo, disponıvel no Apendice B. Esses
calculos sao realizados pela funcao calculateFeatures.m.
feature = A− 2B − 2D + 4E +G− 2H + C − 2F + I (3.3)
30
3.1.2.4 Estabelecimento de Limiares
O armazenamento dos valores das features de cada amostra e feito dentro de uma
matriz, em que cada linha corresponde a uma feature e cada coluna, a uma amostra.
De posse dessa matriz, inicia-se, entao, o principal loop da funcao mainCascade.m,
referente ao treino da cascata de classificadores. Antes de se iniciar o loop, alguns
limiares foram estabelecidos. Os dois primeiros sao as taxas de falsos negativos
dos estagios e falsos positivos da cascatas. Ambas as taxas se referem a erros do
detector, com a diferenca de que falsos negativos sao amostras de face que foram
classificadas como nao-face, ao passo que falsos positivos sao amostras de nao-face
classificadas como face.
E importante que, em cada estagio, especialmente nos primeiros, o mınimo possıvel
de amostras de faces sejam descartadas, pois, caso contrario, tais amostras sequer
serao avaliadas pelos ultimos estagios, os quais sao especializados em exemplos mais
complexos de face, e por isso, sao capazes de realizar uma separacao mais refinada
entre faces e nao-faces. O limiar arbitrado para essa taxa, em cada estagio, foi de
2%. Ja para a cascata completa, a taxa de falsos positivos deve ser muito menor que
as taxas de falsos negativos dos estagios, pois, quando aplicada em conjunto com
o escaneador, conforme dito anteriormente, sera apresentado a ela uma quantidade
de janelas de nao-faces muito superior a de faces e, caso a taxa de falsos positivos
seja alta, a cascata classificara muitas dessas janelas como face, localizando, assim,
incorretamente as faces em uma imagem. Arbitrou-se uma taxa maxima de 0,001%
de falsos positivos.
Como nao se sabia previamente quantas features por estagio e quantos estagios
seriam necessarios para se alcancar os limiares propostos, arbitrou-se, tambem, um
limite para a quantidade de features em um estagio e de estagios na cascata, de modo
a nao prolongar o treino demasiadamente. Com isso, caso o limiar de falsos negativos
para um estagio nao fosse alcancado dentro do limite de features estabelecido, o
treino dele era encerrado e prosseguia-se, entao, para o estagio seguinte. Da mesma
forma, se o limiar de falsos positivos da cascata nao fosse alcancado dentro do numero
maximo de estagios permitido, entao, novos estagios nao seriam mais adicionados
31
e a construcao da cascata seria finalizada. Os limites arbitrados para o numero de
features por estagio e o numero de estagios na cascata foram, respectivamente, 15 e
6. Comentarios acerca desses numeros sao feitos na Secao 5.1.
3.1.2.5 Treinamento dos Estagios
Dentro do loop principal e chamada a funcao stageAdaboost.m, a qual se encarrega
de executar o treino de cada estagio, sendo fornecida a ela a matriz de features, as
classificacoes esperadas de cada amostra e o limiar estabelecido de falsos negativos.
O metodo de treino adotado foi o AdaBoost, conforme feito por Viola e Jones [2], com
ligeiras modificacoes que serao discutidas. O Algoritmo 3 exibe os passos executados
nessa funcao.
Em [2], a busca do melhor limiar para cada feature se da atraves da analise do
valor dela para cada amostra. Cada valor e usado como um possıvel limiar nas
duas direcoes de comparacao (< e ≥) e o melhor e atualizado conforme o erro de
classificacao diminui. Por conta da implementacao feita nesse projeto, tal abordagem
demanda um tempo de execucao muito elevado. Dessa forma, de modo a evitar a
analise de uma quantidade muito grande de combinacoes limiar/feature, estipulou-se
um numero fixo de limiares que cada feature teria que analisar e o melhor deles seria
eleito como o seu limiar. Os valores possıveis de limiar estao igualmente espacados
dentro do intervalo limitado pelo menor valor e pelo maior valor da feature em
questao. Determinou-se que o numero de limiares a se analisar seria de 500, pois
esse foi o que apresentou o melhor compromisso entre acuracia e tempo de execucao
(os outros testes utilizaram 100 e 1000 limiares).
Uma vez descoberto o melhor limiar de cada feature, escolhe-se o par que apresenta
o menor erro de classificacao, sendo considerado como o melhor da rodada (ou
iteracao do loop) em questao. Esse par recebe o nome de classificador fraco ou
hipotese fraca. Cada classificador fraco e associado a um peso, chamado de αt, o
qual e calculado levando-se em conta o erro de classificacao associado a ele. O erro de
classificacao e a soma ponderada de todas as amostras incorretamente classificadas.
Os pesos que integram essa soma sao aqueles conferidos a cada amostra no comeco
de cada rodada e todos eles sao normalizados.
32
Algoritmo 3 Treino de um Estagio
1: Inicialmente, os pesos wt,i de cada amostra sao inicializados com o mesmo valor
1nAmostras
, onde t e a rodada em questao e i e o numero da amostra
2: numero thresholds← quantidade de limiares que serao avaliados em cada fea-
ture
3: T ← 0 (quantidade de classificadores selecionados no estagio)
4: for t = 1 to limiar features estagio do
5: wt,n = wt,n∑nAmostrasj=1 wt,j
(normalizacao dos pesos)
6: for i = 1 to numero features do
7: thresholds← vetor de tamanho 1×numero thresholds contendo valores
de limiares igualmente espacados dentro do intervalo definido pelo menor e maior
valores da feature i em questao
8: Calcula o erro de cada limiar, para a feature em questao, dada pela se-
guinte formula: εlimiar,i =∑nAmostras
n=1 wt,n|h(n) 6= labeln|, onde h(n) e o resultado
do classificador dado para a amostra n.
9: Seleciona o limiar que resulta no menor erro para a feature i em questao,
de modo que εi = min(εlimiar,i)
10: end for
11: Seleciona o par feature e limiar que apresenta o menor erro εi, de modo que
erro rodada(t) = min(εi)
12: T ← T + 1
13: Atribui-se um peso para a classificador fraco escolhido nessa rodada, baseado
no seu erro, que foi o menor encontrado na rodada. A formula do peso e:
αt = 12× ln(1−erro rodada(t)
erro rodada(t))
14: Valida os resultados do estagio com os classificadores fracos ate entao esco-
lhidos e obtem a taxa de falsos negativos
15: if taxa falsos negativos < taxa falsos negativos esperada then
16: Interrompe o loop
17: end if
18: Atualiza os pesos de cada amostra para a rodada seguinte: wt+1,n = wt,n ×
e−(αt×labeln×h(n))
19: end for
33
20: O classificador final (ou forte) e H(n) =∑T
t=1 αtht(n), onde ht(n) e a classi-
ficacao da amostra n pelo classificador fraco escolhido na rodada t
21: Se H(n) ≥ threshold classificador final, entao a amostra n e uma face; caso
contrario, e uma nao-face.
22: Return H(n)
Conforme novos classificadores fracos vao sendo escolhidos, o estagio parcial e
validado, utilizando esses classificadores, para saber se a meta de falsos negativos
foi atingida ou nao (e, portanto, se mais classificadores devem ser escolhidos ou
nao). Caso o objetivo tenha sido alcancado, o treino do estagio e concluıdo. Caso
contrario, os pesos de cada amostra sao atualizados, de acordo com a formula ex-
posta no passo 18 do Algoritmo 3. Para amostras corretamente classificadas, o peso
conferido e menor, enquanto que amostras incorretamente classificadas ganham um
peso maior. Essa abordagem evita que o mesmo classificador seja escolhido na ro-
dada seguinte, pois, com os novos pesos, ele tera rendimento certamente inferior ao
melhor possıvel, forcando, com isso, que na rodada seguinte sejam buscadas outras
informacoes no conjunto de treino, capazes de distinguir faces de nao-faces, que nao
as ja descobertas. Dessa forma, novas features serao escolhidas.
O chamado classificador forte e uma combinacao linear de todos os classificadores
fracos selecionados, na qual os coeficientes que multiplicam cada classificador sao,
na realidade, os pesos α a eles associados. Por conta desses pesos, o resultado obtido
pelo classificador forte e um escalar e, com isso, e necessario calcular um limiar, o
qual separa as amostras de face das de nao-face, fazendo-se valer desses resultados.
Para o calculo desse limiar, adotou-se a abordagem, na qual o classificador forte e
pensado como uma “super feature”, e, dessa forma, a obtencao do limiar associado
a ele foi feita empregando-se o mesmo metodo de obtencao do melhor limiar de
cada feature. Conforme explicado anteriormente, esse metodo consiste em estipular
limiares igualmente espacados entre os valores mınimo e maximo da feature. Nesse
caso, os valores da “super feature”correspondem aos escalares obtidos da combinacao
linear dos classificadores fracos. Tanto a implementacao tradicional do AdaBoost
quanto a realizada por Viola e Jones sugerem valores para esse limiar (0 e 12×∑T
t=1 αt, respectivamente), porem, nao se manteve nenhum deles, porque, nesse
34
projeto, em alguns casos de amostras de face obtidas pela aplicacao do escaneador,
os escalares obtidos pelo classificador forte encontraram-se um pouco abaixo de
ambos os limiares, o que acarretou um aumento na taxa de falsos negativos. A
utilizacao da abordagem da “super feature”melhorou essa taxa, as custas de um
acrescimo nas taxas de falsos positivos.
O estagio recem-treinado e, entao, integrado a cascata e uma validacao da mesma,
assim como fora feita com o novo estagio, e realizada. As amostras de validacao sao
passadas pela cascata parcial e suas estatısticas sao obtidas. Dentre elas, a taxa de
falsos positivos da cascata. Caso essa taxa esteja abaixo do maximo estabelecido, a
adicao de novos estagios se interrompe, finalizando, portanto, a construcao da cas-
cata. Se isso nao ocorrer, um novo estagio precisara ser adicionado e a cascata sera
validada novamente. Conforme apontado na Secao 3.1.1, porem, a porcao de amos-
tras negativas do conjunto de treinamento que sera utilizada no estagio seguinte
deve ser composta, somente, por amostras incorretamente classificadas como face
pela cascata parcial. Os falsos positivos presentes ate o momento sao reaproveitados
e integrados ao novo conjunto. Geralmente eles nao sao suficientes para construir
inteiramente a porcao negativa do novo conjunto, tornando-se necessario, entao, a
inclusao de novas amostras negativas. Essas amostras sao avaliadas pela cascata
parcial e, caso sejam classificadas como face, passam a integrar o novo conjunto
de treinamento. Vale ressaltar que a nova base de amostras negativas de treino e
montada mantendo-se a mesma proporcao de tipos de amostras estabelecidos inici-
almente no codigo (amostras de cenarios de cidade, paisagens e ambientes fechados
e de faces cortadas e descentralizadas)4.
3.2 Escaneamento de Faces em Imagens
O detector de faces construıdo nao e capaz de localizar, sozinho, faces em uma
determinada imagem. Sua tarefa e apenas qualificar imagens a ele apresentadas
como faces ou nao-faces. Com isso, surge a necessidade de se criar um algoritmo
capaz de vasculhar e localizar faces presentes em uma determinada imagem. Com
4 Observacoes sobre esse ponto sao encontradas na Secao 5.1
35
esse proposito, projetou-se o segundo modulo do sistema, chamado de escaneador. A
ideia por tras desse modulo e a seguinte: dada uma imagem que contenha uma face,
serao utilizadas janelas de diferentes resolucoes que conterao regioes dessa imagem.
Cada uma dessas janelas e, portanto, uma nova imagem, a qual sera redimensionada
para a resolucao 24x24, para ser avaliada pelo detector treinado. O resultado do
detector determinara, entao, se a face esta ou nao contida na regiao da imagem
original representada pela janela em questao. Atraves dessa abordagem torna-se
possıvel localizar faces em imagens. O Algoritmo 4 exibe os passos executados pelo
escaneador.
O primeiro passo do algoritmo e determinar que resolucoes terao as janelas de
busca. A escolha dessas resolucoes afeta diretamente o desempenho do detector,
tendo em vista que janelas de tamanhos diferentes enquadrarao a face de forma
distinta, em alguns casos melhores do que em outros. Uma taxa de crescimento
de resolucoes que rende bons resultados e de um fator de 1,25 [2]. Sendo assim,
as escalas de cada uma das janelas podem ser obtidas atraves dessa progressao
geometrica, dada na Equacao (3.4). O arredondamento e necessario, para garantir
que as resolucoes sejam numeros inteiros.
res = round(resolucao base× 1.25q), q = 1, 2, ... (3.4)
A resolucao base adotada e 24x24, que e aquela para a qual o detector foi treinado.
Seria possıvel comecar por essa resolucao e, entao, ajusta-la progressivamente, res-
peitando a Equacao (3.4), ate se alcancar a maior resolucao possıvel para a imagem
em questao. Porem, considerando a natureza das imagens que foram utilizadas pelo
escaneador, concluiu-se que muitas dessas escalas nao seriam capazes de incluir todo
o rosto de uma pessoa, nos moldes utilizados no treino, ja que teriam tamanho muito
reduzido comparado ao tamanho das faces em tais imagens. Com isso, a resolucao
mınima das janelas, estipulada nesse projeto, foi de 179x179, que corresponde ao
nono termo da progressao geometrica em questao. Vale ressaltar que a escolha dessa
resolucao se deve ao tamanho das faces nas imagens que foram utilizadas para testar
36
Algoritmo 4 Algoritmo do Escaneador
1: resolucoes ← vetor contendo as diferentes resolucoes que terao as janelas de
busca
2: posicao janela x← 0
3: posicao janela y ← 0
4: maior coeficiente face← −∞
5: ∆← 5
6: for all res in resolucoes do
7: passo← round(fator escala×∆)
8: while posicao janela y < dimensao y imagem do
9: while posicao janela x < dimensao x imagem do
10: janela← regiao da imagem correspondente a posicao atual da janela
e sua resolucao
11: janela redimensionada ← redimensionamento da imagem represen-
tada pela variavel janela para a resolucao utilizada pelo detector (24x24)
12: classificacao ← classificacao do detector ao analisar a janela redi-
mensionada em questao
13: coeficiente face← resultado obtido pelo detector antes de se aplicar
o limiar a ele associado
14: if classificacao = face then
15: if coeficiente face > maior coeficiente face then
16: maior coeficiente face← coeficiente face
17: janela face← janela
18: end if
19: end if
20: posicao janela x← posicao janela x+ passo
21: end while
22: posicao janela x← 0
23: posicao janela y ← posicao janela y + passo
24: end while
25: end for
26: Return janela face
37
o escaneador, sendo, portanto, a menor resolucao, na qual uma face, presente nes-
sas imagens, poderia ser devidamente enquadrada. Todas as janelas de busca sao
do tipo quadradas e essa necessidade decorre do fato de o detector realizar o redi-
mensionamento delas para a resolucao 24x24, antes de efetuar a deteccao. Janelas
nao quadradas, ao serem redimensionadas para a resolucao do detector, apresentam
deformacoes que afetam o seu desempenho, o que comprometeria a localizacao de
faces na imagem.
Tao importante quanto a resolucao das janelas e tambem o passo de busca adotado
por elas. A quantidade de pixels pela qual a janela e deslocada tem influencia direta
no exito de se localizar corretamente as faces, ja que, dependendo do deslocamento,
pode ser que a face nao seja bem enquadrada por nenhuma das janelas, o que fara
com que o detector as classifique como nao-face. A escolha do passo envolve um
trade-off entre a acuracia e a rapidez do escaneador. Passos menores aumentam a
precisao, pois havera mais janelas com faces devidamente enquadradas e, portanto,
proximas dos exemplos utilizados no treino do detector, porem aumentam, tambem,
o tempo necessario para varrer toda a imagem, enquanto que passos maiores tem
o efeito contrario. Uma formula para o passo, a qual foi adotada nesse projeto, e
sugerida por Viola e Jones e esta exposta na Equacao (3.5).
passo = round(fator escala×∆) (3.5)
A funcao round(x), exibida na Equacao (3.5), arredonda o numero x ∈ Q para o
numero inteiro mais proximo. O fator de escala, dado na Equacao (3.6), e o termo
que multiplica a resolucao base da Equacao (3.4). Ja ∆ e uma constante arbitraria.
Com isso, escolheu-se o valor 5 para ela, pois, com ele, foi possıvel obter janelas
contendo faces enquadradas, sem demandar um tempo de varredura considerado
excessivamente alto para esse projeto. Observacoes sobre esse valor estao expostas
na Secao 5.1
fator escala = 1, 25q, q = 1, 2, ... (3.6)
38
Uma vez determinados a resolucao e o passo, uma varredura e feita em todas as
posicoes possıveis da janela em questao na imagem. As janelas recortam regioes
da imagem original, sendo, portanto, amostras que serao aplicadas ao detector.
Dada a quantidade de amostras analisadas, e esperado que mais de uma delas seja
classificada como face e, consequentemente, que algumas delas enquadrem melhor a
face do que outras. Dessa forma, surge a necessidade de se desenvolver um criterio
para selecionar aquela que melhor localiza o rosto na imagem. O criterio adotado,
mostrado no Algoritmo 4, e detalhado a seguir.
Conforme explicado na Secao 3.1.2.5, a cada amostra analisada pelo detector e
retornado um escalar, fruto da combinacao linear das classificacoes dadas por cada
classificador fraco que compoe o ultimo estagio da cascata, o qual e comparado ao
limiar desse estagio, para decidir a que classe pertence tal amostra. Esse escalar pode
ser pensado como um indicativo da certeza com a qual a amostra corresponde, de
fato, a uma face. Aquelas, cujo escalar resultante encontra-se mais distante do limiar
do classificador, tem mais chances de representar melhor a face do que aquelas, cujo
escalar situa-se proximo ao limiar. Tendo isso em vista, a abordagem adotada para
se selecionar a janela final, que localizara a face, e escolher aquela que possui o maior
escalar obtido pelo classificador forte do ultimo estagio da cascata. A classificacao
das janelas e a geracao de tais resultados e feita na funcao detectFaces.m.
3.3 Treinamento do Reconhecedor
O terceiro modulo do sistema se encarrega de efetuar o reconhecimento da face
presente na imagem em questao, o qual sera feito mediante a analise da janela obtida
do escaneador. Assim como o detector de faces, e preciso treinar o reconhecedor,
de modo a capacita-lo a diferenciar faces de pessoas distintas. O reconhecedor
desenvolvido nesse modulo segue a abordagem das Eigenfaces, explicada na Secao
2.2, e o Algoritmo 5 expoe os passos seguidos na execucao do seu treino. A funcao
que implementa o Algoritmo 5 se chama mainRecognizer.m.
O conjunto de treinamento do reconhecedor contem 7 pessoas diferentes e cada
uma possui 10 amostras, totalizando 70 amostras. Todas elas representam faces
39
Algoritmo 5 Treino do Reconhecedor
1: A← matriz contendo as amostras a serem utilizadas no treino do reconhecedor
2: imagem media← mean(A)
3: A← A− imagem media
4: σ ← vetor de desvios-padrao obtidos das amostras de treino. Cada elemento do
vetor corresponde ao desvio-padrao associado aos pixels de uma mesma regiao
em todas as imagens
5: Cada amostra presente na matriz A e, entao, normalizada em desvio-padrao. A
operacao de normalizacao, dada por A← Aσ
, e realizada pixel por pixel e com o
desvio-padrao correspondente para cada pixel.
6: L← matriz de covariancia obtida das amostras de treino
7: Calcula-se, atraves do metodo de complexidade mais baixa, os autovetores e
os autovalores da matriz de covariancia, ordenados de forma decrescente de
autovalores
8: energia parcial← 0
9: energia total← 1
10: i← 0
11: while energia parcial < fator × energia total do
12: eigenfaces[i]← autovetores[i]
13: energia parcial← autovalores[i]∑nAutovaloresj=1 autovalores[i]
14: i← i+ 1
15: end while
16: wn ← vetor contendo o valor das projecoes de cada amostra de treino n nos
eigenfaces
17: I ← amostra a ser reconhecida
18: I ← I − imagem media
19: Assim como anteriormente, a amostra de entrada e normalizada, tambem, em
desvio-padrao, por meio da operacao I ← Iσ, realizada pixel a pixel e com o
desvio-padrao correspondente para cada pixel.
20: classificacao← reconhecerFace(amostra entrada,Wn, eigenfaces)
21: Return classificacao
40
frontais retiradas de imagens que foram fornecidas ao escaneador. Uma imagem de
dimensao N ×N pode ser interpretada como um vetor no espaco N2, de modo que
esses vetores podem ser utilizados para compor as colunas de uma matriz. Essa e
a abordagem utilizada no codigo para se armazenar as amostras de treino. Antes,
porem, e realizado um redimensionamento das imagens para uma resolucao inferior,
de modo a diminuir o custo computacional do treino, o qual e sobretudo crıtico
no calculo da matriz de covariancia, conforme sera visto adiante. Nesse projeto, a
resolucao utilizada para as amostras de treino foi 30x30. Exemplos de amostras de
cada uma das 7 classes usadas sao mostrados nas Figuras 3.8 e 3.9, antes e depois,
respectivamente, de se realizar o redimensionamento. Cada pessoa foi rotulada com
uma classe distinta e cada classe foi enumerada de 1 a 7, de forma a facilitar a
interpretacao do resultado dado pelo reconhecedor.
(a) Classes 1 a 4 (da esquerda para a direita)
(b) Classes 5 a 7 (da esquerda para a direita)
Figura 3.8: Exemplos de amostras utilizadas de cada uma das classes utilizadas no
treino do reconhecedor
Os valores de um determinado pixel em cada uma das amostras de treino fa-
zem parte de uma determinada distribuicao estatıstica, traduzida por uma variavel
aleatoria. Todas as variaveis aleatorias precisam ser normalizadas em media e em
desvio-padrao, porque essa condicao e requerida na Analise de Componentes Princi-
pais, ou PCA, tecnica aplicada para selecionar as eigenfaces, as quais sao os vetores
41
(a) Classes 1 a 4 (da esquerda para a direita)
(b) Classes 5 a 7 (da esquerda para a direita)
Figura 3.9: Amostras da Figura 3.8 redimensionadas para a resolucao 30x30
que compoem a base do espaco de faces, conforme explicado na Secao 2.2. A imagem
media e aquela na qual o valor de cada pixel e igual a media da variavel aleatoria cor-
respondente, e ela tambem representa uma face, sendo referida como “face media”.
A face media do conjunto de treinamento utilizado e exibida na Figura 3.10.
Imagem Média
Figura 3.10: “Face media” do conjunto de treinamento utilizado
A matriz de covariancia e calculada, utilizando-se a matriz que contem as amos-
tras de treino normalizadas, e o proposito de se obte-la e extrair seus autovetores.
A formula para se calcula-la e dada na Equacao (3.7). A matriz A tem dimensao
N2×M , onde M e o numero de amostras de treino e N e a resolucao dessas amostras.
Dependendo do valor de N , o tamanho da matriz de covariancia pode ser proibi-
tivamente alto, nao sendo possıvel a sua criacao. Para contornar esse problema, e
42
sugerida uma outra abordagem por Turk e Pentland [11], a qual fora explicada na
Secao 2.2, que envolve o calculo de uma matriz intermediaria de tamanho M ×M .
A partir dessa matriz, se obtem os autovetores da matriz de covariancia. Entre-
tanto, de modo a evitar esses passos extras, optou-se por reduzir a resolucao das
amostras de treino, conforme explicado anteriormente, de forma a tornar possıvel
efetuar diretamente o calculo dos autovetores da matriz de covariancia, ja que o
custo computacional, na nova resolucao, nao seria tao elevado. Alem disso, esse
metodo e mais simples do que o proposto em [11].
L = AAT (3.7)
Os autovetores dessa matriz de covariancia, tambem chamados de eigenfaces sao
calculados, tal como os autovalores associados a eles. Aplica-se, entao, a PCA, como
forma de se selecionar os P autovetores (com P << N2) que possuem os maiores
autovalores, visando, com isso, reduzir a dimensionalidade do problema em questao
(de N2 para P ). Os autovalores correspondem a energia retida por cada autovetor.
A quantidade de eigenfaces que serao escolhidas depende, portanto, da parcela da
energia total disponıvel que se deseja atingir, a qual esta representada pela variavel
fator, do Algoritmo 5. Estabeleceu-se, para esse projeto, um mınimo de 95% de
energia e, com isso, dado o numero de amostras, foram escolhidas 30 dentre as
70 eigenfaces possıveis. Como esses vetores contem a maior parte de informacao
relevante acerca das faces presentes no conjunto de treino, o espaco construıdo por
eles e chamado de “espaco de faces”. As eigenfaces selecionadas estao expostas na
Figura 3.11.
Todas as amostras de treino sao projetadas sobre cada uma das eigenfaces, resul-
tando em um vetor de pesos para cada amostra, o qual corresponde a representacao
delas no espaco de faces. A obtencao deles marca o fim do treinamento do reconhe-
cedor. O proximo passo e efetuar a identificacao de uma nova amostra de entrada,
com base nos vetores de peso obtidos. Antes de ser submetida ao reconhecimento,
a amostra deve ser normalizada em media e desvio-padrao, para se manter a con-
formidade com o treino executado. O Algoritmo 6 mostra os passos seguidos pela
43
Figura 3.11: Eigenfaces escolhidas
funcao de reconhecimento. O arquivo que contem a implementacao dessa funcao
chama-se recognizeFace.m.
A amostra de entrada tambem e projetada sobre o espaco de faces, de forma a
se obter seu vetor de pesos. A classificacao da amostra e feita levando-se em conta
em que regiao desse espaco de faces ela se encontra. E esperado que os pontos refe-
rentes a amostras de uma mesma pessoa estejam proximos uns dos outros, de modo
a formar grupamentos, ou clusters. Portanto, se a nova amostra localizar-se dentro
ou muito proxima aos pontos de um certo cluster, entao, ela provavelmente corres-
pondera a pessoa definida por ele. Com isso, para se verificar essa proximidade,
calcula-se as distancias euclidianas entre os pontos do espaco de faces corresponden-
tes a amostra a ser reconhecida e a cada uma amostras de treino.
E possıvel, no entanto, que alguns grupos estejam proximos de outros, tornando
difıcil a classificacao da amostra de entrada, caso ela se encontre nessa regiao de
intersecao. Nesses casos, a amostra de entrada pode estar mais proxima de uma
amostra de treino de um grupo, mas, na realidade, pertencer ao outro. Alem disso,
44
Algoritmo 6 Algoritmo de Reconhecimento
1: function reconhecerFace(amostra entrada,Wn, eigenfaces)
2: wentrada ← vetor contendo o valor da projecao da amostra de entrada nos
eigenfaces
3: distancias← ||wentrada−wn||2 vetor contendo as distancias euclidianas entre
as projecoes da amostra de entrada e cada amostra de treino
4: Define-se um numero K, referente a quantidade de menores distancias que
serao consideradas no reconhecimento
5: classificacao ← se a maioria das K menores distancias corresponderem a
amostras de treino de uma mesma pessoa, entao a amostra de entrada e clas-
sificada como sendo de tal pessoa. Caso nao haja maioria, a classificacao fica
indefinida
6: Return classificacao
7: end function
nem sempre todas as amostras de treino pertencentes a um mesmo grupo estarao
concentradas em uma regiao do espaco de faces. Com isso, podem acontecer casos em
que, embora a amostra de entrada esteja proxima a diversas amostras de treino de
um certo grupo (indicando que ela provavelmente pertence a esse grupo), a amostra
de treino efetivamente mais proxima da amostra de entrada pertencer a outro grupo,
do qual essa amostra de treino, eventualmente, se dispersou.
Para evitar esses casos, que induziriam o reconhecedor ao erro, adota-se a abor-
dagem conhecida como KNN (K-Nearest Neighbors). Define-se um numero K que
corresponde a quantidade de amostras vizinhas que serao levadas em conta na hora
de se determinar a classe da amostra de entrada. Sendo assim, para que uma amos-
tra seja reconhecida como sendo de uma certa classe, e preciso que a maioria das K
menores distancias sejam em relacao a amostras dessa classe. Esse numero deve ser
ımpar, de modo que sempre haja uma maioria quando a decisao estiver entre duas
classes. Um empate, no entanto, e possıvel, caso a indefinicao esteja entre tres clas-
ses. Caso isso ocorra, determinou-se que o reconhecedor emitiria uma mensagem,
informando que nao foi possıvel identificar a pessoa em questao. Diversos valores
para K foram considerados e seus resultados estao expostos na Secao 4.3.
45
Como foram utilizadas, nesse projeto, somente amostras de teste de pessoas pre-
sentes no treino, nao se estabeleceu nenhum limiar maximo, para o qual uma amostra
seria considerada de uma determinada classe, conforme feito por Turk e Pentland
[11], porque nao teriam pessoas desconhecidas no reconhecimento e, logo, nao se
criariam novas classes. Alem disso, como a deteccao de faces ja e realizada pelo
modulo anterior, tambem nao se definiu a distancia maxima a qual a imagem de
teste deveria ter do espaco de face, ja que todas as imagens que chegam ao detector
sao, de fato, de face.
46
Capıtulo 4
Resultados
4.1 Detector de Faces
O detector testado, obtido do treino, possui tres estagios. O primeiro, segundo e
terceiro estagios apresentam, respectivamente, 11, 7 e 15 features. Para a avaliacao
de seu desempenho, montou-se uma base de teste, dividida em duas partes: uma,
gerada atraves das janelas de busca utilizadas pelo escaneador (incluindo, portanto,
faces e nao-faces) e outra, atraves imagens de faces previamente enquadradas, que
nao foram resultantes da aplicacao do escaneador. As imagens sobre as quais o
escaneador foi aplicado para gerar as amostras da base de teste foram retiradas da
base de imagens “Caltech Faces”. Ja as amostras de faces previamente enquadradas
foram retiradas da base de imagens “Georgia Tech Face Database”(ver Apendice
A). As imagens da base de teste nao foram empregadas nem no treino e nem na
validacao do detector.
As amostras correspondentes as janelas de busca foram obtidas mediante o es-
caneamento de 100 imagens, das quais cada uma originou 474 janelas, totalizando,
portanto, 47400 amostras. Desse total, 57 foram separadas como amostras positi-
vas, ou seja, que correspondem a faces que deveriam ser classificadas como tal pelo
detector. As amostras negativas dessa base incluıam tanto elementos de cenario
quanto tambem faces. Nao se espera, no entanto, que o detector os classifique como
face, porque elas nao seguem os modelos de amostras positivas de face apresenta-
das ao mesmo durante seu treino. Muitas delas estao cortadas, descentralizadas,
47
ou ate mesmo centralizadas, porem incluem muito cenario em sua volta, conforme
mostrado na Figura 4.1. Alem disso, as imagens de faces previamente enquadradas,
que nao foram obtidas por meio do escaneador, corresponderam a 100 amostras, as
quais, por sua vez, nao foram misturadas com as 57 anteriores.
Figura 4.1: Exemplos de amostras negativas de face
Conduziu-se, entao, quatro testes para avaliar seu desempenho. No primeiro, a
base de teste apresentou uma quantidade muito maior de amostras de nao-faces do
que de faces, buscando simular a situacao real de escaneamento de uma imagem,
em que a quantidade de janelas de nao-face e muito superior a de faces. Para
tal, utilizou-se as 57 imagens de face, obtidas do escaneador, e 10000 imagens de
nao-face, escolhidas aleatoriamente da porcao de amostras negativas da base. No
segundo teste, repetiu-se o procedimento anterior, porem, utilizando as 100 amostras
de faces obtidas separadamente. No terceiro teste, a proporcao de amostras positivas
e negativas foi mantida igual, seguindo o modelo da base utilizada na validacao do
detector, utilizando-se, portanto, 57 imagens de face e 57 de nao-face. O ultimo teste
tambem foi igual ao terceiro, mudando, somente, as amostras de faces, empregando
100 amostras de face e 100 de nao-face. Os resultados desses testes, tais como
48
Tabela 4.1: Resultados do detector
Tipo de Teste Taxa de Erro (%) Falsos Positivos (%) Falsos Negativos (%)
Teste 1 1,89 1,71 33,33
Teste 2 1,58 1,59 1
Teste 3 17,54 1,75 33,33
Teste 4 1 1 1
Validacao 3 0 6
os resultados da validacao do treino do classificador, encontram-se na Tabela 4.1.
As Tabelas 4.2, 4.3, 4.4 e 4.5 correspondem a uma representacao alternativa dos
resultados do detector para cada um dos testes. Nelas, e apresentada a quantidade
de amostras que foram corretamente e erroneamente classificadas pelo detector, em
vez das estatısticas, ja exibidas na Tabela 4.1.
Tabela 4.2: Quantidade de amostras classificadas corretamente e erroneamente pelo
detector no Teste 1
Classificacoes Esperadas
Face Nao-Face
Classificacoes do DetectorFace 39 171
Nao-Face 18 9829
Tabela 4.3: Quantidade de amostras classificadas corretamente e erroneamente pelo
detector no Teste 2
Classificacoes Esperadas
Face Nao-Face
Classificacoes do DetectorFace 99 159
Nao-Face 1 9841
49
Tabela 4.4: Quantidade de amostras classificadas corretamente e erroneamente pelo
detector no Teste 3
Classificacoes Esperadas
Face Nao-Face
Classificacoes do DetectorFace 38 1
Nao-Face 19 56
Tabela 4.5: Quantidade de amostras classificadas corretamente e erroneamente pelo
detector no Teste 4
Classificacoes Esperadas
Face Nao-Face
Classificacoes do DetectorFace 99 1
Nao-Face 1 99
A taxa de falsos negativos dos testes 1 e 3 deriva-se do fato de que muitas das
57 faces obtidas pelo escaneador sao amostras que nao se enquadram exatamente
nos exemplos de face utilizadas para treinar o classificador. Algumas delas apre-
sentavam elementos frontais parcialmente cortados ou com uma disposicao espacial
diferente do treino, como sobrancelhas cortadas, ou boca localizada muito proxima
da borda inferior da imagem, conforme exposto na Figura 4.2. Amostras de faces
mais proximas das utilizadas no treino poderiam ser obtidas atraves da alteracao do
passo de busca empregado pelo escaneador.
(a) Amostras obtidas do escaneador (b) Amostras de treino
Figura 4.2: Exemplos de amostras obtidas pelo escaneador e utilizadas no treino
50
Quando utilizadas as amostras de face enquadradas, percebe-se que as estatısticas
do desempenho se aproximam das obtidas na validacao. Essa proximidade ocorre
devido as semelhancas entre essas amostras e as de treino, conforme se observa na
Figura 4.3. Condicoes extremas de iluminacao, isto e, imagens muito claras ou
muito escuras, tambem exercem influencia no desempenho do detector. A Figura
4.4 mostra exemplos de amostras que, exceto pela iluminacao, se assemelham as
de treino, porem, foram incorretamente classificadas como nao-faces. Alterar a
luminosidade, tornando a iluminacao das imagens neutra, faz com que o detector
passe a classifica-las como face.
Figura 4.3: Amostras de faces enquadradas, nao obtidas pelo escaneador
(a) Amostra com baixa iluminacao
(classificada como nao-face)
(b) Amostra com iluminacao neutra
(classificada como face)
Figura 4.4: Exemplo da influencia de diferentes iluminacoes na classificacao do
detector
4.2 Escaneador
Cada uma das imagens utilizadas para testar o escaneador apresentam resolucao
de 896x592 e exibem, somente, uma pessoa, a qual se encontra em posicao frontal
e em primeiro plano. Levando-se em conta a resolucao das imagens e o tamanho
das pessoas nelas, foram utilizadas janelas de busca quadradas de diferentes tama-
nhos, na tentativa de encontrar aquela que melhor enquadraria a face, de acordo
51
Tabela 4.6: Resultados do escaneador
Tipo de Classificacao Taxa (%)
Acerto 48
Falsos Positivos 50
Falsos Negativos 2
com seu tamanho e posicao e economizar tempo de escaneamento, evitando utilizar
janelas muito pequenas, que nao seriam capazes de conter toda a face. A Figura
4.5 mostra um exemplo de imagem aplicada ao escaneador. As dimensoes utilizadas
foram: 179x179, 224x224, 279x279, 349x349, 437x437, 546x546. Tanto as dimensoes
quanto os passos de busca associados a cada uma seguem as equacoes (3.4) e (3.5),
respectivamente.
Figura 4.5: Exemplo de imagem escaneada
O desempenho do escaneador foi testado atraves do escaneamento de 50 imagens.
Os resultados encontram-se na Tabela 4.6. Nesse teste, considerou-se como acerto
ou erro se, apos escanear toda a imagem, o escaneador apontasse ou nao a posicao
correta da face, por meio de um enquadramento da mesma. Os falsos positivos
sao os casos em que a janela final, escolhida para localizar a face, nao representa
uma face enquadrada. Ja os falsos negativos correspondem a imagens, nas quais o
escaneador nao encontrou nenhuma janela de face. O que se observou foi a existencia
52
de diversas janelas, em diferentes imagens, que, embora fossem falsos positivos,
possuıam elementos que excitavam as features do classificador, levando-o a conferir
um alto grau de confianca a elas (ou seja, ter um escalar de alto valor associado a ela,
conforme explicado na Secao 3.2). Essas janelas, entao, tinham maior preferencia as
outras que continham a face buscada mas nao apresentavam um grau de confianca
tao alto quanto essas amostras, o que explica as taxas de acerto e de falsos positivos
expostas. Alem disso, por utilizar um passo fixo para cada resolucao, em certas
imagens a face nao foi enquadrada devidamente, seja pela posicao ou pelo tamanho
da janela. A diminuicao do passo aumenta as chances de melhor enquadramento
das faces, e, portanto, de uma classificacao correta do detector, as custas de um
aumento no tempo de escaneamento.
Uma outra observacao a ser feita sobre os falsos positivos e que diversos deles
nao correspondem a janelas de cenario, mas sim de faces cortadas, que nao exibem
todos os elementos frontais necessarios. A Figura 4.6 mostra um exemplo desse caso.
Esse resultado reflete o modo como o detector foi treinado, uma vez que, no treino,
ele dispos de menos exemplos de amostras de faces cortadas e descentralizadas,
em comparacao com o numero de amostras de cenario. Por conta disso, ele tem
mais chances de errar amostras daquele tipo do que deste. A Figura 4.7 mostra
imagens obtidas apos o escaneamento de toda a imagem, utilizando cada uma das
resolucoes e posicoes possıveis para as janelas de busca. Os pixels dessas imagens
sao os valores dos escalares retornados pelo detector ao analisar a janela em questao
(conforme explicado na Secao 3.2). Pixels mais escuros correspondem a valores
mais baixos, ao passo que pixels mais claros, a valores mais altos. Analisando essas
imagens, percebe-se que outras janelas com valores altos para esse escalar (pixels
claros) foram encontradas proximas a janela que foi escolhida, indicando, portanto,
uma forte tendencia de haver uma face na regiao em questao, embora a janela final
nao represente uma face com todos os elementos frontais.
53
Image 1
Figura 4.6: Exemplo de falso positivo, correspondente a face cortada, encontrado
pelo escaneador
Janela 546x546 Janela 437x437 Janela 349x349
Janela 279x279 Janela 224x224 Janela 179x179
Figura 4.7: Classificacoes do detector a cada janela de busca aplicada
4.3 Reconhecedor Facial
Para o teste do reconhecedor, separou-se 5 amostras de face para cada uma das
pessoas para as quais ele foi treinado, totalizando um conjunto de teste de 35 amos-
tras. As classificacoes foram feitas baseando-se nas menores distancias euclidianas
entre as projecoes das amostras de treino e teste. Sendo assim, foram feitos 8 testes,
em que cada um alterava a quantidade de distancias euclidianas a serem consideradas
para se realizar a classificacao. A amostra de teste seria considerada de uma deter-
54
Tabela 4.7: Resultados do reconhecedor facial
Numero de Vizinhos (K) Qtd. de Erros Qtd. de Acertos Taxa de Acerto (%)
1 1 34 97,14
3 3 32 91,43
5 4 31 88,57
7 6 29 82,86
9 8 27 77,14
11 5 30 85,71
13 8 27 77,14
15 6 29 82,86
minada classe, se a maioria dos vizinhos mais proximos, dados por essas distancias,
fossem da classe em questao, conforme explicado na Secao 3.3. Os resultados dos
testes encontram-se na Tabela 4.7.
Embora a maior taxa de acerto tenha sido alcancada com apenas a utilizacao de
1 vizinho, ou seja, da amostra de treino mais proxima da imagem a ser classificada,
isso torna o reconhecedor mais suscetıvel a classificacoes equivocadas, especialmente
no caso de se utilizar um conjunto de testes maior, ja que com um numero maior
de amostras aumentam-se as chances de que uma amostra de uma classe, que nao
a correta, eventualmente, fique mais proxima da imagem a ser reconhecida. Ao se
observar as classes as quais pertencem as amostras mais proximas, e nao somente
a mais proxima, o reconhecedor torna-se mais robusto, porque e esperado que cada
classe corresponda a um agrupamento no espaco de faces, embora algumas des-
sas amostras possam estar mais distantes desse agrupamento (esse fato se observa
atraves da analise dos graficos exibidos nas Figuras 4.14, 4.12 e 4.9, correspondentes
as distancias de cada amostra de treino para a amostra de entrada a ser classifi-
cada). Dessa forma, sendo a maior parte das menores distancias pertencentes a
uma mesma classe, entao, e provavel que a amostra a ser reconhecida tambem per-
tenca a tal classe, mesmo que a amostra mais proxima a ela seja de outra, conforme
explicado na Secao 3.3. A utilizacao de muitos vizinhos pode, tambem, comprome-
55
ter o desempenho do reconhecedor, uma vez que ele comecara a analisar amostras
pertencentes a outras classes nao muito proximas daquela a ser reconhecida.
Imagem de Entrada
(a) Amostra original
Imagem Sintética
(b) Amostra reconstruıda (sintetica)
Figura 4.8: Amostra erroneamente reconhecida
0 10 20 30 40 50 60 700.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
Número da amostra
Err
o (n
orm
aliz
ado)
Distâncias euclidianas entre as amostras de entrada e de treino (normalizadas pela maior distância)
Amostras de classes distintasAmostras de mesma classe
Figura 4.9: Grafico das distancias de cada amostra de treino para a da Figura 4.8
A Figura 4.8 exibe a unica amostra classificada erroneamente pelo reconhecedor,
quando utilizado somente 1 vizinho. A Figura 4.8b corresponde a reconstrucao da
amostra original, exibida na Figura 4.8a, a partir de sua projecao no espaco de faces.
Os diferentes elementos frontais observados na face sintetizada em relacao a original
sugerem a proximidade dessa projecao a classes distintas, e nao somente aquela, a
qual a imagem pertence. A Figura 4.9 exibe um grafico das distancias das amostras
de treino para a amostra em questao, normalizadas pela maior distancia. O eixo
das abscissas corresponde ao numero da amostra de treino ao qual refere-se cada
56
distancia. Cada intervalo consecutivo de 10 amostras corresponde a uma classe.
Sendo assim, a classe 1 e representada pelas amostras de 1 a 10, a classe 2, de 11
a 20, e assim por diante. As marcacoes em vermelho correspondem a amostras de
treino pertencentes a classes diferentes da classe da amostra de entrada, ao passo
que as marcacoes em azul correspondem a amostras de treino de classe igual a classe
da amostra de entrada. E esperado, portanto, que os pontos em azul sejam os de
menor erro, localizando-se mais proximo do eixo das abscissas.
A analise desse grafico confirma a hipotese de que a amostra em questao, perten-
cente a classe 7, encontra-se proxima de mais de uma classe, que, no caso, sao as
classes 1, 2 e 7. Para esse exemplo, a utilizacao de 15 vizinhos, em vez de somente
1, na avaliacao faz com que o classificador acerte o reconhecimento. Na Figura 4.10
encontram-se realcados os 15 vizinhos mais proximos. Em contrapartida, a Figura
4.12 ilustra o exemplo em que a analise de muitos vizinhos induz o reconhecedor ao
erro. A classificacao errada, nesse caso, passa a acontecer quando se analisam 11 ou
mais vizinhos. Esse grafico esta associado a amostra exibida na Figura 4.11.
0 10 20 30 40 50 60 700.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
Número da amostra
Err
o (n
orm
aliz
ado)
Distâncias euclidianas entre as amostras de entrada e de treino (normalizadas pela maior distância)
Amostras de classes distintasAmostras de mesma classe
Figura 4.10: Grafico das distancias de cada amostra de treino para a da Figura 4.8,
com os 15 vizinhos proximos realcados
A face da Figura 4.13 foi corretamente reconhecida em todos os testes e e um
exemplo de classe bem definida. Conforme se observa no grafico da Figura 4.14, as
amostras mais proximas a ela pertencem todas a classe 4, que tambem e a sua. Alem
57
Imagem de Entrada
(a) Amostra original
Imagem Sintética
(b) Amostra reconstruıda (sintetica)
Figura 4.11: Amostra erroneamente reconhecida quando se utiliza muitos vizinhos
0 10 20 30 40 50 60 700.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
Número da amostra
Err
o (n
orm
aliz
ado)
Distâncias euclidianas entre as amostras de entrada e de treino (normalizadas pela maior distância)
Amostras de classes distintasAmostras de mesma classe
Figura 4.12: Grafico das distancias de cada amostra de treino para a da Figura 4.11
58
disso, das 11 menores distancias, 10 correspondem as amostras dessa classe, que e,
na verdade, o numero maximo de amostras por classe, nesse projeto. Essa proxi-
midade pode ser inferida atraves da semelhanca entre as faces original e sintetica,
diferentemente do que ocorreu na amostra da Figura 4.8, quando diversas classes
encontram-se proximas a amostra de teste.
Imagem de Entrada
(a) Amostra original
Imagem Sintética
(b) Amostra reconstruıda (sintetica)
Figura 4.13: Amostra corretamente reconhecida
0 10 20 30 40 50 60 70
0.4
0.5
0.6
0.7
0.8
0.9
1
Número da amostra
Err
o (n
orm
aliz
ado)
Distâncias euclidianas entre as amostras de entrada e de treino (normalizadas pela maior distância)
Amostras de classes distintasAmostras de mesma classe
Figura 4.14: Grafico das distancias de cada amostra de treino para a da Figura 4.13
59
Capıtulo 5
Conclusoes
A analise dos resultados do detector mostra que em todos os testes realizados ele
atingiu uma baixa taxa de falsos positivos. Tal resultado e ainda mais expressivo nos
testes em que a quantidade de amostras negativas foi muito superior as positivas, ja
que esses sao casos mais proximos dos reais, em que o detector tera uma quantidade
de janelas de nao-face muito superior a de faces. Embora a taxa de falsos negativos
tenha sido alta nos testes 1 e 3, contrastando com aquela obtida na validacao do
treino, a analise dos resultados dos testes 2 e 4 deixa claro que quando o detector
e apresentado a amostras de faces devidamente enquadradas, proximas daquelas
utilizadas em seu treino, a deteccao correta e atingida, e, entao, uma baixa taxa de
falsos negativos e alcancada. Portanto, isso sugere que a alta taxa de falsos negativos
dos testes 1 e 3 se deve mais ao tipo de amostras de face passadas ao detector, obtidas
do escaneador, do que a qualidade dos classificadores que o compoem.
O escaneador, por outro lado, exibiu resultados considerados insatisfatorios, uma
vez que em metade das imagens escaneadas as faces foram incorretamente locali-
zadas, ou seja, tais janelas foram consideradas como faces, embora, na verdade,
representassem nao-faces. Entretanto, os resultados do detector e o mapa de classi-
ficacao das janelas do escaneador, exibidos na Secao 4.6 indicam que a abordagem
adotada para se escolher a janela final de localizacao da face foi inapropriada. Ela,
apesar de simples, favorece um aumento da taxa de falsos positivos, o que com-
promete o desempenho do escaneador. Como aspecto positivo, vale destacar que a
taxa de falsos negativos foi baixa, mostrando que o detector e capaz de encontrar
60
faces, na maior parte dos casos em que alguma janela do escaneador a enquadra
devidamente.
As taxas de acerto do reconhecedor foram consideradas altas, mesmo nos casos
em que o aumento do numero de vizinhos representou uma piora em seu desempe-
nho. Dessa forma, os resultados foram considerados bons, especialmente quando se
leva em conta dois fatores: a simplicidade na implementacao do algoritmo execu-
tado pelo reconhecedor e o tamanho do conjunto de treino utilizado, considerado
pequeno. Para sistemas simples e pequenos de reconhecimento facial, a abordagem
de Eigenfaces mostra-se como uma boa opcao. Julga-se que os objetivos propostos
pelo trabalho foram alcancados, ja que o sistema apresenta bons resultados de de-
teccao e reconhecimento e, por meio do estudo das tecnicas empregadas, foi possıvel
descobrir que tipo de caracterısticas sao consideradas importantes para realizar tais
tarefas.
5.1 Trabalhos Futuros
Conforme apontado na Secao 3.1.2.4, a escolha do numero maximo de estagios
e features foi arbitraria. Outras opcoes para tais limites foram testadas e notou-se
uma certa tendencia de aumento da acuracia do detector conforme mais features
e estagios eram permitidos, acompanhada, tambem, de um aumento no tempo de
execucao. Dessa forma, e possıvel realizar uma analise mais aprofundada desses li-
mites, buscando aqueles que proporcionam a melhor relacao entre acuracia e tempo
de execucao. Outro ponto interessante de se analisar no treino do detector consiste
em alterar a proporcao de amostras positivas e negativas na base de validacao utili-
zada por ele. Vale lembrar que, conforme explicado na Secao 3.1.2.1, a proporcao na
base de validacao e de 1:1, enquanto que a base de treino apresenta uma proporcao
de 2:1. Cabe observar, portanto, se a mudanca na proporcao de amostras positivas
e negativas da base de validacao afeta o treino do detector, e, caso afete, de que
forma isso o influencia (melhora ou piora nas suas estatısticas, aumento no numero
de estagios da cascata...).
61
Alem disso, tambem e valido alterar a proporcao do tipo de amostras negativas
(cidades, ambientes fechados, paisagens, faces descentralizadas e faces cortadas) que
compoem a base de treino de cada estagio (nao mantendo essa proporcao fixa, como
fora feito nesse trabalho) e analisar como essa alteracao impacta no desempenho dos
estagios (e, consequentemente, da cascata). Uma outra proposta para o treino seria
observar que impactos se teriam sobre ele ao nao se utilizar uma base com tamanho
fixo e igual para cada estagio, ou seja, nao repor amostras de face nem de falsos
positivos para treinar estagios subsequentes (o que compensaria a perda de amostras
classificadas como nao-face nos estagios anteriores), significando, portanto, que a
base de treino de tais estagios seria formada, somente, por amostras classificadas
como faces nos estagios anteriores (ou seja, todas as amostras que passaram adiante
na cascata). Para tal, no entanto, e preciso garantir que a base de treino seja
grande o suficiente, de forma que, mesmo com a perda das amostras classificadas
anteriormente como nao-faces, ainda se tenha uma quantidade de amostras suficiente
que garanta uma qualidade mınima no treino do novo estagio. Como ultima sugestao
para o detector, uma extensao direta dele seria treina-lo para detectar faces nao-
frontais, ou seja, vistas de outras perspectivas e angulacoes. Para isso, cabe o estudo
de quais features sao relevantes nesse caso e como elas podem ser calculadas.
Assim como os limiares escolhidos para o detector, a constante ∆, presente na
formula que calcula o passo da janela de busca do escaneador, foi arbitrada no valor
5. Testes conduzidos com outros valores sugerem uma melhora no desempenho
do escaneador e piora no tempo de escaneamento quando essa constante assume
valores menores, pois, nesses casos, o passo e menor e a quantidade de janelas
geradas e maior, aumentando, tambem, as chances de se ter mais janelas com as faces
enquadradas. No entanto, um estudo mais minucioso dos valores dessa constante e
requerido para se confirmar essa hipotese. Cabe, tambem, testar outras abordagens
na selecao da janela final que localizara a face na imagem, de modo a comparar seus
resultados e encontrar a mais apropriada.
Para o reconhecedor, uma analise interessante seria encontrar a relacao entre o
numero de vizinhos utilizados e a taxa de acerto, ja que os resultados expostos indi-
cam uma influencia direta do primeiro sobre o segundo. Dessa forma, seria possıvel
62
descobrir qual a quantidade otima de vizinhos que se deve empregar, em cada pro-
blema, de modo a se obter a melhor taxa de acerto. Alem disso, seria interessante,
tambem, aumentar o tamanho da base de testes, de modo a checar se isso influencia
a quantidade otima de vizinhos. Um outro trabalho possıvel seria permitir o reco-
nhecedor incorporar novas classes ao sistema, mediante a apresentacao de amostras
de pessoas que nao estavam originalmente no conjunto de treinamento utilizado,
tornando-o mais versatil.
63
Referencias Bibliograficas
[1] SCHAPIRE, R. E., FREUND, Y., Boosting: Foundations and Algorithms. 1 ed.
Massachusetts, The MIT Press, 2012
[2] VIOLA, P., JONES, M., “Robust Real-Time Face Detection”, International
Journal of Computer Vision, v.57, n. 2, pp. 137-154, 2004
[3] ROWLEY, H. A., BALUJA, S., KANADE, T., “Neural Network-Based Face
Detection”, IEEE Transactions On Pattern Analysis And Machine Intelligence,
v. 20, n. 1, pp. 26-38, 1998
[4] OSUNA, E., FREUND, R., GIROSI, F., “Training Support Vector Machines:
an Application to Face Detection”. In: Proceedings of IEEE Computer Society
Conference on Computer Vision and Pattern Recognition, pp. 130-136, San Juan,
1997
[5] HSU, Rein-Lien, ABDEL-MOTTALEB, M., JAIN, A. K., “Face Detection in Co-
lor Images”, IEEE Transactions On Pattern Analysis And Machine Intelligence,
v. 24, n. 5, pp. 696-706, 2002
[6] HAYKIN, S., Neural Networks: A Comprehensive Foundation. 3 ed. Ontario,
Prentice Hall, 2008
[7] WISKOTT, L., FELLOUS, J. M., KRUGER, N., VON DER MALSBURG, C.,
“Face Recognition by Elastic Bunch Graph Matching”, IEEE Transactions On
Pattern Analysis And Machine Intelligence, v. 19, n. 7, pp. 775-779, 1997
[8] AHONEN, T., HADID, A., PIETKAINEN, M., “Face Description with Local
Binary Patterns: Application to Face Recognition”, IEEE Transactions On Pat-
tern Analysis And Machine Intelligence, v. 28, n. 12, pp. 2037-2041, 2006
64
[9] WRIGHT, J., YANG, A. Y., GANESH, A., SASTRY, S. S., MA, Y., “Robust
Face Recognition via Sparse Recognition”, IEEE Transactions On Pattern Analy-
sis And Machine Intelligence, v. 31, n. 2, pp. 210-227, 2009
[10] PHILLIPS, P. J., MOON, H., RIZVI, S. A., RAUSS, P. J., “The FERET
Evalutation Methodology for Face-Recognition Algorithms”, IEEE Transactions
On Pattern Analysis And Machine Intelligence, v. 22, n. 10, pp. 1090-1104, 2000
[11] TURK, M., PENTLAND, A. P., “Eigenfaces for Recognition”, Journal of Cog-
nitive Neuroscience, v. 3, n. 1, pp. 71-86, 1991
65
Apendice A
Bases de Face Utilizadas
Aqui encontram-se os nomes de todas as bases de imagens de faces que foram
utilizadas nesse projeto.
• AT&T “The Database of Faces”(antigamente conhecida por “The ORL Face
Database”)
• BioID Face DB - HumanScan AG, Switzerland
• Caltech Faces
• Georgia Tech Face Database
• The LFWcrop Database (“Labeled Faces in the Wild”)
• The Yale Face Database
66
Apendice B
Codigo
B.1 Treinamento do Detector de Faces
A Figura B.1 e um fluxograma que mostra quais funcoes sao chamadas dentro do
script mainCascade.m, assim como a ordem dessas chamadas.
Figura B.1: Fluxograma das funcoes chamadas pelo script mainCascade.m
mainCascade.m
67
% This script generates the cascade of classifiers , which will be used to
% detect faces
clear all
close all
clc
% If there is another classifier inside the execution directory , it is
% deleted
if ( exist ( ’ ../ Cascade Data’,’dir’))
rmdir(’Cascade Data’,’s’) ;
else
delete( ’∗.mat’);
end
%% Ratio definitions of the negative training and validation databases
% Definition of the proportions of scenario image types that will
% make the negative samples of the training and validation databases.
neg scenario rate = 0.8;
% Definition of the proportions of different scenario image types that will
% make the samples of the scenario section contained within the negative
% samples part of the training and validation databases
neg indoors rate = 0.5;
neg city rate = 0.3;
% Definition of the proportions of different face image types that will
% make the samples of the face section contained within the negative
% samples part of the training and validation databases
neg cropped face rate = 0.5;
%% Images reading and calculations of number of images of a given type
% The variables ’rows’ and ’cols ’ determine the resolution of the images to
68
% be worked with
rows = 24;
cols = 24;
[images pos, original images neg , images neg face cropped train,
images neg face decentralized train , images pos val, original images neg val , ...
images neg face cropped val, images neg face decentralized val ] = getImages(rows, cols);
% It is desired that the number of negative samples, which are used to
% train the learning algorithm, is larger than the number of positive
% samples. To validate the trained classifier , the number of positive and
% negative samples should be equal
number neg samples train = 2 ∗ size(images pos, 3);
number neg samples val = size(images pos val, 3);
% The negative samples of the training and validation databases are divided
% in two categories : images of scenario elements and incomplete face images
% (which should not be considered as faces by the classifier ) . The variable
% ’neg scenario rate ’ determines the portion of scenario images that will
% construct the negative sample database, while the portion of negative
% face images is the total number of negative sample images minus the
% scenario samples.
number neg samples scenario train = round(neg scenario rate ∗ number neg samples train);
number neg samples scenario val = round(neg scenario rate ∗ number neg samples val);
number neg samples faces train = number neg samples train −
number neg samples scenario train;
number neg samples faces val = number neg samples val − number neg samples scenario val;
% The scenario samples are divided in three categories : indoors ( living
% rooms, classrooms, labs ...) , city ( streets , plazas, parking lots ...) and
% landcapes (fields , mountains, rivers ...) . To guarantee that a wide
% variety of scenario subwindows are collected for the training and the
% validation, the previously defined portions for each scenario type are
% used, in order to establish a number of subwindows of each type to build
% the scenario part of the negative samples database.
69
number neg samples scenario indoors train = round(neg indoors rate ∗
number neg samples scenario train);
number neg samples scenario city train = round(neg city rate ∗
number neg samples scenario train);
number neg samples scenario landscapes train = number neg samples scenario train − (
number neg samples scenario indoors train + ...
number neg samples scenario city train);
number neg samples scenario indoors val = round(neg indoors rate ∗
number neg samples scenario val);
number neg samples scenario city val = round(neg city rate ∗ number neg samples scenario val);
number neg samples scenario landscapes val = number neg samples scenario val − (
number neg samples scenario indoors val + ...
number neg samples scenario city val);
% The negative face samples are divided in two types: the
% decentralized and the cropped images. Cropped images are the ones that
% contain parts of a face , but not the entire face . Note that, for this
% training, the classifier should classify a image as face only if it
% contains the two eyebrows, two eyes, a nose and a mouth
number neg samples faces cropped train = round(number neg samples faces train ∗
neg cropped face rate);
number neg samples faces decentralized train = number neg samples faces train −
number neg samples faces cropped train;
number neg samples faces cropped val = round(number neg samples faces val ∗
neg cropped face rate);
number neg samples faces decentralized val = number neg samples faces val −
number neg samples faces cropped val;
% Since a negative image is any image which does not contain an entire
% face, and this code uses low resolution images (24x24), in order to
% generate a large negative scenario samples database, high resolution
% scenario images can be used to extract lots of low resolution windows and
% each of these windows corresponds to a negative scenario sample (see more
% at extractNegativeScenarioSamples2.m).
70
images neg scenario train = extractNegativeScenarioSamples2(
number neg samples scenario indoors train, number neg samples scenario city train, ...
number neg samples scenario landscapes train, original images neg);
images neg scenario val = extractNegativeScenarioSamples2(
number neg samples scenario indoors val, number neg samples scenario city val, ...
number neg samples scenario landscapes val, original images neg val) ;
%% Integral images calculation
integral pos img = getIntegralImage(images pos);
integral neg scenario img = getIntegralImage(images neg scenario train);
integral neg face cropped img = getIntegralImage(images neg face cropped train);
integral neg face decentralized img = getIntegralImage(images neg face decentralized train) ;
integral pos val img = getIntegralImage(images pos val);
integral neg scenario val img = getIntegralImage(images neg scenario val);
integral neg face cropped val img = getIntegralImage(images neg face cropped val);
integral neg face decentralized val img = getIntegralImage(images neg face decentralized val) ;
clear ( ’images pos’, ’ images neg face cropped train’ , ’ images neg face decentralized train ’ , ’
images pos val’ , ’ images neg val’ , ’ images neg scenario val ’ , ’ images neg face cropped val
’, ’ images neg face decentralized val ’ )
clear ( ’images ∗’, ’ original images neg val ’ )
%% Feature extraction and target vector construction
% The next part of the code will calculate the features from each image.
% The images belong to both the training set and the validation set .
% However, the features from both groups are stored in different variables ,
% so that the correct samples will be used for training and for validating
% the classifier . The variables ’ features pos ’ and ’ features neg ∗’ are
% matrices that contain the features of all types from all the positive
% (face images) and the negative (non−face images) samples, respectively.
% Each line represents a different calculated feature and each column
% represents a different image.
features pos = getFeatures(integral pos img);
71
features neg scenarios = getFeatures(integral neg scenario img) ;
features neg faces cropped = getFeatures(integral neg face cropped img);
features neg faces decentralized = getFeatures( integral neg face decentralized img ) ;
features pos val = getFeatures(integral pos val img) ;
features neg scenarios val = getFeatures( integral neg scenario val img) ;
features neg faces cropped val = getFeatures(integral neg face cropped val img);
features neg faces decentralized val = getFeatures( integral neg face decentralized val img ) ;
clear ( ’ integral pos img ’ , ’ integral neg scenario img ’ , ’ integral neg face cropped img’ , ’
integral neg face decentralized img ’ , ’ integral pos val img ’ , ’
integral neg scenario val img ’ , ’ integral neg face cropped val img ’ , ’
integral neg face decentralized val img ’)
clear ( ’ integral ∗’)
disp( ’Features calculated ! ’ )
disp( ’ ’ )
features selected neg faces cropped = extractNegativeFaceSamples(
number neg samples faces cropped train, features neg faces cropped);
features selected neg faces decentralized = extractNegativeFaceSamples(
number neg samples faces decentralized train, features neg faces decentralized);
features selected neg faces cropped val = extractNegativeFaceSamples(
number neg samples faces cropped val, features neg faces cropped val);
features selected neg faces decentralized val = extractNegativeFaceSamples(
number neg samples faces decentralized val, features neg faces decentralized val) ;
% The variable ’features ’ is a matrix containing all the features , of
% all types, from every single image on the training set . The variable
% ’ features val ’ works the same way, but is related to the images of
% the validation set .
features = [features pos features neg scenarios features selected neg faces cropped
features selected neg faces decentralized ];
features val = [ features pos val features neg scenarios val
features selected neg faces cropped val features selected neg faces decentralized val ];
clear ( ’ features neg scenarios ’ , ’ features neg scenarios val ’ , ’ features selected ∗’)
72
disp([ ’The features matrix has size : ’ num2str(size(features , 1)) ’x’ num2str(size(features ,
2)) ]) ;
disp( ’ ’ )
% The variable ’target’ will contain the correct answers for whether the
% respective image from the training set contains a face or not. This
% vector is needed to train the face−detector classifier . +1 means
% a positive image (contains a face) and −1 means a negative image (does
% not contain a face) .
target = ones(1,size( features ,2) ) ;
target( size (features pos ,2)+1:size( features ,2) ) = −1;
% The variable ’ target val ’ will contain the correct answers for whether
% the respective image, from the validation set , contains a face or not.
% This vector is needed in order to validate the face−detector classifier .
% +1 means a positive image (contains a face) and −1 means a negative image
% (does not contain a face) .
target val = ones(1,size( features val ,2) ) ;
target val ( size ( features pos val ,2)+1:size( features val ,2) ) = −1;
%% Cascade training
% The variable ’max number weak learners’ will determine the maximum number
% of weak hypothesis that should form the strong hypothesis in a single
% stage of the cascade. Similarly , the variable ’max number stages’
% determines the maximum number of stages the cascade should contain. The
% variable ’ expected false negative rate stage ’ defines a maximum false
% negative rate acceptable for the stages of the cascade, while the
% variable ’ expected false positive rate cascade ’ defines the maximum false
% positive rate acceptable for the cascade as a whole.
max number weak learners = 15;
max number stages = 6;
expected false negative rate stage = 0.02;
expected false positive rate cascade = 0.00001;
73
% The upcoming loop is the actual build of the cascade classifier .
for i=1:max number stages
% During the first stage, all the images will be passed for the
% learning algorithm, in order for it to find the weak hypothesis that
% will integrate the strong hypothesis.
if ( i == 1)
[alpha, h, false positive rate stage , false negative rate stage , stage threshold ,
stage direction , neg classifications train ] = ...
stageAdaboost(max number weak learners, features, features val, target, target val
, expected false negative rate stage , i ) ;
else
% Before the training of the current stage begins, it is necessary
% to build another negative sample base, composed by negative
% samples that were misclassified by the partial cascade (built
% from the previous stages). They are false positives for the
% current cascade
new neg features = [];
counter = 0;
% Reusing the scenario false positives from the partial cascade
scenario neg classifications = neg classifications train (1:
number neg samples scenario train);
fp ind = find( scenario neg classifications == 1);
% To maintain the original proportions of image types of the
% negative samples database, a counter for each type is created, in
% order to count how many images of each type are still remaining
% to be added to the new negative sample base
74
[ scenario indoors idx , scenario city idx , scenario landscapes idx ] =
splitScenarioSections(number neg samples scenario indoors train, ...
number neg samples scenario city train, ...
number neg samples scenario landscapes train);
scenario indoors counter = number neg samples scenario indoors train;
scenario city counter = number neg samples scenario city train;
scenario landscapes counter = number neg samples scenario landscapes train;
if ˜isempty(fp ind)
for j=1:length(fp ind)
% The columns of the negative samples are located after the
% columns of the positive samples, in the ’ features ’
% matrix. Therefore, the offset inside this variable is
% necessary, since the ’ neg classifications ’ variable , from
% which the ’fp ind’ is calculated , consists only of the
% negatives samples, and not the entire training database
new neg features = [new neg features features (:, ( size (features pos ,2) +
fp ind(j))) ];
% The next section checks which is the type of the scenario
% false positive (indoors, landscapes or city)
if ˜isempty(find(scenario indoors idx == fp ind(j), 1))
scenario indoors counter = scenario indoors counter − 1;
else if ˜isempty(find( scenario city idx == fp ind(j), 1))
scenario city counter = scenario city counter − 1;
else
scenario landscapes counter = scenario landscapes counter − 1;
end
end
end
end
% If any scenario type counter is not 0, then some images of the
% given type(s) are needed, so that the negative training database
75
% can be reconstructed
for ind = 1:size(original images neg , 4)
switch(ind)
case 1 % Indoors type
counter = scenario indoors counter;
case 2 % City type
counter = scenario city counter ;
case 3 % Landscape type
counter = scenario landscapes counter;
end
while (counter ˜= 0)
switch(ind)
case 1 % Indoors type
new neg sample = extractNegativeScenarioSamples2(1, 0, 0,
original images neg);
case 2 % City type
new neg sample = extractNegativeScenarioSamples2(0, 1, 0,
original images neg);
case 3 % Landscapes type
new neg sample = extractNegativeScenarioSamples2(0, 0, 1,
original images neg);
end
integral img = getIntegralImage(new neg sample);
features new neg sample = getFeatures(integral img);
% The second condition of the upcoming ’if’ clause checks if
% the new chosen sample is already inside the ’new neg feature’
% matrix. This guarantees that this matrix does not possess
% duplicated columns, which would make the training of the
76
% current stage poorer.
if (˜isempty(new neg features))
if ((˜isempty(new neg sample)) && ˜isempty(find(˜any(bsxfun(@minus,
new neg features, features new neg sample)), 1)))
continue;
end
end
classification = getStageNegativeSampleWrongClassification(
features new neg sample, h, alpha, stage threshold, stage direction);
if ( classification == 1)
counter = counter − 1;
new neg features = [new neg features features new neg sample];
end
end
end
% The incomplete face images are once again chosen randomly to
% complete the new negative train database, used to train the
% new stage
neg faces cropped features = extractNegativeFaceSamples(
number neg samples faces cropped train, features neg faces cropped);
neg faces decentralized features = extractNegativeFaceSamples(
number neg samples faces decentralized train, features neg faces decentralized);
features = [features pos new neg features neg faces cropped features
neg faces decentralized features ];
clear ( ’ neg faces cropped features ’ , ’ neg faces decentralized features ’ , ’
new neg features’)
disp([ ’New negative training samples chosen for stage ’ num2str(i) ’ . Beginning
training for this stage ... ’ ])
disp( ’ ’ )
77
disp([ ’The features matrix has size : ’ num2str(size(features , 1)) ’x’ num2str(size(
features , 2)) ]) ;
disp( ’ ’ )
[alpha, h, false positive rate stage , false negative rate stage , stage threshold ,
stage direction , neg classifications train ] = ...
stageAdaboost(max number weak learners, features, features val, target, target val
, expected false negative rate stage , i ) ;
end
stage( i ) .alpha = alpha;
stage( i ) .h = h;
stage( i ) .FP = false positive rate stage ;
stage( i ) .FN = false negative rate stage ;
stage( i ) .threshold = stage threshold;
stage( i ) . direction = stage direction ;
[ false positive rate cascade , false negative rate cascade , error rate cascade ] =
validateCascade(features val, target val , stage, i ) ;
disp( ’ ’ ) ;
if ( i ˜= max number stages)
disp( ’ Partial Cascade’);
else
disp( ’Final Cascade’);
end
disp([ ’Number of stages: ’ num2str(i)]) ;
disp([ ’Cascade Error Rate: ’ num2str(error rate cascade ∗ 100) ’ %’]) ;
disp([ ’Cascade False Positive Rate: ’ num2str( false positive rate cascade ∗ 100) ’ %’]) ;
disp([ ’Cascade False Negative Rate: ’ num2str(false negative rate cascade ∗ 100) ’ %’]) ;
% If the cascade achieves a false positive rate lower than the
% expected, with the current stages , then there is no need to add more
% stages. Therefore, the main loop ends. Otherwise, one more stage
% needs to be added.
if false positive rate cascade < expected false positive rate cascade
78
break;
end
end
%% Save the trained classifier
save( ’cascade’ , ’stage’ )
organizeFiles () ;
clear all
load(’ ../ Cascade Data/cascade.mat’)
getImages.m
function [imgs pos, imgs neg, imgs neg faces cropped, imgs neg faces decentralized ,
imgs pos val, imgs neg val, ...
imgs neg faces cropped val, imgs neg faces decentralized val ] = getImages(rows, columns)
% This function reads all the images which belong to the training and
% validation sets and stores each different type of image (positive
% validation samples, negative training scenario city samples, negative
% cropped validation faces samples, ...) in different matrices. The face
% images (positive samples) are also resized to the resolution of the
% detector (which, in this case, is 24x24).
%
% Arguments: − rows = one of the dimensions of the face samples. This one
% corresponds to the height of such samples. Along with
% the ’columns’ variable , it will define the resolution
% of the face samples that will be used to train the
% detector .
%
% − columns = one of the dimensions of the face samples. This
% one corresponds to the width of such samples.
% Along with the ’rows’ variable , it will define the
% resolution of the face samples that will be used
% to train the detector .
79
%
% Returns: − imgs pos = matrix containing the face samples (positive
% samples) which will be used to train the
% detector . These samples are already resized to
% the resolution of the detector (24x24)
%
% − imgs neg = matrix containing the scenario samples
% (negative samples) which will be used to train
% the detector . The fourth dimension of this
% matrix is used to separate the different types
% of scenarios considered (indoors, cities and
% landscapes)
%
% − imgs neg faces cropped = matrix containing the
% cropped face samples (negative
% samples) which will be used to
% train the detector . These samples
% are already resized to the
% resolution of the detector
% (24x24)
%
% − imgs neg faces decentralized = matrix containing the
% decentralized face samples
% (negative samples) which
% will be used to train the
% detector . These samples are
% already resized to the
% resolution of the detector
% (24x24)
%
% − imgs pos val = matrix containing the face samples
% ( positive samples) which will be used to
% validate the detector . These samples are
% already resized to the resolution of the
% detector (24x24)
%
% − imgs neg val = matrix containing the scenario samples
% (negative samples) which will be used to
% validate the detector . The fourth dimension
80
% of this matrix is used to separate the
% different types of scenarios considered
% (indoors, cities and landscapes)
%
% − imgs neg faces cropped val = matrix containing the cropped
% face samples (negative
% samples) which will be used
% to validate the detector .
% These samples are already
% resized to the resolution of
% the detector (24x24)
%
% − imgs neg faces decentralized val = matrix containing the
% decentralized face
% samples (negative
% samples) which will be
% used to validate the
% detector . These samples
% are already resized to
% the resolution of the
% detector (24x24)
%% Training − Positive Samples
exec path = pwd;
cd(’ ..\..\ IMG\Pos2\’);
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
resolution = [rows columns];
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
81
I = imresize(I , resolution ) ;
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs pos (:,:, img counter) = I;
img counter = img counter + 1;
end
end
%% Training − Negative Samples − Scenario Images
% Indoors images
cd(’ ..\Neg Scenario Train\Indoors’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
scenario type = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg :,:, img counter, scenario type = I;
82
img counter = img counter + 1;
end
end
scenario type = scenario type + 1;
% City images
cd(’ ..\City’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg :,:, img counter, scenario type = I;
img counter = img counter + 1;
end
end
scenario type = scenario type + 1;
% Landscapes images
cd(’ ..\Landscapes’)
curr path = pwd;
83
files = dir;
number of files = size( files ,1) ;
img counter = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg :,:, img counter, scenario type = I;
img counter = img counter + 1;
end
end
%% Training − Negative Samples − Faces
% Cropped faces
cd(’ ..\..\ Neg Faces Train\Cropped’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
84
I = imread(files( i ) .name);
I = imresize(I , resolution ) ;
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg faces cropped (:,:, img counter) = I;
img counter = img counter + 1;
end
end
% Decentralized faces
cd(’ ..\Decentralized’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
I = imresize(I , resolution ) ;
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg faces decentralized (:,:, img counter) = I;
img counter = img counter + 1;
85
end
end
%% Validation − Positive Samples
cd(’ ..\..\ Pos Val2\’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
I = imresize(I , resolution ) ;
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs pos val (:,:, img counter) = I;
img counter = img counter + 1;
end
end
%% Validation − Negative Samples − Scenario Images
% Indoors images
cd(’ ..\Neg Scenario Val\Indoors’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
86
img counter = 1;
scenario type = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg val :,:, img counter, scenario type = I;
img counter = img counter + 1;
end
end
scenario type = scenario type + 1;
% City images
cd(’ ..\City’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
87
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg val :,:, img counter, scenario type = I;
img counter = img counter + 1;
end
end
scenario type = scenario type + 1;
% Landscapes images
cd(’ ..\Landscapes’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg val :,:, img counter, scenario type = I;
img counter = img counter + 1;
end
end
88
%% Validation − Negative Samples − Faces
% Cropped faces
cd(’ ..\..\ Neg Faces Val\Cropped’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
I = imresize(I , resolution ) ;
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg faces cropped val (:,:, img counter) = I;
img counter = img counter + 1;
end
end
% Decentralized faces
cd(’ ..\Decentralized’)
curr path = pwd;
files = dir;
number of files = size( files ,1) ;
img counter = 1;
89
for i = 1:number of files
[˜,˜, ext] = fileparts ( files ( i ) .name);
if (strcmp(ext, ’ .jpg’) == 1)
I = imread(files( i ) .name);
I = imresize(I , resolution ) ;
if ( size ( size (I) , 2) == 3) %RGB image
I = rgb2gray(I);
end
I = double(I);
imgs neg faces decentralized val (:,:, img counter) = I;
img counter = img counter + 1;
end
end
cd(exec path)
end
extractNegativeScenarioSamples2.m
function [subwindows] = extractNegativeScenarioSamples2(number samples indoors,
number samples city, number samples landscapes, images)
% This function extracts lots of subwindows of a given resolution (in the
% case of this project , 24x24) from high resolution images. A large
% database of negative samples can then be generated using few high
% resolution images.
%
% Arguments: − number samples indoors = the number of indoors samples to be
% extracted from the indoors images
%
% − number samples city = the number of city samples to be
90
% extracted from the city images
%
% − number samples landscapes = the number of landscapes samples
% to be extracted from the
% landscapes images
%
% − images = a matrix containing all images from each type. The
% third dimension of the matrix is the image count of
% a given type, while the forth dimension is the type
% count (in this case, there are 3 possible types)
%
% Returns: − subwindows = a matrix containing all the extracted
% subwindows, which are the negative samples
base resolution = 24;
% The variable ’selected subwindows’ is a matrix which serves as a table
% for recording the exact subwindow that were already extracted. It takes
% into the account the image, resolution and the coordinates of the left
% upper corner pixel used.
selected subwindows = zeros(1, 4);
total samples = number samples indoors + number samples city + number samples landscapes;
subwindows = zeros(base resolution, base resolution , total samples) ;
ind = 1;
for type = 1:size(images, 4)
switch type
case 1
number samples = number samples indoors;
case 2
number samples = number samples city;
case 3
number samples = number samples landscapes;
end
91
sample counter = 0;
while sample counter < number samples
nImg = randi(size(images, 3), 1);
factor = randi([9 14], 1);
% The resolutions of the subwindows are given according to the face
% scanner that will be used to find the faces in the image. The face
% scanner will run on the same image many times with different
% resolutions for the scan window. These resolutions were
% pre−established according to the size of the images (and the faces
% contained within) that the face scanner will run on.
resolution = round(base resolution ∗ (1.25 ˆ factor)) ; % Possible resolutions are [179
224 279 349 437 546]
img aux = images:, :, nImg, type;
% The next two lines are to guarantee that the subwindow to be
% extracted will not be out of the bounds of the image
xIni = randi((size(img aux, 2) − (resolution − 1)), 1);
yIni = randi((size(img aux, 1) − (resolution − 1)), 1);
xFin = xIni + resolution − 1;
yFin = yIni + resolution − 1;
new row = [nImg resolution xIni yIni];
% If already exists an entry in the ’selected subwindows’ matrix
% exactly with the same data of the chosen subwindow, then it means
% this subwindow has already been extracted and, therefore, a new
% one must be chosen.
if ismember(new row, selected subwindows, ’rows’)
continue
else
92
% If there are no samples yet, then there are no valid entries
% in the ’selected subwindows’ matrix. So, the invalid first
% entry of zeros is changed by the actual subwindow to be
% extracted. Later on, new entries will increase the matrix
% size.
if sample counter == 0
selected subwindows = new row;
else
selected subwindows = [selected subwindows; new row];
end
subwindow aux = img aux(yIni:yFin, xIni:xFin);
subwindows(:,:,ind) = imresize(subwindow aux, [base resolution base resolution ]) ;
ind = ind + 1;
sample counter = sample counter + 1;
end
end
end
getIntegralImage.m
function [ integral image ] = getIntegralImage(image)
% This function transforms the original image in its integral image
%
% Arguments: − image = original image to be converted
%
% Returns: − integral image = integral image representation of the
% original image
integral image = zeros(size(image));
for i = 1:size(image,3)
93
integral image (:,:, i ) = calculateIntegralImage(image (:,:, i )) ;
end
end
calculateIntegralImage.m
function [int img] = calculateIntegralImage(img)
% This function calculates the integral image of a given input image
%
% Arguments: − img = image to be converted
%
% Returns: − int image = integral image of the input image
int img = cumsum(cumsum(img,2),1);
getFeatures.m
function [ features ] = getFeatures(integral image)
% This function obtains the features values of all input images
%
% Arguments: − integral image = matrix containing the integral image
% representations from all the original
% images
%
% Returns: − features = matrix containing all features from all images
% passed to the function. Every column represents
% an image and every line, its corresponding
% feature
features = [];
for j = 1:size(integral image , 3)
features img = calculateFeatures(integral image (:,:, j )) ;
features = [features features img ];
94
% Resets the vector, so it will hold the features from another image,
% in the next iteration
features img = [];
end
calculateFeatures.m
function [features img] = calculateFeatures(int img)
% This function effectively calculates all the features from a given input
% image.
%
% Arguments: − int img = integral representation of the original image,
% from which it is desired to calculate the features
%
% Returns: features img = vector containing all the features values of the
% input image
features img = [];
[maxHeight, maxWidth] = size(int img);
buildingBlocks = [1 2 % Two−Rectangle Vertical feature
2 1 % Two−Rectangle Horizontal feature
1 3 % Three−Rectangle Vertical feature
3 1 % Three−Rectangle Horizontal feature
2 2]; % Four−Rectangle feature
for type = 1:size(buildingBlocks, 1)
baseHeight = buildingBlocks(type,1);
baseWidth = buildingBlocks(type,2);
height = baseHeight;
width = baseWidth;
while (width <= maxWidth)
while(height <= maxHeight)
95
initialX = 1;
initialY = 1;
finalX = initialX + width − 1;
while(finalX <= maxWidth)
finalY = initialY + height − 1;
midX = initialX + round(width/2) − 1;
twoThirdsX = initialX + round((2/3) ∗ width) − 1;
oneThirdX = initialX + round((1/3) ∗ width) − 1;
while (finalY <= maxHeight)
midY = initialY + round(height/2) − 1;
twoThirdsY = initialY + round((2/3) ∗ height) − 1;
oneThirdY = initialY + round((1/3) ∗ height) − 1;
switch (type)
case 1 % Two−Rectangle Vertical feature
if ( initialX == 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY, midX)
;
else if ( initialX == 1) && (initialY ˜= 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY,
midX) − int img((initialY − 1), finalX) + 2 ∗ int img(( initialY − 1), midX);
else if ( initialX ˜= 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY
, midX) + int img(finalY, (initialX − 1));
else
feature = int img(finalY, finalX) − 2 ∗ int img(finalY
, midX) − int img((initialY − 1), finalX) + 2 ∗ int img(( initialY − 1), midX) + int img(
finalY, (initialX − 1)) − int img((initialY − 1), ( initialX − 1));
end
end
end
case 2 % Two−Rectangle Horizontal feature
if ( initialX == 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(midY, finalX);
96
else if ( initialX == 1) && (initialY ˜= 1)
feature = int img(finalY, finalX) − 2 ∗ int img(midY,
midX) + int img((initialY − 1), finalX);
else if ( initialX ˜= 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(midY,
finalX) − int img(finalY, ( initialX − 1)) + 2 ∗ int img(midY, (initialX − 1));
else
feature = int img(finalY, finalX) − 2 ∗ int img(midY,
finalX) − int img(finalY, ( initialX − 1)) + 2 ∗ int img(midY, (initialX − 1)) + int img((
initialY − 1), finalX) − int img((initialY − 1), ( initialX − 1));
end
end
end
case 3 % Three−Rectangle Vertical feature
if ( initialX == 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY,
twoThirdsX) + 2 ∗ int img(finalY, oneThirdX);
else if ( initialX == 1) && (initialY ˜= 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY,
twoThirdsX) + 2 ∗ int img(finalY, oneThirdX) − int img((initialY − 1), finalX) + 2 ∗
int img(( initialY − 1), twoThirdsX) − 2 ∗ int img((initialY − 1), oneThirdX);
else if ( initialX ˜= 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY
, twoThirdsX) + 2 ∗ int img(finalY, oneThirdX) − int img(finalY, (initialX − 1));
else
feature = int img(finalY, finalX) − 2 ∗ int img(finalY
, twoThirdsX) + 2 ∗ int img(finalY, oneThirdX) − int img((initialY − 1), finalX) + 2 ∗
int img(( initialY − 1), twoThirdsX) − 2 ∗ int img((initialY − 1), oneThirdX) − int img(
finalY, (initialX − 1)) + int img((initialY − 1), ( initialX − 1));
end
end
end
case 4 % Three−Rectangle Horizontal feature
if ( initialX == 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(twoThirdsY,
finalX) + 2 ∗ int img(oneThirdY, finalX);
else if ( initialX == 1) && (initialY ˜= 1)
97
feature = int img(finalY, finalX) − 2 ∗ int img(
twoThirdsY, finalX) + 2 ∗ int img(oneThirdY, finalX) − int img((initialY − 1), finalX) ;
else if ( initialX ˜= 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(
twoThirdsY, finalX) + 2 ∗ int img(oneThirdY, finalX) − int img(finalY, (initialX − 1)) +
2 ∗ int img(twoThirdsY, (initialX − 1)) − 2 ∗ int img(oneThirdY, (initialX − 1));
else
feature = int img(finalY, finalX) − 2 ∗ int img(
twoThirdsY, finalX) + 2 ∗ int img(oneThirdY, finalX) − int img(finalY, (initialX − 1)) +
2 ∗ int img(twoThirdsY, (initialX − 1)) − 2 ∗ int img(oneThirdY, (initialX − 1)) − int img
((initialY − 1), finalX) + int img((initialY − 1), ( initialX − 1));
end
end
end
case 5 % Four−Rectangle feature
if ( initialX == 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY, midX)
− 2 ∗ int img(midY, finalX) + 4 ∗ int img(midY, midX);
else if ( initialX == 1) && (initialY ˜= 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY,
midX) − 2 ∗ int img(midY, finalX) + 4 ∗ int img(midY, midX) + int img((initialY − 1),
finalX) − 2 ∗ int img((initialY − 1), midX);
else if ( initialX ˜= 1) && (initialY == 1)
feature = int img(finalY, finalX) − 2 ∗ int img(finalY
, midX) − 2 ∗ int img(midY, finalX) + 4 ∗ int img(midY, midX) + int img(finalY, (
initialX − 1)) − 2 ∗ int img(midY, (initialX − 1));
else
feature = int img(finalY, finalX) − 2 ∗ int img(finalY
, midX) − 2 ∗ int img(midY, finalX) + 4 ∗ int img(midY, midX) + int img((initialY − 1),
finalX) − 2 ∗ int img((initialY − 1), midX) + int img(finalY, (initialX − 1)) − 2 ∗ int img(
midY, (initialX − 1)) + int img((initialY − 1), ( initialX − 1));
end
end
end
end
features img = [features img; feature ];
98
initialY = initialY + 1;
finalY = initialY + height − 1;
end
initialX = initialX + 1;
finalX = initialX + width − 1;
initialY = 1;
end
height = height + baseHeight;
end
width = width + baseWidth;
height = baseHeight;
end
end
end
extractNegativeFaceSamples.m
function [selected samples ] = extractNegativeFaceSamples(number samples, feature database)
% This function randomly selects a determined amount of negative face
% samples that will build the negative face samples portion of the
% training set of a stage.
%
% Arguments: − number samples = number of negative face samples that will
% be selected
%
% − feature database = matrix containing the features of all the
% available negative face samples. Columns
% of this matrix, which represent the
% negative face samples available , will be
% chosen randomly
%
% Returns: − selected samples = matrix containing all the features of the
% selected negative face samples
chosen indexes = [];
99
selected samples = [];
for i = 1:number samples
if (length(chosen indexes) == size(feature database, 2))
disp( ’Warning! Number of samples required is larger than the size of the database’)
break;
end
ind = ceil(rand(1) ∗ size (feature database, 2)) ;
while (ismember(ind, chosen indexes))
ind = ceil(rand(1) ∗ size (feature database, 2)) ;
end
chosen indexes = [chosen indexes ind ];
selected samples = [selected samples feature database (:, ind) ];
end
stageAdaboost.m
function [alpha, h, false positive rate , false negative rate , stage threshold , stage direction
, neg classifications train ] = ...
stageAdaboost (max number weak learners, features, features val, target , target val ,
expected false negative rate , stage number)
% This function implements the ”AdaBoost” algorithm, in order to train one
% stage of the cascade.
%
% Arguments: − max number weak learners = maximum number of features (or
% weak classifiers ) the stage is
% allowed to have
%
% − features = matrix containing all the features calculated for
% each sample of the training set . Each line
% corresponds to a feature , while each column
% corresponds to a sample
%
% − features val = matrix containing all the features calculated
% for each sample of the validation set . Each
% line corresponds to a feature , while each
100
% column corresponds to a sample
%
% − target = vector containing the correct classifications for
% each sample of the training set . Each column
% corresponds to a sample. +1 refers to face samples,
% while −1, to non−face samples
%
% − target val = vector containing the correct
% classifications for each sample of the
% validation set . Each column corresponds to a
% sample. +1 refers to face samples, while −1, to
% non−face samples
%
% − expected false negative rate = maximum false negative rate
% expected for the stage
%
% − stage number = variable used to identify which stage is being
% trained
%
% Returns: − alpha = vector containing the weights assigned to each
% feature selected during the training
%
% − h = vector of structures containing the classification
% rules . The fields of this structrure are:
%
% − h(k).feature = feature selected in the k−th iteration
% of the main loop
%
% − h(k).error = error associated with the selected
% feature
%
% − h(k).threshold = threshold associated with the
% selected feature
%
% − h(k).direction = direction, in which the value of the
% feature will be compared to its
% threshold (+1 means >=, while −1
% means <)
%
101
% − h(k).FN = false negative rate associated with the
% selected feature
%
% − false positive rate = false positive rate of the stage
%
% − false negative rate = false negative rate of the stage
%
% − stage threshold = threshold associated with the strong
% classifier , which is built through the
% linear combination of all the features
% selected during the training
%
% − stage direction = direction associated with the strong
% classification rule , in which the value of
% the linear combination of all the features
% selected during the training will be
% compared to its threshold (+1 means >=,
% while −1 means <)
%
% − neg classifications train = vector containing the
% classification given by the
% strong learner to each of the
% negative training samples
%% Training of the stage
% The variable ’D’ is the vector of weights, which will be applied
% to each image. It is updated every loop, having the wrongly classified
% images a higher weight than the correctly classified . Initially , every
% image has the same weight.
D = ones(1,size(features ,2) ) / size ( features ,2) ;
% The variable ’number thresholds’ determines how many thresholds will be
% used in each feature, in order to find the best one, together with a
% given feature, that yields the lowest classification error . The
% thresholds that will be tested are values equally spaced between the
% minimum and the maximum value of all features.
102
number thresholds = 500;
for t = 1:max number weak learners
D = D ./ sum(D);
min error(t) = inf;
for j = 1:size( features ,1)
thresholds = linspace(min(features(j ,:) ) , max(features(j ,:) ) , number thresholds);
for i=1:length(thresholds)
classifications = classifier ( features(j ,:) , thresholds( i )) ;
for k = 1:2
error(k) = sum(D .∗ (double(classifications (k ,:) ˜= target)));
end
if min(error) < min error(t)
min error(t) = min(error);
% The variable ’h’ will contain the best updated
% classifier , i .e ., the one that has the best
% feature/threshold pair that yields the lowest error rate .
h(t) . feature = j;
h(t) . error = min error(t);
h(t) .threshold = thresholds(i) ;
if (find(error==min(error)) == 1)
h(t) . direction = 1;
h(t) .FN = calculateFeatureFalseNegativeRate(classifications (1,:) , target) ;
else
h(t) . direction = −1;
h(t) .FN = calculateFeatureFalseNegativeRate(classifications (2,:) , target) ;
end
end
end
end
if h(t) . error > 1/2
103
disp( ’Error rate beyond 1/2’)
break;
end
% The variable ’alpha’ is a vector that weights the best classifier of
% the every iteration , based on the error rate of each one. These will
% be used later, on the strong learner , that will contain every weak
% classifier multiplied by its weight.
beta(t) = h(t).error / (1 − h(t).error) ;
alpha(t) = (1/2) ∗ log(1/beta(t)) ;
[ false positive rate , false negative rate , error rate , stage threshold , stage direction ,
neg classifications train ] = validateStage( features val , features , target val , target , h,
alpha);
% The next if clause compares to see if the desired false negative rate
% has already been achieved, with the amount of weak hypothesis that
% form the strong hypothesis being less than the maximum initially
% determined. If that is not the case, then the main loop will iterate ,
% at least , once more.
if false negative rate < expected false negative rate
disp( ’ ’ )
disp([ ’Desired false negative rate for stage ’ num2str(stage number) ’ achieved!’])
break;
end
classifications = classifier ( features(h(t) . feature ,:) , h(t) .threshold) ;
if h(t) . direction == 1
weak classifications = classifications (1,:) ;
else
weak classifications = classifications (2,:) ;
end
D = D .∗ exp(−alpha(t) .∗ target .∗ weak classifications ) ;
end
disp( ’ ’ ) ;
disp([ ’Stage ’ num2str(stage number)]);
104
disp([ ’Number of Features: ’ num2str(length(h))])
disp([ ’Stage Error Rate: ’ num2str(error rate ∗ 100) ’ %’]) ;
disp([ ’Stage False Positive Rate: ’ num2str( false positive rate ∗ 100) ’ %’]) ;
disp([ ’Stage False Negative Rate: ’ num2str(false negative rate ∗ 100) ’ %’]) ;
features false negative rate = zeros(size(h));
disp([ ’SL FN: ’ num2str(false negative rate) ])
for test = 1:length( features false negative rate )
features false negative rate ( test ) = h(test).FN;
disp([ ’h’ num2str(test) ’ FN: ’ num2str(h(test).FN)])
end
if sum(false negative rate > features false negative rate ) ˜= 0
disp( ’ Is the FN from the Strong Learner lower than every feature that composes it? No’)
else
disp( ’ Is the FN from the Strong Learner lower than every feature that composes it? Yes’)
end
classifier.m
function [ classifications ] = classifier (feature , threshold)
% This function compares the value of a given feature to a given threshold,
% yielding the classification of each sample given by the stage
%
% Arguments: − feature = vector containing the values of a certain feature
% for all samples of the given set (validation or
% training)
%
% − threshold = value to which the feature will be compared, in
% order to classify the sample as face or non−face
%
% Returns: − classifications = matrix, which contains the results of
% the classification of every image, given a
% certain threshold and feature. Since there
% are two possible directions of
% classification (e.g. ’>=’ and ’<’) for the
% threshold, each line of the vector
% contains the results for a different
105
% direction . The results from both
% directions need to be stored, so the best
% direction , the one which gives the lowest
% error rate , can be chosen. The line ’1’
% corresponds to ’>=’ and the line ’2’, to
% ’<’
classifications (1,:) = double(feature >= threshold);
classifications (2,:) = double(feature < threshold);
classifications ( classifications == 0) = −1;
end
calculateFeatureFalseNegativeRate.m
function [ feature false negative rate ] = calculateFeatureFalseNegativeRate( classifications ,
target)
% This function calculates the false negative rate of the current feature .
% It is important to assure that the chosen feature achieves a low false
% negative rate (idealy , zero) , so no faces are discarded by the cascade.
%
% Arguments: − classifications = vector containing the classifications
% given by the selected feature (aka weak
% classifier ) to each sample. +1 means face
% and −1 means non−face
%
% − target = vector containing the correct classifications for
% each sample. +1 means face and −1 means non−face
%
% Returns: − feature false negative rate = false negative rate associated
% with the feature being
% evaluated
ind = find(target == −1);
target non faces = target(ind(1):end);
classifications non face = classifications (ind(1):end);
106
feature false negative rate = sum( classifications non face ˜= target non faces)/length(
target non faces) ;
validateStage.m
function [ false positive rate , false negative rate , error rate , stage threshold ,
stage direction , neg classifications train ] = ...
validateStage( features val , features train , target val , target train , h, alpha)
% This function validates the partial stages , i .e, calculates the
% statistics of the stage built with the features selected so far
%
% Arguments: − features val = matrix containing all the features calculated
% for each sample of the validation set . Each
% line corresponds to a feature , while each
% column corresponds to a sample
%
% − features = matrix containing all the features calculated for
% each sample of the training set . Each line
% corresponds to a feature , while each column
% corresponds to a sample
%
% − target val = vector containing the correct classifications
% for each sample of the validation set . Each
% column corresponds to a sample. +1 refers to
% face samples, while −1, to non−face samples
%
% − target train = vector containing the correct classifications
% for each sample of the training set . Each
% column corresponds to a sample. +1 refers to
% face samples, while −1, to non−face samples
%
% − alpha = vector containing the weights assigned to each
% feature selected during the training
%
% − h = vector of structures containing the classification
% rules . The fields of this structrure are:
107
%
% − h(k).feature = feature selected in the k−th iteration
% of the main loop
%
% − h(k).error = error associated with the selected
% feature
%
% − h(k).threshold = threshold associated with the
% selected feature
%
% − h(k).direction = direction, in which the value of the
% feature will be compared to its
% threshold (+1 means >=, while −1
% means <)
%
% − h(k).FN = false negative rate associated with the
% selected feature
%
% Returns: − false positive rate = false positive rate of the stage
%
% − false negative rate = false negative rate of the stage
%
% − error rate = error rate of the stage
%
% − stage threshold = threshold associated with the strong
% classifier , which is built through the
% linear combination of all the features
% selected during the training
%
% − stage direction = direction associated with the strong
% classification rule , in which the value of
% the linear combination of all the features
% selected during the training will be
% compared to its threshold (+1 means >=,
% while −1 means <)
%
% − neg classifications train = vector containing the
% classification given by the
% strong learner to each of the
108
% negative training samples
[ val classifications , stage threshold , stage direction ] = getStageClassifications ( features val
, h, alpha, target val ) ;
[ train classifications , ˜, ˜] = getStageClassifications ( features train , h, alpha, target train
) ;
error rate = sum(double( val classifications ˜= target val)) / length( target val ) ;
ind val = find( target val == −1);
ind train = find( target train == −1);
% The variables ’negatives ’ and ’ positives ’ refer to the portion of the
% ’target’ vector that contain, respectively , the correct
% classification for the non−face and the face samples.
negatives = target val( ind val(1) :end);
positives = target val (1:( ind val(1) − 1));
% The variables ’ neg classifications ’ and ’ pos classifications ’ refer
% to the portion of the ’ final classifications ’ vector that contain,
% respectively, the results from the classifications of the strong
% learner for the non−face and the face samples. It is expected that
% the results are ’1’ for faces and ’−1’ for the non−faces.
neg classifications val = val classifications ( ind val(1) :end);
neg classifications train = train classifications ( ind train (1) :end);
pos classifications val = val classifications (1:( ind val(1) − 1));
false positive rate = sum(double(neg classifications val ˜= negatives)) / length(negatives) ;
false negative rate = sum(double( pos classifications val ˜= positives)) / length( positives ) ;
end
getStageClassifications.m
function [ final classifications , stage threshold , stage direction ] = getStageClassifications (
features , h, alpha, target)
% This function implements the process of classification of a sample by the
109
% current stage. The features selected until now are used to classify the
% training samples as face or non−face. Moreover, the threshold and
% direction of comparison of the strong classifier are adjusted.
%
% Arguments: − features = matrix containing all the features calculated for
% each sample of the training set . Each line
% corresponds to a feature , while each column
% corresponds to a sample
%
% − h = vector of structures containing the classification
% rules . The fields of this structrure are:
%
% − h(k).feature = feature selected in the k−th iteration
% of the main loop
%
% − h(k).error = error associated with the selected
% feature
%
% − h(k).threshold = threshold associated with the
% selected feature
%
% − h(k).direction = direction, in which the value of the
% feature will be compared to its
% threshold (+1 means >=, while −1
% means <)
%
% − h(k).FN = false negative rate associated with the
% selected feature
%
% − alpha = vector containing the weights assigned to each
% feature selected during the training
%
% − target = vector containing the correct classifications for
% each sample of the training set . Each column
% corresponds to a sample. +1 refers to face samples,
% while −1, to non−face samples
%
% Returns: − final classifications = vector containing the classification
% given by the strong classifier to
110
% each sample of the training set . +1
% means face, while −1 means non−face
%
% − stage threshold = threshold associated with the strong
% classifier , which is built through the
% linear combination of all the features
% selected during the training
%
% − stage direction = direction associated with the strong
% classification rule , in which the value of
% the linear combination of all the features
% selected during the training will be
% compared to its threshold (+1 means >=,
% while −1 means <)
%
%
strong classifications = zeros(1, size ( features ,2) ) ;
for t = 1:length(alpha)
classifications = classifier ( features(h(t) . feature ,:) , h(t) .threshold) ;
if h(t) . direction == 1
weak classifications = classifications (1,:) ;
else
weak classifications = classifications (2,:) ;
end
strong classifications = strong classifications + alpha(t) ∗ weak classifications ;
end
number thresholds = length(alpha);
strong learner error = inf;
thresholds = linspace(min( strong classifications ) , max( strong classifications ) ,
number thresholds);
for i = 1:length(thresholds)
partial classifications = classifier ( strong classifications , thresholds( i )) ;
for k = 1:2
111
error(k) = sum(double( partial classifications (k ,:) ˜= target));
end
if min(error) < strong learner error
strong learner error = min(error);
stage threshold = thresholds(i) ;
if (find(error==min(error)) == 1)
final classifications = partial classifications (1,:) ;
stage direction = 1;
else
final classifications = partial classifications (2,:) ;
stage direction = −1;
end
end
end
end
splitScenarioSections.m
function [ scenario indoors idx , scenario city idx , scenario landscapes idx ] = ...
splitScenarioSections (number indoors samples, number city samples,
number landscapes samples)
% This function splits the range of the scenario samples indexes into 3
% ranges, which represent the region of a given scenario type. Since there
% are 3 scenario type, the range representation is defined below:
%
% 1st range (1st third) : Indoors
% 2nd range (2nd third): City
% 3rd range (3rd third) : Landscapes
%
% Arguments: − number indoors samples = number of samples of the indoors
% scenario type
%
% − number city samples = number of samples of the city scenario
% type
%
112
% − number landscapes samples = number of samples of the
% landscapes scenario type
%
% Returns: − scenario indoors idx = indexes range which correspond to the
% indoors scenario type
%
% − scenario city idx = indexes range which correspond to the city
% scenario type
%
% − scenario landscapes idx = indexes range which correspond to
% the landscapes scenario type
scenario indoors ind start = 1;
scenario indoors ind end = number indoors samples;
scenario city ind start = scenario indoors ind end + 1;
scenario city ind end = scenario city ind start + number city samples − 1;
scenario landscapes ind start = scenario city ind end + 1;
scenario landscapes ind end = scenario landscapes ind start + number landscapes samples − 1;
scenario indoors idx = scenario indoors ind start : scenario indoors ind end;
scenario city idx = scenario city ind start : scenario city ind end ;
scenario landscapes idx = scenario landscapes ind start :scenario landscapes ind end;
end
getStageNegativeSampleWrongClassification.m
function [ final classification ] = getStageNegativeSampleWrongClassification(features, h,
alpha, stage threshold, stage direction )
% This function submits a negative sample to be classified by the trained
% stage. The purpose of the function is to find negatives samples which
% will be classified as faces by the current stage, because, if this
% happens, then the sample will be used to build the negative samples
% portion of the training set of the next stage.
%
% Arguments: − features = vector containing the values of each feature for
% the current sample
113
%
% − h = vector of structures containing the classification
% rules . The fields of this structrure are:
%
% − h(k).feature = feature selected in the k−th iteration
% of the main loop
%
% − h(k).error = error associated with the selected
% feature
%
% − h(k).threshold = threshold associated with the
% selected feature
%
% − h(k).direction = direction, in which the value of the
% feature will be compared to its
% threshold (+1 means >=, while −1
% means <)
%
% − h(k).FN = false negative rate associated with the
% selected feature
%
% − alpha = vector containing the weights assigned to each
% feature selected during the training
%
% − stage threshold = threshold associated with the strong
% classifier trained for the current stage
%
% − stage direction = direction associated with the strong
% classification rule , in which the value of
% the linear combination of all the features
% selected for the trained classifer of the
% current stage will be compared to its
% threshold (+1 means >=, while −1 means <)
%
% Returns: − final classification = classification given by the stage to
% the current sample
strong classification = zeros(1, size ( features ,2) ) ;
114
for t = 1:length(alpha)
classifications = classifier ( features(h(t) . feature ,:) , h(t) .threshold) ;
if h(t) . direction == 1
weak classifications = classifications (1,:) ;
else
weak classifications = classifications (2,:) ;
end
strong classification = strong classification + alpha(t) ∗ weak classifications ;
end
if ( stage direction == 1)
final classification = double( strong classification >= stage threshold);
final classification ( final classification == 0) = −1;
else
final classification = double( strong classification < stage threshold);
final classification ( final classification == 0)= −1;
end
validateCascade.m
function [ false positive rate , false negative rate , error rate ] = validateCascade (
features val , target val , stage, number stages)
% This function validates the current cascade, i .e, it calculates the
% statistics associated with the current cascade.
%
% Arguments: − features val = matrix containing the values of all the
% features from every image of the validation
% set . The columns of the matrix correspond to
% the images of the set and the lines
% correspond to the features
%
% − target val = vector containing the correct classifications
% of each sample of the validation set . +1 means
% face and −1 means non−face
%
% − stage = vector of structures containing all the informations
% associated with the classifier from each stage. The fields of
115
% the structure are:
%
% − stage(k).alpha = vector containing the weights for
% each feature selected to build the
% strong classifier of the k−th stage
%
% − stage(k).h = vector of structures containing the
% informations of each weak classification
% rule
%
% − stage(k).FP = false positive rate associated with the
% k−th stage of the cascade
%
% − stage(k).FN = false negative rate associated with the
% k−th stage of the cascade
%
% − stage(k).threshold = threshold associated with the
% strong classifier of the k−th
% stage
%
% − stage(k).direction = direction associated with the
% strong classification rule of
% the k−th stage, in which the
% value of the linear combination
% of all the features selected
% during the training will be
% compared to its threshold (+1
% means >=, while −1 means <)
%
% − number stages = total number of stages of the current
% cascade
%
% Returns: − false positive rate = false positive rate associated with
% the current cascade
%
% − false negative rate = false negative rate associated with
% the current cascade
%
% − error rate = error rate associated with the current cascade
116
final classifications = zeros(size( target val )) ;
for i=1:number stages
stage classifications = getStageClassifications ( features val , stage( i ) .h, stage( i ) .alpha,
target val ) ;
stage classifications ( stage classifications == −1) = 0;
if ( i == 1)
final classifications = stage classifications ;
else
final classifications = final classifications & stage classifications ;
end
end
% The ’ final classifications ’ variable started as a double type, but after
% the first logical ’and’, it was cast to logical type. The next line of
% the code will re−cast to double type.
final classifications = double( final classifications ) ;
% The re−cast to double was needed, because, if the previous variable was
% logical , the next line would not behave as expected.
final classifications ( final classifications == 0) = −1;
error rate = sum(double( final classifications ˜= target val)) / length( target val ) ;
ind = find( target val == −1);
% The variables ’negatives ’ and ’ positives ’ refer to the portion of the
% ’target val ’ vector that contain, respectively , the correct
% classification for the non−face and the face samples.
negatives = target val(ind(1):end);
positives = target val (1:( ind(1) − 1));
% The variables ’ neg classifications ’ and ’ pos classifications ’ refer
% to the portion of the ’ final classifications ’ vector that contain,
117
% respectively, the results from the classifications of the strong
% learner for the non−face and the face samples. It is expected that
% the results are ’1’ for faces and ’−1’ for the non−faces.
neg classifications = final classifications (ind(1):end);
pos classifications = final classifications (1:( ind(1) − 1));
false positive rate = sum(double(neg classifications ˜= negatives)) / length(negatives) ;
false negative rate = sum(double(pos classifications ˜= positives)) / length( positives ) ;
end
organizeFiles.m
function organizeFiles ()
% This function organizes the cascade .mat data files , moving them to the
% correct folder
movefile( ’∗.mat’,’ ../ Cascade Data’)
end
B.2 Escaneador
A Figura B.2 e um fluxograma que mostra quais funcoes sao chamadas dentro do
script mainScanner.m, assim como a ordem dessas chamadas. As funcoes getInte-
gralImage.m, calculateIntegralImage.m, getFeatures.m e calculateFeatures.m sao as
mesmas utilizadas no modulo do detector de faces e, portanto, nao serao repetidas
nessa secao.
118
Figura B.2: Fluxograma das funcoes chamadas pelo script mainScanner.m
mainScanner.m
% This script implements the scanner algorithm. The algorithm
% searches for a frontal face in images and locates it . Uncomment the
% commented lines to generate the data required to plot the face map
% images.
close all
clear all
clc
list = [
001 022 042 047 069 090 119 133 138 159 176 196 217 242 269 289 309 337 357 377
002 023 043 048 070 091 120 134 139 160 183 198 218 246 272 290 310 338 359 379
003 024 044 049 071 094 121 135 140 161 186 202 221 247 274 291 312 340 365 382
008 025 045 050 072 095 123 136 141 162 189 203 222 248 276 294 314 343 368 383
010 037 046 052 073 097 131 137 142 165 193 207 223 255 277 302 315 346 375 386
];
119
list = reshape(list , 1, numel(list)) ;
I = getIndexedImages(list, ’Caltech’) ;
face found = 0;
resize = 1;
stop search = 0;
debug = 1;
% pos x = 1;
% pos y = 1;
% idx = 1;
factor = 14; % Initial factor of 1.25
base resolution = 24; % Base resolution of the detector
counter = 0;
max face indicator = −Inf;
% ’ table results ’ is a matrix which contains the classification results
% of each image, i .e, the id of the image and if it was correctly
% classified , was a false positive or a false negative. There is also a
% column containing an ’obs flag’. If it is 1, then there is an observation
% written by the user about the sample, which can be found in the
% ’notes.txt ’ file
% The possible values of the classification flag are given below:
% 0 − false negative (face not found)
% 1 − false positive (face not found, but program classified one as so)
% 2 − positive (face found)
table results = zeros(length( list ) , 3);
table ind = 1;
for i = 1:size(I ,3)
while (˜face found)
while ( resize )
width = round(base resolution ∗ (1.25 ˆ factor)) ;
120
height = width;
step size = round(5 ∗ 1.25 ˆ factor) ;
while ((width > size(I ,2) ) || (height() > size(I ,1) ))
factor = factor − 1;
width = round(base resolution ∗ (1.25 ˆ factor)) ;
height = width;
end
if ( factor == 0)
stop search = 1;
break;
end
keep search y = 1;
curr y = 1;
while (keep search y)
keep search x = 1;
curr x = 1;
while (keep search x)
sub window = I(curr y:(curr y+height−1),curr x:(curr x+width−1),i);
if (debug == 1)
imshow(sub window)
title ([ ’Image ’ num2str(list( i )) ])
size (sub window)
counter = counter + 1;
counter
if counter == 1
pause
else
pause(0.01)
end
end
% The extracted subwindow will then be passed to the
% detector, which will classify whether it is a face or
% not
121
sub window = imresize(sub window, [base resolution base resolution]);
sub window = double(sub window);
[face found, face indicator ] = detectFaces(sub window, debug);
if (face found == 1)
if max face indicator < face indicator
max face indicator = face indicator ;
x pos = curr x;
y pos = curr y;
curr width = width;
curr height = height;
end
end
% img map(pos y, pos x) = face indicator;
curr x = curr x + step size ;
keep search x = curr x + width − 1 < size(I,2);
% pos x = pos x + 1;
end
% pos x = 1;
curr y = curr y + step size ;
keep search y = curr y + height − 1 < size(I,1) ;
% pos y = pos y + 1;
end
% pos y = 1;
factor = factor − 1;
% resultadosidx = img map;
% idx = idx + 1;
% clear (’ img map’);
if ( factor == 8)
resize = 0;
122
stop search = 1;
end
end
if (stop search == 1)
break;
end
end
if ( isinf (max face indicator))
disp( ’ ’ )
disp( ’Face could not be found for the current image’)
disp( ’ ’ )
else
face found = 1;
disp( ’ ’ )
disp( ’Face found!’)
disp([ ’x pos: ’ num2str(x pos)])
disp([ ’y pos: ’ num2str(y pos)])
disp([ ’curr width: ’ num2str(curr width)])
disp([ ’ curr height : ’ num2str(curr height)])
disp([ ’max face indicator: ’ num2str(max face indicator)])
disp( ’ ’ )
markFaceWindow(I(:,:,i), x pos, y pos, curr width, curr height , 0, list ( i )) ;
end
if debug
if ˜face found
result classification = 0; % False negative
opt = ’’ ;
while ˜(strcmp(opt, ’Y’) || strcmp(opt, ’N’))
disp( ’ ’ )
disp( ’ Is there a note about this result? (Y/N)’)
disp( ’ ’ )
123
opt = upper(input(’’, ’ s ’ )) ;
end
switch opt
case ’Y’
obs flag = 1;
case ’N’
obs flag = 0;
end
else
opt = −1;
while ˜(opt == 1 || opt == 2)
disp( ’ ’ )
disp( ’ Classify the result : ’ )
disp( ’ (1) − False Positive ’ )
disp( ’ (2) − Positive’)
disp( ’ ’ )
opt = input(’’) ;
end
result classification = opt;
opt = ’’ ;
while ˜(strcmp(opt, ’Y’) || strcmp(opt, ’N’))
disp( ’ ’ )
disp( ’ Is there an observation about this result? (Y/N)’)
disp( ’ ’ )
opt = upper(input(’’, ’ s ’ )) ;
end
124
switch opt
case ’Y’
obs flag = 1;
case ’N’
obs flag = 0;
end
end
img id = list ( i ) ;
table results (table ind , :) = [img id result classification obs flag ];
table ind = table ind + 1;
end
% Reseting the values of important variables for the next image
face found = 0;
resize = 1;
factor = 14;
stop search = 0;
max face indicator = −Inf;
face indicator = 0;
curr width = 0;
curr height = 0;
x pos = 0;
y pos = 0;
counter = 0;
end
% save(’resultados .mat’, ’ resultados ’) ;
save( ’ face detector results .mat’, ’ table results ’ ) ;
if exist ( ’Detector Results’ , ’ dir ’ )
rmdir(’Detector Results’)
else
mkdir(’Detector Results’)
125
end
movefile( ’∗.mat’, ’ ./Detector Results/’)
getIndexedImages.m
function images = getIndexedImages(list, face base name)
% This function reads the images to be scanned from a specific database.
% Arguments: − list = matrix containing the ids of the images to be read
% from the database. Each column represents one person
% and the each line contains an image id. Therefore,
% each column of the matrix contain image ids from a
% specific person
%
% − face base name = string representing the name of the
% database, from which the images will be
% read
%
% Returns: − images = matrix containing the images to be scanned
exec path = pwd;
switch(face base name)
case ’BioID’
face base path = ’ ../../../ Face Database/BioID’;
cd(face base path)
files = dir(’∗.pgm’);
img counter = 1;
for i = 1:length( list )
images (:,:, img counter) = imread(files( list ( i ) + 1).name); % For instance: image
’0’ is located at position ’1’ of the vector ’ files ’
img counter = img counter + 1;
126
end
case ’Caltech’
face base path = ’ ../../../ Face Database/Caltech/JPG’;
cd(face base path)
files = dir(’∗.jpg’) ;
img counter = 1;
for i = 1:length( list )
images (:,:, img counter) = imread(files( list ( i )) .name);
img counter = img counter + 1;
end
end
cd(exec path);
end
detectFaces.m
function [face found, face indicator ] = detectFaces(sub window, debug)
% This function indicates whether the current subwindow represents a face or
% not, by analyzing it with a previously trained face detector .
%
% Arguments: − sub window = matrix containing the region of the original
% image which will be analyzed by the face
% detector , to determine if it represents a face
% or not
%
% − debug = logical variable used to execute parts of the code
% (debugging purposes only)
%
% Returns: − face found = logical value indicating whether the analyzed
% subwindow represents a face or not
%
127
% − face indicator = value of the linear combination returned by
% the last stage of the trained face detector . The higher this
% value is , the more probable is, that the current subwindow
% represents , indeed, a face
integral img = getIntegralImage(sub window);
features = getFeatures(integral img);
face detector = loadDetector();
face found = 0;
strong classifications = zeros(1, length( face detector .stage)) ;
% The next loop will iterate through each stage of the cascade
for i = 1:length(face detector .stage)
% The next loop will iterate through each feature from the current
% stage, in order to build the strong classifier and obtain the
% classification of the stage for whether the image is a face or not
for t = 1:length(face detector .stage( i ) .h)
classification = classifier ( features( face detector .stage( i ) .h(t) . feature ,:) ,
face detector .stage( i ) .h(t) .threshold) ;
if ( face detector .stage( i ) .h(t) . direction == 1)
weak classification = classification (1,:) ;
else
weak classification = classification (2,:) ;
end
strong classifications ( i ) = strong classifications ( i ) + face detector.stage( i ) .alpha(t
) ∗ weak classification ;
end
if ( face detector .stage( i ) . direction == 1)
final classification = double( strong classifications ( i ) >= face detector.stage(i) .
threshold) ;
else
128
final classification = double( strong classifications ( i ) < face detector.stage( i ) .
threshold) ;
end
if (debug == 1)
disp([ ’Stage ’ num2str(i)])
disp([ ’Strong Classification : ’ num2str( strong classifications ( i )) ])
disp([ ’Threshold: ’ num2str(face detector.stage( i ) .threshold) ])
disp([ ’Alpha sum: ’ num2str((1/2) ∗ sum(face detector.stage(i).alpha)) ])
if ( face detector .stage( i ) . direction == 1)
disp( ’Direction: >=’)
else
disp( ’Direction: <’)
end
end
if ( final classification == 0)
break;
end
end
face indicator = strong classifications (end);
if ( final classification == 1)
face found = 1;
end
loadDetector.m
function faceDetector = loadDetector()
% This function simply loads one previously trained face detector , which
% will be used by the scanner to classify each subwindow of the image being
% scanned.
%
% Returns: − faceDetector = face detector selected
129
exec path = pwd;
cd(’ ../ Classifiers /’)
faceDetector = load(’ classifier 5 ’ ) ;
cd(exec path)
end
markFaceWindow.m
function markFaceWindow(img, curr x, curr y, width, height, img id)
% This function marks the subwindow that was selected to locate the face in
% the image.
%
% Arguments: − img = image being scanned
%
% − curr x = x coordinate (column) of the image being scanned
% that locates the higher left corner of the
% subwindow selected to locate the face
%
% − curr t = y coordinate (line) of the image being scanned
% that locates the higher left corner of the
% subwindow selected to locate the face
%
% − width = width of the subwindow selected to locate the face
%
% − height = height of the subwindow selected to locate the face
%
% − img id = id of the image being scanned
final x = curr x + width;
final y = curr y + height;
if ( final x > size(img,2))
final x = size(img,2);
end
130
if ( final y > size(img,1))
final y = size(img,1);
end
img(curr y, curr x: final x ) = 0;
img(final y , curr x: final x ) = 0;
img(curr y: final y , curr x) = 0;
img(curr y: final y , final x ) = 0;
imshow(img)
title ([ ’Image ’ num2str(img id)])
pause
plotImageMap.m
% This script plots the face map images, using the data obtained from the
% scanner script (mainScanner.m)
a = load(’resultados .mat’);
b = load(’ ../ Classifiers / classifier 5 .mat’);
menor = −sum(b.stage(end).alpha);
disp([ ’Menor: ’ num2str(menor)])
maior = −Inf;
for i = 1:length(a.resultados)
a.resultadosi(a.resultadosi == 0) = menor;
c = max(max(a.resultadosi));
if c > maior
maior = c;
end
end
for i = 1:length(a.resultados)
figure ;
imagesc(a.resultadosi, [menor maior]);
colormap(’gray’);
131
axis off
switch ( i )
case 1
title ( ’Janela 546x546’, ’FontSize’ , 20)
case 2
title ( ’Janela 437x437’, ’FontSize’ , 20)
case 3
title ( ’Janela 349x349’, ’FontSize’ , 20)
case 4
title ( ’Janela 279x279’, ’FontSize’ , 20)
case 5
title ( ’Janela 224x224’, ’FontSize’ , 20)
case 6
title ( ’Janela 179x179’, ’FontSize’ , 20)
end
pause;
end
B.3 Reconhecedor Facial
A Figura B.3 e um fluxograma que mostra quais funcoes sao chamadas dentro do
script mainRecognizer.m, assim como a ordem dessas chamadas.
Figura B.3: Fluxograma das funcoes chamadas pelo script mainRecognizer.m
mainRecognizer.m
% This script implements the face recognition algorithm. It not only
% identifies face samples (provided that these samples corresponds to
132
% people known to the recoginizer, i .e, people for which the recognizer was
% trained to identify ) , but also trains the recognizer , using the
% ”Eigenfaces” algorithm, which is implemented here.
close all
clear all
clc
samples person = 10;
debug = 1;
resolution = 30;
train path = ’ ../Reconhecimento Facial/train recognizer3/’;
test path = ’ ../Reconhecimento Facial/test recognizer3/’;
%% Image reading
% The variable ’A’ is a matrix whose columns are the training images,
% subtracted from the mean image of the training set, represented as a
% vector. The vector representations of an image corresponds to each pixel
% representing a dimension in a Nˆ2 space (assuming the image is of
% resolution NxN)
A = getImages(train path, resolution);
%% Image mean subtraction and standard deviation normalization from the training images
img mean = mean(A, 2);
A = A − repmat(img mean, 1, size(A, 2));
if debug
a = mean(A, 2);
for i = 1:length(img mean)
if a(i ) > 1e−12
disp(a(i ))
disp( ’Mean is not zero’)
pause
133
break
end
end
end
std dev = std(A, [], 2);
A = A ./ repmat(std dev, 1, size(A, 2)) ;
if debug
a = sum(std(A, [], 2)) ;
if a ˜= size(A, 1)
disp( ’Standard deviation is not unitary’)
pause
break
end
end
if debug
imagesc(reshape(img mean, sqrt(size(img mean, 1)), sqrt(size(img mean, 1))));
colormap(’gray’)
title ( ’Imagem Media’, ’FontSize’, 20)
axis off
pause
end
%% Calculation of the eigenvectors of the covariance matrix
L = A ∗ A’;
[V,D] = eig(L);
eigenvectors = V;
eigenvalues = diag(D);
energy eigenvectors = zeros(length(eigenvalues) , 2);
energy eigenvectors = [eigenvalues (1:length(eigenvalues)) ’];
134
if debug
for i = 1:(size (eigenvectors , 2) − 1)
for j = (i + 1):size (eigenvectors , 2)
proj = eigenvectors (:, j) ’ ∗ eigenvectors (:, i ) ;
if proj > 1e−13
disp(proj)
disp( ’Eigenvectors are not orthogonal’)
disp( ’ ’ )
pause
break
end
end
end
end
%% Selection of the eigenvectors
energy eigenvectors = sortrows(energy eigenvectors, −1);
eigenvectors = eigenvectors (:, energy eigenvectors (:,2) ) ; % Decreasing order
if debug
stem((1:length(energy eigenvectors (:,1) )) , (cumsum(energy eigenvectors(:,1)) / sum(
energy eigenvectors(:,1))))
ylabel( ’Energy accumulated’)
xlabel( ’Number of eigenfaces’)
title ( ’Energy ratio’)
pause
end
energy ratios = cumsum(energy eigenvectors(:,1)) / sum(energy eigenvectors(:,1));
number eigenvectors = find(energy ratios > 0.95, 1);
selected eigenvectors = eigenvectors (:, 1:(number eigenvectors − 1));
if debug
for i = 1:size( selected eigenvectors , 2)
135
figure (30)
subplot(6,5, i )
imagesc(reshape(selected eigenvectors (:, i ) , sqrt( size ( selected eigenvectors (:, i ) , 1)) ,
sqrt( size ( selected eigenvectors (:, i ) , 1))))
colormap(’gray’)
axis off
end
pause
figure (2)
end
%% Projection of training images onto the face space
W = selected eigenvectors’ ∗ A;
%% Input images reading
img dir = dir(strcat(test path , ’∗.jpg’)) ;
for i = 1:length(img dir)
images (:,:, i ) = double(imread(strcat(test path, img dir(i ) .name)));
end
for i = 1:size(images, 3)
disp([ ’Image ’ num2str(i)])
disp( ’ ’ )
input img = images(:,:, i ) ;
if exist ( ’ resolution ’ , ’var’)
input img = imresize(input img, [ resolution resolution ]) ;
end
input img = reshape(input img, numel(input img), 1);
%% Mean subtraction and standard deviation normalization from the input images
% The input image is the one which needs to be recognized
136
input img = input img − repmat(img mean, 1, size(input img, 2));
% The variable ’class ’ is for debug purpose only. It defines the class to
% which the input image belongs, in order to give different colors to the
% samples of the same class, depicted in the distance error graphic.
if i <= 5
class = 1;
else if i > 5 && i <= 10
class = 2;
else if i > 10 && i <= 15
class = 3;
else if i > 15 && i <= 20
class = 4;
else if i > 20 && i <= 25
class = 5;
else if i > 25 && i <= 30
class = 6;
else
class = 7;
end
end
end
end
end
end
input img = input img ./ repmat(std dev, 1, size(input img, 2)) ;
%% Classification of the input images
recognizeFace(input img, selected eigenvectors , W, samples person, debug, class)
end
getImages.m
function [images] = getImages(path, resolution)
137
% This function reads the training samples, convert them to vectors and
% stores them in columns of a matrix
%
% Arguments: − path = string containing the path for the folder where all
% the training samples are located
%
% − resolution = resolution to which the samples will be resized
% and at which the recognizer will be trained to
% identify
%
% Returns: − images = matrix containing all the training samples. The
% columns of this matrix represent the samples
exec path = pwd;
cd(path)
files = dir(’∗.jpg’) ;
cd(exec path)
files = sortFiles( files ) ;
cd(path)
for i = 1:length( files )
img = double(imread(filesi)) ;
if nargin == 2
img = imresize(img, [resolution resolution ]) ;
end
images(:, i ) = reshape(img, numel(img), 1); % Transforming each image into a vector
end
cd(exec path)
end
sortFiles.m
138
function [ sorted files ] = sortFiles( files )
% This function sorts the names of the image files from a folder according
% to the id of the image, which is located at the end of the file name.
%
% Arguments: − files = vector of a structure which contains informations
% about the files inside a folder . In this function,
% the only field of interest is the file ( i ) .name,
% which is a string representing the name of the i−th
% file inside the folder
%
% Returns: − sorted files = cell vector of strings containing the names
% of the image files ordered by their id , which
% is located at the end of the file name
sorted files = cell( size ( files )) ;
for i = 1:length( files )
[˜, filename,ext] = fileparts ( files ( i ) .name);
j = length(filename);
while ˜isnan(str2double(filename(j)))
j = j − 1;
end
j = j + 1;
index = str2double(filename(j:end));
sorted files index = strcat([filename, ext ]) ;
end
end
recognizeFace.m
function recognizeFace(input img, selected eigenvectors , W, samples person, debug, class)
139
% This function performs the recognition of a person in a given image.
%
% Arguments: − input img = the input image containing the person to be
% recognized
%
% − selected eigenvectors = the vectors selected during the
% training of the recognizer , which
% will build the face space
%
% − W = matrix containing the coordinates of each training
% sample in the face space. The columns represent the
% training samples, while the lines represent the
% coordinates
%
% − samples person = number of samples that each person had in
% the training set of the recognizer . In this
% project , there were 10 samples per person
% in the training set
%
% − debug = logical variable used to execute some parts of the
% code (debug purposes only)
%
% − class = number indicating to which class, i .e, to which
% person the face in the input image belongs (debug
% purposes only)
%% Initialization of some constants
neighbors = 15;
face threshold = Inf;
number people = size(W, 2) / samples person;
highlight = 1;
classes = zeros(1, number people);
%% Projection of the input images onto the face space
input weights = selected eigenvectors ’ ∗ input img;
140
if debug
for i = 1:length(input weights)
synthetic face (:, i ) = input weights(i) ∗ selected eigenvectors (:, i ) ;
end
synthetic face = sum(synthetic face, 2);
imagesc(reshape(synthetic face, sqrt( size (input img, 1)) , sqrt( size (input img, 1))))
colormap(’gray’)
title ( ’Imagem Sintetica’, ’FontSize’ , 20)
axis off
figure (3)
imagesc(reshape(input img, sqrt(size(input img, 1)) , sqrt( size (input img, 1))))
colormap(’gray’)
title ( ’Imagem de Entrada’, ’FontSize’, 20)
axis off
pause
figure (4)
end
%% Classification of each face based on the KNN algorithm
for i = 1:size(input weights, 2)
sample = input weights(:,i) ;
errors = sqrt(sum((W − repmat(sample, 1, size(W, 2))) .ˆ 2, 1));
if min(errors) > face threshold
disp( ’This person is unknown’)
disp( ’ ’ )
break
end
if debug
switch class
case 1
correct class range = 1:10;
incorrect class range = 11:70;
case 2
correct class range = 11:20;
incorrect class range = [1:10 21:70];
case 3
141
correct class range = 21:30;
incorrect class range = [1:20 31:70];
case 4
correct class range = 31:40;
incorrect class range = [1:30 41:70];
case 5
correct class range = 41:50;
incorrect class range = [1:40 51:70];
case 6
correct class range = 51:60;
incorrect class range = [1:50 61:70];
case 7
correct class range = 61:70;
incorrect class range = 1:60;
end
plot( incorrect class range , errors ( incorrect class range )/max(errors), ’rx ’ , ’
LineWidth’, 3)
hold on
plot( correct class range , errors ( correct class range )/max(errors), ’bo ’ , ’LineWidth’,
3)
if highlight % Highlight the closest neighbors
errors aux = errors;
for k = 1:neighbors
idx(k) = find(errors aux == min(errors aux));
errors aux(errors aux == min(errors aux)) = Inf;
end
for k = 1:length(idx)
if ˜isempty(find( correct class range == idx(k), 1))
plot(idx(k), errors (idx(k))/max(errors), ’bo ’ , ’LineWidth’, 8)
else
plot(idx(k), errors (idx(k))/max(errors), ’rx ’ , ’LineWidth’, 8)
end
end
end
142
hold off
legendVar = legend(’Amostras de classes distintas ’ , ’Amostras de mesma classe’);
set(legendVar, ’FontSize’ , 20);
title ( ’Distancias euclidianas entre as amostras de entrada e de treino (normalizadas
pela maior distancia)’ , ’FontSize’ , 20)
xlabel( ’Numero da amostra’, ’FontSize’, 20)
ylabel( ’Erro (normalizado)’, ’FontSize’ , 20)
set(gca, ’FontSize’ , 20)
pause
end
for j = 1:neighbors
ind = find(errors == min(errors), 1);
errors (ind) = Inf;
ind = ceil(ind / samples person);
classes (ind) = classes(ind) + 1;
end
if debug
disp( classes )
pause
end
ind = find( classes == max(classes));
if size (ind, 2) > 1
disp( ’Cannot identify the person’)
disp( ’ ’ )
else
disp([ ’This is class ’ num2str(ind)])
switch ind
case 1
disp( ’This is John’)
case 2
disp( ’This is Patrick’ )
case 3
disp( ’This is Simon’)
case 4
disp( ’This is Betty’)
143
case 5
disp( ’This is Eric’ )
case 6
disp( ’This is Ryan’)
case 7
disp( ’This is Joseph’)
end
disp( ’ ’ )
end
end
end
144