diff options
| -rw-r--r-- | megapixels/app/processors/face_age.py | 8 | ||||
| -rw-r--r-- | megapixels/app/processors/face_beauty.py | 6 | ||||
| -rw-r--r-- | megapixels/app/processors/face_detector.py | 11 | ||||
| -rw-r--r-- | megapixels/app/processors/face_emotion.py | 10 | ||||
| -rw-r--r-- | megapixels/app/processors/face_gender.py | 9 | ||||
| -rw-r--r-- | megapixels/app/processors/face_landmarks_3d.py | 99 | ||||
| -rw-r--r-- | megapixels/app/processors/face_recognition.py | 9 | ||||
| -rw-r--r-- | megapixels/app/settings/app_cfg.py | 1 | ||||
| -rw-r--r-- | megapixels/app/utils/draw_utils.py | 8 | ||||
| -rw-r--r-- | megapixels/commands/cv/face_roi.py | 4 | ||||
| -rw-r--r-- | megapixels/commands/cv/face_vector.py | 8 | ||||
| -rw-r--r-- | megapixels/commands/demo/face_age.py | 106 | ||||
| -rw-r--r-- | megapixels/commands/demo/face_beauty.py | 28 | ||||
| -rw-r--r-- | megapixels/commands/demo/face_detection.py | 2 | ||||
| -rw-r--r-- | megapixels/commands/demo/face_emotion.py | 106 | ||||
| -rw-r--r-- | megapixels/commands/demo/face_gender.py | 106 | ||||
| -rw-r--r-- | megapixels/commands/demo/face_vector.py | 7 |
17 files changed, 382 insertions, 146 deletions
diff --git a/megapixels/app/processors/face_age.py b/megapixels/app/processors/face_age.py index 222858a5..35174628 100644 --- a/megapixels/app/processors/face_age.py +++ b/megapixels/app/processors/face_age.py @@ -18,11 +18,11 @@ class FaceAge: # Estimates face age - def __init__(self): + def __init__(self, gpu=0): self.log = logger_utils.Logger.getLogger() pass - def age(self): - # use enum typed emotions - return {'age': types.Age.ADULT, 'confidence': 0.5}
\ No newline at end of file + def age(self, im, bbox_dim): + self.log.warn('not yet implemented') + return 0.0
\ No newline at end of file diff --git a/megapixels/app/processors/face_beauty.py b/megapixels/app/processors/face_beauty.py index 2e8221b7..a01c6834 100644 --- a/megapixels/app/processors/face_beauty.py +++ b/megapixels/app/processors/face_beauty.py @@ -9,12 +9,10 @@ import numpy as np import imutils import pickle -os.environ['CUDA_VISIBLE_DEVICES'] = '' import keras from keras.layers import Conv2D, Input, MaxPool2D,Flatten, Dense, Permute, GlobalAveragePooling2D from keras.models import Model from keras.optimizers import adam -import os.path from keras.models import Sequential from keras.applications.resnet50 import ResNet50 #from keras.applications.resnet50 import Dense @@ -33,7 +31,9 @@ class FaceBeauty: # Estimates beauty using CNN - def __init__(self, gpu=-1): + def __init__(self): + # ensure Keras uses CPU (no GPU, it takes up all memory) + os.environ['CUDA_VISIBLE_DEVICES'] = '' # don't really need GPU, CPU is quick enough self.log = logger_utils.Logger.getLogger() resnet = ResNet50(include_top=False, pooling='avg') diff --git a/megapixels/app/processors/face_detector.py b/megapixels/app/processors/face_detector.py index c0762564..0e194f7d 100644 --- a/megapixels/app/processors/face_detector.py +++ b/megapixels/app/processors/face_detector.py @@ -21,9 +21,14 @@ class DetectorMTCNN: dnn_size = (300, 300) - def __init__(self, size=(400,400)): + def __init__(self, size=(400,400), gpu=0): + self.log = logger_utils.Logger.getLogger() + device_cur = os.getenv('CUDA_VISIBLE_DEVICES', '') + self.log.info(f'Change CUDA_VISIBLE_DEVICES from "{device_cur}" to "{gpu}"') + os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu) from mtcnn.mtcnn import MTCNN self.detector = MTCNN() + os.environ['CUDA_VISIBLE_DEVICES'] = device_cur # reset def detect(self, im, size=(400,400), conf_thresh=None, pyramids=None, largest=False, zone=None): '''Detects face using MTCNN and returns (list) of BBox @@ -70,14 +75,14 @@ class DetectorDLIBCNN: def __init__(self, gpu=0): import dlib self.log = logger_utils.Logger.getLogger() - cuda_visible_devices = os.getenv('CUDA_VISIBLE_DEVICES', '') + device_cur = os.getenv('CUDA_VISIBLE_DEVICES', '') if dlib.DLIB_USE_CUDA and gpu < 0: self.log.error('dlib was compiled with CUDA but you selected CPU. Use GPU >= 0 if dlib.DLIB_USE_CUDA') sys.exit() os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu) self.log.info('load model: {}'.format(cfg.DIR_MODELS_DLIB_CNN)) self.detector = dlib.cnn_face_detection_model_v1(cfg.DIR_MODELS_DLIB_CNN) - os.environ['CUDA_VISIBLE_DEVICES'] = cuda_visible_devices # reset + os.environ['CUDA_VISIBLE_DEVICES'] = device_cur # reset def detect(self, im, conf_thresh=None, pyramids=None, largest=False, zone=None): bboxes = [] diff --git a/megapixels/app/processors/face_emotion.py b/megapixels/app/processors/face_emotion.py index c45da9ba..a04d7afd 100644 --- a/megapixels/app/processors/face_emotion.py +++ b/megapixels/app/processors/face_emotion.py @@ -16,13 +16,13 @@ from app.settings import types class FaceEmotion: - # Estimates face emotion + # Estimates face age - def __init__(self): + def __init__(self, gpu=0): self.log = logger_utils.Logger.getLogger() pass - def emotion(self): - # use enum typed emotions - return {'emotion': types.Emotion.NEUTRAL, 'confidence': 0.5}
\ No newline at end of file + def emotion(self, im, bbox_dim): + self.log.warn('not yet implemented') + return 0.0
\ No newline at end of file diff --git a/megapixels/app/processors/face_gender.py b/megapixels/app/processors/face_gender.py index ee152098..ea64b828 100644 --- a/megapixels/app/processors/face_gender.py +++ b/megapixels/app/processors/face_gender.py @@ -16,12 +16,13 @@ from app.settings import types class FaceGender: - # Estimates gender using CNN + # Estimates face age - def __init__(self): + def __init__(self, gpu=0): self.log = logger_utils.Logger.getLogger() pass - def gender(self): - return 'm'
\ No newline at end of file + def gender(self, im, bbox_dim): + self.log.warn('not yet implemented') + return 0.0
\ No newline at end of file diff --git a/megapixels/app/processors/face_landmarks_3d.py b/megapixels/app/processors/face_landmarks_3d.py deleted file mode 100644 index 5a0d6097..00000000 --- a/megapixels/app/processors/face_landmarks_3d.py +++ /dev/null @@ -1,99 +0,0 @@ -import os -from os.path import join -from pathlib import Path -import math - -import cv2 as cv -import numpy as np -import imutils - -from app.utils import im_utils, logger_utils -from app.models.bbox import BBox -from app.settings import app_cfg as cfg -from app.settings import types - -class Landmarks3D: - - def __init__(self): - self.log = logger_utils.Logger.getLogger() - - def landmarks(self, im, bbox): - pass - - -class FaceAlignment3D(Landmarks3D): - - # Estimates 3D facial landmarks - import face_alignment - - def __init__(self, gpu=0, flip_input=True): - super().__init__() - device = f'cuda:{gpu}' if gpu > -1 else 'cpu' - self.fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._3D, device=device, flip_input=flip_input) - - def landmarks(self, im, bbox, as_type=str): - '''Calculates the 3D facial landmarks - :param im: (numpy.ndarray) image - :param bbox: (BBox) dimensioned to real (int) sizes - :param as_type: (str) or (list) type to return data - ''' - preds = self.fa.get_landmarks(im) - # convert to comma separated ints - # storing data as "[1,2], [3,4]" is larger file size than storing as "1,2,3,4" - # storing a list object in Pandas seems to result in 30% larger CSV files - # TODO optimize this - preds_int = [list(map(int, x)) for x in preds[0]] # list of ints - if as_type is str: - return ','.join([','.join(list(map(str,[x,y]))) for x,y in preds_int]) - else - return preds_int - - - def draw(self, im): - '''draws landmarks in 3d scene''' - - # TODO - ''' - import face_alignment - import numpy as np - from mpl_toolkits.mplot3d import Axes3D - import matplotlib.pyplot as plt - from skimage import io - - # Run the 3D face alignment on a test image, without CUDA. - fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._3D, device='cuda:0', flip_input=True) - - input = io.imread('../test/assets/aflw-test.jpg') - preds = fa.get_landmarks(input)[-1] - - #TODO: Make this nice - fig = plt.figure(figsize=plt.figaspect(.5)) - ax = fig.add_subplot(1, 2, 1) - ax.imshow(input) - ax.plot(preds[0:17,0],preds[0:17,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.plot(preds[17:22,0],preds[17:22,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.plot(preds[22:27,0],preds[22:27,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.plot(preds[27:31,0],preds[27:31,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.plot(preds[31:36,0],preds[31:36,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.plot(preds[36:42,0],preds[36:42,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.plot(preds[42:48,0],preds[42:48,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.plot(preds[48:60,0],preds[48:60,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.plot(preds[60:68,0],preds[60:68,1],marker='o',markersize=6,linestyle='-',color='w',lw=2) - ax.axis('off') - - ax = fig.add_subplot(1, 2, 2, projection='3d') - surf = ax.scatter(preds[:,0]*1.2,preds[:,1],preds[:,2],c="cyan", alpha=1.0, edgecolor='b') - ax.plot3D(preds[:17,0]*1.2,preds[:17,1], preds[:17,2], color='blue' ) - ax.plot3D(preds[17:22,0]*1.2,preds[17:22,1],preds[17:22,2], color='blue') - ax.plot3D(preds[22:27,0]*1.2,preds[22:27,1],preds[22:27,2], color='blue') - ax.plot3D(preds[27:31,0]*1.2,preds[27:31,1],preds[27:31,2], color='blue') - ax.plot3D(preds[31:36,0]*1.2,preds[31:36,1],preds[31:36,2], color='blue') - ax.plot3D(preds[36:42,0]*1.2,preds[36:42,1],preds[36:42,2], color='blue') - ax.plot3D(preds[42:48,0]*1.2,preds[42:48,1],preds[42:48,2], color='blue') - ax.plot3D(preds[48:,0]*1.2,preds[48:,1],preds[48:,2], color='blue' ) - - ax.view_init(elev=90., azim=90.) - ax.set_xlim(ax.get_xlim()[::-1]) - plt.show() - ''' - return im
\ No newline at end of file diff --git a/megapixels/app/processors/face_recognition.py b/megapixels/app/processors/face_recognition.py index a56b1634..76f00aa1 100644 --- a/megapixels/app/processors/face_recognition.py +++ b/megapixels/app/processors/face_recognition.py @@ -54,6 +54,15 @@ class RecognitionDLIB: #vec = self.facerec.compute_face_descriptor(im, face_shape) return vec + def flatten(self, vec): + '''Converts 128D vector into a flattened list for CSV + :param points: (list) a feature vector as list of floats + :returns dict item for each point (eg {'d1':0.28442156, 'd1': 0.1868632}) + ''' + vec_flat = {} + for idx, val in enumerate(vec, 1): + vec_flat[f'd{idx}'] = val + return vec_flat def similarity(self, query_enc, known_enc): return np.linalg.norm(query_enc - known_enc, axis=1) diff --git a/megapixels/app/settings/app_cfg.py b/megapixels/app/settings/app_cfg.py index d206f40b..2d51a607 100644 --- a/megapixels/app/settings/app_cfg.py +++ b/megapixels/app/settings/app_cfg.py @@ -44,6 +44,7 @@ DIR_MODELS_DARKNET_PJREDDIE = join(DIR_MODELS_DARKNET, 'pjreddie') DIR_MODELS_PYTORCH = join(DIR_MODELS,'pytorch') DIR_MODELS_TORCH = join(DIR_MODELS,'torch') DIR_MODELS_MXNET = join(DIR_MODELS,'mxnet') +DIR_MODELS_KERAS = join(DIR_MODELS,'keras') DIR_MODELS_TF = join(DIR_MODELS,'tensorflow') DIR_MODELS_DLIB = join(DIR_MODELS,'dlib') DIR_MODELS_DLIB_CNN = join(DIR_MODELS_DLIB, 'mmod_human_face_detector.dat') diff --git a/megapixels/app/utils/draw_utils.py b/megapixels/app/utils/draw_utils.py index 47bb7978..cafac5a5 100644 --- a/megapixels/app/utils/draw_utils.py +++ b/megapixels/app/utils/draw_utils.py @@ -34,12 +34,18 @@ def draw_bbox(im, bbox, color=(0,255,0), stroke_weight=2): def draw_pose(im, pt_nose, image_pts): '''Draws 3-axis pose over image - ''' + ''' cv.line(im, pt_nose, tuple(image_pts['pitch'].ravel()), pose_types['pitch'], 3) cv.line(im, pt_nose, tuple(image_pts['yaw'].ravel()), pose_types['yaw'], 3) cv.line(im, pt_nose, tuple(image_pts['roll'].ravel()), pose_types['roll'], 3) +def draw_text(im, pt, text, color=(0,255,0)): + '''Draws degrees as text over image + ''' + cv.putText(im, text, pt, cv.FONT_HERSHEY_SIMPLEX, 0.5, color, thickness=2, lineType=2) + + def draw_degrees(im, pose_data, color=(0,255,0)): '''Draws degrees as text over image ''' diff --git a/megapixels/commands/cv/face_roi.py b/megapixels/commands/cv/face_roi.py index 6d42924e..70fff401 100644 --- a/megapixels/commands/cv/face_roi.py +++ b/megapixels/commands/cv/face_roi.py @@ -94,11 +94,11 @@ def cli(ctx, opt_fp_in, opt_dir_media, opt_fp_out, opt_data_store, opt_dataset, if opt_detector_type == types.FaceDetectNet.CVDNN: detector = face_detector.DetectorCVDNN() elif opt_detector_type == types.FaceDetectNet.DLIB_CNN: - detector = face_detector.DetectorDLIBCNN(opt_gpu) + detector = face_detector.DetectorDLIBCNN(gpu=opt_gpu) elif opt_detector_type == types.FaceDetectNet.DLIB_HOG: detector = face_detector.DetectorDLIBHOG() elif opt_detector_type == types.FaceDetectNet.MTCNN: - detector = face_detector.DetectorMTCNN() + detector = face_detector.DetectorMTCNN(gpu=opt_gpu) elif opt_detector_type == types.FaceDetectNet.HAAR: log.error('{} not yet implemented'.format(opt_detector_type.name)) return diff --git a/megapixels/commands/cv/face_vector.py b/megapixels/commands/cv/face_vector.py index 9251c053..4df647f5 100644 --- a/megapixels/commands/cv/face_vector.py +++ b/megapixels/commands/cv/face_vector.py @@ -13,7 +13,7 @@ from app.settings import app_cfg as cfg help='Override enum output filename CSV') @click.option('-m', '--media', 'opt_dir_media', default=None, help='Override enum media directory') -@click.option('--data_store', 'opt_data_store', +@click.option('--store', 'opt_data_store', type=cfg.DataStoreVar, default=click_utils.get_default(types.DataStore.HDD), show_default=True, @@ -105,8 +105,10 @@ def cli(ctx, opt_fp_out, opt_dir_media, opt_data_store, opt_dataset, opt_size, # compute vec # padding=opt_padding not yet implemented in dlib===19.16 but merged in master vec = facerec.vec(im, bbox_dim, jitters=opt_jitters) - vec_str = ','.join([repr(x) for x in vec]) # convert to string for CSV - vecs.append( {'roi_index': roi_index, 'record_index': record_index, 'vec': vec_str}) + vec_flat = facerec.flatten(vec) + vec_flat['roi_index'] = roi_index + vec_flat['record_index'] = record_index + vecs.append(vec_flat) # create DataFrame and save to CSV diff --git a/megapixels/commands/demo/face_age.py b/megapixels/commands/demo/face_age.py new file mode 100644 index 00000000..45ae5190 --- /dev/null +++ b/megapixels/commands/demo/face_age.py @@ -0,0 +1,106 @@ +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('-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=False, + help='Display detections to debug') +@click.pass_context +def cli(ctx, opt_fp_in, opt_fp_out, opt_gpu, opt_size, opt_force, opt_display): + """Face detector demo""" + + 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 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_age + from app.models.data_store import DataStore + + + 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.DetectorDLIBCNN(gpu=opt_gpu) # -1 for CPU + bboxes = face_detector.detect(im_resized, largest=True) + bbox = bboxes[0] + dim = im_resized.shape[:2][::-1] + bbox_dim = bbox.to_dim(dim) + if not bbox: + log.error('no face detected') + return + else: + log.info(f'face detected: {bbox_dim.to_xyxy()}') + + + # ---------------------------------------------------------------------------- + # age + + age_predictor = face_age.FaceAge(gpu=opt_gpu) + age_score = age_predictor.age(im_resized, bbox_dim) + + + # ---------------------------------------------------------------------------- + # output + + log.info(f'Face coords: {bbox_dim} face') + log.info(f'age score: {(100*age_score):.2f}') + + + # ---------------------------------------------------------------------------- + # draw + + # draw 2d landmarks + im_age = im_resized.copy() + draw_utils.draw_bbox(im_age, bbox_dim) + txt = f'age score: {(100*age_score):.2f}' + draw_utils.draw_text(im_age, bbox_dim.pt_tl, txt) + + + # ---------------------------------------------------------------------------- + # save + + if opt_fp_out: + # save pose only + cv.imwrite(opt_fp_out, im_age) + + + # ---------------------------------------------------------------------------- + # display + + if opt_display: + # show all images here + cv.imshow('age', im_age) + display_utils.handle_keyboard()
\ No newline at end of file diff --git a/megapixels/commands/demo/face_beauty.py b/megapixels/commands/demo/face_beauty.py index b1612f7c..d31c5cee 100644 --- a/megapixels/commands/demo/face_beauty.py +++ b/megapixels/commands/demo/face_beauty.py @@ -1,6 +1,3 @@ -""" -""" - import click from app.settings import types @@ -51,25 +48,23 @@ def cli(ctx, opt_fp_in, opt_fp_out, opt_gpu, opt_size, opt_force, opt_display): # load image im = cv.imread(opt_fp_in) - # im = cv.cvtColor(im, cv.COLOR_BGR2RGB) - if im.shape[0] > 1280: - new_shape = (1280, im.shape[1] * 1280 / im.shape[0]) - elif im.shape[1] > 1280: - new_shape = (im.shape[0] * 1280 / im.shape[1], 1280) - elif im.shape[0] < 640 or im.shape[1] < 640: - new_shape = (im.shape[0] * 2, im.shape[1] * 2) - else: - new_shape = im.shape[0:2] + im_resized = im_utils.resize(im, width=opt_size[0], height=opt_size[1]) - im_resized = cv.resize(im, (int(new_shape[1]), int(new_shape[0]))) - #im_resized = im_utils.resize(im, width=opt_size[0], height=opt_size[1]) + # TODO fix Keras CPU/GPU device selection issue + # NB: GPU visibility issues with dlib/keras + # Wrap this with cuda toggle and run before init dlib GPU + + device_cur = os.getenv('CUDA_VISIBLE_DEVICES', '') + os.environ['CUDA_VISIBLE_DEVICES'] = '' + beauty_predictor = face_beauty.FaceBeauty() + os.environ['CUDA_VISIBLE_DEVICES'] = device_cur # ---------------------------------------------------------------------------- # detect face - face_detector = face_detector.DetectorDLIBCNN() # -1 for CPU + face_detector = face_detector.DetectorDLIBCNN(gpu=opt_gpu) # -1 for CPU bboxes = face_detector.detect(im_resized, largest=True) bbox = bboxes[0] dim = im_resized.shape[:2][::-1] @@ -82,8 +77,7 @@ def cli(ctx, opt_fp_in, opt_fp_out, opt_gpu, opt_size, opt_force, opt_display): # ---------------------------------------------------------------------------- # beauty - - beauty_predictor = face_beauty.FaceBeauty() + beauty_score = beauty_predictor.beauty(im_resized, bbox_dim) diff --git a/megapixels/commands/demo/face_detection.py b/megapixels/commands/demo/face_detection.py index fb23704b..488cc80d 100644 --- a/megapixels/commands/demo/face_detection.py +++ b/megapixels/commands/demo/face_detection.py @@ -39,8 +39,6 @@ def cli(ctx, opt_fp_in, opt_fp_out, opt_gpu, opt_size, opt_force, opt_display): 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 diff --git a/megapixels/commands/demo/face_emotion.py b/megapixels/commands/demo/face_emotion.py new file mode 100644 index 00000000..5e06eace --- /dev/null +++ b/megapixels/commands/demo/face_emotion.py @@ -0,0 +1,106 @@ +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='Imemotion 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 imemotion size') +@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=False, + help='Display detections to debug') +@click.pass_context +def cli(ctx, opt_fp_in, opt_fp_out, opt_gpu, opt_size, opt_force, opt_display): + """Face detector demo""" + + 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 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_emotion + from app.models.data_store import DataStore + + + log = logger_utils.Logger.getLogger() + + + # ------------------------------------------------- + # load imemotion + + 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.DetectorDLIBCNN(gpu=opt_gpu) # -1 for CPU + bboxes = face_detector.detect(im_resized, largest=True) + bbox = bboxes[0] + dim = im_resized.shape[:2][::-1] + bbox_dim = bbox.to_dim(dim) + if not bbox: + log.error('no face detected') + return + else: + log.info(f'face detected: {bbox_dim.to_xyxy()}') + + + # ---------------------------------------------------------------------------- + # emotion + + emotion_predictor = face_emotion.FaceEmotion(gpu=opt_gpu) + emotion_score = emotion_predictor.emotion(im_resized, bbox_dim) + + + # ---------------------------------------------------------------------------- + # output + + log.info(f'Face coords: {bbox_dim} face') + log.info(f'emotion score: {(100*emotion_score):.2f}') + + + # ---------------------------------------------------------------------------- + # draw + + # draw 2d landmarks + im_emotion = im_resized.copy() + draw_utils.draw_bbox(im_emotion, bbox_dim) + txt = f'emotion score: {(100*emotion_score):.2f}' + draw_utils.draw_text(im_emotion, bbox_dim.pt_tl, txt) + + + # ---------------------------------------------------------------------------- + # save + + if opt_fp_out: + # save pose only + cv.imwrite(opt_fp_out, im_emotion) + + + # ---------------------------------------------------------------------------- + # display + + if opt_display: + # show all imemotions here + cv.imshow('emotion', im_emotion) + display_utils.handle_keyboard()
\ No newline at end of file diff --git a/megapixels/commands/demo/face_gender.py b/megapixels/commands/demo/face_gender.py new file mode 100644 index 00000000..8e8c86f3 --- /dev/null +++ b/megapixels/commands/demo/face_gender.py @@ -0,0 +1,106 @@ +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='Imgender 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 imgender size') +@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=False, + help='Display detections to debug') +@click.pass_context +def cli(ctx, opt_fp_in, opt_fp_out, opt_gpu, opt_size, opt_force, opt_display): + """Face detector demo""" + + 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 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_gender + from app.models.data_store import DataStore + + + log = logger_utils.Logger.getLogger() + + + # ------------------------------------------------- + # load imgender + + 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.DetectorDLIBCNN(gpu=opt_gpu) # -1 for CPU + bboxes = face_detector.detect(im_resized, largest=True) + bbox = bboxes[0] + dim = im_resized.shape[:2][::-1] + bbox_dim = bbox.to_dim(dim) + if not bbox: + log.error('no face detected') + return + else: + log.info(f'face detected: {bbox_dim.to_xyxy()}') + + + # ---------------------------------------------------------------------------- + # gender + + gender_predictor = face_gender.FaceGender(gpu=opt_gpu) + gender_score = gender_predictor.gender(im_resized, bbox_dim) + + + # ---------------------------------------------------------------------------- + # output + + log.info(f'Face coords: {bbox_dim} face') + log.info(f'gender score: {(100*gender_score):.2f}') + + + # ---------------------------------------------------------------------------- + # draw + + # draw 2d landmarks + im_gender = im_resized.copy() + draw_utils.draw_bbox(im_gender, bbox_dim) + txt = f'gender score: {(100*gender_score):.2f}' + draw_utils.draw_text(im_gender, bbox_dim.pt_tl, txt) + + + # ---------------------------------------------------------------------------- + # save + + if opt_fp_out: + # save pose only + cv.imwrite(opt_fp_out, im_gender) + + + # ---------------------------------------------------------------------------- + # display + + if opt_display: + # show all imgenders here + cv.imshow('gender', im_gender) + display_utils.handle_keyboard()
\ No newline at end of file diff --git a/megapixels/commands/demo/face_vector.py b/megapixels/commands/demo/face_vector.py index 1104f923..3ff68001 100644 --- a/megapixels/commands/demo/face_vector.py +++ b/megapixels/commands/demo/face_vector.py @@ -68,10 +68,11 @@ def cli(ctx, opt_fp_in, opt_gpu, opt_size, opt_display): # generate face vectors, only to test if feature extraction works from app.processors import face_recognition - face_rec = face_recognition.RecognitionDLIB() - vec = face_rec.vec(im_resized, bbox_dim) + facerec = face_recognition.RecognitionDLIB() + vec = facerec.vec(im_resized, bbox_dim) + vec_flat = facerec.flatten(vec) log.info(f'generated vector. showing vec[0:10]:') - log.info(f'\n{vec[0:10]}') + log.info(f'\n{vec_flat}') if opt_display: draw_utils.draw_bbox(im_resized, bbox_dim) |
