Skip to content

Instantly share code, notes, and snippets.

@st235
Created December 25, 2022 21:18
Show Gist options
  • Save st235/b79b04bfbd0779b248e2271fc7a2d706 to your computer and use it in GitHub Desktop.
Save st235/b79b04bfbd0779b248e2271fc7a2d706 to your computer and use it in GitHub Desktop.
Face recognition with Dlib
cmake_minimum_required(VERSION 3.0.0)
project(face_detection VERSION 0.0.1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
include(FetchContent)
FetchContent_Declare(dlib
GIT_REPOSITORY https://github.com/davisking/dlib.git
GIT_TAG v19.24
)
FetchContent_MakeAvailable(dlib)
add_executable(face_detection main.cpp dnn_face_recognition_model.h)
target_link_libraries(face_detection dlib::dlib)
#ifndef FACE_DETECTION_DNN_FACE_RECOGNITION_MODEL_H
#define FACE_DETECTION_DNN_FACE_RECOGNITION_MODEL_H
#include <dlib/dnn.h>
#include <dlib/clustering.h>
template <template <int,template<typename>class,int,typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual = dlib::add_prev1<block<N,BN,1,dlib::tag1<SUBNET>>>;
template <template <int,template<typename>class,int,typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual_down = dlib::add_prev2<dlib::avg_pool<2,2,2,2,dlib::skip1<dlib::tag2<block<N,BN,2,dlib::tag1<SUBNET>>>>>>;
template <int N, template <typename> class BN, int stride, typename SUBNET>
using block = BN<dlib::con<N,3,3,1,1,dlib::relu<BN<dlib::con<N,3,3,stride,stride,SUBNET>>>>>;
template <int N, typename SUBNET> using ares = dlib::relu<residual<block,N,dlib::affine,SUBNET>>;
template <int N, typename SUBNET> using ares_down = dlib::relu<residual_down<block,N,dlib::affine,SUBNET>>;
template <typename SUBNET> using alevel0 = ares_down<256,SUBNET>;
template <typename SUBNET> using alevel1 = ares<256,ares<256,ares_down<256,SUBNET>>>;
template <typename SUBNET> using alevel2 = ares<128,ares<128,ares_down<128,SUBNET>>>;
template <typename SUBNET> using alevel3 = ares<64,ares<64,ares<64,ares_down<64,SUBNET>>>>;
template <typename SUBNET> using alevel4 = ares<32,ares<32,ares<32,SUBNET>>>;
using face_recognition_dnn_model = dlib::loss_metric<dlib::fc_no_bias<128,dlib::avg_pool_everything<
alevel0<
alevel1<
alevel2<
alevel3<
alevel4<
dlib::max_pool<3,3,2,2,dlib::relu<dlib::affine<dlib::con<32,7,7,2,2,
dlib::input_rgb_image_sized<150>
>>>>>>>>>>>>;
#endif //FACE_DETECTION_DNN_FACE_RECOGNITION_MODEL_H
#include <iostream>
// Load Image
#include <dlib/image_io.h>
// Shape predictor
// dlib::shape_predictor
// landmarks: http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
#include <dlib/image_processing/shape_predictor.h>
// Face detector
// dlib::frontal_face_detector
#include <dlib/image_processing/frontal_face_detector.h>
// Render face landmarks (for win overlays)
// dlib::render_face_detections
#include <dlib/image_processing/render_face_detections.h>
// face_recognition_dnn_model
#include "dnn_face_recognition_model.h"
// Gui
#include <dlib/gui_widgets.h>
void ShowImage(const dlib::array2d<dlib::rgb_pixel>& image) {
dlib::image_window win;
win.set_image(image);
// using of title creates
// memory leak at least on MacOS
// win.set_title(title)
win.wait_until_closed();
}
int main(int argc, char** argv) {
if (argc <= 3) {
std::cout
<< "Call app with the image param" << std::endl
<< "./face_detection image_name" << std::endl;
return 1;
}
dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
dlib::shape_predictor shape_predictor;
// shape_predictor_68_face_landmarks.dat
dlib::deserialize(argv[1]) >> shape_predictor;
face_recognition_dnn_model face_recognition_dnn_model;
// dlib_face_recognition_resnet_model_v1.dat
dlib::deserialize(argv[2]) >> face_recognition_dnn_model;
dlib::image_window win;
for (int i = 3; i < argc; i++) {
dlib::array2d<dlib::rgb_pixel> image;
dlib::load_image(image, argv[i]);
dlib::pyramid_up(image);
std::vector<dlib::matrix<dlib::rgb_pixel>> face_images;
std::vector<dlib::rectangle> face_rectangles = detector(image);
std::vector<dlib::full_object_detection> faces_landmarks;
for (const auto& face_rectangle: face_rectangles) {
dlib::full_object_detection landmarks = shape_predictor(image, face_rectangle);
faces_landmarks.push_back(landmarks);
dlib::matrix<dlib::rgb_pixel> face_image;
dlib::extract_image_chip(image, dlib::get_face_chip_details(landmarks, 150, 0.25), face_image);
face_images.push_back(std::move(face_image));
}
win.clear_overlay();
win.set_image(image);
// add red faces rectangle
win.add_overlay(face_rectangles);
win.add_overlay(dlib::render_face_detections(faces_landmarks));
std::vector<dlib::matrix<float, 0, 1>> face_descriptors = face_recognition_dnn_model(face_images);
std::cout << argv[i] << std::endl;
for (size_t di = 0; di < face_descriptors.size(); di++) {
auto& face_descriptor = face_descriptors[di];
std::cout << "face " << di << ": [";
for (auto iterator = face_descriptor.begin(); iterator < face_descriptor.end(); iterator++) {
std::cout << *iterator << ", ";
}
std::cout << "]" << std::endl;
}
if (i < argc - 1) {
std::cout << "Press any button to continue..." << std::endl;
std::cin.get();
}
}
win.wait_until_closed();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment