Neste post, é apresentado como realizar a detecção de pontos faciais com o algoritmo de Kazemi, implementado na biblioteca Dlib utilizando Shape Predictor. Na primeira parte deste tutorial, é apresentado o conceito de shape predictor (preditor de forma/ponto de referência) e como ele pode se usado para prever localizações específicas em objetos estruturais.
Este conteúdo é continuação do post Detecção de pontos faciais (Facemark) com OpenCV, recomendo a leitura dele primeiro, para melhor entender os conceitos básicos aqui apresentados.
Revisão de Conteúdo
Caso você não queira ler o post anterior, segue uma rápida revisão do conteúdo.
Os pontos faciais, em visão computacional, como o próprio nome diz, são pequenas regiões faciais identificadas por uma numeração, conforme ilustra a Fig 1.. Estas regiões, são identificadas por um ponto e uma numeração que pode variar de técnica para técnica utilizada.
Para realizar a detecção de pontos faciais, são necessárias as seguintes etapas antecessoras à coleta dos pontos na imagem: (1) identificar os rostos na imagem; (2) rotacionar o rosto caso necessário e (3) identificar os pontos faciais A Fig 2. Ilustra estas etapas..
Algoritmo Shape Predictor de Kazemi
“Shape Predictor” são utilizados para localizar coordenadas (x, y) específicas a partir de uma forma de entrada. O termo “Shape” é arbitrário, mas presume-se que a forma seja de natureza estrutural, como: rostos; mãos; dedos; etc [R].
Por exemplo, os rostos têm formas e tamanhos diversos, e todos eles compartilham características estruturais comuns: os olhos estão acima do nariz, o nariz está acima da boca, etc. O objetivo dos preditores de forma/ponto de referência, é explorar esse conhecimento estrutural e, com dados de treinamento suficientes, aprender como prever automaticamente a localização dessas estruturas [R].
Existem vários algoritmos preditores de forma. O algoritmo do preditor de forma implementado na biblioteca Dlib vem do artigo CVPR de Kazemi e Sullivan de 2014, One Millisecond Face Alignment with an Ensemble of Regression Trees [KJ1].
Código e Experimentos
A seguir, são apresentados partes do código criado para realizar os experimentos de detecção de pontos faciais. Caso queira replicar estes experimentos, basta baixar o código fonte disponível no github (link na seção “Source” no final deste post).
Neste primeiro bloco, são inicializados todos os detectores do sistema, o detector facial e o detector de pontos faciais. Para iniciar todos estes detectores é muito simples, basta instanciar a classe dlib::frontal_face_detector, instanciar a classe dlib::shape_predictor e carregar o modelo treinado para a classe shape_predictor.
...
#include < dlib/image_processing/frontal_face_detector.h >
#include < dlib/image_processing.h >
dlib::frontal_face_detector detector;
dlib::shape_predictor shapePredictor;
main() {
...
// Inicia Detector faciauk
detector = dlib::get_frontal_face_detector();
//Carrega o modelo treinado do shape predictor
iniciarDetectorPontosFacialSP(shapePredictor);
...
}
void iniciarDetectorPontosFacialSP(dlib::shape_predictor &sp)
{
dlib::deserialize("../../extra/shape_predictor_68_face_landmarks.dat") >> sp;
}
Para carregar o modelo de dados com Dlib, basta utilizar a função de dlib::deserialize e informar o caminho do arquivo. Esta função carrega o modelo treinado e transfere os dados carregados para a classe de predição com o operador “>>” conforme trecho de código “>> sp”.
Com os detectores/preditores carregados, agora precisamos carregar a imagem com os rostos a serem detectados. Neste experimento, utilizamos a webcam para este fim e para carregar as imagens da webcam, utilizamos a biblioteca OpenCV, que é de fácil instalação.
Para capturar a câmera do vídeo com o OpenCV, basta instanciar a classe “cv::VideoCapturecap” e coletar a imagem do vídeo com o operador “>>” conforme trecho de código “cap>>img”.
main() {
...
//Inicia captura dos vídeos
cv::VideoCapturecap cap(0);
if (!cap.isOpened()) {
std::cout<<"Video Capture Fail"<<std::endl; return1; } cv::Mat img; cap>>img;
return 1;
}
//Calcula nova dimensão da imagem para 320 pixels
auto showSize = cv::Size(320, ((float)320 / img.cols) * img.rows);
for (;;)
{
//Coleta a imagem da camera
cap>>img;
//Reescala a imagem para uma largura de 320 pixels
cv::resize(img, img, showSize, 0, 0, cv::INTER_LINEAR_EXACT);
coletarPontosFaciais(img);
cv::imshow("Origem", img);
cv::waitKey(5);
}
}
Por fim, no último trecho de código, é apresentado como coletar os pontos faciais com o OpenCV.
dlib::image_window win, win_faces;
std::vector< dlib::rectangle > rostosDetectados;
void coletarPontosFaciais(const dlib::array2d& imagemOriginal)
{
//Detecta os pontos faciais e retorna a lista de rostos detectados
rostosDetectados = detector(imagemOriginal);
//Percorre os rostos detectados e coloca os pontos faciais
std::vector< dlib::full_object_detection > pontosFaciais;
for (unsigned long j = 0; j < rostosDetectados.size(); ++j)
{
//Coleta os pontos faciais de um único rosto
dlib::full_object_detection shape = shapePredictor(imagemOriginal, rostosDetectados[j]);
pontosFaciais.push_back(shape);
}
// Exibe a imagem com o contorno dos pontos.
win.clear_overlay();
win.set_image(imagemOriginal);
win.add_overlay(render_face_detections(pontosFaciais));
// Recorta o rosto da imagem original e a exibe.
dlib::array rostosRecortados;
extract_image_chips(imagemOriginal, get_face_chip_details(pontosFaciais), rostosRecortados);
win_faces.set_image(tile_images(rostosRecortados));
}
Observe que para detectar os rostos faciais com a classe dlib::frontal_face_detector, basta utilizar a variável detector como fosse uma função, passando a imagem como parâmetro. Ao utilizar o detector como função, serão detectados os rostos e retorna uma lista de retângulos com sua localização.
Com os rostos detectados, basta percorrer cada região dos rostos e chamar a função do shapePredictor, para coletar os pontos faciais. Esta função retorna uma lista com todos pontos localizados.
A classe dlib::image_window é utilizada para criar uma janela para exibição das imagens. A função render_face_detections é disponibilizada pela própria Dlib a fim de demarcar as regiões do rosto na imagem. E as funções extract_image_chips e get_face_chip_details recortam o rosto a partir dos pontos faciais. Como resultado deste projeto, foi realizado o experimento ilustrado pela Fig 3.
Espero que esse conteúdo os ajudem na tarefa de identificação de pontos faciais.
Caso tenham dúvidas e sugestões de melhorias no post, deixe seu comentário abaixo.
Source:
Referencias:
Huber, Patrik. (2018). Real-time 3D morphable shape model fitting to monocular in-the-wild videos.
[R] Rosebrock, A, Training a custom dlib shape predictor, 2019, acessado em: 18/10/2101





