Source code for annotations.FaceDetection.imgfacedetect

# -*- coding : UTF-8 -*-
"""
:filename: sppas.src.annotations.FaceDetection.imgfacedetect.py
:author:   Brigitte Bigi
:contact:  develop@sppas.org
:summary:  Automatic detection of faces in an image.

.. _This file is part of SPPAS: http://www.sppas.org/
..
    ---------------------------------------------------------------------

     ___   __    __    __    ___
    /     |  \  |  \  |  \  /              the automatic
    \__   |__/  |__/  |___| \__             annotation and
       \  |     |     |   |    \             analysis
    ___/  |     |     |   | ___/              of speech

    Copyright (C) 2011-2021  Brigitte Bigi
    Laboratoire Parole et Langage, Aix-en-Provence, France

    Use of this software is governed by the GNU Public License, version 3.

    SPPAS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    SPPAS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with SPPAS. If not, see <http://www.gnu.org/licenses/>.

    This banner notice must not be removed.

    ---------------------------------------------------------------------

"""

from sppas.src.imgdata import sppasImage
from sppas.src.imgdata import sppasImageObjectDetection

# ---------------------------------------------------------------------------


[docs]class ImageFaceDetection(sppasImageObjectDetection): """Detect faces in an image. Automatic face detection, based on opencv HaarCascadeClassifier and Artificial Neural Networks: this class allows to analyze an image in order to detect all faces. It stores internally the list of sppasCoords() for each detected face. Like the base class, this class allows multiple models in order to launch multiple detections and to combine results. Moreover, it allows to convert the coordinates into the portrait instead of the face. :Example: >>> f = ImageFaceDetection() >>> f.load_model(filename1, filename2...) >>> # Detect all the faces in an image >>> image = sppasImage(filename="image path")) >>> f.detect(image) >>> # Get number of detected faces >>> len(f) >>> # Browse through all the detected face coordinates: >>> for c in f: >>> print(c) >>> # Get the detected faces with the highest score >>> f.get_best() >>> # Get the 2 faces with the highest scores >>> f.get_best(2) >>> # Get detected faces with a confidence score greater than 0.8 >>> f.get_confidence(0.8) >>> # Convert coordinates to a portrait size (i.e. scale by 2.1) >>> f.to_portrait(image) """
[docs] def __init__(self): """Create a new instance.""" super(ImageFaceDetection, self).__init__() self._extension = ""
# -----------------------------------------------------------------------
[docs] def detect(self, image): """Determine the coordinates of all the detected faces. :param image: (sppasImage or numpy.ndarray) """ # Launch the base method to detect objects, here objects are faces sppasImageObjectDetection.detect(self, image) # Overlapped faces are much rarer than overlapped objects: # re-filter with overlapping portraits. # Backup the current coords in a dictionary with key=portrait backup_coords = dict() for coord in self._coords: portrait = self.eval_portrait(coord, image) backup_coords[portrait] = coord # Replace the original coords by the portrait self._coords = list(backup_coords.keys()) # Filter the overlapping portraits but do not re-normalize the scores # by the number of classifiers. self.filter_overlapped(overlap=60., norm_score=False) self.sort_by_score() # re-assign the normal size new_coords = list() for portrait_coord in self._coords: normal_coord = backup_coords[portrait_coord] new_coords.append(normal_coord) self._coords = new_coords
# -----------------------------------------------------------------------
[docs] def to_portrait(self, image=None): """Scale coordinates of faces to a portrait size. The given image allows to ensure we wont scale larger than what the image can do. :param image: (sppasImage) The original image. """ if len(self._coords) == 0: return False portraits = list() for coord in self._coords: c = self.eval_portrait(coord, image) portraits.append(c) # no error occurred, all faces are converted to their portrait self._coords = portraits return True
# -----------------------------------------------------------------------
[docs] @staticmethod def eval_portrait(coordinate, image=None): """Return the coordinates converted to the portrait scale. :param coordinate: (sppasCoords) :param image: (sppasImage) The original image. :return: (sppasCoords) """ coord = coordinate.copy() # Scale the image. Shift values indicate how to shift x,y to get # the face exactly at the center of the new coordinates. # The scale is done without matter of the image size. shift_x, shift_y = coord.scale(2.8) # the face is at top, not at the middle shift_y = int(float(shift_y) * 0.6) if image is None: coord.shift(shift_x, shift_y) else: try: coord.shift(shift_x, 0, image) shifted_x = True except: shifted_x = False try: coord.shift(0, shift_y, image) shifted_y = True except: shifted_y = False w, h = image.size() if coord.x + coord.w > w or shifted_x is False: coord.x = max(0, w - coord.w) if coord.y + coord.h > h or shifted_y is False: coord.y = max(0, h - coord.h) return coord