Source code for bob.bio.base.utils.annotations

#!/usr/bin/env python
# vim: set fileencoding=utf-8 :

import collections
import json
import logging
import os

from bob.bio.base.database.utils import search_and_open

logger = logging.getLogger(__name__)

_idiap_annotations = {
    1: "reyeo",
    2: "reyet",
    3: "reyep",
    4: "reyeb",
    5: "reyei",
    6: "leyei",
    7: "leyet",
    8: "leyep",
    9: "leyeb",
    10: "leyeo",
    11: "rbrowo",
    12: "rbrowi",
    13: "lbrowi",
    14: "lbrowo",
    15: "noser",
    16: "noset",
    17: "nosel",
    18: "mouthr",
    19: "moutht",
    20: "mouthb",
    21: "mouthl",
    22: "chin",
}


[docs]def read_annotation_file(file_name, annotation_type): """This function provides default functionality to read annotation files. Parameters ---------- file_name : str The full path of the annotation file to read. The path can also be like ``base_path:relative_path`` where the base_path can be both a directory or a tarball. This allows you to read annotations from inside a tarball. annotation_type : str The type of the annotation file that should be read. The following annotation_types are supported: * ``eyecenter``: The file contains a single row with four entries: ``re_x re_y le_x le_y`` * ``named``: The file contains named annotations, one per line, e.g.: ``reye re_x re_y`` or ``pose 25.7`` * ``idiap``: The file contains enumerated annotations, one per line, e.g.: ``1 key1_x key1_y``, and maybe some additional annotations like gender, age, ... * ``json``: The file contains annotations of any format, dumped in a text json file. Returns ------- dict A python dictionary with the keypoint name as key and the position ``(y,x)`` as value, and maybe some additional annotations. Raises ------ IOError If the annotation file is not found. ValueError If the annotation type is not known. """ if not file_name: return None if ":" in file_name: base_path, tail = file_name.split(":", maxsplit=1) f = search_and_open(search_pattern=tail, base_dir=base_path) else: if not os.path.exists(file_name): raise IOError("The annotation file '%s' was not found" % file_name) f = open(file_name) annotations = {} try: if str(annotation_type) == "eyecenter": # only the eye positions are written, all are in the first row line = f.readline() positions = line.split() assert len(positions) == 4 annotations["reye"] = (float(positions[1]), float(positions[0])) annotations["leye"] = (float(positions[3]), float(positions[2])) elif str(annotation_type) == "named": # multiple lines, no header line, each line contains annotation and # position or single value annotation for line in f: positions = line.split() if len(positions) == 3: annotations[positions[0]] = ( float(positions[2]), float(positions[1]), ) elif len(positions) == 2: annotations[positions[0]] = float(positions[1]) else: logger.error( "Could not interpret line '%s' in annotation file '%s'", line, file_name, ) elif str(annotation_type) == "idiap": # Idiap format: multiple lines, no header, each line contains an integral # keypoint identifier, or other identifier like 'gender', 'age',... for line in f: positions = line.rstrip().split() if positions: if positions[0].isdigit(): # position field assert len(positions) == 3 id = int(positions[0]) annotations[_idiap_annotations[id]] = ( float(positions[2]), float(positions[1]), ) else: # another field, we take the first entry as key and the rest as # values annotations[positions[0]] = positions[1:] # finally, we add the eye center coordinates as the center between the # eye corners; the annotations 3 and 8 are the pupils... if "reyeo" in annotations and "reyei" in annotations: annotations["reye"] = ( (annotations["reyeo"][0] + annotations["reyei"][0]) / 2.0, (annotations["reyeo"][1] + annotations["reyei"][1]) / 2.0, ) if "leyeo" in annotations and "leyei" in annotations: annotations["leye"] = ( (annotations["leyeo"][0] + annotations["leyei"][0]) / 2.0, (annotations["leyeo"][1] + annotations["leyei"][1]) / 2.0, ) elif str(annotation_type) == "json": annotations = json.load( f, object_pairs_hook=collections.OrderedDict ) else: raise ValueError( "The given annotation type '%s' is not known, choose one of ('eyecenter', 'named', 'idiap')" % annotation_type ) finally: f.close() if ( annotations is not None and "leye" in annotations and "reye" in annotations and annotations["leye"][1] < annotations["reye"][1] ): logger.warn( "The eye annotations in file '%s' might be exchanged!" % file_name ) return annotations