faceMorph.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/usr/bin/env python
  2. import numpy as np
  3. import cv2
  4. import sys
  5. # Read points from text file
  6. def readPoints(path) :
  7. # Create an array of points.
  8. points = [];
  9. # Read points
  10. with open(path) as file :
  11. for line in file :
  12. x, y = line.split()
  13. points.append((int(x), int(y)))
  14. return points
  15. # Apply affine transform calculated using srcTri and dstTri to src and
  16. # output an image of size.
  17. def applyAffineTransform(src, srcTri, dstTri, size) :
  18. # Given a pair of triangles, find the affine transform.
  19. warpMat = cv2.getAffineTransform( np.float32(srcTri), np.float32(dstTri) )
  20. # Apply the Affine Transform just found to the src image
  21. dst = cv2.warpAffine( src, warpMat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 )
  22. return dst
  23. # Warps and alpha blends triangular regions from img1 and img2 to img
  24. def morphTriangle(img1, img2, img, t1, t2, t, alpha) :
  25. # Find bounding rectangle for each triangle
  26. r1 = cv2.boundingRect(np.float32([t1]))
  27. r2 = cv2.boundingRect(np.float32([t2]))
  28. r = cv2.boundingRect(np.float32([t]))
  29. # Offset points by left top corner of the respective rectangles
  30. t1Rect = []
  31. t2Rect = []
  32. tRect = []
  33. for i in range(0, 3):
  34. tRect.append(((t[i][0] - r[0]),(t[i][1] - r[1])))
  35. t1Rect.append(((t1[i][0] - r1[0]),(t1[i][1] - r1[1])))
  36. t2Rect.append(((t2[i][0] - r2[0]),(t2[i][1] - r2[1])))
  37. # Get mask by filling triangle
  38. mask = np.zeros((r[3], r[2], 3), dtype = np.float32)
  39. cv2.fillConvexPoly(mask, np.int32(tRect), (1.0, 1.0, 1.0), 16, 0);
  40. # Apply warpImage to small rectangular patches
  41. img1Rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
  42. img2Rect = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]]
  43. size = (r[2], r[3])
  44. warpImage1 = applyAffineTransform(img1Rect, t1Rect, tRect, size)
  45. warpImage2 = applyAffineTransform(img2Rect, t2Rect, tRect, size)
  46. # Alpha blend rectangular patches
  47. imgRect = (1.0 - alpha) * warpImage1 + alpha * warpImage2
  48. # Copy triangular region of the rectangular patch to the output image
  49. img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] = img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] * ( 1 - mask ) + imgRect * mask
  50. if __name__ == '__main__' :
  51. filename1 = 'hillary_clinton.jpg'
  52. filename2 = 'ted_cruz.jpg'
  53. alpha = 0.5
  54. # Read images
  55. img1 = cv2.imread(filename1);
  56. img2 = cv2.imread(filename2);
  57. # Convert Mat to float data type
  58. img1 = np.float32(img1)
  59. img2 = np.float32(img2)
  60. # Read array of corresponding points
  61. points1 = readPoints(filename1 + '.txt')
  62. points2 = readPoints(filename2 + '.txt')
  63. points = [];
  64. # Compute weighted average point coordinates
  65. for i in range(0, len(points1)):
  66. x = ( 1 - alpha ) * points1[i][0] + alpha * points2[i][0]
  67. y = ( 1 - alpha ) * points1[i][1] + alpha * points2[i][1]
  68. points.append((x,y))
  69. # Allocate space for final output
  70. imgMorph = np.zeros(img1.shape, dtype = img1.dtype)
  71. # Read triangles from tri.txt
  72. with open("tri.txt") as file :
  73. for line in file :
  74. x,y,z = line.split()
  75. x = int(x)
  76. y = int(y)
  77. z = int(z)
  78. t1 = [points1[x], points1[y], points1[z]]
  79. t2 = [points2[x], points2[y], points2[z]]
  80. t = [ points[x], points[y], points[z] ]
  81. # Morph one triangle at a time.
  82. morphTriangle(img1, img2, imgMorph, t1, t2, t, alpha)
  83. # Display Result
  84. cv2.imshow("Morphed Face", np.uint8(imgMorph))
  85. cv2.waitKey(0)