使用dlib和opencv 簡答的實現一個換臉程序

人生第一次寫博客,有錯誤的地方,給我回復下 , 話不多說,直接上代碼

#include <dlib/opencv.h>  
#include <opencv2/opencv.hpp>  
//#include<opencv2/photo.hpp>
#include <dlib/image_processing/frontal_face_detector.h>  
#include <dlib/image_processing/render_face_detections.h>  
#include <dlib/image_processing.h>  
#include<facedetect-dll.h>
#include"ColorT.h"
#include<vector>


dlib::shape_predictor sp;                


int detectctFace(cv::Mat &mat, std::vector<cv::Point> &point)                                    //使用的是於仕琪老師的人臉檢測
{
dlib::full_object_detection shape1;
cv::Mat mat1, gra;
mat.copyTo(mat1);
cv::cvtColor(mat1, gra, CV_BGR2GRAY);
int * pResults = NULL;
unsigned char * pBuffer = (unsigned char *)malloc(0x20000);
if (!pBuffer)
{
fprintf(stderr, "Can not alloc buffer.\n");
return -1;
}
pResults = facedetect_multiview_reinforce(pBuffer, (unsigned char*)(gra.ptr(0)), gra.cols, gra.rows, (int)gra.step, 1.15f, 5, 15, 0, 0);
std::vector<cv::Point>().swap(point);
point.clear();
if (*pResults > 0)
{
for (int i = 0; i < (pResults ? *pResults : 0); i++)
{
dlib::rectangle det;
short * p = ((short*)(pResults + 1)) + 142 * i;
int x = p[0];
int y = p[1];
int w = p[2];
int h = p[3];
if (w > 0 && h > 0 && x + w < gra.cols&&y + h < gra.rows)
{
det.set_top(y);
det.set_left(x);
det.set_bottom(y + h);
det.set_right(x + w);
dlib::cv_image<dlib::bgr_pixel> cimg(mat);
shape1 = sp(cimg, det);                //特徵點檢測
for (int s = 0; s < 17; s++)
{
cv::Point2f pt(shape1.part(s).x(), shape1.part(s).y());
point.push_back(pt);
}
for (int s = 26; s > 16; s--)
{
cv::Point2f pt(shape1.part(s).x(), shape1.part(s).y());
point.push_back(pt);
}
}
}


}
free(pBuffer);
pResults = NULL;
}

//這個函數是將三角剖分後的三角對點與人臉的特徵點位置相匹配,拿出三角對的序列
void getImgTriangleList(Size size, Subdiv2D &subdiv, vector<Point> &point, vector<int>&triangleSeq)
{
Rect rect(0, 0, size.width, size.height);
vector<Vec6f> triangleList;
subdiv.getTriangleList(triangleList);
vector<Point> pt(3);
cout << "triangleList Size is:" << triangleList.size() << endl;
for (size_t i = 0; i < triangleList.size(); i++)
{


Vec6i t = triangleList[i];
pt[0] = Point(t[0], t[1]);
pt[1] = Point(t[2], t[3]);
pt[2] = Point(t[4], t[5]);




if (rect.contains(pt[0]) && rect.contains(pt[1]) && rect.contains(pt[2]))
{
for (int j = 0; j < 3; j++)
for (int k = 0; k < point.size(); k++)
{
if (pt[j].x == point[k].x&& pt[j].y == point[k].y)
{
triangleSeq.push_back(k);
break;
}
}
}
}
}



