summaryrefslogtreecommitdiff
path: root/megapixels/app/processors/face_beauty.py
blob: e2d54c981a511d5d40212b042f0cf95b3f4f9a2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
"""
https://github.com/ustcqidi/BeautyPredict
"""

import sys
import os
from os.path import join
from pathlib import Path
import math

import cv2 as cv
import numpy as np
import imutils
import pickle

import keras
from keras.layers import Conv2D, Input, MaxPool2D,Flatten, Dense, Permute, GlobalAveragePooling2D
from keras.models import Model
from keras.optimizers import adam
from keras.models import Sequential
from keras.applications.resnet50 import ResNet50
#from keras.applications.resnet50 import Dense
from keras.layers import Dense
from keras.optimizers import Adam
from keras.layers import Dropout

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 FaceBeauty:

  # Estimates beauty using CNN

  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')
    self.model = Sequential()
    self.model.add(resnet)
    self.model.add(Dense(5, activation='softmax'))
    self.model.layers[0].trainable = False
    fp_model = join(cfg.DIR_MODELS_KERAS, 'model-ldl-resnet.h5')
    self.model.load_weights(fp_model)


  def beauty(self, im, bbox_norm):
    '''Predicts facial "beauty" score based on SCUT-FBP attractiveness labels
    :param im: (numpy.ndarray) BGR image
    :param bbox_dim: (BBox) dimensioned BBox
    :returns (float) 0.0-1.0 with 1 being most attractive
    '''
    dim = im.shape[:2][::-1]
    roi = bbox_norm.to_dim(dim).to_xyxy()
    cropped_im = im[roi[1]:roi[3], roi[0]:roi[2]]
    im_resized = cv.resize(cropped_im, (224, 224))  # force size
    im_norm = np.array([(im_resized - 127.5) / 127.5])  # subtract mean

    # forward pass
    pred = self.model.predict(im_norm)

    # combines score to make final estimate?
    ldList = pred[0]
    score = 1 * ldList[0] + 2 * ldList[1] + 3 * ldList[2] + 4 * ldList[3] + 5 * ldList[4]
    return score/5.0


  def score_mapping(self, score):
    '''(deprecated)
    '''

    # if score <= 1.9:
    #   score_mapped = ((4 - 2.5) / (1.9 - 1.0)) * (score-1.0) + 2.5
    # elif score <= 2.8:
    #   score_mapped = ((5.5 - 4) / (2.8 - 1.9)) * (score-1.9) + 4
    # elif score <= 3.4:
    #   score_mapped = ((6.5 - 5.5) / (3.4 - 2.8)) * (score-2.8) + 5.5
    # elif score <= 4:
    #   score_mapped = ((8 - 6.5) / (4 - 3.4)) * (score-3.4) + 6.5
    # elif score < 5:
    #   score_mapped = ((9 - 8) / (5 - 4)) * (score-4) + 8

    # return score_mapped
    return False