diff --git a/bob/pad/face/utils/load_utils.py b/bob/pad/face/utils/load_utils.py index 4bddd8830bfbe3a5fe92f957656fd6b4f095f2aa..47b79368494d0a109ad1d6c10b19767819265f90 100644 --- a/bob/pad/face/utils/load_utils.py +++ b/bob/pad/face/utils/load_utils.py @@ -45,14 +45,20 @@ def number_of_frames(path): def bbx_cropper(frame, annotations): - bbx = bounding_box_from_annotation(**annotations) - return frame[..., bbx.top:bbx.bottom, bbx.left:bbx.right] + for source in ("direct", "eyes", None): + try: + bbx = bounding_box_from_annotation(source=source, **annotations) + break + except Exception: + if source is None: + raise + return frame[..., bbx.top : bbx.bottom, bbx.left : bbx.right] def min_face_size_normalizer(annotations, max_age=15, **kwargs): - return normalize_annotations(annotations, - partial(min_face_size_validator, **kwargs), - max_age=max_age) + return normalize_annotations( + annotations, partial(min_face_size_validator, **kwargs), max_age=max_age + ) def yield_faces(padfile, cropper, normalizer=None): @@ -120,7 +126,7 @@ def scale_face(face, face_height, face_width=None): 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') + scaled_face = numpy.empty(shape, dtype="float64") scale(face, scaled_face) return scaled_face @@ -150,12 +156,12 @@ def blocks(data, block_size, block_overlap=(0, 0)): data = numpy.asarray(data) # if a gray scale image: if data.ndim == 2: - output = block(data, block_size, block_overlap, - flat=True) + 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)) + 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): @@ -163,8 +169,7 @@ def blocks(data, block_size, block_overlap=(0, 0)): 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 = [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)) @@ -206,7 +211,7 @@ def blocks_generator(data, block_size, block_overlap=(0, 0)): raise ValueError("Unknown data dimension {}".format(data.ndim)) -def color_augmentation(image, channels=('rgb',)): +def color_augmentation(image, channels=("rgb",)): """Converts an RGB image to different color channels. Parameters @@ -225,13 +230,13 @@ def color_augmentation(image, channels=('rgb',)): """ final_image = [] - if 'rgb' in channels: + if "rgb" in channels: final_image.append(image) - if 'yuv' in channels: + if "yuv" in channels: final_image.append(rgb_to_yuv(image)) - if 'hsv' in channels: + if "hsv" in channels: final_image.append(rgb_to_hsv(image)) return numpy.concatenate(final_image, axis=0) @@ -251,26 +256,33 @@ def random_patches(image, block_size, n_random_patches=1): hl = numpy.random.randint(0, h - bh, size=n_random_patches) wl = numpy.random.randint(0, w - bw, size=n_random_patches) for ch, cw in zip(hl, wl): - yield image[..., ch:ch + bh, cw:cw + bw] + yield image[..., ch : ch + bh, cw : cw + bw] -def extract_patches(image, block_size, block_overlap=(0, 0), - n_random_patches=None): +def extract_patches(image, block_size, block_overlap=(0, 0), n_random_patches=None): """Yields either all patches from an image or N random patches.""" if n_random_patches is None: return blocks_generator(image, block_size, block_overlap) else: - return random_patches( - image, block_size, n_random_patches=n_random_patches) - - -def the_giant_video_loader(paddb, padfile, - region='whole', scaling_factor=None, cropper=None, - normalizer=None, patches=False, - block_size=(96, 96), block_overlap=(0, 0), - random_patches_per_frame=None, augment=None, - multiple_bonafide_patches=1, keep_pa_samples=None, - keep_bf_samples=None): + return random_patches(image, block_size, n_random_patches=n_random_patches) + + +def the_giant_video_loader( + paddb, + padfile, + region="whole", + scaling_factor=None, + cropper=None, + normalizer=None, + patches=False, + block_size=(96, 96), + block_overlap=(0, 0), + random_patches_per_frame=None, + augment=None, + multiple_bonafide_patches=1, + keep_pa_samples=None, + keep_bf_samples=None, +): """Loads a video pad file frame by frame and optionally applies transformations. @@ -316,41 +328,40 @@ def the_giant_video_loader(paddb, padfile, ValueError If region is not whole or crop. """ - if region == 'whole': + if region == "whole": generator = padfile.frames - elif region == 'crop': - generator = yield_faces( - padfile, cropper=cropper, normalizer=normalizer) + elif region == "crop": + generator = yield_faces(padfile, cropper=cropper, normalizer=normalizer) else: raise ValueError("Invalid region value: `{}'".format(region)) if scaling_factor is not None: - generator = (scale(frame, scaling_factor) - for frame in generator) + generator = (scale(frame, scaling_factor) for frame in generator) if patches: if random_patches_per_frame is None: generator = ( - patch for frame in generator - for patch in blocks_generator( - frame, block_size, block_overlap)) + patch + for frame in generator + for patch in blocks_generator(frame, block_size, block_overlap) + ) else: if padfile.attack_type is None: random_patches_per_frame *= multiple_bonafide_patches generator = ( - patch for frame in generator + patch + for frame in generator for patch in random_sample( - blocks(frame, block_size, block_overlap), - random_patches_per_frame)) + blocks(frame, block_size, block_overlap), random_patches_per_frame + ) + ) if augment is not None: generator = (augment(frame) for frame in generator) if keep_pa_samples is not None and padfile.attack_type is not None: - generator = (frame for frame in generator - if random.random() < keep_pa_samples) + generator = (frame for frame in generator if random.random() < keep_pa_samples) if keep_bf_samples is not None and padfile.attack_type is None: - generator = (frame for frame in generator - if random.random() < keep_bf_samples) + generator = (frame for frame in generator if random.random() < keep_bf_samples) return generator