// Copyright (C) 2017 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #include "opaque_types.h" #include #include #include #include #include #include "indexing.h" #include #include #include #include using namespace dlib; using namespace std; namespace py = pybind11; typedef matrix cv; class face_recognition_model_v1 { public: face_recognition_model_v1(const std::string& model_filename) { deserialize(model_filename) >> net; } matrix compute_face_descriptor ( numpy_image img, const full_object_detection& face, const int num_jitters, float padding = 0.25 ) { std::vector faces(1, face); return compute_face_descriptors(img, faces, num_jitters, padding)[0]; } matrix compute_face_descriptor_from_aligned_image ( numpy_image img, const int num_jitters ) { std::vector> images{img}; return batch_compute_face_descriptors_from_aligned_images(images, num_jitters)[0]; } std::vector> compute_face_descriptors ( numpy_image img, const std::vector& faces, const int num_jitters, float padding = 0.25 ) { std::vector> batch_img(1, img); std::vector> batch_faces(1, faces); return batch_compute_face_descriptors(batch_img, batch_faces, num_jitters, padding)[0]; } std::vector>> batch_compute_face_descriptors ( const std::vector>& batch_imgs, const std::vector>& batch_faces, const int num_jitters, float padding = 0.25 ) { if (batch_imgs.size() != batch_faces.size()) throw dlib::error("The array of images and the array of array of locations must be of the same size"); int total_chips = 0; for (const auto& faces : batch_faces) { total_chips += faces.size(); for (const auto& f : faces) { if (f.num_parts() != 68 && f.num_parts() != 5) throw dlib::error("The full_object_detection must use the iBUG 300W 68 point face landmark style or dlib's 5 point style."); } } dlib::array> face_chips; for (int i = 0; i < batch_imgs.size(); ++i) { auto& faces = batch_faces[i]; auto& img = batch_imgs[i]; std::vector dets; for (const auto& f : faces) dets.push_back(get_face_chip_details(f, 150, padding)); dlib::array> this_img_face_chips; extract_image_chips(img, dets, this_img_face_chips); for (auto& chip : this_img_face_chips) face_chips.push_back(chip); } std::vector>> face_descriptors(batch_imgs.size()); if (num_jitters <= 1) { // extract descriptors and convert from float vectors to double vectors auto descriptors = net(face_chips, 16); auto next = std::begin(descriptors); for (int i = 0; i < batch_faces.size(); ++i) { for (int j = 0; j < batch_faces[i].size(); ++j) { face_descriptors[i].push_back(matrix_cast(*next++)); } } DLIB_ASSERT(next == std::end(descriptors)); } else { // extract descriptors and convert from float vectors to double vectors auto fimg = std::begin(face_chips); for (int i = 0; i < batch_faces.size(); ++i) { for (int j = 0; j < batch_faces[i].size(); ++j) { auto& r = mean(mat(net(jitter_image(*fimg++, num_jitters), 16))); face_descriptors[i].push_back(matrix_cast(r)); } } DLIB_ASSERT(fimg == std::end(face_chips)); } return face_descriptors; } std::vector> batch_compute_face_descriptors_from_aligned_images ( const std::vector>& batch_imgs, const int num_jitters ) { dlib::array> face_chips; for (auto& img : batch_imgs) { matrix image; if (is_image(img)) assign_image(image, numpy_image(img)); else if (is_image(img)) assign_image(image, numpy_image(img)); else throw dlib::error("Unsupported image type, must be 8bit gray or RGB image."); // Check for the size of the image if ((image.nr() != 150) || (image.nc() != 150)) { throw dlib::error("Unsupported image size, it should be of size 150x150. Also cropping must be done as `dlib.get_face_chip` would do it. \ That is, centered and scaled essentially the same way."); } face_chips.push_back(image); } std::vector> face_descriptors; if (num_jitters <= 1) { // extract descriptors and convert from float vectors to double vectors auto descriptors = net(face_chips, 16); for (auto& des: descriptors) { face_descriptors.push_back(matrix_cast(des)); } } else { // extract descriptors and convert from float vectors to double vectors for (auto& fimg : face_chips) { auto& r = mean(mat(net(jitter_image(fimg, num_jitters), 16))); face_descriptors.push_back(matrix_cast(r)); } } return face_descriptors; } private: dlib::rand rnd; std::vector> jitter_image( const matrix& img, const int num_jitters ) { std::vector> crops; for (int i = 0; i < num_jitters; ++i) crops.push_back(dlib::jitter_image(img,rnd)); return crops; } template