Reconhecimento Facial em Python com a biblioteca OpenCV

Fernando Marcos Wittmann
Data Science BR
Published in
5 min readSep 8, 2018

Neste post vamos utilizar a biblioteca OpenCV para reconhecimento de facial. A melhor parte é que isso pode ser feito utilizando menos de 20 linhas de código:

O resto deste post será dedicado ao desenvolvimento deste código passo à passo no console do Python. O mesmo estará dividido em quatro partes:

  1. Pré-requisitos.
  2. Como capturar um frame de sua webcam.
  3. Como fazer detecção de faces do frame que foi previamente capturado.
  4. No final há um quiz para você terminar o código para detecção de faces em tempo real. A solução está no final do artigo.

Primeiramente, vamos à instalação dos pré-requisitos.

1. Pré-requisitos

Para este tutorial, você vai precisar do Python 2.7 ou 3. Você também precisará ter instalado o OpenCV. Minha sugestão:

  1. Instale utilizando o Python utilizando o Anaconda. Desta forma, já serão inclusos os pacotes mais importantes de Data Science.
  2. Crie um novo ambiente para instalação do OpenCV:

conda create -n image-detection anaconda

3. Ative este ambiente. Em Linux/Mac o comando é:

source activate image-detection

Já no Windows:

activate image-detection

4. Instale o OpenCV neste ambiente:

conda install opencv

Pronto! Alternativamente você pode testar pip install opencv-python. Eu recomendo instalar em um ambiente separado pois a instalação do OpenCV tem como pré-requisito a desatualização de pacotes para versões mais antigas.

2. Leitura da webcam

Para ganhar intuição, vamos construindo o nosso código aos poucos pelo console do ipython. Com o seu terminal aberto, ative o seu ambiente e depois abra o ipython:

...$ source activate image-detection
...$ ipython

Vamos agora primeiro importa a única dependência desse tutorial:

In [1]: import cv2

Em seguida a primeira coisa que vamos fazer é inicializar a webcam. Isso pode ser feito utilizando o comando cv2.VideoCapture(0):

In [2]: cap = cv2.VideoCapture(0)

O LED de sua webcam vai provavelmente acender (DICA: caso você não possua uma webcam, você também definir um vídeo como entrada em VideoCapture, por exemplo cap = cv2.VideoCapture('c:/my_video.mp4')). Agora, vamos aprender a tirar uma “foto” a partir de sua webcam. Isso pode ser feito a partir do método cap.read seguido do método release para desligá-la:

In [3]: ret, frame = cap.read()In [4]: cap.release()

A imagem capturada estará armazenada em frame. Já em ret estará um binário indicando se uma imagem foi obtida (retrieved). Agora para visualizar esta imagem, precisamos da função imshow combinada com waitKey:

In [5]: cv2.imshow('frame', frame)In [6]: cv2.waitKey(1)
Out[6]: -1

Para atualizar a exibição ou fechamento da imagem, note que precisamos do método cv2.waitKey(1) que basicamente aguarda que uma tecla seja pressionada. Agora para fechar a imagem fazemos o seguinte via terminal:

In [7]: cv2.destroyAllWindows()In [8]: cv2.waitKey(1)
Out[8]: -1

Um pouco sobre a função waitKey: Note que tanto para a exibição quanto fechamento de imagens, o uso dela é obrigatória. Esta função é a única que tem acesso à interface gráfica e irá aguardar o pressionamento de uma tecla pelos milissegundos especificados. Como queremos que a imagem seja exibida ou fechada independente do pressionamento de uma tecla, utilizamos o delay de 1 ms. Ela também é necessária para exibição quadro a quadro em loops para a exibição de vídeos. Para exibir o conteúdo da webcam em tempo real, precisamos colocar estes comandos dentro de um while loop:

In [10]: cap = cv2.VideoCapture(0)
...: while(not cv2.waitKey(20) & 0xFF == ord('q')):
...: ret, frame = cap.read()
...: cv2.imshow('frame',frame)
...: cap.release()
...: cv2.destroyAllWindows()
...: cv2.waitKey(1)
...:

O comandocv2.waitKey(20) & 0xFF == ord(‘q’) vai esperar que a tecla ‘q’ seja pressionada na janela do vídeo (não no terminal!) para em seguida encerrar a exibição. Sendo assim, terminamos a primeira parte deste tutorial. Na próxima seção vamos aprender a reconhecer faces em cima desta exibição em tempo real.

3. Detecção de faces

