Manual
do
Maker
.
com
Nesse artigo mostrei como utilizar DNN para fazer face detection com OpenCV. Mas que tal um reconhecimento facial com dlib usando um model com 99.38% de acurácia agora? Essa é molezinha! Trata-se de um projeto entregue praticamente pronto, só precisamos compilar a dlib, que é a única que tem um macete para quem tem CUDA instalado na máquina.
Essa semana tenho andado bastante empolgado com meus estudos de redes neurais e, não por acaso, acabei me deparando com um projeto fantástico, passível de adaptações. Trata-se do face_recognition, um excelente projeto, cujo repositório do projeto está nesse link.
Esse tutorial é para utilizar com Python3 e estou testando e escrevendo a partir de um Ubuntu 18.04.
A dlib é a grande sacada aqui. Claro que tem todo o projeto por trás, mas ela é o motor da coisa toda. Para compilá-la, precisamos cumprir com alguns pré-requisitos, mas tudo se resume ao procedimento abaixo:
sudo su
apt-get install -y --fix-missing \
build-essential \
cmake \
gfortran \
git \
wget \
curl \
graphicsmagick \
libgraphicsmagick1-dev \
libatlas-dev \
libavcodec-dev \
libavformat-dev \
libgtk2.0-dev \
libjpeg-dev \
liblapack-dev \
libswscale-dev \
pkg-config \
python3-dev \
python3-numpy \
software-properties-common \
zip \
&& apt-get clean && rm -rf /tmp/* /var/tmp/*
mkdir -p dlib && \
git clone -b 'v19.9' --single-branch https://github.com/davisking/dlib.git dlib/ && \
cd dlib/ && \
python3 setup.py install --yes USE_AVX_INSTRUCTIONS --no DLIB_USE_CUDA
Se a compilação ocorrer sem problemas, já deve ser possível importar a dlib. Teste assim, se não retornar erro, está ok:
python3 -c "import dlib"
Se teve algum problema, meus mais sinceros sentimentos, mas dê um jeito aí porque você não pode ficar sem esse brinquedo! Por fim, instale o pacote pip para Python3 e já instale o programa para reconhecimento facial com dlib:
pip install python3-pip
pip3 install face_recognition
Pronto, a instalação está finalizada. Agora vamos ver como usar os programas e alguns dos recursos da biblioteca.
Muitas pessoas ainda fazem confusão em relação a isso. Face detection simplesmente detecta um rosto, mas não sabe quem é. Esse recurso é útil para economizar processamento (ficará clara a razão no próximo artigo), pois detectar uma face requer bem menos processamento que fazer o reconhecimento.
Para detecção facial, utilize o programa face_detection. Por exemplo, tenho um diretório com imagens e quero separar minhas fotos com a família, mas como são muitas fotos, demoraria horas para classificar. Então:
ls *jpg|while read line; do \
echo "Detectiong on: $line"; \
face_detection $line;sleep 2; \
done
O resultado seria algo como:
O programa devolve a região da face, podendo-se então recortá-la com a utilização do ImageMagick de forma automática, caso fosse de interesse.
convert copa.jpg -gravity northwest -crop 80x180x200x80 -compose over -composite copa_crop.jpg
Coloquei um espaço extra pra não ficar grudado na região da detecção.
O programa também permite a execução sobre um diretório de imagens:
face_recognition ./pictures_of_people_i_know/
As coordenadas são top, direita, base, esquerda.
Também podemos fazer uso de múltiplas CPUs para acelerar a detecção. Por exemplo:
face_detection --cpus 8 ./diretorio_de_imagens
Agora começa a brincadeira para programadores.
Quando terminar a compilação, além de instalar a dlib ainda contaremos com um módulo para programar em Python. Isso facilita muito o uso de visão computacional para quem está iniciando, hum?
Um exemplo simples, fazendo o cropping mais preciso e sem precisar usar shell script:
import sys
from PIL import Image
import face_recognition
if len(sys.argv) == 1:
print("passe uma imagem como parameto")
sys.exit(0)
image = face_recognition.load_image_file("biden.jpg")
face_locations = face_recognition.face_locations(image)
print("I found {} face(s) in this photograph.".format(len(face_locations)))
for face_location in face_locations:
top, right, bottom, left = face_location
print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
face_image = image[top:bottom, left:right]
pil_image = Image.fromarray(face_image)
pil_image.show()
A compilação foi explicada sem a utilização de CUDA. Ainda assim, é possível utilizar uma CNN para fazer a detecção de face e pode valer a pena se distribuir o processamento em vários núcleos. Para linha de comando:
face_detection --cpus 8 --model cnn ./jpg/
E dentro do código Python, basta incluir o parâmetro na respectiva linha:
face_locations = face_recognition.face_locations(image, model="cnn")
Olha só que incrível. Se quiser fazer montagens ou ocultar uma parte do rosto (por exemplo, esconder os olhos de uma criança), as referências do posicionamento podem ser pegas com uma linha de Python:
import face_recognition
image = face_recognition.load_image_file("perfil_dj.jpg")
face_landmarks_list = face_recognition.face_landmarks(image)
Essa referência foi tirada da imagem desse bonitão aqui:
Se resolver pegar essa imagem, ela foi redimensionada e dará outras dimensões na execução do código agora.
Para fazer reconhecimento facial com dlib por linha de comando é tão simples quanto fazer o face detection. Começando os parâmetros com as opções disponíveis, pode-se (e talvez se deva) passar um número de cpu, da mesma forma que para o face detection. Outro parâmetro disponível é a tolerância (--tolerance), que é 0.6 por padrão. Pode ser necessário definir um limite para evitar falso-positivo. Uma linha de comando de exemplo seria:
Simples e indolor.
A simplicidade para fazer reconhecimento facial com dlib com Python é a mesma. Quando utilizando em tempo-real, a melhor opção sem sombra de dúvidas é utilizar GPU, mas aí a compilação da dlib muda. Fora isso, podemos também utilizar Python 2.7, que também é outra configuração de compilação.
Para fazer um reconhecimento facial a partir de imagens, utiliza-se algo como isto:
import face_recognition
its_me = face_recognition.load_image_file("djames.jpg")
me_encoding = face_recognition.face_encodings(its_me)[0]
unknown_picture = face_recognition.load_image_file("another_picture.jpg")
unknown_face_encoding = face_recognition.face_encodings(unknown_picture)[0]
results = face_recognition.compare_faces([my_face_encoding], unknown_face_encoding)
if results[0] == True:
print("It's me!")
else:
print("It's not me!")
Completamente simples; seleciona modelo, codifica, seleciona alvo, codifica, compara. Só isso!
Para uma brincadeira mais interessante, vou dispor o código para receber como parâmetro uma foto sua, então abre-se a webcam e faz-se o reconhecimento. Tem aplicações interessantes, vou fazer outro artigo a respeito só para mostrar uma delas.
Podemos carregar várias fotos de pessoas diferentes, eu coloquei só 2 minhas mesmo e o resultado é a imagem de destaque desse artigo.
import face_recognition
import cv2
video_capture = cv2.VideoCapture(0)
djames = face_recognition.load_image_file("/home/djames/jpg/perfil_dj.jpg")
djames_enc = face_recognition.face_encodings(djames)[0]
outra_pessoa = face_recognition.load_image_file("/home/djames/me_again.jpg")
outra_pessoa_enc = face_recognition.face_encodings(outra_pessoa)[0]
known_face_encodings = [
djames_enc,
outra_pessoa_enc
]
#usei 2 fotos minhas, portanto:
known_face_names = [
"djames",
"djames"
]
face_locations = []
face_encodings = []
face_names = []
process_this_frame = True
while True:
ret, frame = video_capture.read()
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
rgb_small_frame = small_frame[:, :, ::-1]
if process_this_frame:
face_locations = face_recognition.face_locations(rgb_small_frame)
face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
face_names = []
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
name = "Estranho"
if True in matches:
first_match_index = matches.index(True)
name = known_face_names[first_match_index]
face_names.append(name)
process_this_frame = not process_this_frame
for (top, right, bottom, left), name in zip(face_locations, face_names):
top *= 4
right *= 4
bottom *= 4
left *= 4
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)
cv2.imshow('Video', frame)
# letra 'q' para sair
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
Terei que fazer um vídeo desse material, devo colocar em breve no nosso canal DobitAoByteBrasil no youtube.
Inscreva-se no nosso canal Manual do Maker no YouTube.
Também estamos no Instagram.
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.