//人臉融合函數
void morphFaceFunc(Mat srcA, Mat &srcB, vector<cv::Point> pointA, vector<cv::Point> pointB, vector<int> triangleSeq)
{
Mat srcBCopy;
srcB.copyTo(srcBCopy);  //原圖複製一個


int size = triangleSeq.size();
for (int j = 0; j < size; j += 3)            //對所有的三角形遍歷並進行復制
{
vector<Point> pointAFace(3);

vector<Point> pointBFace(3);

                //A圖人臉上的三個點

pointAFace[0] = pointA[triangleSeq[j]];
pointAFace[1] = pointA[triangleSeq[j + 1]];
pointAFace[2] = pointA[triangleSeq[j + 2]];

                //B圖對應A 圖的三個點,映射關係
pointBFace[0] = pointB[triangleSeq[j]];
pointBFace[1] = pointB[triangleSeq[j + 1]];
pointBFace[2] = pointB[triangleSeq[j + 2]];

                //爲三個點包一個矩形
Rect rectA = boundingRect(pointAFace);
Rect rectB = boundingRect(pointBFace);


Point2f pointAf[3];

Point2f pointBf[3];

                //計算相對於剛纔rectA 的點,以及對應於rectB 的點 ,爲之後的仿射變換做準備

pointAf[0] = Point(pointAFace[0].x - rectA.x, pointAFace[0].y - rectA.y);
pointAf[1] = Point(pointAFace[1].x - rectA.x, pointAFace[1].y - rectA.y);
pointAf[2] = Point(pointAFace[2].x - rectA.x, pointAFace[2].y - rectA.y);
pointBf[0] = Point(pointBFace[0].x - rectB.x, pointBFace[0].y - rectB.y);
pointBf[1] = Point(pointBFace[1].x - rectB.x, pointBFace[1].y - rectB.y);
pointBf[2] = Point(pointBFace[2].x - rectB.x, pointBFace[2].y - rectB.y);

                //獲取Rect部分的ROI
Mat roiMat(srcA, rectA);
Mat maskA(srcA.size(), CV_8UC1);
maskA.setTo(0);
Mat maskB(srcB.size(), CV_8UC1);
maskB.setTo(0);

                

                //用三個點做一個三角形的mask

cv::fillConvexPoly(maskA, pointAFace, Scalar(255), 16);
cv::fillConvexPoly(maskB, pointBFace, Scalar(255), 16);

Mat skinA(rectA.size(), CV_8UC3); 
skinA.setTo(0);
Mat MaskAROI, MaskBROI;
maskA(rectA).copyTo(MaskAROI);
maskB(rectB).copyTo(MaskBROI);
roiMat.copyTo(skinA, MaskAROI);

Mat outImg(rectB.size(), srcB.type());

Mat outMaskB(rectB.size(), CV_8UC1);//), outImg2;

                //將 a 臉上的一個三角形紋理向b臉上進行仿射變換,同時把mask也進行仿射變換,如果直接用b圖的三角形 mask 

                //進行復制,人臉上會有縫隙產生

cv::Mat warpMat = cv::getAffineTransform(pointAf, pointBf);
cv::warpAffine(skinA, outImg, warpMat, outImg.size(), cv::INTER_NEAREST, cv::BORDER_REFLECT_101);// cv::BORDER_REFLECT_101);
cv::warpAffine(MaskAROI, outMaskB, warpMat, outMaskB.size(), cv::INTER_NEAREST, cv::BORDER_CONSTANT,Scalar(0));
Mat roiNewMat(srcB, rectB);

                
outImg.copyTo(roiNewMat, outMaskB);
imshow("test", srcB);
waitKey(10);

}

        //整個人臉的mask
Mat maskFace(srcB.size(), CV_8UC1);
cv::fillConvexPoly(maskFace, pointB, Scalar(255), 8, 0);

        //mask 的大致中心點
int x1 = (pointB[0].x + pointB[16].x) / 2;
int y1 = ((pointB[19].y + pointB[24].y) / 2 + pointB[8].y) / 2;

        //泊松融合
seamlessClone(srcB, srcBCopy, maskFace, cv::Point(x1, y1), srcB, 1);


imshow("test", srcB);
waitKey(0);
}




int  main()
{
string shape_model = "shape_predictor_68_face_landmarks.dat";
cout << "加載模型文件" << endl;
dlib::deserialize(shape_model) >> sp;

Mat srcA = imread("A.jpg");
Mat srcB = imread("B.jpg");


Size sizeA = srcA.size();
Size sizeB= srcB.size();

Rect rectA(0, 0, sizeA.width, sizeA.height);
Rect rectB(0, 0, sizeB.width, sizeB.height);
//三角剖分的對象以及三角剖分的位置
Subdiv2D subdivA(rectA);
Subdiv2D subdivB(rectB);

        //保存人臉特徵點的
vector<cv::Point> pointA, pointB;

cout << "開始人臉檢測" << endl;

        //人臉檢測,以及特徵點檢測

detectctFace(srcA , pointA);
detectctFace(srcB, pointB);

        //將檢測到的人臉特徵點插入到三角剖分裏
for (int i = 0; i < pointA.size(); i++)
{
subdivA.insert(pointA[i]);
subdivB.insert(pointB[i]);
}


vector<int> triangleSeqA;
vector<int> triangleSeqB;

        
getImgTriangleList(sizeA, subdivA, pointA, triangleSeqA);
morphFaceFunc(srcA, srcB, pointA, pointB, triangleSeqA);

        return 0;

}

A 圖

B圖


複製的過程圖


人臉融合以後



原工程下載地址,哈哈,賺點積分而已

http://download.csdn.net/download/wz9ixk58/10269365