diff --git a/cv/controllers.py b/cv/controllers.py index 4251e6a..9577886 100644 --- a/cv/controllers.py +++ b/cv/controllers.py @@ -3,7 +3,9 @@ import time from random import randint +import cv2 from django.http import HttpResponse +from mtcnn.mtcnn import MTCNN BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -60,3 +62,30 @@ def upload_and_rec(request): json_result = json.dumps(result, ensure_ascii=False) return HttpResponse(json_result) + + +def detect_face(img_path): + """ + detect face with MTCNN + :param img_path: + :return: + """ + img = cv2.imread(img_path) + detector = MTCNN() + mtcnn_result = detector.detect_faces(img) + + return mtcnn_result + + +class BeautyRecognizer: + def __init__(self, pretrained_model): + self.model = None + + def infer(self, img_path): + img = cv2.imread(img_path) + mtcnn_result = detect_face(img_path) + bbox = mtcnn_result['box'] + face_region = img[bbox[0] - int(bbox[2] / 2): bbox[0] + int(bbox[2] / 2), + bbox[1] - int(bbox[3] / 2): bbox[1] + int(bbox[3] / 2)] + + return self.model.infer(face_region) diff --git a/cv/features.py b/cv/features.py new file mode 100644 index 0000000..385f730 --- /dev/null +++ b/cv/features.py @@ -0,0 +1,116 @@ +""" +feature extractor +""" +import cv2 +import dlib +import numpy as np +import skimage.color +from skimage import io +from skimage.feature import hog, local_binary_pattern, corner_harris + +DLIB_MODEL = "E:\ModelZoo\shape_predictor_68_face_landmarks.dat" +predictor = dlib.shape_predictor(DLIB_MODEL) +detector = dlib.get_frontal_face_detector() + + +def HOG(img_path): + """ + extract HOG feature + :param img_path: + :return: + :version: 1.0 + """ + img = io.imread(img_path) + img = skimage.color.rgb2gray(img) + img = (img - np.mean(img)) / np.std(img) + feature = hog(img, orientations=8, pixels_per_cell=(16, 16), cells_per_block=(1, 1), block_norm='L2-Hys') + + return feature + + +def LBP(img_path): + """ + extract LBP features + :param img_path: + :return: + """ + img = io.imread(img_path) + img = skimage.color.rgb2gray(img) + img = (img - np.mean(img)) / np.std(img) + feature = local_binary_pattern(img, P=8, R=0.2) + # im = Image.fromarray(np.uint8(feature)) + # im.show() + + return feature.reshape(feature.shape[0] * feature.shape[1]) + + +def LBP_from_cv(img): + """ + extract LBP features from opencv region + :param img: + :return: + """ + img = skimage.color.rgb2gray(img) + img = (img - np.mean(img)) / np.std(img) + feature = local_binary_pattern(img, P=8, R=0.2) + # im = Image.fromarray(np.uint8(feature)) + # im.show() + + return feature.reshape(feature.shape[0] * feature.shape[1]) + + +def HARRIS(img_path): + """ + extract HARR features + :param img_path: + :return: + :Version:1.0 + """ + img = io.imread(img_path) + img = skimage.color.rgb2gray(img) + img = (img - np.mean(img)) / np.std(img) + feature = corner_harris(img, method='k', k=0.05, eps=1e-06, sigma=1) + + return feature.reshape(feature.shape[0] * feature.shape[1]) + + +def RAW(img_path): + img = io.imread(img_path) + img = skimage.color.rgb2gray(img) + img = (img - np.mean(img)) / np.std(img) + + return img.reshape(img.shape[0] * img.shape[1]) + + +def HOG_from_cv(img): + """ + extract HOG feature from opencv image object + :param img: + :return: + :Version:1.0 + """ + img = skimage.color.rgb2gray(img) + img = (img - np.mean(img)) / np.std(img) + + return hog(img, orientations=8, pixels_per_cell=(16, 16), cells_per_block=(1, 1), block_norm='L2-Hys') + + +def Geo_from_cv(img): + """ + 68 facial landmarks as geometry feature + :param img: + :return: + """ + faces = detector(img, 1) + + result = {} + if len(faces) > 0: + for k, d in enumerate(faces): + shape = predictor(img, d) + result[k] = {"bbox": [d.left(), d.top(), d.right(), d.bottom()], + "landmarks": [[shape.part(i).x, shape.part(i).y] for i in range(68)]} + + xs = np.array([_[0] for _ in result['landmarks']]) + ys = np.array([_[1] for _ in result['landmarks']]) + + return list(xs - np.mean(xs)) + list(ys - np.mean(ys)) diff --git a/cv/train_and_test_fbp_with_ml.py b/cv/train_and_test_fbp_with_ml.py new file mode 100644 index 0000000..09b810f --- /dev/null +++ b/cv/train_and_test_fbp_with_ml.py @@ -0,0 +1,84 @@ +""" +train and test FBP with traditional ML, instead of DL +""" +import os +import sys + +import pandas as pd +from mtcnn.mtcnn import MTCNN +from sklearn.externals import joblib +from sklearn.model_selection import train_test_split +from sklearn.ensemble import RandomForestRegressor +from sklearn.metrics import mean_absolute_error, mean_squared_error + +sys.path.append('../') +from cv.features import * + +SCUT5500_DIR = "E:\DataSet\CV\SCUT-FBP5500\Images" +LABEL_CSV = "E:\DataSet\CV\SCUT-FBP5500/train_test_files\SCUT-FBP5500-With-Head.csv" + + +def prepare_data(): + features = [] + lbs = [] + + df = pd.read_csv(LABEL_CSV) + files = df['file'] + scores = df['score'] + detector = MTCNN() + + for i in range(len(files)): + img = cv2.imread(os.path.join(SCUT5500_DIR, files[i])) + mtcnn_result = detector.detect_faces(img) + bbox = mtcnn_result['box'] + + if bbox is not None: + face_region = img[bbox[0] - int(bbox[2] / 2): bbox[0] + int(bbox[2] / 2), + bbox[1] - int(bbox[3] / 2): bbox[1] + int(bbox[3] / 2)] + ratio = max(face_region[0], face_region[1]) / min(face_region[0], face_region[1]) + if face_region[0] > face_region[1]: + face_region = cv2.resize(face_region, (int((face_region[0] / ratio) * 64 / face_region[1]), 64)) + else: + face_region = cv2.resize(face_region, (64, int((face_region[1] / ratio) * 64 / face_region[0]))) + else: + face_region = cv2.resize(img, (64, 64)) + + lbp = LBP_from_cv(face_region) + hog = HOG_from_cv(face_region) + ldmk = Geo_from_cv(img) + + feature = lbp + hog + ldmk + features.append(feature) + lbs.append(scores[i]) + + return features, lbs + + +def train_fbp(X, y): + X_train, X_test, y_train, y_test = train_test_split( + X, y, test_size=0.2, random_state=42) + + rfreg = RandomForestRegressor() + print('start training Random Forest Regressor...') + rfreg.fit(X_train, y_train) + + if not os.path.exists('./model'): + os.makedirs('./model') + + joblib.dump(rfreg, './model/RandomForestRegressor.pkl') + print('The regression model has been persisted...') + + y_pred = rfreg.predict(X_test) + + mae_lr = round(mean_absolute_error(y_test, np.array(y_pred).ravel()), 4) + rmse_lr = round(np.math.sqrt(mean_squared_error(np.array(y_test), np.array(y_pred).ravel())), 4) + pc = round(np.corrcoef(np.array(y_test), np.array(y_pred).ravel())[0, 1], 4) + + print('===============The Mean Absolute Error of ANet is {0}===================='.format(mae_lr)) + print('===============The Root Mean Square Error of ANet is {0}===================='.format(rmse_lr)) + print('===============The Pearson Correlation of ANet is {0}===================='.format(pc)) + + +if __name__ == '__main__': + X, y = prepare_data() + train_fbp(X, y) diff --git a/cv/urls.py b/cv/urls.py index 35236b5..b503066 100644 --- a/cv/urls.py +++ b/cv/urls.py @@ -6,7 +6,7 @@ urlpatterns = [ path('welcome', views.welcome, name='welcome'), path('index', views.index, name='index'), - path('facerank', views.facerank, name='facerank'), - url('fbp', views.fbp, name='fbp'), + path('fbp', views.fbp, name='fbp'), + url('fbpview', views.fbp_view, name='fbpview'), url('detectface', views.detect_face, name='detectface'), ] diff --git a/cv/views.py b/cv/views.py index 750bcbb..22bb77d 100644 --- a/cv/views.py +++ b/cv/views.py @@ -26,12 +26,12 @@ def index(request): return render(request, 'index.html') -def facerank(request): +def fbp(request): from cv import controllers return controllers.upload_and_rec(request) -def fbp(request): +def fbp_view(request): return render(request, 'fbp.html')