sample_face_swapping.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include "opencv2/face.hpp"
  2. #include "opencv2/imgproc.hpp"
  3. #include "opencv2/imgcodecs.hpp"
  4. #include "opencv2/highgui.hpp"
  5. #include "opencv2/objdetect.hpp"
  6. #include "opencv2/photo.hpp" // seamlessClone()
  7. #include <iostream>
  8. using namespace cv;
  9. using namespace cv::face;
  10. using namespace std;
  11. static bool myDetector(InputArray image, OutputArray faces, CascadeClassifier *face_cascade)
  12. {
  13. Mat gray;
  14. if (image.channels() > 1)
  15. cvtColor(image, gray, COLOR_BGR2GRAY);
  16. else
  17. gray = image.getMat().clone();
  18. equalizeHist(gray, gray);
  19. std::vector<Rect> faces_;
  20. face_cascade->detectMultiScale(gray, faces_, 1.4, 2, CASCADE_SCALE_IMAGE, Size(30, 30));
  21. Mat(faces_).copyTo(faces);
  22. return true;
  23. }
  24. void divideIntoTriangles(Rect rect, vector<Point2f> &points, vector< vector<int> > &delaunayTri);
  25. void warpTriangle(Mat &img1, Mat &img2, vector<Point2f> &triangle1, vector<Point2f> &triangle2);
  26. //Divide the face into triangles for warping
  27. void divideIntoTriangles(Rect rect, vector<Point2f> &points, vector< vector<int> > &Tri){
  28. // Create an instance of Subdiv2D
  29. Subdiv2D subdiv(rect);
  30. // Insert points into subdiv
  31. for( vector<Point2f>::iterator it = points.begin(); it != points.end(); it++)
  32. subdiv.insert(*it);
  33. vector<Vec6f> triangleList;
  34. subdiv.getTriangleList(triangleList);
  35. vector<Point2f> pt(3);
  36. vector<int> ind(3);
  37. for( size_t i = 0; i < triangleList.size(); i++ )
  38. {
  39. Vec6f triangle = triangleList[i];
  40. pt[0] = Point2f(triangle[0], triangle[1]);
  41. pt[1] = Point2f(triangle[2], triangle[3]);
  42. pt[2] = Point2f(triangle[4], triangle[5]);
  43. if ( rect.contains(pt[0]) && rect.contains(pt[1]) && rect.contains(pt[2])){
  44. for(int j = 0; j < 3; j++)
  45. for(size_t k = 0; k < points.size(); k++)
  46. if(abs(pt[j].x - points[k].x) < 1.0 && abs(pt[j].y - points[k].y) < 1)
  47. ind[j] =(int) k;
  48. Tri.push_back(ind);
  49. }
  50. }
  51. }
  52. void warpTriangle(Mat &img1, Mat &img2, vector<Point2f> &triangle1, vector<Point2f> &triangle2)
  53. {
  54. Rect rectangle1 = boundingRect(triangle1);
  55. Rect rectangle2 = boundingRect(triangle2);
  56. // Offset points by left top corner of the respective rectangles
  57. vector<Point2f> triangle1Rect, triangle2Rect;
  58. vector<Point> triangle2RectInt;
  59. for(int i = 0; i < 3; i++)
  60. {
  61. triangle1Rect.push_back( Point2f( triangle1[i].x - rectangle1.x, triangle1[i].y - rectangle1.y) );
  62. triangle2Rect.push_back( Point2f( triangle2[i].x - rectangle2.x, triangle2[i].y - rectangle2.y) );
  63. triangle2RectInt.push_back( Point((int)(triangle2[i].x - rectangle2.x),(int) (triangle2[i].y - rectangle2.y))); // for fillConvexPoly
  64. }
  65. // Get mask by filling triangle
  66. Mat mask = Mat::zeros(rectangle2.height, rectangle2.width, CV_32FC3);
  67. fillConvexPoly(mask, triangle2RectInt, Scalar(1.0, 1.0, 1.0), 16, 0);
  68. // Apply warpImage to small rectangular patches
  69. Mat img1Rect;
  70. img1(rectangle1).copyTo(img1Rect);
  71. Mat img2Rect = Mat::zeros(rectangle2.height, rectangle2.width, img1Rect.type());
  72. Mat warp_mat = getAffineTransform(triangle1Rect, triangle2Rect);
  73. warpAffine( img1Rect, img2Rect, warp_mat, img2Rect.size(), INTER_LINEAR, BORDER_REFLECT_101);
  74. multiply(img2Rect,mask, img2Rect);
  75. multiply(img2(rectangle2), Scalar(1.0,1.0,1.0) - mask, img2(rectangle2));
  76. img2(rectangle2) = img2(rectangle2) + img2Rect;
  77. }
  78. int main( int argc, char** argv)
  79. {
  80. //Give the path to the directory containing all the files containing data
  81. CommandLineParser parser(argc, argv,
  82. "{ help h usage ? | | give the following arguments in following format }"
  83. "{ image1 i1 | | (required) path to the first image file in which you want to apply swapping }"
  84. "{ image2 i2 | | (required) path to the second image file in which you want to apply face swapping }"
  85. "{ model m | | (required) path to the file containing model to be loaded for face landmark detection}"
  86. "{ face_cascade f | | Path to the face cascade xml file which you want to use as a detector}"
  87. );
  88. // Read in the input arguments
  89. if (parser.has("help")){
  90. parser.printMessage();
  91. cerr << "TIP: Use absolute paths to avoid any problems with the software!" << endl;
  92. return 0;
  93. }
  94. Mat img1=imread(parser.get<string>("image1"));
  95. Mat img2=imread(parser.get<string>("image2"));
  96. if (img1.empty()||img2.empty()){
  97. if(img1.empty()){
  98. parser.printMessage();
  99. cerr << parser.get<string>("image1")<<" not found" << endl;
  100. return -1;
  101. }
  102. if (img2.empty()){
  103. parser.printMessage();
  104. cerr << parser.get<string>("image2")<<" not found" << endl;
  105. return -1;
  106. }
  107. }
  108. string modelfile_name(parser.get<string>("model"));
  109. if (modelfile_name.empty()){
  110. parser.printMessage();
  111. cerr << "Model file name not found." << endl;
  112. return -1;
  113. }
  114. string cascade_name(parser.get<string>("face_cascade"));
  115. if (cascade_name.empty()){
  116. parser.printMessage();
  117. cerr << "The name of the cascade classifier to be loaded to detect faces is not found" << endl;
  118. return -1;
  119. }
  120. //create a pointer to call the base class
  121. //pass the face cascade xml file which you want to pass as a detector
  122. CascadeClassifier face_cascade;
  123. face_cascade.load(cascade_name);
  124. FacemarkKazemi::Params params;
  125. Ptr<FacemarkKazemi> facemark = FacemarkKazemi::create(params);
  126. facemark->setFaceDetector((FN_FaceDetector)myDetector, &face_cascade);
  127. facemark->loadModel(modelfile_name);
  128. cout<<"Loaded model"<<endl;
  129. //vector to store the faces detected in the image
  130. vector<Rect> faces1,faces2;
  131. vector< vector<Point2f> > shape1,shape2;
  132. //Detect faces in the current image
  133. float ratio1 = (float)img1.cols/(float)img1.rows;
  134. float ratio2 = (float)img2.cols/(float)img2.rows;
  135. resize(img1,img1,Size((int)(640*ratio1),(int)(640*ratio1)), 0, 0, INTER_LINEAR_EXACT);
  136. resize(img2,img2,Size((int)(640*ratio2),(int)(640*ratio2)), 0, 0, INTER_LINEAR_EXACT);
  137. Mat img1Warped = img2.clone();
  138. facemark->getFaces(img1,faces1);
  139. facemark->getFaces(img2,faces2);
  140. //Initialise the shape of the faces
  141. facemark->fit(img1,faces1,shape1);
  142. facemark->fit(img2,faces2,shape2);
  143. unsigned long numswaps = (unsigned long)min((unsigned long)shape1.size(),(unsigned long)shape2.size());
  144. for(unsigned long z=0;z<numswaps;z++){
  145. vector<Point2f> points1 = shape1[z];
  146. vector<Point2f> points2 = shape2[z];
  147. img1.convertTo(img1, CV_32F);
  148. img1Warped.convertTo(img1Warped, CV_32F);
  149. // Find convex hull
  150. vector<Point2f> boundary_image1;
  151. vector<Point2f> boundary_image2;
  152. vector<int> index;
  153. convexHull(Mat(points2),index, false, false);
  154. for(size_t i = 0; i < index.size(); i++)
  155. {
  156. boundary_image1.push_back(points1[index[i]]);
  157. boundary_image2.push_back(points2[index[i]]);
  158. }
  159. // Triangulation for points on the convex hull
  160. vector< vector<int> > triangles;
  161. Rect rect(0, 0, img1Warped.cols, img1Warped.rows);
  162. divideIntoTriangles(rect, boundary_image2, triangles);
  163. // Apply affine transformation to Delaunay triangles
  164. for(size_t i = 0; i < triangles.size(); i++)
  165. {
  166. vector<Point2f> triangle1, triangle2;
  167. // Get points for img1, img2 corresponding to the triangles
  168. for(int j = 0; j < 3; j++)
  169. {
  170. triangle1.push_back(boundary_image1[triangles[i][j]]);
  171. triangle2.push_back(boundary_image2[triangles[i][j]]);
  172. }
  173. warpTriangle(img1, img1Warped, triangle1, triangle2);
  174. }
  175. // Calculate mask
  176. vector<Point> hull;
  177. for(size_t i = 0; i < boundary_image2.size(); i++)
  178. {
  179. Point pt((int)boundary_image2[i].x,(int)boundary_image2[i].y);
  180. hull.push_back(pt);
  181. }
  182. Mat mask = Mat::zeros(img2.rows, img2.cols, img2.depth());
  183. fillConvexPoly(mask,&hull[0],(int)hull.size(), Scalar(255,255,255));
  184. // Clone seamlessly.
  185. Rect r = boundingRect(boundary_image2);
  186. Point center = (r.tl() + r.br()) / 2;
  187. Mat output;
  188. img1Warped.convertTo(img1Warped, CV_8UC3);
  189. seamlessClone(img1Warped,img2, mask, center, output, NORMAL_CLONE);
  190. imshow("Face_Swapped", output);
  191. waitKey(0);
  192. destroyAllWindows();
  193. }
  194. return 0;
  195. }