使用dlib和opencv 简答的实现一个换脸程序

使用dlib和opencv 简答的实现一个换脸程序

 

人生第一次写博客,有错误的地方,给我回复下 , 话不多说,直接上代码

#include   
#include   
//#include
#include   
#include   
#include   
#include
#include"ColorT.h"
#include


dlib::shape_predictor sp;                


int detectctFace(cv::Mat &mat, std::vector &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().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 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, vector&triangleSeq)
{
Rect rect(0, 0, size.width, size.height);
vector triangleList;
subdiv.getTriangleList(triangleList);
vector 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 pointA, vector pointB, vector triangleSeq)
{
Mat srcBCopy;
srcB.copyTo(srcBCopy);  //原图复制一个


int size = triangleSeq.size();
for (int j = 0; j < size; j += 3)            //对所有的三角形遍历并进行复制
{
vector pointAFace(3);

vector 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 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 triangleSeqA;
vector triangleSeqB;

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

        return 0;

}

A 图

使用dlib和opencv 简答的实现一个换脸程序_第1张图片

B图

使用dlib和opencv 简答的实现一个换脸程序_第2张图片

复制的过程图

使用dlib和opencv 简答的实现一个换脸程序_第3张图片

人脸融合以后

使用dlib和opencv 简答的实现一个换脸程序_第4张图片

 

原工程下载地址,哈哈,赚点积分而已

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

你可能感兴趣的:(使用dlib和opencv 简答的实现一个换脸程序)