Commit 1c7bbbd4 authored by Davis King's avatar Davis King

Upgraded render_face_detections() and get_face_chip_details() to support 5

point face landmark models.
parent 3fff7f84
...@@ -18,52 +18,63 @@ namespace dlib ...@@ -18,52 +18,63 @@ namespace dlib
std::vector<image_window::overlay_line> lines; std::vector<image_window::overlay_line> lines;
for (unsigned long i = 0; i < dets.size(); ++i) for (unsigned long i = 0; i < dets.size(); ++i)
{ {
DLIB_CASSERT(dets[i].num_parts() == 68, DLIB_CASSERT(dets[i].num_parts() == 68 || dets[i].num_parts() == 5,
"\t std::vector<image_window::overlay_line> render_face_detections()" "\t std::vector<image_window::overlay_line> render_face_detections()"
<< "\n\t Invalid inputs were given to this function. " << "\n\t You have to give either a 5 point or 68 point face landmarking output to this function. "
<< "\n\t dets["<<i<<"].num_parts(): " << dets[i].num_parts() << "\n\t dets["<<i<<"].num_parts(): " << dets[i].num_parts()
); );
const full_object_detection& d = dets[i]; const full_object_detection& d = dets[i];
// Around Chin. Ear to Ear
for (unsigned long i = 1; i <= 16; ++i) if (d.num_parts() == 5)
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); {
lines.push_back(image_window::overlay_line(d.part(0), d.part(1), color));
// Line on top of nose lines.push_back(image_window::overlay_line(d.part(1), d.part(4), color));
for (unsigned long i = 28; i <= 30; ++i) lines.push_back(image_window::overlay_line(d.part(4), d.part(3), color));
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); lines.push_back(image_window::overlay_line(d.part(3), d.part(2), color));
}
// left eyebrow else
for (unsigned long i = 18; i <= 21; ++i) {
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); // Around Chin. Ear to Ear
// Right eyebrow for (unsigned long i = 1; i <= 16; ++i)
for (unsigned long i = 23; i <= 26; ++i) lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
// Bottom part of the nose // Line on top of nose
for (unsigned long i = 31; i <= 35; ++i) for (unsigned long i = 28; i <= 30; ++i)
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
// Line from the nose to the bottom part above
lines.push_back(image_window::overlay_line(d.part(30), d.part(35), color)); // left eyebrow
for (unsigned long i = 18; i <= 21; ++i)
// Left eye lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
for (unsigned long i = 37; i <= 41; ++i) // Right eyebrow
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); for (unsigned long i = 23; i <= 26; ++i)
lines.push_back(image_window::overlay_line(d.part(36), d.part(41), color)); lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
// Bottom part of the nose
// Right eye for (unsigned long i = 31; i <= 35; ++i)
for (unsigned long i = 43; i <= 47; ++i) lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); // Line from the nose to the bottom part above
lines.push_back(image_window::overlay_line(d.part(42), d.part(47), color)); lines.push_back(image_window::overlay_line(d.part(30), d.part(35), color));
// Lips outer part // Left eye
for (unsigned long i = 49; i <= 59; ++i) for (unsigned long i = 37; i <= 41; ++i)
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
lines.push_back(image_window::overlay_line(d.part(48), d.part(59), color)); lines.push_back(image_window::overlay_line(d.part(36), d.part(41), color));
// Lips inside part // Right eye
for (unsigned long i = 61; i <= 67; ++i) for (unsigned long i = 43; i <= 47; ++i)
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color)); lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
lines.push_back(image_window::overlay_line(d.part(60), d.part(67), color)); lines.push_back(image_window::overlay_line(d.part(42), d.part(47), color));
// Lips outer part
for (unsigned long i = 49; i <= 59; ++i)
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
lines.push_back(image_window::overlay_line(d.part(48), d.part(59), color));
// Lips inside part
for (unsigned long i = 61; i <= 67; ++i)
lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));
lines.push_back(image_window::overlay_line(d.part(60), d.part(67), color));
}
} }
return lines; return lines;
} }
......
...@@ -18,14 +18,21 @@ namespace dlib ...@@ -18,14 +18,21 @@ namespace dlib
/*! /*!
requires requires
- for all valid i: - for all valid i:
- dets[i].num_parts() == 68 - dets[i].num_parts() == 68 || dets[i].num_parts() == 5
ensures ensures
- Interprets the given objects as face detections with parts annotated using - Interprets the given objects as face detections with parts annotated using
the iBUG face landmark scheme. We then return a set of overlay lines that either the iBUG face landmark scheme or a 5 point face annotation. We then
will draw the objects onto the screen in a way that properly draws the return a set of overlay lines that will draw the objects onto the screen in a
outline of the face features defined by the part locations. way that properly draws the outline of the face features defined by the part
locations.
- returns a vector with dets.size() elements, each containing the lines - returns a vector with dets.size() elements, each containing the lines
necessary to render a face detection from dets. necessary to render a face detection from dets.
- The 5 point face annotation scheme is assumed to be:
- det part 0 == left eye corner, outside part of eye.
- det part 1 == left eye corner, inside part of eye.
- det part 2 == right eye corner, outside part of eye.
- det part 3 == right eye corner, inside part of eye.
- det part 4 == immediately under the nose, right at the top of the philtrum.
!*/ !*/
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -36,7 +43,7 @@ namespace dlib ...@@ -36,7 +43,7 @@ namespace dlib
); );
/*! /*!
requires requires
- det.num_parts() == 68 - det.num_parts() == 68 || det.num_parts() == 5
ensures ensures
- This function is identical to the above render_face_detections() routine - This function is identical to the above render_face_detections() routine
except that it takes just a single full_object_detection instead of a except that it takes just a single full_object_detection instead of a
......
...@@ -1991,9 +1991,9 @@ namespace dlib ...@@ -1991,9 +1991,9 @@ namespace dlib
const double padding = 0.2 const double padding = 0.2
) )
{ {
DLIB_CASSERT(det.num_parts() == 68, DLIB_CASSERT(det.num_parts() == 68 || det.num_parts() == 5,
"\t chip_details get_face_chip_details()" "\t chip_details get_face_chip_details()"
<< "\n\t You must give a detection with exactly 68 parts in it." << "\n\t You have to give either a 5 point or 68 point face landmarking output to this function. "
<< "\n\t det.num_parts(): " << det.num_parts() << "\n\t det.num_parts(): " << det.num_parts()
); );
DLIB_CASSERT(padding >= 0 && size > 0, DLIB_CASSERT(padding >= 0 && size > 0,
...@@ -2003,43 +2003,84 @@ namespace dlib ...@@ -2003,43 +2003,84 @@ namespace dlib
<< "\n\t size: " << size << "\n\t size: " << size
); );
// Average positions of face points 17-67
const double mean_face_shape_x[] = {
0.000213256, 0.0752622, 0.18113, 0.29077, 0.393397, 0.586856, 0.689483, 0.799124,
0.904991, 0.98004, 0.490127, 0.490127, 0.490127, 0.490127, 0.36688, 0.426036,
0.490127, 0.554217, 0.613373, 0.121737, 0.187122, 0.265825, 0.334606, 0.260918,
0.182743, 0.645647, 0.714428, 0.793132, 0.858516, 0.79751, 0.719335, 0.254149,
0.340985, 0.428858, 0.490127, 0.551395, 0.639268, 0.726104, 0.642159, 0.556721,
0.490127, 0.423532, 0.338094, 0.290379, 0.428096, 0.490127, 0.552157, 0.689874,
0.553364, 0.490127, 0.42689
};
const double mean_face_shape_y[] = {
0.106454, 0.038915, 0.0187482, 0.0344891, 0.0773906, 0.0773906, 0.0344891,
0.0187482, 0.038915, 0.106454, 0.203352, 0.307009, 0.409805, 0.515625, 0.587326,
0.609345, 0.628106, 0.609345, 0.587326, 0.216423, 0.178758, 0.179852, 0.231733,
0.245099, 0.244077, 0.231733, 0.179852, 0.178758, 0.216423, 0.244077, 0.245099,
0.780233, 0.745405, 0.727388, 0.742578, 0.727388, 0.745405, 0.780233, 0.864805,
0.902192, 0.909281, 0.902192, 0.864805, 0.784792, 0.778746, 0.785343, 0.778746,
0.784792, 0.824182, 0.831803, 0.824182
};
COMPILE_TIME_ASSERT(sizeof(mean_face_shape_x)/sizeof(double) == 68-17); std::vector<dpoint> from_points, to_points;
if (det.num_parts() == 5)
{
dpoint p0(0.8595674595992, 0.2134981538014);
dpoint p1(0.6460604764104, 0.2289674387677);
dpoint p2(0.1205750620789, 0.2137274526848);
dpoint p3(0.3340850613712, 0.2290642403242);
dpoint p4(0.4901123135679, 0.6277975316475);
p0 = (padding+p0)/(2*padding+1);
p1 = (padding+p1)/(2*padding+1);
p2 = (padding+p2)/(2*padding+1);
p3 = (padding+p3)/(2*padding+1);
p4 = (padding+p4)/(2*padding+1);
from_points.push_back(p0*size);
to_points.push_back(det.part(0));
from_points.push_back(p1*size);
to_points.push_back(det.part(1));
std::vector<dlib::vector<double,2> > from_points, to_points; from_points.push_back(p2*size);
for (unsigned long i = 17; i < det.num_parts(); ++i) to_points.push_back(det.part(2));
from_points.push_back(p3*size);
to_points.push_back(det.part(3));
from_points.push_back(p4*size);
to_points.push_back(det.part(4));
}
else
{ {
// Ignore the lower lip // Average positions of face points 17-67
if ((55 <= i && i <= 59) || (65 <= i && i <= 67)) const double mean_face_shape_x[] = {
continue; 0.000213256, 0.0752622, 0.18113, 0.29077, 0.393397, 0.586856, 0.689483, 0.799124,
// Ignore the eyebrows 0.904991, 0.98004, 0.490127, 0.490127, 0.490127, 0.490127, 0.36688, 0.426036,
if (17 <= i && i <= 26) 0.490127, 0.554217, 0.613373, 0.121737, 0.187122, 0.265825, 0.334606, 0.260918,
continue; 0.182743, 0.645647, 0.714428, 0.793132, 0.858516, 0.79751, 0.719335, 0.254149,
0.340985, 0.428858, 0.490127, 0.551395, 0.639268, 0.726104, 0.642159, 0.556721,
dlib::vector<double,2> p; 0.490127, 0.423532, 0.338094, 0.290379, 0.428096, 0.490127, 0.552157, 0.689874,
p.x() = (padding+mean_face_shape_x[i-17])/(2*padding+1); 0.553364, 0.490127, 0.42689
p.y() = (padding+mean_face_shape_y[i-17])/(2*padding+1); };
from_points.push_back(p*size); const double mean_face_shape_y[] = {
to_points.push_back(det.part(i)); 0.106454, 0.038915, 0.0187482, 0.0344891, 0.0773906, 0.0773906, 0.0344891,
0.0187482, 0.038915, 0.106454, 0.203352, 0.307009, 0.409805, 0.515625, 0.587326,
0.609345, 0.628106, 0.609345, 0.587326, 0.216423, 0.178758, 0.179852, 0.231733,
0.245099, 0.244077, 0.231733, 0.179852, 0.178758, 0.216423, 0.244077, 0.245099,
0.780233, 0.745405, 0.727388, 0.742578, 0.727388, 0.745405, 0.780233, 0.864805,
0.902192, 0.909281, 0.902192, 0.864805, 0.784792, 0.778746, 0.785343, 0.778746,
0.784792, 0.824182, 0.831803, 0.824182
};
COMPILE_TIME_ASSERT(sizeof(mean_face_shape_x)/sizeof(double) == 68-17);
for (unsigned long i = 17; i < det.num_parts(); ++i)
{
// Ignore the lower lip
if ((55 <= i && i <= 59) || (65 <= i && i <= 67))
continue;
// Ignore the eyebrows
if (17 <= i && i <= 26)
continue;
if (1+i != 37 &&
1+i != 40 &&
1+i != 43 &&
1+i != 46 &&
1+i != 34)
continue;
dpoint p;
p.x() = (padding+mean_face_shape_x[i-17])/(2*padding+1);
p.y() = (padding+mean_face_shape_y[i-17])/(2*padding+1);
from_points.push_back(p*size);
to_points.push_back(det.part(i));
}
} }
return chip_details(from_points, to_points, chip_dims(size,size)); return chip_details(from_points, to_points, chip_dims(size,size));
......
...@@ -1365,20 +1365,30 @@ namespace dlib ...@@ -1365,20 +1365,30 @@ namespace dlib
); );
/*! /*!
requires requires
- det.num_parts() == 68 - det.num_parts() == 68 || det.num_parts() == 5
- size > 0 - size > 0
- padding >= 0 - padding >= 0
ensures ensures
- This function assumes det contains a human face detection with face parts - This function assumes det contains a human face detection with face parts
annotated using the annotation scheme from the iBUG 300-W face landmark annotated using the annotation scheme from the iBUG 300-W face landmark
dataset. Given these assumptions, it creates a chip_details object that will dataset or a 5 point face annotation. Given these assumptions, it creates a
extract a copy of the face that has been rotated upright, centered, and chip_details object that will extract a copy of the face that has been
scaled to a standard size when given to extract_image_chip(). rotated upright, centered, and scaled to a standard size when given to
extract_image_chip().
- This function is specifically calibrated to work with one of these models:
- http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2
- http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
- The extracted chips will have size rows and columns in them. - The extracted chips will have size rows and columns in them.
- if padding == 0 then the chip will be closely cropped around the face. - if padding == 0 then the chip will be closely cropped around the face.
Setting larger padding values will result a looser cropping. In particular, Setting larger padding values will result a looser cropping. In particular,
a padding of 0.5 would double the width of the cropped area, a value of 1 a padding of 0.5 would double the width of the cropped area, a value of 1
would triple it, and so forth. would triple it, and so forth.
- The 5 point face annotation scheme is assumed to be:
- det part 0 == left eye corner, outside part of eye.
- det part 1 == left eye corner, inside part of eye.
- det part 2 == right eye corner, outside part of eye.
- det part 3 == right eye corner, inside part of eye.
- det part 4 == immediately under the nose, right at the top of the philtrum.
!*/ !*/
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment