""" Crop images to prepare for training """ import click from app.settings import types from app.utils import click_utils from app.settings import app_cfg as cfg @click.command() @click.option('-i', '--input', 'opt_fp_in', default=None, required=True, help='Image filepath') @click.option('-o', '--output', 'opt_fp_out', default=None, help='GIF output path') @click.option('--size', 'opt_size', type=(int, int), default=(300, 300), help='Output image size') @click.option('--gif-size', 'opt_gif_size', type=(int, int), default=(480, 480), help='GIF output size') @click.option('--gif-frames', 'opt_gif_frames', default=15, help='GIF frames') @click.option('-g', '--gpu', 'opt_gpu', default=0, help='GPU index') @click.option('-f', '--force', 'opt_force', is_flag=True, help='Force overwrite file') @click.option('--display/--no-display', 'opt_display', is_flag=True, default=True, help='Display detections to debug') @click.pass_context def cli(ctx, opt_fp_in, opt_fp_out, opt_gpu, opt_gif_frames, opt_size, opt_gif_size, opt_force, opt_display): """Generates 3D landmark animations from CSV files""" import sys import os from os.path import join from pathlib import Path import time from tqdm import tqdm import numpy as np import pandas as pd import cv2 as cv import dlib from PIL import Image import matplotlib.pyplot as plt from app.utils import logger_utils, file_utils, im_utils, display_utils, draw_utils from app.utils import plot_utils from app.processors import face_detector, face_landmarks from app.models.data_store import DataStore # ------------------------------------------------- # init here log = logger_utils.Logger.getLogger() # load image im = cv.imread(opt_fp_in) im_resized = im_utils.resize(im, width=opt_size[0], height=opt_size[1]) # ---------------------------------------------------------------------------- # detect face face_detector = face_detector.DetectorCVDNN() log.info('detecting face...') st = time.time() bboxes = face_detector.detect(im_resized, largest=True) bbox_norm = bboxes[0] dim = im_resized.shape[:2][::-1] bbox_dim = bbox_norm.to_dim(dim) if not bbox_norm: log.error('no face detected') return else: log.info(f'Detected face in {(time.time() - st):.2f}s') log.info('') # ---------------------------------------------------------------------------- # detect 3D landmarks log.info('loading 3D landmark generator files...') landmark_detector_3d_68 = face_landmarks.FaceAlignment3D_68(gpu=opt_gpu) # -1 for CPU log.info('generating 3D landmarks...') st = time.time() points_3d_68 = landmark_detector_3d_68.landmarks(im_resized, bbox_norm) log.info(f'generated 3D landmarks in {(time.time() - st):.2f}s') log.info('') # ---------------------------------------------------------------------------- # generate 3D GIF animation log.info('generating 3D animation...') if not opt_fp_out: fpp_im = Path(opt_fp_in) fp_out = join(fpp_im.parent, f'{fpp_im.stem}_anim.gif') else: fp_out = opt_fp_out st = time.time() plot_utils.generate_3d_landmark_anim(np.array(points_3d_68), fp_out, size=opt_gif_size, num_frames=opt_gif_frames) log.info(f'Generated animation in {(time.time() - st):.2f}s') log.info(f'Saved to: {fp_out}') log.info('') # ---------------------------------------------------------------------------- # generate 68 point landmarks using dlib log.info('initializing face landmarks 68 dlib...') from app.processors import face_landmarks landmark_detector_2d_68 = face_landmarks.Dlib2D_68() log.info('generating 2D 68PT landmarks...') st = time.time() points_2d_68 = landmark_detector_2d_68.landmarks(im_resized, bbox_norm) log.info(f'generated 2D 68PT face landmarks in {(time.time() - st):.2f}s') log.info('') # display if opt_display: # draw landmarks im_lmarks = im_resized.copy() im_lmarks = draw_utils.draw_bbox(im_lmarks, bbox_norm) im_lmarks = draw_utils.draw_landmarks2D(im_lmarks, points_2d_68, radius=1, color=(0,0,255)) im_lmarks = draw_utils.draw_landmarks3D(im_lmarks, points_3d_68, radius=3, color=(0,255,0)) # draw animated GIF im = Image.open(fp_out) im_frames = [] duration = im.info['duration'] try: while True: im.seek(len(im_frames)) mypalette = im.getpalette() im.putpalette(mypalette) im_jpg = Image.new("RGB", im.size) im_jpg.paste(im) im_np = im_utils.pil2np(im_jpg.copy()) im_frames.append(im_np) except EOFError: pass # end of GIF sequence n_frames = len(im_frames) frame_number = 0 while True: # show all images here cv.imshow('2D/3D 68PT Landmarks', im_lmarks) cv.imshow('3D 68pt GIF', im_frames[frame_number]) frame_number = (frame_number + 1) % n_frames k = cv.waitKey(duration) & 0xFF if k == 27 or k == ord('q'): # ESC cv.destroyAllWindows() sys.exit() elif k != 255: # any key to continue break