SPPAS 4.22

https://sppas.org/

Module sppas.src.annotations

Class sppasFaceSights

Description

SPPAS integration of the automatic face sights annotation.

Requires both an image/video and an XRA or CSV file with faces or face identities.

Constructor

Create a new sppasFaceSights instance.

Parameters
  • log: (sppasLog) Human-readable logs.
View Source
def __init__(self, log=None):
    """Create a new sppasFaceSights instance.

    :param log: (sppasLog) Human-readable logs.

    """
    if cfg.feature_installed('facedetect') is False:
        raise sppasEnableFeatureError('facedetect')
    if cfg.feature_installed('facemark') is False:
        raise sppasEnableFeatureError('facemark')
    super(sppasFaceSights, self).__init__('facesights.json', log)
    self.__fli = ImageFaceLandmark()
    self.__img_writer = sppasFaceSightsImageWriter()
    self.__flv = VideoFaceLandmark(self.__fli)
    self.__video_writer = sppasKidsSightsVideoWriter(self.__img_writer)

Public functions

load_resources

Fix the model and proto files.

Parameters
  • args: models for landmark(Kazemi/LBF/AAM)
View Source
def load_resources(self, *args, **kwargs):
    """Fix the model and proto files.

        :param args: models for landmark (Kazemi/LBF/AAM)

        """
    for model in args:
        self.__fli.add_model(model)

fix_options

Fix all options.

Parameters
  • options: (sppasOption)
View Source
def fix_options(self, options):
    """Fix all options.

        :param options: (sppasOption)

        """
    for opt in options:
        key = opt.get_key()
        if key == 'csv':
            self.set_out_csv(opt.get_value())
        elif key == 'tag':
            self.set_img_tag(opt.get_value())
        elif key == 'crop':
            self.set_img_crop(opt.get_value())
        elif key == 'folder':
            self.set_out_folder(opt.get_value())
        elif key == 'width':
            self.set_img_width(opt.get_value())
        elif key == 'height':
            self.set_img_height(opt.get_value())
        elif 'pattern' in key:
            self._options[key] = opt.get_value()
        else:
            raise AnnotationOptionError(key)

set_out_csv

The result includes a CSV file.

Parameters
  • out_csv: (bool) Create a CSV file with the coordinates
View Source
def set_out_csv(self, out_csv=False):
    """The result includes a CSV file.

        :param out_csv: (bool) Create a CSV file with the coordinates

        """
    out_csv = bool(out_csv)
    self.__video_writer.set_options(csv=out_csv)
    self._options['csv'] = out_csv
    self.__video_writer.set_options(xra=not out_csv)
    self._options['xra'] = not out_csv

set_img_tag

Draw the landmark points to the image.

Parameters
  • value: (bool) Tag the images
View Source
def set_img_tag(self, value=True):
    """Draw the landmark points to the image.

        :param value: (bool) Tag the images

        """
    value = bool(value)
    self.__img_writer.set_options(tag=value)
    self.__video_writer.set_options(tag=value)
    self._options['tag'] = value

set_out_folder

The result includes a folder with image files -- if video input.

Parameters
  • out_folder: (bool) Create a folder with image files when detecting
View Source
def set_out_folder(self, out_folder=False):
    """The result includes a folder with image files -- if video input.

        :param out_folder: (bool) Create a folder with image files when detecting

        """
    out_folder = bool(out_folder)
    self.__video_writer.set_options(folder=out_folder)
    self._options['folder'] = out_folder

set_img_crop

Create an image/video for each detected person.

Parameters
  • value: (bool) Crop the images
View Source
def set_img_crop(self, value=True):
    """Create an image/video for each detected person.

        :param value: (bool) Crop the images

        """
    value = bool(value)
    self.__video_writer.set_options(crop=value)
    self._options['crop'] = value

set_img_width

Width of the resulting images/video.

Parameters
  • value: (int) Number of pixels
View Source
def set_img_width(self, value):
    """Width of the resulting images/video.

        :param value: (int) Number of pixels

        """
    self.__video_writer.set_options(width=value)
    self._options['width'] = value

set_img_height

Height of the resulting images/video.

Parameters
  • value: (int) Number of pixel
View Source
def set_img_height(self, value):
    """Height of the resulting images/video.

        :param value: (int) Number of pixel

        """
    self.__video_writer.set_options(height=value)
    self._options['height'] = value

image_face_sights

Get the image, get or detect faces, eval sights and write results.

Parameters
  • image_file: (str) Image filename
  • annot_faces: (str) CSV/XRA filename
  • output: (str) The output name for the image
