Source code for annotations.FaceClustering.sppasfaceid

# -*- coding: UTF-8 -*-
:author:   Brigitte Bigi
:summary:  SPPAS integration of FaceClustering automatic annotation

.. _This file is part of SPPAS: <>

     ___   __    __    __    ___
    /     |  \  |  \  |  \  /              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
    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 <>.

    This banner notice must not be removed.



import os
import logging

from ..annotationsexc import AnnotationOptionError
from ..baseannot import sppasBaseAnnotation
from ..autils import SppasFiles
from ..annotationsexc import NoInputError

from .identifycoords import VideoCoordsIdentification
from .kidswriter import sppasKidsVideoWriter

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

[docs]class sppasFaceIdentifier(sppasBaseAnnotation): """SPPAS integration of the automatic video coordinates identification. Requires both an image/video and a CSV file with face coordinates. """
[docs] def __init__(self, log=None): """Create a new sppasFaceIdentifier instance. :param log: (sppasLog) Human-readable logs. """ super(sppasFaceIdentifier, self).__init__("faceidentity.json", log) # The objects to store the input data and the results self.__video_writer = sppasKidsVideoWriter() # The annotator self.__pfv = VideoCoordsIdentification()
# ----------------------------------------------------------------------- # Methods to fix options # -----------------------------------------------------------------------
[docs] def fix_options(self, options): """Fix all options. :param options: (sppasOption) """ for opt in options: key = opt.get_key() if key == "fdmin": self.set_fd_threshold(opt.get_value()) elif key == "ident": self.set_ident_export(opt.get_value()) elif key == "csv": self.set_out_csv(opt.get_value()) elif key == "folder": self.set_out_folder(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 == "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)
# ---------------------------------------------------------------------- # Getters and setters # -----------------------------------------------------------------------
[docs] def set_ident_export(self, value): """Set the export of a video/csv file for each identified person. :param value: (bool) True to export video/csv files """ self.__pfv.set_out_ident(value)
# -----------------------------------------------------------------------
[docs] def set_fd_threshold(self, value): """Threshold to FD confidence to assign a person to a face. :param value: (float) fd score """ value = float(value) self.__pfv.set_ident_min_confidence(value) self._options["fdmin"] = value
# -----------------------------------------------------------------------
[docs] def set_out_csv(self, out_csv=False): """The result includes a CSV file. :param out_csv: (bool) Create a CSV file when detecting """ self.__video_writer.set_options(csv=out_csv) self._options["csv"] = out_csv
# -----------------------------------------------------------------------
[docs] def set_out_folder(self, out_folder=False): """The result includes a folder with image files. :param out_folder: (bool) Create a folder with image files when detecting """ self.__video_writer.set_options(folder=out_folder) self._options["folder"] = out_folder
# -----------------------------------------------------------------------
[docs] def set_img_tag(self, value=True): """Surround the faces with a square. :param value: (bool) Tag the images """ self.__video_writer.set_options(tag=value) self._options["tag"] = value
# -----------------------------------------------------------------------
[docs] def set_img_crop(self, value=True): """Create an image/video for each detected person. :param value: (bool) Crop the images """ self.__video_writer.set_options(crop=value) self._options["crop"] = value
# -----------------------------------------------------------------------
[docs] 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
# -----------------------------------------------------------------------
[docs] 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
# -----------------------------------------------------------------------
[docs] 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] csv_ext = ext[1] media = None csv = None for filename in input_files: fn, fe = os.path.splitext(filename) if media is None and fe in media_ext: # The video or the image is found. media = filename elif csv is None and fe.lower() in csv_ext: csv = filename if media is None: logging.error("No video was found.") raise NoInputError if csv is None: logging.error("The CSV file with faces was not found.") raise NoInputError return media, csv
# -----------------------------------------------------------------------
[docs] def run(self, input_files, output=None): """Run the automatic annotation process on an input. :param input_files: (list of str) (video ) Video file, CSV file with coords of faces :param output: (str) the output base name for files :returns: (list) Either the list of list of detected faces or the list of all created files. """ # Get and open the video filename from the input video_file, csv_file = self.get_inputs(input_files) self.__video_writer.set_video_extension(self._out_extensions["VIDEO"]) # Assign a person identity to the faces if output.endswith(self.get_output_pattern()): output = output[:-len(self.get_output_pattern())] result = self.__pfv.video_identity(video_file, csv_file, self.__video_writer, output) self.__video_writer.close() return result
# -----------------------------------------------------------------------
[docs] def get_input_patterns(self): """Patterns this annotation expects for its input filenames. """ return [ self._options.get("inputpattern1", ""), # video self._options.get("inputpattern2", '-face') # csv ]
# -----------------------------------------------------------------------
[docs] def get_output_pattern(self): """Pattern this annotation adds to the output filename.""" return self._options.get("outputpattern", "-ident")
# -----------------------------------------------------------------------
[docs] @staticmethod def get_input_extensions(): """Extensions that the annotation expects for its input filename. """ return [ SppasFiles.get_informat_extensions("VIDEO"), [".csv"] ]