faceSwap.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. #include <fstream>
  4. #include <string>
  5. using namespace cv;
  6. using namespace std;
  7. //Read points from text file
  8. vector<Point2f> readPoints(string pointsFileName){
  9. vector<Point2f> points;
  10. ifstream ifs (pointsFileName.c_str());
  11. float x, y;
  12. int count = 0;
  13. while(ifs >> x >> y)
  14. {
  15. points.push_back(Point2f(x,y));
  16. }
  17. return points;
  18. }
  19. // Apply affine transform calculated using srcTri and dstTri to src
  20. void applyAffineTransform(Mat &warpImage, Mat &src, vector<Point2f> &srcTri, vector<Point2f> &dstTri)
  21. {
  22. // Given a pair of triangles, find the affine transform.
  23. Mat warpMat = getAffineTransform( srcTri, dstTri );
  24. // Apply the Affine Transform just found to the src image
  25. warpAffine( src, warpImage, warpMat, warpImage.size(), INTER_LINEAR, BORDER_REFLECT_101);
  26. }
  27. // Calculate Delaunay triangles for set of points
  28. // Returns the vector of indices of 3 points for each triangle
  29. static void calculateDelaunayTriangles(Rect rect, vector<Point2f> &points, vector< vector<int> > &delaunayTri){
  30. // Create an instance of Subdiv2D
  31. Subdiv2D subdiv(rect);
  32. // Insert points into subdiv
  33. for( vector<Point2f>::iterator it = points.begin(); it != points.end(); it++)
  34. subdiv.insert(*it);
  35. vector<Vec6f> triangleList;
  36. subdiv.getTriangleList(triangleList);
  37. vector<Point2f> pt(3);
  38. vector<int> ind(3);
  39. for( size_t i = 0; i < triangleList.size(); i++ )
  40. {
  41. Vec6f t = triangleList[i];
  42. pt[0] = Point2f(t[0], t[1]);
  43. pt[1] = Point2f(t[2], t[3]);
  44. pt[2] = Point2f(t[4], t[5 ]);
  45. if ( rect.contains(pt[0]) && rect.contains(pt[1]) && rect.contains(pt[2])){
  46. for(int j = 0; j < 3; j++)
  47. for(size_t k = 0; k < points.size(); k++)
  48. if(abs(pt[j].x - points[k].x) < 1.0 && abs(pt[j].y - points[k].y) < 1)
  49. ind[j] = k;
  50. delaunayTri.push_back(ind);
  51. }
  52. }
  53. }
  54. // Warps and alpha blends triangular regions from img1 and img2 to img
  55. void warpTriangle(Mat &img1, Mat &img2, vector<Point2f> &t1, vector<Point2f> &t2)
  56. {
  57. Rect r1 = boundingRect(t1);
  58. Rect r2 = boundingRect(t2);
  59. // Offset points by left top corner of the respective rectangles
  60. vector<Point2f> t1Rect, t2Rect;
  61. vector<Point> t2RectInt;
  62. for(int i = 0; i < 3; i++)
  63. {
  64. t1Rect.push_back( Point2f( t1[i].x - r1.x, t1[i].y - r1.y) );
  65. t2Rect.push_back( Point2f( t2[i].x - r2.x, t2[i].y - r2.y) );
  66. t2RectInt.push_back( Point(t2[i].x - r2.x, t2[i].y - r2.y) ); // for fillConvexPoly
  67. }
  68. // Get mask by filling triangle
  69. Mat mask = Mat::zeros(r2.height, r2.width, CV_32FC3);
  70. fillConvexPoly(mask, t2RectInt, Scalar(1.0, 1.0, 1.0), 16, 0);
  71. // Apply warpImage to small rectangular patches
  72. Mat img1Rect;
  73. img1(r1).copyTo(img1Rect);
  74. Mat img2Rect = Mat::zeros(r2.height, r2.width, img1Rect.type());
  75. applyAffineTransform(img2Rect, img1Rect, t1Rect, t2Rect);
  76. multiply(img2Rect,mask, img2Rect);
  77. multiply(img2(r2), Scalar(1.0,1.0,1.0) - mask, img2(r2));
  78. img2(r2) = img2(r2) + img2Rect;
  79. }
  80. int main( int argc, char** argv)
  81. {
  82. //Read input images
  83. string filename1 = "ted_cruz.jpg";
  84. string filename2 = "donald_trump.jpg";
  85. Mat img1 = imread(filename1);
  86. Mat img2 = imread(filename2);
  87. Mat img1Warped = img2.clone();
  88. //Read points
  89. vector<Point2f> points1, points2;
  90. points1 = readPoints(filename1 + ".txt");
  91. points2 = readPoints(filename2 + ".txt");
  92. //convert Mat to float data type
  93. img1.convertTo(img1, CV_32F);
  94. img1Warped.convertTo(img1Warped, CV_32F);
  95. // Find convex hull
  96. vector<Point2f> hull1;
  97. vector<Point2f> hull2;
  98. vector<int> hullIndex;
  99. convexHull(points2, hullIndex, false, false);
  100. for(int i = 0; i < hullIndex.size(); i++)
  101. {
  102. hull1.push_back(points1[hullIndex[i]]);
  103. hull2.push_back(points2[hullIndex[i]]);
  104. }
  105. // Find delaunay triangulation for points on the convex hull
  106. vector< vector<int> > dt;
  107. Rect rect(0, 0, img1Warped.cols, img1Warped.rows);
  108. calculateDelaunayTriangles(rect, hull2, dt);
  109. // Apply affine transformation to Delaunay triangles
  110. for(size_t i = 0; i < dt.size(); i++)
  111. {
  112. vector<Point2f> t1, t2;
  113. // Get points for img1, img2 corresponding to the triangles
  114. for(size_t j = 0; j < 3; j++)
  115. {
  116. t1.push_back(hull1[dt[i][j]]);
  117. t2.push_back(hull2[dt[i][j]]);
  118. }
  119. warpTriangle(img1, img1Warped, t1, t2);
  120. }
  121. // Calculate mask
  122. vector<Point> hull8U;
  123. for(int i = 0; i < hull2.size(); i++)
  124. {
  125. Point pt(hull2[i].x, hull2[i].y);
  126. hull8U.push_back(pt);
  127. }
  128. Mat mask = Mat::zeros(img2.rows, img2.cols, img2.depth());
  129. fillConvexPoly(mask,&hull8U[0], hull8U.size(), Scalar(255,255,255));
  130. // Clone seamlessly.
  131. Rect r = boundingRect(hull2);
  132. Point center = (r.tl() + r.br()) / 2;
  133. Mat output;
  134. img1Warped.convertTo(img1Warped, CV_8UC3);
  135. seamlessClone(img1Warped,img2, mask, center, output, NORMAL_CLONE);
  136. imshow("Face Swapped", output);
  137. waitKey(0);
  138. destroyAllWindows();
  139. return 1;
  140. }