Estimate the 68 sights on one face of an image with several detectors.
Module sppas.src.annotations
Class ImageFaceLandmark
Description
Constructor
Create a new ImageFaceLandmark instance.
View Source
def __init__(self):
"""Create a new ImageFaceLandmark instance.
"""
super(ImageFaceLandmark, self).__init__()
self.__basic = None
self.__mediapipe = MediaPipeFaceMesh()
self.__markers = list()
Public functions
get_nb_recognizers
Return the number of initialized landmark recognizers.
View Source
def get_nb_recognizers(self) -> int:
"""Return the number of initialized landmark recognizers."""
nb = 2
if self.__basic is None:
nb = 1
return nb + len(self.__markers)
add_model
Append an OpenCV recognizer into the list and load the model.
Parameters
- filename: (str) A recognizer model (Kazemi, LBF, AAM).
Raises
IOError, IOExtensionError, Exception
View Source
def add_model(self, filename: str) -> None:
"""Append an OpenCV recognizer into the list and load the model.
:param filename: (str) A recognizer model (Kazemi, LBF, AAM).
:raise: IOError, IOExtensionError, Exception
"""
predictor = OpenCVFaceMark(filename)
self.__markers.append(predictor)
enable_empirical_predictor
Enable the basic predictor with empirically fixed sights.
Parameters
- value: (bool) True to enable
View Source
def enable_empirical_predictor(self, value: str=True) -> None:
"""Enable the basic predictor with empirically fixed sights.
:param value: (bool) True to enable
"""
if bool(value) is True:
self.__basic = BasicFaceMark()
else:
self.__basic = None
Private functions
_detect
Detect sights on an image with the coords of the face.
Parameters
- image: (sppasImage or numpy.ndarray) The image to be processed.
- coords: (sppasCoords) Coordinates of the face in the image or None for the full image
View Source
def _detect(self, image, coords=None):
"""Detect sights on an image with the coords of the face.
:param image: (sppasImage or numpy.ndarray) The image to be processed.
:param coords: (sppasCoords) Coordinates of the face in the image or None for the full image
"""
success, all_points = self.__detect_with_markers(image, coords)
if success is True:
for i in range(len(self._sights)):
x, y, score = self.__points_to_coords(image, coords, all_points[i])
self._sights.set_sight(i, x, y, None, score)
return success
Protected functions
__points_to_coords
Convert a list of estimated points into coordinates of a sight.
The confidence score of each sight depends on the area covered by the points. The image and the coords are used only to estimate the score.
Parameters
- image: (numpy.ndarray) The image.
- coords: (sppasCoords) Coordinates of the face in the image.
- points: (list of (x,y) values) A sight detected by each method
Returns
- Estimated(x,y,c) values
View Source
def __points_to_coords(self, image, coords, points):
"""Convert a list of estimated points into coordinates of a sight.
The confidence score of each sight depends on the area covered by the
points. The image and the coords are used only to estimate the score.
:param image: (numpy.ndarray) The image.
:param coords: (sppasCoords) Coordinates of the face in the image.
:param points: (list of (x,y) values) A sight detected by each method
:return: Estimated (x,y,c) values
"""
if coords is not None:
img = image.icrop(coords)
else:
img = image.copy()
h, w = img.shape[:2]
face_area = h * w
min_x = min((result[0] for result in points))
min_y = min((result[1] for result in points))
max_x = max((result[0] for result in points))
max_y = max((result[1] for result in points))
points_area = (max_x - min_x) * (max_y - min_y)
if face_area > 0.0:
ratio = float(points_area) / float(face_area)
else:
ratio = 1.0
coeff = max(1.0, min(5.0, 100.0 * ratio))
score = min(1.0, max(0.0, 1.0 - coeff * ratio))
avg_points = [p for p in points]
for i in range(4):
avg_points.append(points[0])
sum_x = sum((result[0] for result in avg_points))
sum_y = sum((result[1] for result in avg_points))
x = round(float(sum_x) / float(len(avg_points)))
y = round(float(sum_y) / float(len(avg_points)))
return (x, y, score)
__detect_with_markers
Estimate all the 68 points by each instantiated face-marker.
The returned result is a list of 68 lists of tuples with (x,y) values because it's the data structure OpenCV is returning when invoking the method 'fit()' of each recognizer.
Parameters
- image
- coords
View Source
def __detect_with_markers(self, image, coords):
"""Estimate all the 68 points by each instantiated face-marker.
The returned result is a list of 68 lists of tuples with (x,y) values
because it's the data structure OpenCV is returning when invoking
the method 'fit()' of each recognizer.
"""
all_points = {i: list() for i in range(len(self._sights))}
if coords is not None:
c = coords.portrait()
else:
w, h = image.get_size()
c = sppasCoords(0, 0, w, h)
success = self.__mediapipe.detect_sights(image.icrop(c))
if success is True:
for i, sight in enumerate(self.__mediapipe):
x, y, z, s = sight
all_points[i].append((x + c.x, y + c.y))
for cv_marker in self.__markers:
s = cv_marker.detect_sights(image, coords)
if s is True:
success = True
for i, sight in enumerate(cv_marker):
x, y, z, s = sight
all_points[i].append((x, y))
if self.__basic is not None:
self.__basic.detect_sights(image, coords)
for i, sight in enumerate(self.__basic):
x, y, z, s = sight
all_points[i].append((x, y))
return (success, all_points)