Source code for bob.pad.face.utils.load_utils

from bob.io.video import reader
from bob.ip.base import scale, block, block_output_shape
from bob.ip.facedetect import bounding_box_from_annotation
import numpy
import six


[docs]def frames(path): """Yields the frames of a video file. Parameters ---------- path : str Path to the video file. Yields ------ :any:`numpy.array` A frame of the video. The size is (3, 240, 320). """ video = reader(path) for frame in video: yield frame
[docs]def number_of_frames(path): """returns the number of frames of a video file. Parameters ---------- path : str Path to the video file. Returns ------- int The number of frames. Then, it yields the frames. """ video = reader(path) return video.number_of_frames
[docs]def yield_frames(paddb, padfile): """Loads the frames of a video PAD database. Parameters ---------- paddb : :any:`bob.pad.base.database.PadDatabase` The video PAD database. The database needs to have implemented the `.frames()` method. padfile : :any:`bob.pad.face.database.VideoPadFile` The PAD file. Yields ------ :any:`numpy.array` Frames of the PAD file one by one. """ frames = paddb.frames(padfile) for image in frames: yield image
[docs]def normalize_detections(detections, nframes, max_age=-1, faceSizeFilter=0): """Calculates a list of "nframes" with the best possible detections taking into consideration the ages of the last valid detection on the detections list. Parameters ---------- detections : dict A dictionary containing keys that indicate the frame number of the detection and a value which is a BoundingBox object. nframes : int An integer indicating how many frames has the video that will be analyzed. max_age : :obj:`int`, optional An integer indicating for a how many frames a detected face is valid if no detection occurs after such frame. A value of -1 == forever faceSizeFilter : :obj:`int`, optional The minimum required size of face height (in pixels) Yields ------ object The bounding box or None. """ curr = None age = 0 for k in range(nframes): if detections and k in detections and \ (detections[k].size[0] > faceSizeFilter): curr = detections[k] age = 0 elif max_age < 0 or age < max_age: age += 1 else: # no detections and age is larger than maximum allowed curr = None yield curr
[docs]def yield_faces(database, padfile, **kwargs): """Yields face images of a padfile. It uses the annotations from the database. The annotations are further normalized. Parameters ---------- database : :any:`bob.pad.base.database.PadDatabase` A face PAD database. This database needs to have implemented the `frames` method. padfile : :any:`bob.pad.base.database.PadFile` The padfile to return the faces. **kwargs They are passed to :any:`normalize_detections`. Yields ------ numpy.array Face images Raises ------ ValueError If the database returns None for annotations. """ frames_gen = database.frames(padfile) nframes = database.number_of_frames(padfile) # read annotation annots = database.annotations(padfile) if annots is None: raise ValueError("No annotations were returned.") # normalize annotations annots = {int(k): bounding_box_from_annotation(**v) for k, v in six.iteritems(annots)} bounding_boxes = normalize_detections(annots, nframes, **kwargs) for frame, bbx in six.moves.zip(frames_gen, bounding_boxes): if bbx is None: continue face = frame[..., bbx.top:bbx.bottom, bbx.left:bbx.right] yield face
[docs]def scale_face(face, face_height, face_width=None): """Scales a face image to the given size. Parameters ---------- face : :any:`numpy.array` The face image. It can be 2D or 3D in bob image format. face_height : int The height of the scaled face. face_width : :obj:`None`, optional The width of the scaled face. If None, face_height is used. Returns ------- :any:`numpy.array` The scaled face. """ face_width = face_height if face_width is None else face_width shape = list(face.shape) shape[-2:] = (face_height, face_width) scaled_face = numpy.empty(shape, dtype='float64') scale(face, scaled_face) return scaled_face
[docs]def blocks(data, block_size, block_overlap=(0, 0)): """Extracts patches of an image Parameters ---------- data : :any:`numpy.array` The image in gray-scale, color, or color video format. block_size : (int, int) The size of patches block_overlap : (:obj:`int`, :obj:`int`), optional The size of overlap of patches Returns ------- :any:`numpy.array` The patches. Raises ------ ValueError If data dimension is not between 2 and 4 (inclusive). """ data = numpy.asarray(data) # if a gray scale image: if data.ndim == 2: output = block(data, block_size, block_overlap, flat=True) # if a color image: elif data.ndim == 3: out_shape = list(data.shape[0:1]) + list(block_output_shape( data[0], block_size, block_overlap, flat=True)) output = numpy.empty(out_shape, dtype=data.dtype) for i, img2d in enumerate(data): block(img2d, block_size, block_overlap, output[i], flat=True) output = numpy.moveaxis(output, 0, 1) # if a color video: elif data.ndim == 4: output = [blocks(img3d, block_size, block_overlap) for img3d in data] output = numpy.concatenate(output, axis=0) else: raise ValueError("Unknown data dimension {}".format(data.ndim)) return output