baldgan / bald_face.py
leonelhs's picture
init space
ff65b0b
#############################################################################
#
# Source from:
# https://github.com/leonelhs/baldgan
# Forked from:
# https://github.com/david-svitov/baldgan
# Reimplemented by: Leonel Hernández
#
##############################################################################
import os
import PIL.Image
import cv2
import numpy as np
from retinaface import RetinaFace
from skimage import transform as trans
from huggingface_hub import hf_hub_download
from baldgan.model import buildModel
BALDGAN_REPO_ID = "leonelhs/baldgan"
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" # see issue #152
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
gpu_id = -1
image_size = [256, 256]
src = np.array([
[30.2946, 51.6963],
[65.5318, 51.5014],
[48.0252, 71.7366],
[33.5493, 92.3655],
[62.7299, 92.2041]], dtype=np.float32)
src[:, 0] += 8.0
src[:, 0] += 15.0
src[:, 1] += 30.0
src /= 112
src *= 200
def list2array(values):
return np.array(list(values))
def align_face(img):
faces = RetinaFace.detect_faces(img)
bounding_boxes = np.array([list2array(faces[face]['facial_area']) for face in faces])
points = np.array([list2array(faces[face]['landmarks'].values()) for face in faces])
white_image = np.ones(img.shape, dtype=np.uint8) * 255
result_faces = []
result_masks = []
result_matrix = []
if bounding_boxes.shape[0] > 0:
det = bounding_boxes[:, 0:4]
for i in range(det.shape[0]):
_det = det[i]
dst = points[i]
tform = trans.SimilarityTransform()
tform.estimate(dst, src)
M = tform.params[0:2, :]
warped = cv2.warpAffine(img, M, (image_size[1], image_size[0]), borderValue=0.0)
mask = cv2.warpAffine(white_image, M, (image_size[1], image_size[0]), borderValue=0.0)
result_faces.append(warped)
result_masks.append(mask)
result_matrix.append(tform.params[0:3, :])
return result_faces, result_masks, result_matrix
def put_face_back(img, faces, masks, result_matrix):
for i in range(len(faces)):
M = np.linalg.inv(result_matrix[i])[0:2]
warped = cv2.warpAffine(faces[i], M, (img.shape[1], img.shape[0]), borderValue=0.0)
mask = cv2.warpAffine(masks[i], M, (img.shape[1], img.shape[0]), borderValue=0.0)
mask = mask // 255
img = img * (1 - mask)
img = img.astype(np.uint8)
img += warped * mask
return img
class BaldFace:
def __init__(self):
self.model = buildModel()
model_path = hf_hub_download(repo_id=BALDGAN_REPO_ID, filename='model_G_5_170.hdf5')
self.model.load_weights(model_path)
def make(self, image):
# image = np.array(image)
faces, masks, matrix = align_face(image)
result_faces = []
for face in faces:
input_face = np.expand_dims(face, axis=0)
input_face = input_face / 127.5 - 1.
result = self.model.predict(input_face)[0]
result = ((result + 1.) * 127.5)
result = result.astype(np.uint8)
result_faces.append(result)
img_result = put_face_back(image, result_faces, masks, matrix)
return PIL.Image.fromarray(img_result)