summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--megapixels/app/processors/face_age.py8
-rw-r--r--megapixels/app/processors/face_beauty.py6
-rw-r--r--megapixels/app/processors/face_detector.py11
-rw-r--r--megapixels/app/processors/face_emotion.py10
-rw-r--r--megapixels/app/processors/face_gender.py9
-rw-r--r--megapixels/app/processors/face_landmarks_3d.py99
-rw-r--r--megapixels/app/processors/face_recognition.py9
-rw-r--r--megapixels/app/settings/app_cfg.py1
-rw-r--r--megapixels/app/utils/draw_utils.py8
-rw-r--r--megapixels/commands/cv/face_roi.py4
-rw-r--r--megapixels/commands/cv/face_vector.py8
-rw-r--r--megapixels/commands/demo/face_age.py106
-rw-r--r--megapixels/commands/demo/face_beauty.py28
-rw-r--r--megapixels/commands/demo/face_detection.py2
-rw-r--r--megapixels/commands/demo/face_emotion.py106
-rw-r--r--megapixels/commands/demo/face_gender.py106
-rw-r--r--megapixels/commands/demo/face_vector.py7
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)