├── kb.png ├── lbj.png ├── lbj.png0.jpg ├── lbj.png1.jpg ├── lbj.png10.jpg ├── lbj.png11.jpg ├── lbj.png2.jpg ├── lbj.png3.jpg ├── lbj.png4.jpg ├── lbj.png5.jpg ├── lbj.png6.jpg ├── lbj.png7.jpg ├── lbj.png8.jpg ├── lbj.png9.jpg ├── lbj.pngkb.png.avi ├── README.md ├── CMakeLists.txt └── detectFace.cpp /kb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/kb.png -------------------------------------------------------------------------------- /lbj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png -------------------------------------------------------------------------------- /lbj.png0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png0.jpg -------------------------------------------------------------------------------- /lbj.png1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png1.jpg -------------------------------------------------------------------------------- /lbj.png10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png10.jpg -------------------------------------------------------------------------------- /lbj.png11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png11.jpg -------------------------------------------------------------------------------- /lbj.png2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png2.jpg -------------------------------------------------------------------------------- /lbj.png3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png3.jpg -------------------------------------------------------------------------------- /lbj.png4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png4.jpg -------------------------------------------------------------------------------- /lbj.png5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png5.jpg -------------------------------------------------------------------------------- /lbj.png6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png6.jpg -------------------------------------------------------------------------------- /lbj.png7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png7.jpg -------------------------------------------------------------------------------- /lbj.png8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png8.jpg -------------------------------------------------------------------------------- /lbj.png9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.png9.jpg -------------------------------------------------------------------------------- /lbj.pngkb.png.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwx/FaceMorph/HEAD/lbj.pngkb.png.avi -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FaceMorph 2 | 3 | 基于opencv+Dlib的面部合成(Face Morph) 4 | 这里的面部合成指的的是把一张脸逐渐的变化成另外一张脸。 5 | 具体见[我的博客](http://blog.csdn.net/wangxing233/article/details/51549880 "悬停显示") 6 | 7 | ![](lbj.png0.jpg)![](lbj.png1.jpg)![](lbj.png2.jpg)![](lbj.png3.jpg)![](lbj.png4.jpg)![](lbj.png5.jpg)![](lbj.png6.jpg)![](lbj.png7.jpg)![](lbj.png8.jpg)![](lbj.png9.jpg)![](lbj.png10.jpg)![](lbj.png11.jpg) 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | #cmake_minimum_required(VERSION 3.5) 3 | 4 | PROJECT(detectFace) 5 | 6 | include(./lib/dlib-18.18/dlib/cmake) 7 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "lib/") 8 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "lib/") 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/") 10 | find_package(OpenCV REQUIRED) 11 | if(OpenCV_FOUND) 12 | include_directories(${OpenCV_INCLUDE_DIRS}) 13 | 14 | ADD_EXECUTABLE(detectFace detectFace.cpp) 15 | TARGET_LINK_LIBRARIES(detectFace dlib ${OpenCV_LIBS}) 16 | else() 17 | ADD_EXECUTABLE(detectFace detectFace.cpp) 18 | TARGET_LINK_LIBRARIES(detectFace dlib) 19 | endif() 20 | 21 | if(DLIB_LINK_WITH_SQLITE3) 22 | add_example(sqlite_ex) 23 | endif() 24 | #set(CMAKE_CXX_FLAGS "-std=c++11") 25 | -------------------------------------------------------------------------------- /detectFace.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | //#include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace cv; 14 | using namespace dlib; 15 | using namespace std; 16 | 17 | // ---------------------------------------------------------------------------------------- 18 | 19 | /* detect 68 face landmarks on the input image by using the face landmark detector in dlib. 20 | // 21 | */ 22 | void faceLandmarkDetection(dlib::array2d& img, shape_predictor sp, std::vector& landmark) 23 | { 24 | dlib::frontal_face_detector detector = get_frontal_face_detector(); 25 | //dlib::pyramid_up(img); 26 | 27 | std::vector dets = detector(img); 28 | //cout << "Number of faces detected: " << dets.size() << endl; 29 | 30 | 31 | full_object_detection shape = sp(img, dets[0]); 32 | //image_window win; 33 | //win.clear_overlay(); 34 | //win.set_image(img); 35 | //win.add_overlay(render_face_detections(shape)); 36 | for (int i = 0; i < shape.num_parts(); ++i) 37 | { 38 | float x=shape.part(i).x(); 39 | float y=shape.part(i).y(); 40 | landmark.push_back(Point2f(x,y)); 41 | } 42 | 43 | 44 | } 45 | 46 | 47 | /* 48 | //add eight keypoints to the keypoints set of the input image. 49 | //the added eight keypoints are the four corners points of the image, plus four median points of the four edges of the image. 50 | */ 51 | 52 | void addKeypoints(std::vector& points,Size imgSize) 53 | { 54 | points.push_back(Point2f(1,1)); 55 | points.push_back(Point2f(1,imgSize.height-1)); 56 | points.push_back(Point2f(imgSize.width-1,imgSize.height-1)); 57 | points.push_back(Point2f(imgSize.width-1,1)); 58 | points.push_back(Point2f(1,imgSize.height/2)); 59 | points.push_back(Point2f(imgSize.width/2,imgSize.height-1)); 60 | points.push_back(Point2f(imgSize.width-1,imgSize.height/2)); 61 | points.push_back(Point2f(imgSize.width/2,1)); 62 | } 63 | 64 | 65 | 66 | /* 67 | // calculate the keypoints on the morph image. 68 | */ 69 | 70 | void morpKeypoints(const std::vector& points1,const std::vector& points2,std::vector& pointsMorph, double alpha) 71 | { 72 | for (int i = 0; i < points1.size(); i++) 73 | { 74 | float x, y; 75 | x = (1 - alpha) * points1[i].x + alpha * points2[i].x; 76 | y = (1 - alpha) * points1[i].y + alpha * points2[i].y; 77 | 78 | pointsMorph.push_back(Point2f(x, y)); 79 | 80 | } 81 | } 82 | 83 | 84 | /* 85 | //perform Delaunay Triangulation on the keypoints of the morph image. 86 | */ 87 | struct correspondens{ 88 | std::vector index; 89 | }; 90 | 91 | void delaunayTriangulation(const std::vector& points1,const std::vector& points2, 92 | std::vector& pointsMorph,double alpha,std::vector& delaunayTri,Size imgSize) 93 | { 94 | //cout<<"begin delaunayTriangulation......"<::iterator it = pointsMorph.begin(); it != pointsMorph.end(); it++) 108 | subdiv.insert(*it); 109 | //cout<<"done subdiv add......"< triangleList; 111 | subdiv.getTriangleList(triangleList); 112 | //cout<<"traingleList number is "< pt; 117 | //correspondens ind; 118 | for (size_t i = 0; i < triangleList.size(); ++i) 119 | { 120 | 121 | std::vector pt; 122 | correspondens ind; 123 | Vec6f t = triangleList[i]; 124 | pt.push_back( Point2f(t[0], t[1]) ); 125 | pt.push_back( Point2f(t[2], t[3]) ); 126 | pt.push_back( Point2f(t[4], t[5]) ); 127 | //cout<<"pt.size() is "< & srcTri, std::vector & dstTri) 156 | { 157 | Mat warpMat = getAffineTransform(srcTri, dstTri); 158 | 159 | warpAffine(src, warpImage, warpMat, warpImage.size(), cv::INTER_LINEAR, BORDER_REFLECT_101); 160 | } 161 | 162 | 163 | /* 164 | //the core function of face morph. 165 | //morph the two input image to the morph image by transacting the set of triangles in the two input image to the morph image. 166 | */ 167 | void morphTriangle(Mat &img1, Mat &img2, Mat &img, std::vector &t1, std::vector &t2, std::vector &t, double alpha) 168 | { 169 | Rect r = cv::boundingRect(t); 170 | Rect r1 = cv::boundingRect(t1); 171 | Rect r2 = cv::boundingRect(t2); 172 | 173 | std::vector t1Rect, t2Rect, tRect; 174 | std::vector tRectInt; 175 | for (int i = 0; i < 3; ++i) 176 | { 177 | tRect.push_back(Point2f(t[i].x - r.x, t[i].y - r.y)); 178 | tRectInt.push_back(Point(t[i].x - r.x, t[i].y - r.y)); 179 | 180 | t1Rect.push_back(Point2f(t1[i].x - r1.x, t1[i].y - r1.y)); 181 | t2Rect.push_back(Point2f(t2[i].x - r2.x, t2[i].y - r2.y)); 182 | } 183 | 184 | Mat mask = Mat::zeros(r.height, r.width, CV_32FC3); 185 | fillConvexPoly(mask, tRectInt, Scalar(1.0, 1.0, 1.0), 16, 0); 186 | 187 | Mat img1Rect, img2Rect; 188 | img1(r1).copyTo(img1Rect); 189 | img2(r2).copyTo(img2Rect); 190 | 191 | Mat warpImage1 = Mat::zeros(r.height, r.width, img1Rect.type()); 192 | Mat warpImage2 = Mat::zeros(r.height, r.width, img2Rect.type()); 193 | 194 | applyAffineTransform(warpImage1, img1Rect, t1Rect, tRect); 195 | applyAffineTransform(warpImage2, img2Rect, t2Rect, tRect); 196 | 197 | Mat imgRect = (1.0 - alpha)*warpImage1 + alpha*warpImage2; 198 | 199 | multiply(imgRect, mask, imgRect); 200 | multiply(img(r), Scalar(1.0, 1.0, 1.0) - mask, img(r)); 201 | img(r) = img(r) + imgRect; 202 | } 203 | 204 | 205 | 206 | 207 | /* 208 | //morp the two input images into the morph image. 209 | //first get the keypoints correspondents of the set of triangles, then call the core function. 210 | */ 211 | void morp(Mat &img1, Mat &img2, Mat& imgMorph, double alpha, const std::vector &points1, const std::vector &points2, const std::vector &triangle) 212 | { 213 | img1.convertTo(img1, CV_32F); 214 | img2.convertTo(img2, CV_32F); 215 | 216 | 217 | 218 | std::vector points; 219 | morpKeypoints(points1,points2,points,alpha); 220 | 221 | 222 | int x, y, z; 223 | int count = 0; 224 | for (int i=0;i t1, t2, t; 231 | t1.push_back(points1[x]); 232 | t1.push_back(points1[y]); 233 | t1.push_back(points1[z]); 234 | 235 | t2.push_back(points2[x]); 236 | t2.push_back(points2[y]); 237 | t2.push_back(points2[z]); 238 | 239 | t.push_back(points[x]); 240 | t.push_back(points[y]); 241 | t.push_back(points[z]); 242 | morphTriangle(img1, img2, imgMorph, t1, t2, t, alpha); 243 | //count++; 244 | //string shun = "hunhe"; 245 | //if (count % 10 == 0 || count == triangle.size() - 1 || count == triangle.size()) 246 | // imwrite(shun+to_string(count)+".jpg", imgMorph); 247 | } 248 | 249 | } 250 | 251 | 252 | 253 | 254 | 255 | 256 | int main(int argc, char** argv) 257 | { 258 | 259 | if (argc < 3) 260 | { 261 | cout << "Give some image files as arguments to this program." << endl; 262 | return 0; 263 | } 264 | 265 | 266 | 267 | //-------------- step 1. load the input two images -------------------------------------------- 268 | shape_predictor sp; 269 | deserialize("shape_predictor_68_face_landmarks.dat") >> sp; 270 | dlib::array2d img1,img2; 271 | dlib::load_image(img1, argv[1]); 272 | dlib::load_image(img2, argv[2]); 273 | std::vector landmarks1,landmarks2; 274 | 275 | Mat img1CV = imread(argv[1]); 276 | Mat img2CV = imread(argv[2]); 277 | if(!img1CV.data || !img2CV.data) 278 | { 279 | printf("No image data \n"); 280 | return -1; 281 | } 282 | else 283 | cout<<"image readed by opencv"< resultImage; 312 | resultImage.push_back(img1CV); 313 | cout<<"add the first image"< pointsMorph; 318 | 319 | std::vector delaunayTri; 320 | delaunayTriangulation(landmarks1,landmarks2,pointsMorph,alpha,delaunayTri,img1CV.size()); 321 | cout<<"done "< pic; 349 | 350 | for (int i=0;i