You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.9 KiB
143 lines
5.9 KiB
2 months ago
|
// License: Apache 2.0. See LICENSE file in root directory.
|
||
|
// Copyright(c) 2019 Intel Corporation. All Rights Reserved.
|
||
|
|
||
|
#include <librealsense2/rs.hpp> // Include RealSense Cross Platform API
|
||
|
#include <dlib/image_processing/frontal_face_detector.h>
|
||
|
#include <dlib/image_processing/render_face_detections.h>
|
||
|
#include <dlib/image_processing.h>
|
||
|
#include <dlib/gui_widgets.h> // image_window, etc.
|
||
|
#include "../rs_frame_image.h"
|
||
|
#include "validate_face.h"
|
||
|
#include "render_face.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
The data pointed to by 'frame.get_data()' is a uint16_t 'depth unit' that needs to be scaled.
|
||
|
|
||
|
We return the scaling factor to convert these pixels to meters. This can differ depending
|
||
|
on different cameras.
|
||
|
*/
|
||
|
float get_depth_scale( rs2::device dev )
|
||
|
{
|
||
|
// Go over the device's sensors
|
||
|
for( rs2::sensor& sensor : dev.query_sensors() )
|
||
|
{
|
||
|
// Check if the sensor if a depth sensor
|
||
|
if( rs2::depth_sensor dpt = sensor.as<rs2::depth_sensor>() )
|
||
|
{
|
||
|
return dpt.get_depth_scale();
|
||
|
}
|
||
|
}
|
||
|
throw std::runtime_error( "Device does not have a depth sensor" );
|
||
|
}
|
||
|
|
||
|
|
||
|
int main(int argc, char * argv[]) try
|
||
|
{
|
||
|
// Declare RealSense pipeline, encapsulating the actual device and sensors
|
||
|
rs2::pipeline pipe;
|
||
|
// Start streaming with default recommended configuration
|
||
|
rs2::pipeline_profile profile = pipe.start();
|
||
|
// Each depth camera might have different units for depth pixels, so we get it here
|
||
|
// Using the pipeline's profile, we can retrieve the device that the pipeline uses
|
||
|
float const DEVICE_DEPTH_SCALE = get_depth_scale( profile.get_device() );
|
||
|
|
||
|
|
||
|
/*
|
||
|
The face detector we use is made using the classic Histogram of Oriented
|
||
|
Gradients (HOG) feature combined with a linear classifier, an image pyramid,
|
||
|
and sliding window detection scheme, using dlib's implementation of:
|
||
|
One Millisecond Face Alignment with an Ensemble of Regression Trees by
|
||
|
Vahid Kazemi and Josephine Sullivan, CVPR 2014
|
||
|
and was trained on the iBUG 300-W face landmark dataset (see
|
||
|
https://ibug.doc.ic.ac.uk/resources/facial-point-annotations/):
|
||
|
C. Sagonas, E. Antonakos, G, Tzimiropoulos, S. Zafeiriou, M. Pantic.
|
||
|
300 faces In-the-wild challenge: Database and results.
|
||
|
Image and Vision Computing (IMAVIS), Special Issue on Facial Landmark Localisation "In-The-Wild". 2016.
|
||
|
|
||
|
You can get the trained model file from:
|
||
|
http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
|
||
|
|
||
|
Note that the license for the iBUG 300-W dataset excludes commercial use.
|
||
|
So you should contact Imperial College London to find out if it's OK for
|
||
|
you to use this model file in a commercial product.
|
||
|
*/
|
||
|
dlib::frontal_face_detector face_bbox_detector = dlib::get_frontal_face_detector();
|
||
|
dlib::shape_predictor face_landmark_annotator;
|
||
|
dlib::deserialize( "shape_predictor_68_face_landmarks.dat" ) >> face_landmark_annotator;
|
||
|
/*
|
||
|
The 5-point landmarks model file can be used, instead. It's 10 times smaller and runs
|
||
|
faster, from:
|
||
|
http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2
|
||
|
But the validate_face() and render_face() functions will then need to be changed
|
||
|
to handle 5 points.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
We need to map pixels on the color frame to a depth frame, so we can
|
||
|
determine their depth. The problem is that the frames may (and probably
|
||
|
will!) be of different resolutions, and so alignment is necessary.
|
||
|
|
||
|
See the rs-align example for a better understanding.
|
||
|
|
||
|
We align the depth frame so it fits in resolution with the color frame
|
||
|
since we go from color to depth.
|
||
|
*/
|
||
|
rs2::align align_to_color( RS2_STREAM_COLOR );
|
||
|
|
||
|
// Display annotations in one of two colors: if the face is determined to be that of a real
|
||
|
// person, it is "good". Otherwise, "bad".
|
||
|
dlib::rgb_pixel bad_color( 255, 0, 0 );
|
||
|
dlib::rgb_pixel good_color( 0, 255, 0 );
|
||
|
|
||
|
dlib::image_window win;
|
||
|
while( ! win.is_closed() )
|
||
|
{
|
||
|
rs2::frameset data = pipe.wait_for_frames(); // Wait for next set of frames from the camera
|
||
|
data = align_to_color.process( data ); // Replace with aligned frames
|
||
|
auto depth_frame = data.get_depth_frame();
|
||
|
auto color_frame = data.get_color_frame();
|
||
|
|
||
|
// Create a dlib image for face detection
|
||
|
rs_frame_image< dlib::rgb_pixel, RS2_FORMAT_RGB8 > image( color_frame );
|
||
|
|
||
|
// Detect faces: find bounding boxes around all faces, then annotate each to find its landmarks
|
||
|
std::vector< dlib::rectangle > face_bboxes = face_bbox_detector( image );
|
||
|
std::vector< dlib::full_object_detection > faces;
|
||
|
for( auto const & bbox : face_bboxes )
|
||
|
faces.push_back( face_landmark_annotator( image, bbox ));
|
||
|
|
||
|
// Display it all on the screen
|
||
|
win.clear_overlay();
|
||
|
win.set_image( image );
|
||
|
for( auto const & face : faces )
|
||
|
{
|
||
|
dlib::rgb_pixel & color =
|
||
|
validate_face( depth_frame, DEVICE_DEPTH_SCALE, face )
|
||
|
? good_color : bad_color;
|
||
|
win.add_overlay( render_face( face, color ));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|
||
|
catch( dlib::serialization_error const & e )
|
||
|
{
|
||
|
std::cerr << "You need dlib's default face landmarking model file to run this example." << std::endl;
|
||
|
std::cerr << "You can get it from the following URL: " << std::endl;
|
||
|
std::cerr << " http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << std::endl;
|
||
|
std::cerr << std::endl << e.what() << std::endl;
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
catch (const rs2::error & e)
|
||
|
{
|
||
|
std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl;
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
catch (const std::exception& e)
|
||
|
{
|
||
|
std::cerr << e.what() << std::endl;
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|