# 二 具体步骤

## 1 人脸关键点检测

void faceLandmarkDetection(dlib::array2d<unsigned char>& img, shape_predictor sp, std::vector<Point2f>& landmark)
{
dlib::frontal_face_detector detector = get_frontal_face_detector();
//dlib::pyramid_up(img);

std::vector<dlib::rectangle> dets = detector(img);
//cout << "Number of faces detected: " << dets.size() << endl;

full_object_detection shape = sp(img, dets[0]);
//image_window win;
//win.clear_overlay();
//win.set_image(img);
for (int i = 0; i < shape.num_parts(); ++i)
{
float x=shape.part(i).x();
float y=shape.part(i).y();
landmark.push_back(Point2f(x,y));
}

}

## 2 . 计算凸包

    std::vector<Point2f> hull1;
std::vector<Point2f> hull2;
std::vector<int> hullIndex;//保存组成凸包的关键点的下标索引。

cv::convexHull(points2, hullIndex, false, false);//计算凸包

//保存组成凸包的关键点。
for(int i = 0; i < hullIndex.size(); i++)
{
hull1.push_back(points1[hullIndex[i]]);
hull2.push_back(points2[hullIndex[i]]);
}

## 3. Delaunay 三角剖份 和 仿射变换

for(size_t i=0;i<delaunayTri.size();++i)
{
std::vector<Point2f> t1,t2;//存放三角形的顶点
correspondens corpd=delaunayTri[i];
for(size_t j=0;j<3;++j)
{
t1.push_back(hull1[corpd.index[j]]);
t2.push_back(hull2[corpd.index[j]]);
}

warpTriangle(imgCV1,imgCV1Warped,t1,t2); //进行仿射变换
}

void warpTriangle(Mat &img1, Mat &img2, std::vector<Point2f> &t1, std::vector<Point2f> &t2)
{

Rect r1 = boundingRect(t1);
Rect r2 = boundingRect(t2);

// Offset points by left top corner of the respective rectangles
std::vector<Point2f> t1Rect, t2Rect;
std::vector<Point> t2RectInt;
for(int i = 0; i < 3; i++)
{

t1Rect.push_back( Point2f( t1[i].x - r1.x, t1[i].y -  r1.y) );
t2Rect.push_back( Point2f( t2[i].x - r2.x, t2[i].y - r2.y) );
t2RectInt.push_back( Point(t2[i].x - r2.x, t2[i].y - r2.y) ); // for fillConvexPoly

}

// Get mask by filling triangle
Mat mask = Mat::zeros(r2.height, r2.width, CV_32FC3);
fillConvexPoly(mask, t2RectInt, Scalar(1.0, 1.0, 1.0), 16, 0);

// Apply warpImage to small rectangular patches
Mat img1Rect;
img1(r1).copyTo(img1Rect);

Mat img2Rect = Mat::zeros(r2.height, r2.width, img1Rect.type());

applyAffineTransform(img2Rect, img1Rect, t1Rect, t2Rect);

img2(r2) = img2(r2) + img2Rect;

}

void applyAffineTransform(Mat &warpImage, Mat &src, std::vector<Point2f> &srcTri, std::vector<Point2f> &dstTri)
{
// Given a pair of triangles, find the affine transform.
Mat warpMat = getAffineTransform( srcTri, dstTri );

// Apply the Affine Transform just found to the src image
warpAffine( src, warpImage, warpMat, warpImage.size(), cv::INTER_LINEAR, BORDER_REFLECT_101);
}


## 4. 无缝融合

    //calculate mask
std::vector<Point> hull8U;

for(int i=0; i< hull2.size();++i)
{
Point pt(hull2[i].x,hull2[i].y);
hull8U.push_back(pt);
}

fillConvexPoly(mask, &hull8U[0], hull8U.size(), Scalar(255,255,255));

#include<opencv2/photo.hpp>

seamlessClone的具体定义可以参考opencv的官方文档[3]。在本文中的使用如下：

Rect r = boundingRect(hull2);
Point center = (r.tl() +r.br()) / 2;

Mat output;
imgCV1Warped.convertTo(imgCV1Warped, CV_8UC3);
seamlessClone(imgCV1Warped,imgCV2,mask,center,output,NORMAL_CLONE);

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120