From bb5b1b700309948b190432b339157dc2ae1f0376 Mon Sep 17 00:00:00 2001
From: Laurent COLBOIS <lcolbois@.idiap.ch>
Date: Mon, 21 Dec 2020 15:53:21 +0100
Subject: [PATCH] Integrated MultiFaceCrop into the baselines

---
 bob/bio/face/config/baseline/helpers.py | 143 +++++++++++++-----------
 bob/bio/face/helpers.py                 |  28 +++--
 2 files changed, 96 insertions(+), 75 deletions(-)

diff --git a/bob/bio/face/config/baseline/helpers.py b/bob/bio/face/config/baseline/helpers.py
index 7bb2b74b..42898f61 100644
--- a/bob/bio/face/config/baseline/helpers.py
+++ b/bob/bio/face/config/baseline/helpers.py
@@ -17,65 +17,71 @@ def embedding_transformer_default_cropping(cropped_image_size, annotation_type):
        cropped_image_size : tuple
           A tuple (HEIGHT, WIDTH) describing the target size of the cropped image.
 
-       annotation_type: str
+       annotation_type: str or list of str
           Type of annotations. Possible values are: `bounding-box`, `eyes-center`, 'left-profile', 
-          'right-profile'  and None
+          'right-profile'  and None, or a combination of those as a list
 
     Returns
     -------
 
       cropped_positions:
-         The dictionary of cropped positions that will be feeded to the FaceCropper.
+         The dictionary of cropped positions that will be feeded to the FaceCropper, or a list of such dictionaries if
+         ``annotation_type`` is a list
     """
-    CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH = cropped_image_size
+    if isinstance(annotation_type, list):
+        return [embedding_transformer_default_cropping(cropped_image_size, item) for item in annotation_type]
+    
+    else:
 
-    if annotation_type == "bounding-box":
+        CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH = cropped_image_size
 
-        TOP_LEFT_POS = (0, 0)
-        BOTTOM_RIGHT_POS = (CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH)
-        cropped_positions = {"topleft": TOP_LEFT_POS, "bottomright": BOTTOM_RIGHT_POS}
+        if annotation_type == "bounding-box":
 
-    elif annotation_type == "eyes-center":
+            TOP_LEFT_POS = (0, 0)
+            BOTTOM_RIGHT_POS = (CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH)
+            cropped_positions = {"topleft": TOP_LEFT_POS, "bottomright": BOTTOM_RIGHT_POS}
 
-        RIGHT_EYE_POS = (
-            round(2 / 7 * CROPPED_IMAGE_HEIGHT),
-            round(1 / 3 * CROPPED_IMAGE_WIDTH),
-        )
-        LEFT_EYE_POS = (
-            round(2 / 7 * CROPPED_IMAGE_HEIGHT),
-            round(2 / 3 * CROPPED_IMAGE_WIDTH),
-        )
-        cropped_positions = {"leye": LEFT_EYE_POS, "reye": RIGHT_EYE_POS}
+        elif annotation_type == "eyes-center":
 
-    elif annotation_type == "left-profile":
+            RIGHT_EYE_POS = (
+                round(2 / 7 * CROPPED_IMAGE_HEIGHT),
+                round(1 / 3 * CROPPED_IMAGE_WIDTH),
+            )
+            LEFT_EYE_POS = (
+                round(2 / 7 * CROPPED_IMAGE_HEIGHT),
+                round(2 / 3 * CROPPED_IMAGE_WIDTH),
+            )
+            cropped_positions = {"leye": LEFT_EYE_POS, "reye": RIGHT_EYE_POS}
 
-        EYE_POS = (
-            round(2 / 7 * CROPPED_IMAGE_HEIGHT),
-            round(3 / 8 * CROPPED_IMAGE_WIDTH),
-        )
-        MOUTH_POS = (
-            round(5 / 7 * CROPPED_IMAGE_HEIGHT),
-            round(3 / 8 * CROPPED_IMAGE_WIDTH),
-        )
-        cropped_positions = {"leye": EYE_POS, "mouth": MOUTH_POS}
+        elif annotation_type == "left-profile":
 
-    elif annotation_type == "right-profile":
+            EYE_POS = (
+                round(2 / 7 * CROPPED_IMAGE_HEIGHT),
+                round(3 / 8 * CROPPED_IMAGE_WIDTH),
+            )
+            MOUTH_POS = (
+                round(5 / 7 * CROPPED_IMAGE_HEIGHT),
+                round(3 / 8 * CROPPED_IMAGE_WIDTH),
+            )
+            cropped_positions = {"leye": EYE_POS, "mouth": MOUTH_POS}
 
-        EYE_POS = (
-            round(2 / 7 * CROPPED_IMAGE_HEIGHT),
-            round(5 / 8 * CROPPED_IMAGE_WIDTH),
-        )
-        MOUTH_POS = (
-            round(5 / 7 * CROPPED_IMAGE_HEIGHT),
-            round(5 / 8 * CROPPED_IMAGE_WIDTH),
-        )
-        cropped_positions = {"reye": EYE_POS, "mouth": MOUTH_POS}
+        elif annotation_type == "right-profile":
 
-    else:
+            EYE_POS = (
+                round(2 / 7 * CROPPED_IMAGE_HEIGHT),
+                round(5 / 8 * CROPPED_IMAGE_WIDTH),
+            )
+            MOUTH_POS = (
+                round(5 / 7 * CROPPED_IMAGE_HEIGHT),
+                round(5 / 8 * CROPPED_IMAGE_WIDTH),
+            )
+            cropped_positions = {"reye": EYE_POS, "mouth": MOUTH_POS}
 
-        cropped_positions = None
+        else:
 
-    return cropped_positions
+            cropped_positions = None
+
+        return cropped_positions
 
 
 def legacy_default_cropping(cropped_image_size, annotation_type):
@@ -91,45 +97,50 @@ def legacy_default_cropping(cropped_image_size, annotation_type):
 
        annotation_type: str
           Type of annotations. Possible values are: `bounding-box`, `eyes-center`, 'left-profile', 
-          'right-profile' and None
+          'right-profile' and None, or a combination of those as a list
 
     Returns
     -------
 
       cropped_positions:
-         The dictionary of cropped positions that will be feeded to the FaceCropper.
+         The dictionary of cropped positions that will be feeded to the FaceCropper, or a list of such dictionaries if
+         ``annotation_type`` is a list
     """