Returns
  • (list) the sights of all detected faces or created filenames
View Source
def image_face_sights(self, image_file, annot_faces=None, output=None):
    """Get the image, get or detect faces, eval sights and write results.

        :param image_file: (str) Image filename
        :param annot_faces: (str) CSV/XRA filename
        :param output: (str) The output name for the image

        :return: (list) the sights of all detected faces or created filenames

        """
    image = sppasImage(filename=image_file)
    coords = list()
    if annot_faces is not None:
        try:
            cr = sppasCoordsReader(annot_faces)
            if len(cr.coords) > 0:
                coords = cr.coords
            else:
                raise Exception('No coordinates found')
        except Exception as e:
            logging.error(str(e))
            sppasError(ERR_NO_FACE)
    all_sights = list()
    for face_coord in coords:
        success = self.__fli.detect_sights(image, face_coord)
        if success is True:
            sights = self.__fli.get_sights()
            all_sights.append(sights)
    if output is not None:
        new_files = list()
        output_file = self.fix_out_file_ext(output, out_format='IMAGE')
        if len(all_sights) > 1:
            for i, sights in enumerate(all_sights):
                fn, fe = os.path.splitext(output_file)
                pattern = self.get_output_pattern()
                if len(pattern) > 0 and fn.endswith(pattern):
                    fn = fn[:len(fn) - len(pattern)]
                out_name = '{:s}_{:d}{:s}{:s}'.format(fn, i + 1, pattern, fe)
                _files = self.__img_writer.write(image, [sights], out_name)
                new_files.extend(_files)
        else:
            new_files = self.__img_writer.write(image, all_sights, output_file)
        return new_files
    return all_sights

get_inputs

Return the media and the csv filenames.

Parameters
  • input_files: (list)
Raises

NoInputError

Returns
  • (str, str) Names of the 2 expected files
View Source
def get_inputs(self, input_files):
    """Return the media and the csv filenames.

        :param input_files: (list)
        :raise: NoInputError
        :return: (str, str) Names of the 2 expected files

        """
    ext = self.get_input_extensions()
    media_ext = ext[0]
    annot_ext = ext[1]
    media = None
    annot = None
    for filename in input_files:
        fn, fe = os.path.splitext(filename)
        if media is None and fe in media_ext:
            media = filename
        elif annot is None and fe.lower() in annot_ext:
            annot = filename
    if media is None:
        logging.error('Neither a video nor an image was found.')
        raise NoInputError
    if annot is None:
        logging.error('The CSV or XRA file with identities/faces was not found.')
        raise NoInputError
    return (media, annot)

run

Run the automatic annotation process on an input.

Parameters
  • input_files: (list of str) Input file is an image or a video
  • output: (str) the output file name
Returns
  • (list of points or filenames) detected sights or created filenames
View Source
def run(self, input_files, output=None):
    """Run the automatic annotation process on an input.

        :param input_files: (list of str) Input file is an image or a video
        :param output: (str) the output file name
        :returns: (list of points or filenames) detected sights or created filenames

        """
    media_file, annot_file = self.get_inputs(input_files)
    fn, ext = os.path.splitext(media_file)
    self.__video_writer.set_image_extension(self._out_extensions['IMAGE'])
    self.__video_writer.set_video_extension(self._out_extensions['VIDEO'])
    result_files = list()
    if ext in video_extensions:
        try:
            result_files = self.__flv.video_face_sights(media_file, annot_file, self.__video_writer, output)
            self.__video_writer.close()
        except:
            import traceback
            print(traceback.format_exc())
            raise
    if ext in image_extensions:
        result_files = self.image_face_sights(media_file, annot_file, output)
    return result_files

get_output_pattern

Pattern this annotation uses in an output filename.

View Source
def get_output_pattern(self):
    """Pattern this annotation uses in an output filename."""
    return self._options.get('outputpattern', '-sights')

get_input_patterns

Pattern this annotation expects for its input filename.

View Source
def get_input_patterns(self):
    """Pattern this annotation expects for its input filename."""
    return [self._options.get('inputpattern1', ''), self._options.get('inputpattern2', '-ident')]

get_input_extensions

Extensions that the annotation expects for its input filename.

Priority is given to video files, then image files.

View Source
@staticmethod
def get_input_extensions():
    """Extensions that the annotation expects for its input filename.

        Priority is given to video files, then image files.

        """
    out_ext = list(sppasFiles.get_informat_extensions('VIDEO'))
    for img_ext in sppasFiles.get_informat_extensions('IMAGE'):
        out_ext.append(img_ext)
    return [out_ext, ['.xra', '.csv']]