Para reconhecimento de faces, nós vamos importar um modelo pré-treinado com o tipo de atributo a ser identificado. Estes modelos estão salvos como arquivos XML e sua localização pode variar dependendo de seu sistema operacional ou da forma que instalou o OpenCV. Como nosso objetivo é a identificação de rostos, o arquivo do modelo que queremos importar chama-se haarcascade_frontalface_alt2.xml. Uma possibilidade seria baixar pelo código fonte. Alternativamente, você pode procurá-lo a partir do diretório do OpenCV da seguinte forma:

In [11]: import osIn [12]: cv2path = os.path.dirname(cv2.__file__)In [13]: def find(name, path):
...: for root, dirs, files in os.walk(path):
...: if (name in files) or (name in dirs):
...: return os.path.join(root, name)
...: # Caso nao encontre, recursao para diretorios anteriores
...: return find(name, os.path.dirname(path))
In [14]: xml_path = find('haarcascade_frontalface_alt2.xml', cv2path)In [15]: xml_path
Out[15]: '/Users/wittmann/anaconda/envs/image-detection/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml'

No código anterior foi definido uma função find para buscar um arquivo a tomando-se um diretório como ponto de partida. Em seguida, o diretório no qual o OpenCV está instalado foi utilizado como entrada para a busca do modelo em XML. Outra opção seria buscar pelo diretório haarcascades para testar os outros modelos em XML pré-treinados:

In [16]: haar_path = find('haarcascades', cv2path)In [17]: os.listdir(haar_path)
Out[17]:
['haarcascade_eye.xml',
'haarcascade_eye_tree_eyeglasses.xml',
'haarcascade_frontalcatface.xml',
'haarcascade_frontalcatface_extended.xml',
'haarcascade_frontalface_alt.xml',
'haarcascade_frontalface_alt2.xml',
'haarcascade_frontalface_alt_tree.xml',
'haarcascade_frontalface_default.xml',
'haarcascade_fullbody.xml',
'haarcascade_lefteye_2splits.xml',
'haarcascade_licence_plate_rus_16stages.xml',
'haarcascade_lowerbody.xml',
'haarcascade_profileface.xml',
'haarcascade_righteye_2splits.xml',
'haarcascade_russian_plate_number.xml',
'haarcascade_smile.xml',
'haarcascade_upperbody.xml']

Por exemplo, se quiséssemos identificar olhos em vez de faces, poderíamos utilizar o modelo haarcascade_eye.xml. Vamos agora inicializar o classificador a partir do arquivo XML com o modelo pré-treinado:

In [18]: clf = cv2.CascadeClassifier(xml_path)

Agora com o classificador inicializado, nós podemos fazer a identificação de rostos em imagens. No entanto, este classificador apenas aceita como entra imagens em tons de cinza. A conversão do frame para tons de cinza pode ser feito da seguinte forma:

In [19]: gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

E finalmente a detecção de rostos pode ser realizada em cima da imagem convertida em tons de cinza

In [20]: faces = clf.detectMultiScale(gray)

A variável faces contém uma lista das coordenadas das faces identificadas. Como resultado, é retornado as coordenadas de um retângulo que corresponde ao rosto identificado (caso seja identificado). Note que foi necessário converter a imagem para tons de cinza em cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY). E finalmente, para visualizar estas coordenadas, nós podemos desenhar um retângulo utilizando cv2.rectangle:

In [21]: for x, y, w, h in faces:
...: cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0))
In [22]: cv2.imshow('frame', frame); cv2.waitKey(1)

As coordenadas x e y correspondem ao ponto inferior esquerdo do retângulo enquanto que w e h correspondem às sua largura (width) e altura (height). A função cv2.rectangle também tem como entrada obrigatória a cor em formato BGR, que no nosso exemplo escolhemos azul. E por fim, podemos fechar via console:

In [23]: cv2.destroyAllWindows(); cv2.waitKey(1)

4. QUIZ: Juntando tudo

Agora fica como exercício juntar as ideias das duas seções anteriores:

import cv2, os# TODO: Importar arquivo XML# TODO: Inicializar Classificador# Inicializar webcam
cap = cv2.VideoCapture(0)
# Loop para leitura do conteúdo
while(not cv2.waitKey(20) & 0xFF == ord('q')):
# Capturar proximo frame
ret, frame = cap.read()
# TODO: Converter para tons de cinza # TODO: Classificar # TODO: Desenhar retangulo # Visualizar
cv2.imshow('frame',frame)
# Desligar a webcam
cap.release()
#Fechar janela do vídeo
cv2.destroyAllWindows()

A resposta mais simples está no início da página. Segue uma solução mais completa em relação ao inicio do vídeo com busca automática do modelo em XML:

--

--

Fernando Marcos Wittmann
Data Science BR

Head of Data Science @ Awari | Machine Learning Expert | E-Learning