align_and_crop.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import cv2
  2. import numpy as np
  3. from .crop_or_pad import crop_or_pad as _crop_or_pad
  4. def get_similarity_transform(src_pts, dst_pts):
  5. """Get similarity transform matrix from src_pts to dst_pts
  6. Args:
  7. src_pts: Kx2 np.array
  8. source points matrix, each row is a pair of coordinates (x, y)
  9. dst_pts: Kx2 np.array
  10. destination points matrix, each row is a pair of coordinates (x, y)
  11. Returns:
  12. xform_matrix: 3x3 np.array
  13. transform matrix from src_pts to dst_pts
  14. """
  15. src_pts = np.asarray(src_pts)
  16. dst_pts = np.asarray(dst_pts)
  17. assert src_pts.ndim == 2
  18. assert dst_pts.ndim == 2
  19. assert src_pts.shape[-1] == 2
  20. assert dst_pts.shape[-1] == 2
  21. npts = src_pts.shape[0]
  22. A = np.empty((npts * 2, 4))
  23. b = np.empty((npts * 2,))
  24. for k in range(npts):
  25. A[2 * k + 0] = [src_pts[k, 0], -src_pts[k, 1], 1, 0]
  26. A[2 * k + 1] = [src_pts[k, 1], src_pts[k, 0], 0, 1]
  27. b[2 * k + 0] = dst_pts[k, 0]
  28. b[2 * k + 1] = dst_pts[k, 1]
  29. x = np.linalg.lstsq(A, b)[0]
  30. xform_matrix = np.empty((3, 3))
  31. xform_matrix[0] = [x[0], -x[1], x[2]]
  32. xform_matrix[1] = [x[1], x[0], x[3]]
  33. xform_matrix[2] = [0, 0, 1]
  34. return xform_matrix
  35. def align_and_crop(image, landmarks, std_landmarks, align_size,
  36. crop_size=None, crop_center=None,
  37. return_transform_matrix=False):
  38. landmarks = np.asarray(landmarks)
  39. std_landmarks = np.asarray(std_landmarks)
  40. xform_matrix = get_similarity_transform(landmarks, std_landmarks)
  41. landmarks_ex = np.pad(landmarks, ((0,0),(0,1)), mode='constant', constant_values=1)
  42. dst_landmarks = np.dot(landmarks_ex, xform_matrix[:2,:].T)
  43. dst_image = cv2.warpAffine(image, xform_matrix[:2,:], dsize=align_size)
  44. if crop_size is not None:
  45. crop_center_ex = (crop_center[0], crop_center[1], 1)
  46. aligned_crop_center = np.dot(xform_matrix, crop_center_ex)
  47. dst_image = _crop_or_pad(dst_image, crop_size, aligned_crop_center)
  48. crop_begin_x = int(round(aligned_crop_center[0] - crop_size[0] / 2.0))
  49. crop_begin_y = int(round(aligned_crop_center[1] - crop_size[1] / 2.0))
  50. dst_landmarks -= np.asarray([[crop_begin_x, crop_begin_y]])
  51. if return_transform_matrix:
  52. return dst_image, dst_landmarks, xform_matrix
  53. else:
  54. return dst_image, dst_landmarks