| | """This script contains the image preprocessing code for Deep3DFaceRecon_pytorch |
| | """ |
| |
|
| | import numpy as np |
| | from scipy.io import loadmat |
| | from PIL import Image |
| | import cv2 |
| | import os |
| | from skimage import transform as trans |
| | import torch |
| | import warnings |
| | warnings.filterwarnings("ignore", category=np.VisibleDeprecationWarning) |
| | warnings.filterwarnings("ignore", category=FutureWarning) |
| |
|
| |
|
| | |
| | def POS(xp, x): |
| | npts = xp.shape[1] |
| |
|
| | A = np.zeros([2*npts, 8]) |
| |
|
| | A[0:2*npts-1:2, 0:3] = x.transpose() |
| | A[0:2*npts-1:2, 3] = 1 |
| |
|
| | A[1:2*npts:2, 4:7] = x.transpose() |
| | A[1:2*npts:2, 7] = 1 |
| |
|
| | b = np.reshape(xp.transpose(), [2*npts, 1]) |
| |
|
| | k, _, _, _ = np.linalg.lstsq(A, b) |
| |
|
| | R1 = k[0:3] |
| | R2 = k[4:7] |
| | sTx = k[3] |
| | sTy = k[7] |
| | s = (np.linalg.norm(R1) + np.linalg.norm(R2))/2 |
| | t = np.stack([sTx, sTy], axis=0) |
| |
|
| | return t, s |
| | |
| | |
| | def resize_n_crop_img(img, lm, t, s, target_size=224., mask=None): |
| | w0, h0 = img.size |
| | w = (w0*s).astype(np.int32) |
| | h = (h0*s).astype(np.int32) |
| | left = (w/2 - target_size/2 + float((t[0] - w0/2)*s)).astype(np.int32) |
| | right = left + target_size |
| | up = (h/2 - target_size/2 + float((h0/2 - t[1])*s)).astype(np.int32) |
| | below = up + target_size |
| |
|
| | img = img.resize((w, h), resample=Image.BICUBIC) |
| | img = img.crop((left, up, right, below)) |
| |
|
| | if mask is not None: |
| | mask = mask.resize((w, h), resample=Image.BICUBIC) |
| | mask = mask.crop((left, up, right, below)) |
| |
|
| | lm = np.stack([lm[:, 0] - t[0] + w0/2, lm[:, 1] - |
| | t[1] + h0/2], axis=1)*s |
| | lm = lm - np.reshape( |
| | np.array([(w/2 - target_size/2), (h/2-target_size/2)]), [1, 2]) |
| |
|
| | return img, lm, mask |
| |
|
| | |
| | def extract_5p(lm): |
| | lm_idx = np.array([31, 37, 40, 43, 46, 49, 55]) - 1 |
| | lm5p = np.stack([lm[lm_idx[0], :], np.mean(lm[lm_idx[[1, 2]], :], 0), np.mean( |
| | lm[lm_idx[[3, 4]], :], 0), lm[lm_idx[5], :], lm[lm_idx[6], :]], axis=0) |
| | lm5p = lm5p[[1, 2, 0, 3, 4], :] |
| | return lm5p |
| |
|
| | |
| | def align_img(img, lm, lm3D, mask=None, target_size=224., rescale_factor=102.): |
| | """ |
| | Return: |
| | transparams --numpy.array (raw_W, raw_H, scale, tx, ty) |
| | img_new --PIL.Image (target_size, target_size, 3) |
| | lm_new --numpy.array (68, 2), y direction is opposite to v direction |
| | mask_new --PIL.Image (target_size, target_size) |
| | |
| | Parameters: |
| | img --PIL.Image (raw_H, raw_W, 3) |
| | lm --numpy.array (68, 2), y direction is opposite to v direction |
| | lm3D --numpy.array (5, 3) |
| | mask --PIL.Image (raw_H, raw_W, 3) |
| | """ |
| |
|
| | w0, h0 = img.size |
| | if lm.shape[0] != 5: |
| | lm5p = extract_5p(lm) |
| | else: |
| | lm5p = lm |
| |
|
| | |
| | t, s = POS(lm5p.transpose(), lm3D.transpose()) |
| | s = rescale_factor/s |
| |
|
| | |
| | img_new, lm_new, mask_new = resize_n_crop_img(img, lm, t, s, target_size=target_size, mask=mask) |
| | trans_params = np.array([w0, h0, s, t[0], t[1]]) |
| |
|
| | return trans_params, img_new, lm_new, mask_new |
| |
|