Commit 9997ef5c authored by Amir MOHAMMADI's avatar Amir MOHAMMADI
Browse files

Do not allow upside down faces in FaceCrop by default

parent 73afe5f7
Pipeline #28965 passed with stage
in 21 minutes and 8 seconds
......@@ -85,6 +85,12 @@ class FaceCrop (Base):
mask_seed : int or None
The random seed to apply for mask extrapolation.
allow_upside_down_normalized_faces: bool, optional
If ``False`` (default), a ValueError is raised when normalized faces are going to be
upside down compared to input image. This allows you to catch wrong annotations in
your database easily. If you are sure about your input, you can set this flag to
.. warning::
When run in parallel, the same random seed will be applied to all
......@@ -109,6 +115,7 @@ class FaceCrop (Base):
......@@ -140,6 +147,7 @@ class FaceCrop (Base):
self.mask_rng = bob.core.random.mt19937(
mask_seed) if mask_seed is not None else bob.core.random.mt19937()
self.annotator = annotator
self.allow_upside_down_normalized_faces = allow_upside_down_normalized_faces
# create objects required for face cropping
self.cropper = bob.ip.base.FaceEyesNorm(
......@@ -185,6 +193,22 @@ class FaceCrop (Base):
"At least one of the expected annotations '%s' are not given "
"in '%s'." % (self.cropped_keys, annotations.keys()))
reye = self.cropped_keys[0]
leye = self.cropped_keys[1]
reye_desired_width = self.cropped_positions[reye][1]
leye_desired_width = self.cropped_positions[leye][1]
right_eye = annotations[reye]
left_eye = annotations[leye]
if not self.allow_upside_down_normalized_faces:
if (reye_desired_width > leye_desired_width and right_eye[1] < left_eye[1]) or \
(reye_desired_width < leye_desired_width and right_eye[1] > left_eye[1]):
raise ValueError(
"Looks like {leye} and {reye} in annotations: {annot} are swapped. "
"This will make the normalized face upside down (compared to the original "
"image). Most probably your annotations are wrong. Otherwise, you can set "
"the ``allow_upside_down_normalized_faces`` parameter to "
"True.".format(leye=leye, reye=reye, annot=annotations))
# create output
mask = numpy.ones(image.shape[-2:], dtype=numpy.bool)
shape = self.cropped_image_size if image.ndim == 2 else [
......@@ -199,9 +223,9 @@ class FaceCrop (Base):
cropped_image, # cropped image
self.cropped_mask, # cropped mask
# position of first annotation, usually right eye
# position of second annotation, usually left eye
if self.mask_sigma is not None:
......@@ -18,7 +18,6 @@
# along with this program. If not, see <>.
import unittest
import numpy
import pkg_resources
......@@ -106,6 +105,14 @@ def test_face_crop():
assert cropped.shape[1:] == ref_image.shape
assert numpy.allclose(bob.ip.color.rgb_to_gray(cropped), ref_image, atol = 1., rtol = 1.)
# test a ValueError is raised if eye annotations are swapped
annot = dict(reye=annotation['leye'], leye=annotation['reye'])
cropper(image, annot)
assert 0, 'FaceCrop did not raise a ValueError for swapped eye annotations'
except ValueError:
# reset the configuration, so that later tests don't get screwed. = 'gray'
Supports Markdown
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