Skip to content
Snippets Groups Projects
Commit 9997ef5c authored by Amir MOHAMMADI's avatar Amir MOHAMMADI
Browse files

Do not allow upside down faces in FaceCrop by default

parent 73afe5f7
No related branches found
No related tags found
1 merge request!53Do not allow upside down faces in FaceCrop by default
Pipeline #28965 passed
...@@ -85,6 +85,12 @@ class FaceCrop (Base): ...@@ -85,6 +85,12 @@ class FaceCrop (Base):
mask_seed : int or None mask_seed : int or None
The random seed to apply for mask extrapolation. 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
``True``.
.. warning:: .. warning::
When run in parallel, the same random seed will be applied to all When run in parallel, the same random seed will be applied to all
...@@ -109,6 +115,7 @@ class FaceCrop (Base): ...@@ -109,6 +115,7 @@ class FaceCrop (Base):
mask_neighbors=5, mask_neighbors=5,
mask_seed=None, mask_seed=None,
annotator=None, annotator=None,
allow_upside_down_normalized_faces=False,
**kwargs **kwargs
): ):
...@@ -140,6 +147,7 @@ class FaceCrop (Base): ...@@ -140,6 +147,7 @@ class FaceCrop (Base):
self.mask_rng = bob.core.random.mt19937( self.mask_rng = bob.core.random.mt19937(
mask_seed) if mask_seed is not None else bob.core.random.mt19937() mask_seed) if mask_seed is not None else bob.core.random.mt19937()
self.annotator = annotator self.annotator = annotator
self.allow_upside_down_normalized_faces = allow_upside_down_normalized_faces
# create objects required for face cropping # create objects required for face cropping
self.cropper = bob.ip.base.FaceEyesNorm( self.cropper = bob.ip.base.FaceEyesNorm(
...@@ -185,6 +193,22 @@ class FaceCrop (Base): ...@@ -185,6 +193,22 @@ class FaceCrop (Base):
"At least one of the expected annotations '%s' are not given " "At least one of the expected annotations '%s' are not given "
"in '%s'." % (self.cropped_keys, annotations.keys())) "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 # create output
mask = numpy.ones(image.shape[-2:], dtype=numpy.bool) mask = numpy.ones(image.shape[-2:], dtype=numpy.bool)
shape = self.cropped_image_size if image.ndim == 2 else [ shape = self.cropped_image_size if image.ndim == 2 else [
...@@ -199,9 +223,9 @@ class FaceCrop (Base): ...@@ -199,9 +223,9 @@ class FaceCrop (Base):
cropped_image, # cropped image cropped_image, # cropped image
self.cropped_mask, # cropped mask self.cropped_mask, # cropped mask
# position of first annotation, usually right eye # position of first annotation, usually right eye
right_eye=annotations[self.cropped_keys[0]], right_eye=right_eye,
# position of second annotation, usually left eye # position of second annotation, usually left eye
left_eye=annotations[self.cropped_keys[1]] left_eye=left_eye,
) )
if self.mask_sigma is not None: if self.mask_sigma is not None:
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
import numpy import numpy
import pkg_resources import pkg_resources
...@@ -106,6 +105,14 @@ def test_face_crop(): ...@@ -106,6 +105,14 @@ def test_face_crop():
assert cropped.shape[1:] == ref_image.shape assert cropped.shape[1:] == ref_image.shape
assert numpy.allclose(bob.ip.color.rgb_to_gray(cropped), ref_image, atol = 1., rtol = 1.) 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
try:
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:
pass
# reset the configuration, so that later tests don't get screwed. # reset the configuration, so that later tests don't get screwed.
cropper.channel = 'gray' cropper.channel = 'gray'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment