SPPAS integration of the automatic face sights annotation.
Requires both an image/video and an XRA or CSV file with faces or face identities.
SPPAS integration of the automatic face sights annotation.
Requires both an image/video and an XRA or CSV file with faces or face identities.
Create a new sppasFaceSights instance.
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)
Fix the model and proto files.
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 all options.
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)
The result includes a CSV file.
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
Draw the landmark points to the image.
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
The result includes a folder with image files -- if video input.
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
Create an image/video for each detected person.
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
Width of the resulting images/video.
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
Height of the resulting images/video.
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
Get the image, get or detect faces, eval sights and write results.
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
Return the media and the csv filenames.
NoInputError
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 the automatic annotation process on an input.
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
Pattern this annotation uses in an output filename.
def get_output_pattern(self):
"""Pattern this annotation uses in an output filename."""
return self._options.get('outputpattern', '-sights')
Pattern this annotation expects for its input filename.
def get_input_patterns(self):
"""Pattern this annotation expects for its input filename."""
return [self._options.get('inputpattern1', ''), self._options.get('inputpattern2', '-ident')]
Extensions that the annotation expects for its input filename.
Priority is given to video files, then image files.
@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']]