validate_face.h
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2019 Intel Corporation. All Rights Reserved.
3 
4 #pragma once
5 
6 #include <librealsense2/rs.hpp> // Include RealSense Cross Platform API
7 #include <dlib/image_processing/full_object_detection.h>
8 #include "markup_68.h"
9 
10 
11 /*
12  Calculates the average depth for a range of two-dimentional points in face, such that:
13  point(n) = face.part(n)
14  and puts the result in *p_average_depth.
15 
16  Points for which no depth is available (is 0) are ignored and not factored into the average.
17 
18  Returns true if an average is available (at least one point has depth); false otherwise.
19 */
21  rs2::depth_frame const & frame,
22  float const depth_scale,
23  dlib::full_object_detection const & face,
24  markup_68 markup_from, markup_68 markup_to,
25  float * p_average_depth
26 )
27 {
28  uint16_t const * data = reinterpret_cast<uint16_t const *>(frame.get_data());
29 
30  float average_depth = 0;
31  size_t n_points = 0;
32  for( int i = markup_from; i <= markup_to; ++i )
33  {
34  auto pt = face.part( i );
35  auto depth_in_pixels = *(data + pt.y() * frame.get_width() + pt.x());
36  if( !depth_in_pixels )
37  continue;
38  average_depth += depth_in_pixels * depth_scale;
39  ++n_points;
40  }
41  if( !n_points )
42  return false;
43  if( p_average_depth )
44  *p_average_depth = average_depth / n_points;
45  return true;
46 }
47 
48 
49 /*
50  Returns whether the given 68-point facial landmarks denote the face of a real
51  person (and not a picture of one), using the depth data in depth_frame.
52 
53  See markup_68 for an explanation of the point topology.
54 
55  NOTE: requires the coordinates in face align with those of the depth frame.
56 */
58  rs2::depth_frame const & frame,
59  float const depth_scale,
60  dlib::full_object_detection const & face
61 )
62 {
63  // Collect all the depth information for the different facial parts
64 
65  // For the ears, only one may be visible -- we take the closer one!
66  float left_ear_depth = 100, right_ear_depth = 100;
67  if( !find_depth_from( frame, depth_scale, face, markup_68::RIGHT_EAR, markup_68::RIGHT_1, &right_ear_depth )
68  && !find_depth_from( frame, depth_scale, face, markup_68::LEFT_1, markup_68::LEFT_EAR, &left_ear_depth ) )
69  return false;
70  float ear_depth = std::min( right_ear_depth, left_ear_depth );
71 
72  float chin_depth;
73  if( !find_depth_from( frame, depth_scale, face, markup_68::CHIN_FROM, markup_68::CHIN_TO, &chin_depth ) )
74  return false;
75 
76  float nose_depth;
77  if( !find_depth_from( frame, depth_scale, face, markup_68::NOSE_RIDGE_2, markup_68::NOSE_TIP, &nose_depth ) )
78  return false;
79 
80  float right_eye_depth;
81  if( !find_depth_from( frame, depth_scale, face, markup_68::RIGHT_EYE_FROM, markup_68::RIGHT_EYE_TO, &right_eye_depth ) )
82  return false;
83  float left_eye_depth;
84  if( !find_depth_from( frame, depth_scale, face, markup_68::LEFT_EYE_FROM, markup_68::LEFT_EYE_TO, &left_eye_depth ) )
85  return false;
86  float eye_depth = std::min( left_eye_depth, right_eye_depth );
87 
88  float mouth_depth;
89  if( !find_depth_from( frame, depth_scale, face, markup_68::MOUTH_OUTER_FROM, markup_68::MOUTH_INNER_TO, &mouth_depth ) )
90  return false;
91 
92  // We just use simple heuristics to determine whether the depth information agrees with
93  // what's expected: that the nose tip, for example, should be closer to the camera than
94  // the eyes.
95 
96  // These heuristics are fairly basic but nonetheless serve to illustrate the point that
97  // depth data can effectively be used to distinguish between a person and a picture of a
98  // person...
99 
100  if( nose_depth >= eye_depth )
101  return false;
102  if( eye_depth - nose_depth > 0.07f )
103  return false;
104  if( ear_depth <= eye_depth )
105  return false;
106  if( mouth_depth <= nose_depth )
107  return false;
108  if( mouth_depth > chin_depth )
109  return false;
110 
111  // All the distances, collectively, should not span a range that makes no sense. I.e.,
112  // if the face accounts for more than 20cm of depth, or less than 2cm, then something's
113  // not kosher!
114  float x = std::max( { nose_depth, eye_depth, ear_depth, mouth_depth, chin_depth } );
115  float n = std::min( { nose_depth, eye_depth, ear_depth, mouth_depth, chin_depth } );
116  if( x - n > 0.20f )
117  return false;
118  if( x - n < 0.02f )
119  return false;
120 
121  return true;
122 }
bool find_depth_from(rs2::depth_frame const &frame, float const depth_scale, dlib::full_object_detection const &face, markup_68 markup_from, markup_68 markup_to, float *p_average_depth)
Definition: validate_face.h:20
const void * get_data() const
Definition: rs_frame.hpp:545
unsigned short uint16_t
Definition: stdint.h:79
GLdouble n
Definition: glext.h:1966
GLdouble f
GLdouble x
markup_68
Definition: markup_68.h:15
int min(int a, int b)
Definition: lz4s.c:73
bool validate_face(rs2::depth_frame const &frame, float const depth_scale, dlib::full_object_detection const &face)
Definition: validate_face.h:57
int i
int get_width() const
Definition: rs_frame.hpp:659
Definition: parser.hpp:150
GLenum GLuint GLint GLenum face
Definition: glext.h:3377


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:50:14