Skip to main content
Balneário Camboriú - SC +55 (47) 99725 1117
Siga-nos:

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.

Fig 1. Principais pontos faciais utilizados.

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..

Fig 2. Etapas antecessoras a detecção de pontos faciais.

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. 

Fig 4. Resultados obtidos com este experimento

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:

https://github.com/visaocomputacionalexemplos/experimentos_faciais/tree/main/detectar_pontos_faciais_dlib

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

[KJ1] V. Kazemi and J. Sullivan, “One millisecond face alignment with an ensemble of regression trees,” 2014 IEEE Conference on Computer Vision and Pattern Recognition, 2014, pp. 1867-1874, doi: 10.1109/CVPR.2014.241.

Nenhum comentário ainda!

Seu endereço de e-mail não será publicado