From 9fe352d69679e45b3379efc07c0f92be032d8026 Mon Sep 17 00:00:00 2001 From: Varun Chatterji Date: Mon, 18 Sep 2017 19:54:26 +0800 Subject: [PATCH 1/4] Added size and padding as optional parameters --- python_examples/face_clustering.py | 3 ++- tools/python/src/face_recognition.cpp | 28 +++++++++++++++++---------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/python_examples/face_clustering.py b/python_examples/face_clustering.py index 96515a780..6c1dc4eee 100755 --- a/python_examples/face_clustering.py +++ b/python_examples/face_clustering.py @@ -119,7 +119,8 @@ print("Saving faces in largest cluster to output folder...") for i, index in enumerate(indices): img, shape = images[index] file_path = os.path.join(output_folder_path, "face_" + str(i)) - dlib.save_face_chip(img, shape, file_path) + # The size and padding arguments are optional with default size=150x150 and padding=0.25 + dlib.save_face_chip(img, shape, file_path, size=150, padding=0.25) diff --git a/tools/python/src/face_recognition.cpp b/tools/python/src/face_recognition.cpp index f3c8204ef..f06e416a7 100644 --- a/tools/python/src/face_recognition.cpp +++ b/tools/python/src/face_recognition.cpp @@ -177,13 +177,15 @@ boost::python::list chinese_whispers_clustering(boost::python::list descriptors, void save_face_chips ( object img, const std::vector& faces, - const std::string& chip_filename + const std::string& chip_filename, + size_t size = 150, + float padding = 0.25 ) { int num_faces = faces.size(); std::vector dets; for (auto& f : faces) - dets.push_back(get_face_chip_details(f, 150, 0.25)); + dets.push_back(get_face_chip_details(f, size, padding)); dlib::array> face_chips; extract_image_chips(numpy_rgb_image(img), dets, face_chips); int i=0; @@ -206,14 +208,18 @@ void save_face_chips ( void save_face_chip ( object img, const full_object_detection& face, - const std::string& chip_filename + const std::string& chip_filename, + size_t size = 150, + float padding = 0.25 ) { std::vector faces(1, face); - save_face_chips(img, faces, chip_filename); + save_face_chips(img, faces, chip_filename, size, padding); return; } +BOOST_PYTHON_FUNCTION_OVERLOADS(save_face_chip_with_defaults, save_face_chip, 3, 5) +BOOST_PYTHON_FUNCTION_OVERLOADS(save_face_chips_with_defaults, save_face_chips, 3, 5) // ---------------------------------------------------------------------------------------- @@ -232,12 +238,14 @@ void bind_face_recognition() ); } - def("save_face_chip", &save_face_chip, (arg("img"),arg("face"),arg("chip_filename")), - "Takes an image and a full_object_detection that references a face in that image and saves the face with the specified file name prefix. The face will be rotated upright and scaled to 150x150 pixels." - ); - def("save_face_chips", &save_face_chips, (arg("img"),arg("faces"),arg("chip_filename")), - "Takes an image and a full_object_detections object that reference faces in that image and saves the faces with the specified file name prefix. The faces will be rotated upright and scaled to 150x150 pixels." - ); + def("save_face_chip", &save_face_chip, save_face_chip_with_defaults( + "Takes an image and a full_object_detection that references a face in that image and saves the face with the specified file name prefix. The face will be rotated upright and scaled to 150x150 pixels or with the optional specified size and padding.", + (arg("img"), arg("face"), arg("chip_filename"), arg("size"), arg("padding")) + )); + def("save_face_chips", &save_face_chips, save_face_chips_with_defaults( + "Takes an image and a full_object_detections object that reference faces in that image and saves the faces with the specified file name prefix. The faces will be rotated upright and scaled to 150x150 pixels or with the optional specified size and padding.", + (arg("img"), arg("faces"), arg("chip_filename"), arg("size"), arg("padding")) + )); def("chinese_whispers_clustering", &chinese_whispers_clustering, (arg("descriptors"), arg("threshold")), "Takes a list of descriptors and returns a list that contains a label for each descriptor. Clustering is done using dlib::chinese_whispers." ); From 5f26972551dac0820b8abb27891f1f4e26f11702 Mon Sep 17 00:00:00 2001 From: Varun Chatterji Date: Tue, 19 Sep 2017 13:08:51 +0800 Subject: [PATCH 2/4] Added code to get face_chip images.. --- python_examples/face_alignment.py | 98 +++++++++++++++++++++++++++ tools/python/src/face_recognition.cpp | 82 +++++++++++++++++++++- 2 files changed, 179 insertions(+), 1 deletion(-) create mode 100755 python_examples/face_alignment.py diff --git a/python_examples/face_alignment.py b/python_examples/face_alignment.py new file mode 100755 index 000000000..9b15e179f --- /dev/null +++ b/python_examples/face_alignment.py @@ -0,0 +1,98 @@ +#!/usr/bin/python +# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt +# +# This example shows how to use dlib's face recognition tool for image alignment. +# +# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE +# You can install dlib using the command: +# pip install dlib +# +# Alternatively, if you want to compile dlib yourself then go into the dlib +# root folder and run: +# python setup.py install +# or +# python setup.py install --yes USE_AVX_INSTRUCTIONS +# if you have a CPU that supports AVX instructions, since this makes some +# things run faster. This code will also use CUDA if you have CUDA and cuDNN +# installed. +# +# Compiling dlib should work on any operating system so long as you have +# CMake and boost-python installed. On Ubuntu, this can be done easily by +# running the command: +# sudo apt-get install libboost-python-dev cmake +# +# Also note that this example requires OpenCV and Numpy which can be installed +# via the command: +# pip install opencv-python numpy +# Or downloaded from http://opencv.org/releases.html + +import sys +import os +import dlib +import glob +import cv2 +import numpy as np + +if len(sys.argv) != 4: + print( + "Call this program like this:\n" + " ./face_alignment.py shape_predictor_5_face_landmarks.dat dlib_face_recognition_resnet_model_v1.dat ../examples/faces/bald_guys.jpg\n" + "You can download a trained facial shape predictor and recognition model from:\n" + " http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2\n" + " http://dlib.net/files/dlib_face_recognition_resnet_model_v1.dat.bz2") + exit() + +predictor_path = sys.argv[1] +face_rec_model_path = sys.argv[2] +face_file_path = sys.argv[3] + +# Load all the models we need: a detector to find the faces, a shape predictor +# to find face landmarks so we can precisely localize the face, and finally the +# face recognition model. +detector = dlib.get_frontal_face_detector() +sp = dlib.shape_predictor(predictor_path) +facerec = dlib.face_recognition_model_v1(face_rec_model_path) + +# Load the image using OpenCV +bgr_img = cv2.imread(face_file_path) +if bgr_img is None: + print("Sorry, we could not load '{}' as an image".format(face_file_path)) + exit() + +# Convert to RGB since dlib uses RGB images +img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2RGB) + +# Ask the detector to find the bounding boxes of each face. The 1 in the +# second argument indicates that we should upsample the image 1 time. This +# will make everything bigger and allow us to detect more faces. +dets = detector(img, 1) + +num_faces = len(dets) +if num_faces == 0: + print("Sorry, there were no faces found in '{}'".format(face_file_path)) + exit() + +# The full object detection object +faces = dlib.full_object_detections() +for detection in dets: + faces.append(sp(img, detection)) + +# Get the aligned face images +# Optionally: +# images = dlib.get_face_chips(img, faces, size=160, padding=0.25) +images = dlib.get_face_chips(img, faces, size=320) +for image in images: + cv_rgb_image = np.array(image).astype(np.uint8) + cv_bgr_img = cv2.cvtColor(cv_rgb_image, cv2.COLOR_RGB2BGR) + cv2.imshow('image',cv_bgr_img) + cv2.waitKey(0) + +# It is also possible to get a single chip +image = dlib.get_face_chip(img, faces[0]) +cv_rgb_image = np.array(image).astype(np.uint8) +cv_bgr_img = cv2.cvtColor(cv_rgb_image, cv2.COLOR_RGB2BGR) +cv2.imshow('image',cv_bgr_img) +cv2.waitKey(0) + +cv2.destroyAllWindows() + diff --git a/tools/python/src/face_recognition.cpp b/tools/python/src/face_recognition.cpp index f06e416a7..5f2ef4aef 100644 --- a/tools/python/src/face_recognition.cpp +++ b/tools/python/src/face_recognition.cpp @@ -182,6 +182,9 @@ void save_face_chips ( float padding = 0.25 ) { + if (!is_rgb_python_image(img)) + throw dlib::error("Unsupported image type, must be RGB image."); + int num_faces = faces.size(); std::vector dets; for (auto& f : faces) @@ -221,6 +224,75 @@ void save_face_chip ( BOOST_PYTHON_FUNCTION_OVERLOADS(save_face_chip_with_defaults, save_face_chip, 3, 5) BOOST_PYTHON_FUNCTION_OVERLOADS(save_face_chips_with_defaults, save_face_chips, 3, 5) +// ---------------------------------------------------------------------------------------- + +boost::python::list get_face_chips ( + object img, + const std::vector& faces, + size_t size = 150, + float padding = 0.25 +) +{ + if (!is_rgb_python_image(img)) + throw dlib::error("Unsupported image type, must be RGB image."); + + if (faces.size() < 1) { + throw dlib::error("No face were specified in the faces array."); + } + + boost::python::list chips_list; + + int num_faces = faces.size(); + std::vector dets; + for (auto& f : faces) + dets.push_back(get_face_chip_details(f, size, padding)); + dlib::array> face_chips; + extract_image_chips(numpy_rgb_image(img), dets, face_chips); + + for (auto& chip : face_chips) + { + boost::python::list img; + + for(int row=0; row faces(1, face); + boost::python::list result = get_face_chips(img, faces, size, padding); + size_t num_images = boost::python::len(result); + if(num_images == 1) { + return boost::python::extract(result[0]); + } else { + throw dlib::error("No face chips found!"); + } +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(get_face_chip_with_defaults, get_face_chip, 2, 4) +BOOST_PYTHON_FUNCTION_OVERLOADS(get_face_chips_with_defaults, get_face_chips, 2, 4) + + // ---------------------------------------------------------------------------------------- void bind_face_recognition() @@ -246,11 +318,19 @@ void bind_face_recognition() "Takes an image and a full_object_detections object that reference faces in that image and saves the faces with the specified file name prefix. The faces will be rotated upright and scaled to 150x150 pixels or with the optional specified size and padding.", (arg("img"), arg("faces"), arg("chip_filename"), arg("size"), arg("padding")) )); + def("get_face_chip", &get_face_chip, get_face_chip_with_defaults( + "Takes an image and a full_object_detection that references a face in that image and returns the face as a list of lists representing the image. The face will be rotated upright and scaled to 150x150 pixels or with the optional specified size and padding.", + (arg("img"), arg("face"), arg("size"), arg("padding")) + )); + def("get_face_chips", &get_face_chips, get_face_chips_with_defaults( + "Takes an image and a full_object_detections object that reference faces in that image and returns the faces as a list of list of lists representing the image. The faces will be rotated upright and scaled to 150x150 pixels or with the optional specified size and padding.", + (arg("img"), arg("faces"), arg("size"), arg("padding")) + )); def("chinese_whispers_clustering", &chinese_whispers_clustering, (arg("descriptors"), arg("threshold")), "Takes a list of descriptors and returns a list that contains a label for each descriptor. Clustering is done using dlib::chinese_whispers." ); - { + { typedef std::vector type; class_("full_object_detections", "An array of full_object_detection objects.") .def(vector_indexing_suite()) From 7e94daad4d40dc906666c2daeeec9e89ffa210e5 Mon Sep 17 00:00:00 2001 From: Varun Chatterji Date: Tue, 19 Sep 2017 23:08:54 +0800 Subject: [PATCH 3/4] Cleaned up example file. --- python_examples/face_alignment.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/python_examples/face_alignment.py b/python_examples/face_alignment.py index 9b15e179f..ba3b39f8e 100755 --- a/python_examples/face_alignment.py +++ b/python_examples/face_alignment.py @@ -27,31 +27,26 @@ # Or downloaded from http://opencv.org/releases.html import sys -import os + import dlib -import glob import cv2 import numpy as np -if len(sys.argv) != 4: +if len(sys.argv) != 3: print( "Call this program like this:\n" - " ./face_alignment.py shape_predictor_5_face_landmarks.dat dlib_face_recognition_resnet_model_v1.dat ../examples/faces/bald_guys.jpg\n" - "You can download a trained facial shape predictor and recognition model from:\n" - " http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2\n" - " http://dlib.net/files/dlib_face_recognition_resnet_model_v1.dat.bz2") + " ./face_alignment.py shape_predictor_5_face_landmarks.dat ../examples/faces/bald_guys.jpg\n" + "You can download a trained facial shape predictor from:\n" + " http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2\n") exit() predictor_path = sys.argv[1] -face_rec_model_path = sys.argv[2] -face_file_path = sys.argv[3] +face_file_path = sys.argv[2] # Load all the models we need: a detector to find the faces, a shape predictor -# to find face landmarks so we can precisely localize the face, and finally the -# face recognition model. +# to find face landmarks so we can precisely localize the face detector = dlib.get_frontal_face_detector() sp = dlib.shape_predictor(predictor_path) -facerec = dlib.face_recognition_model_v1(face_rec_model_path) # Load the image using OpenCV bgr_img = cv2.imread(face_file_path) From 67e6957b1e3934bf542afd81b061ade8460ae6f2 Mon Sep 17 00:00:00 2001 From: Davis King Date: Fri, 22 Sep 2017 21:52:15 -0400 Subject: [PATCH 4/4] Clarified comment and updated requirements.txt --- python_examples/face_alignment.py | 2 +- python_examples/requirements.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/python_examples/face_alignment.py b/python_examples/face_alignment.py index ba3b39f8e..b8e2ca862 100755 --- a/python_examples/face_alignment.py +++ b/python_examples/face_alignment.py @@ -67,7 +67,7 @@ if num_faces == 0: print("Sorry, there were no faces found in '{}'".format(face_file_path)) exit() -# The full object detection object +# Find the 5 face landmarks we need to do the alignment. faces = dlib.full_object_detections() for detection in dets: faces.append(sp(img, detection)) diff --git a/python_examples/requirements.txt b/python_examples/requirements.txt index aa950c107..8fa92c8a0 100644 --- a/python_examples/requirements.txt +++ b/python_examples/requirements.txt @@ -1 +1,3 @@ scikit-image>=0.9.3 +opencv-python +numpy