-    CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH = cropped_image_size
+    if isinstance(annotation_type, list):
+        return [legacy_default_cropping(cropped_image_size, item) for item in annotation_type]
+    else:
 
-    if annotation_type == "bounding-box":
+        CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH = cropped_image_size
 
-        TOP_LEFT_POS = (0, 0)
-        BOTTOM_RIGHT_POS = (CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH)
-        cropped_positions = {"topleft": TOP_LEFT_POS, "bottomright": BOTTOM_RIGHT_POS}
+        if annotation_type == "bounding-box":
 
-    elif annotation_type == "eyes-center":
+            TOP_LEFT_POS = (0, 0)
+            BOTTOM_RIGHT_POS = (CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH)
+            cropped_positions = {"topleft": TOP_LEFT_POS, "bottomright": BOTTOM_RIGHT_POS}
 
-        RIGHT_EYE_POS = (CROPPED_IMAGE_HEIGHT // 5, CROPPED_IMAGE_WIDTH // 4 - 1)
-        LEFT_EYE_POS = (CROPPED_IMAGE_HEIGHT // 5, CROPPED_IMAGE_WIDTH // 4 * 3)
-        cropped_positions = {"leye": LEFT_EYE_POS, "reye": RIGHT_EYE_POS}
+        elif annotation_type == "eyes-center":
 
-    elif annotation_type == "left-profile":
-        # Main reference https://gitlab.idiap.ch/bob/bob.chapter.FRICE/-/blob/master/bob/chapter/FRICE/script/pose.py
-        EYE_POS = (CROPPED_IMAGE_HEIGHT // 5, CROPPED_IMAGE_WIDTH // 7 * 3 - 2)
-        MOUTH_POS = (CROPPED_IMAGE_HEIGHT // 3 * 2, CROPPED_IMAGE_WIDTH // 7 * 3 - 2)
-        cropped_positions = {"leye": EYE_POS, "mouth": MOUTH_POS}
+            RIGHT_EYE_POS = (CROPPED_IMAGE_HEIGHT // 5, CROPPED_IMAGE_WIDTH // 4 - 1)
+            LEFT_EYE_POS = (CROPPED_IMAGE_HEIGHT // 5, CROPPED_IMAGE_WIDTH // 4 * 3)
+            cropped_positions = {"leye": LEFT_EYE_POS, "reye": RIGHT_EYE_POS}
 
-    elif annotation_type == "right-profile":
-        # Main reference https://gitlab.idiap.ch/bob/bob.chapter.FRICE/-/blob/master/bob/chapter/FRICE/script/pose.py
-        EYE_POS = (CROPPED_IMAGE_HEIGHT // 5, CROPPED_IMAGE_WIDTH // 7 * 4 + 2)
-        MOUTH_POS = (CROPPED_IMAGE_HEIGHT // 3 * 2, CROPPED_IMAGE_WIDTH // 7 * 4 + 2)
-        cropped_positions = {"reye": EYE_POS, "mouth": MOUTH_POS}
+        elif annotation_type == "left-profile":
+            # Main reference https://gitlab.idiap.ch/bob/bob.chapter.FRICE/-/blob/master/bob/chapter/FRICE/script/pose.py
+            EYE_POS = (CROPPED_IMAGE_HEIGHT // 5, CROPPED_IMAGE_WIDTH // 7 * 3 - 2)
+            MOUTH_POS = (CROPPED_IMAGE_HEIGHT // 3 * 2, CROPPED_IMAGE_WIDTH // 7 * 3 - 2)
+            cropped_positions = {"leye": EYE_POS, "mouth": MOUTH_POS}
 
-    else:
+        elif annotation_type == "right-profile":
+            # Main reference https://gitlab.idiap.ch/bob/bob.chapter.FRICE/-/blob/master/bob/chapter/FRICE/script/pose.py
+            EYE_POS = (CROPPED_IMAGE_HEIGHT // 5, CROPPED_IMAGE_WIDTH // 7 * 4 + 2)
+            MOUTH_POS = (CROPPED_IMAGE_HEIGHT // 3 * 2, CROPPED_IMAGE_WIDTH // 7 * 4 + 2)
+            cropped_positions = {"reye": EYE_POS, "mouth": MOUTH_POS}
+
+        else:
 
-        cropped_positions = None
+            cropped_positions = None
 
-    return cropped_positions
+        return cropped_positions
 
 
 def embedding_transformer(
@@ -156,7 +167,7 @@ def embedding_transformer(
     )
 
     transform_extra_arguments = (
-        None if cropped_positions is None else (("annotations", "annotations"),)
+        None if (cropped_positions is None or fixed_positions is not None) else (("annotations", "annotations"),)
     )
 
     transformer = make_pipeline(
diff --git a/bob/bio/face/helpers.py b/bob/bio/face/helpers.py
index dbdeed95..51bdf9b8 100644
--- a/bob/bio/face/helpers.py
+++ b/bob/bio/face/helpers.py
@@ -1,4 +1,4 @@
-from bob.bio.face.preprocessor import FaceCrop, Scale
+from bob.bio.face.preprocessor import FaceCrop, MultiFaceCrop, Scale
 
 
 def face_crop_solver(
@@ -17,11 +17,21 @@ def face_crop_solver(
         return Scale(cropped_image_size)
     else:
         # Detects the face and crops it without eye detection
-        return FaceCrop(
-            cropped_image_size=cropped_image_size,
-            cropped_positions=cropped_positions,
-            color_channel=color_channel,
-            fixed_positions=fixed_positions,
-            dtype=dtype,
-            annotator=annotator,
-        )
+        if isinstance(cropped_positions, list):
+            return MultiFaceCrop(
+                cropped_image_size=cropped_image_size,
+                cropped_positions_list=cropped_positions,
+                fixed_positions_list=fixed_positions,
+                color_channel=color_channel,
+                dtype=dtype,
+                annotation=annotator,
+            )
+        else:
+            return FaceCrop(
+                cropped_image_size=cropped_image_size,
+                cropped_positions=cropped_positions,
+                color_channel=color_channel,
+                fixed_positions=fixed_positions,
+                dtype=dtype,
+                annotator=annotator,
+            )
-- 
GitLab