import cv2 import numpy as np def umeyama(src, dst, estimate_scale): num = src.shape[0] dim = src.shape[1] src_mean = src.mean(axis=0) dst_mean = dst.mean(axis=0) src_demean = src - src_mean dst_demean = dst - dst_mean A = np.dot(dst_demean.T, src_demean) / num d = np.ones((dim,), dtype=np.double) if np.linalg.det(A) < 0: d[dim - 1] = -1 T = np.eye(dim + 1, dtype=np.double) U, S, V = np.linalg.svd(A) rank = np.linalg.matrix_rank(A) if rank == 0: return np.nan * T elif rank == dim - 1: if np.linalg.det(U) * np.linalg.det(V) > 0: T[:dim, :dim] = np.dot(U, V) else: s = d[dim - 1] d[dim - 1] = -1 T[:dim, :dim] = np.dot(U, np.dot(np.diag(d), V)) d[dim - 1] = s else: T[:dim, :dim] = np.dot(U, np.dot(np.diag(d), V.T)) if estimate_scale: scale = 1.0 / src_demean.var(axis=0).sum() * np.dot(S, d) else: scale = 1.0 T[:dim, dim] = dst_mean - scale * np.dot(T[:dim, :dim], src_mean.T) T[:dim, :dim] *= scale return T arcface_dst = np.array( [[38.2946, 51.6963], [73.5318, 51.5014], [56.0252, 71.7366], [41.5493, 92.3655], [70.7299, 92.2041]], dtype=np.float32) def estimate_norm(lmk, image_size=112, mode='arcface'): assert lmk.shape == (5, 2) assert image_size % 112 == 0 or image_size % 128 == 0 if image_size % 112 == 0: ratio = float(image_size) / 112.0 diff_x = 0 else: ratio = float(image_size) / 128.0 diff_x = 8.0 * ratio dst = arcface_dst * ratio dst[:, 0] += diff_x M = umeyama(lmk, dst, True)[0:2, :] return M def norm_crop2(img, landmark, image_size=112, mode='arcface'): M = estimate_norm(landmark, image_size, mode) warped = cv2.warpAffine(img, M, (image_size, image_size), borderValue=0.0, borderMode=cv2.BORDER_REPLICATE) return warped, M def get_cropped_head(img, landmark, scale=1.4): # it is ugly but works :D center = np.mean(landmark, axis=0) landmark = center + (landmark - center) * scale M = estimate_norm(landmark, 128, mode='arcface') warped = cv2.warpAffine(img, M/0.25, (512, 512), borderValue=0.0) return warped