基于Opencv和MTCNN检测人脸五个关键点进行仿射变换人脸对齐 - C++版本
opencv
OpenCV: 开源计算机视觉库
项目地址:https://gitcode.com/gh_mirrors/opencv31/opencv
免费下载资源
·
这篇文章是对应之前人脸对齐的python版本的C++版本,之前python版本见这里。通俗理解就是将图片人人脸姿态不太正确的给矫正过来,所以写了C++版本的人脸对齐算法。基本原理是先通过MTCNN检测到人脸的五个关键点,再把原图中人脸区域外扩100%(这样做的目的是保证对齐后图片中没有黑色区域,当然这个外扩的比例是看对齐效果自己可以调节的,我这里设置的100%)。最后的人脸对齐尺寸分为两种:112X96尺寸和112X112尺寸,其中首先需要定死仿射变换后人脸在目标图上的坐标,然后直接变换。废话不多说,直接手撕代码。
#include<iostream>
#include<fstream>
#include<stdio.h>
#include<math.h>
#include<opencv2/opencv.hpp>
#include<opencv2/dnn.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include "detect/mtcnn/detector.h"
#include "detect/draw.hpp"
#include "align/FaceProprocess.h"
#include "align/FaceAlign.h"
int main()
{
/检测部分/
std::string modelPath = "detect/models/";
std::string picPath;
ProposalNetwork::Config pConfig;
pConfig.caffeModel = modelPath + "det1.caffemodel";
pConfig.protoText = modelPath + "det1.prototxt";
pConfig.threshold = 0.6f;
RefineNetwork::Config rConfig;
rConfig.caffeModel = modelPath + "/det2.caffemodel";
rConfig.protoText = modelPath + "/det2.prototxt";
rConfig.threshold = 0.7f;
OutputNetwork::Config oConfig;
oConfig.caffeModel = modelPath + "/det3.caffemodel";
oConfig.protoText = modelPath + "/det3.prototxt";
oConfig.threshold = 0.7f;
MTCNNDetector detector(pConfig, rConfig, oConfig);
ifstream infile("data.txt");
if (!infile) {//文件没打开
std::cout << "文件不存在!" << std::endl;
}
while (infile >> picPath)
{
cv::Mat img = cv::imread(picPath);
std::vector<Face> faces;
{
faces = detector.detect(img, 20.f, 0.709f);
}
std::cout << "Number of faces found in the supplied image - " << faces.size()
<< std::endl;
std::vector<rectPoints> data;
/检测部分/
/对齐部分1/
double coord5point1[10] = { 30.2946, 65.5318, 48.0252, 33.5493, 62.7299, 51.6963, 51.5014, 71.7366, 92.3655, 92.2041 }; //112x96的目标点
double coord5point2[10] = { 30.2946 + 8.0000, 65.5318 + 8.0000, 48.0252 + 8.0000, 33.5493 + 8.0000, 62.7299 + 8.0000, 51.6963, 51.5014, 71.7366, 92.3655, 92.2041 }; //112x112的目标点
for (size_t i = 0; i < faces.size(); i++)
{
int x1 = faces[i].bbox.x1;
int y1 = faces[i].bbox.y1;
int x2 = faces[i].bbox.x2;
int y2 = faces[i].bbox.y2;
//外扩100%,防止对齐后人脸出现黑边
int new_x1 = std::max(int(1.50 * x1 - 0.50 * x2), 0);
int new_x2 = std::min(int(1.50 * x2 - 0.50 * x1), img.cols - 1);
int new_y1 = std::max(int(1.50 * y1 - 0.50 * y2), 0);
int new_y2 = std::min(int(1.50 * y2 - 0.50 * y1), img.rows - 1);
Mat enlargedFace = img(Rect(new_x1, new_y1, new_x2 - new_x1 + 1, new_y2 - new_y1 + 1));
//imwrite("enlargedFace.jpg", enlargedFace);
//得到原始图中关键点
int left_eye_x = faces[i].ptsCoords[0];
int left_eye_y = faces[i].ptsCoords[1];
int right_eye_x = faces[i].ptsCoords[2];
int right_eye_y = faces[i].ptsCoords[3];
int nose_x = faces[i].ptsCoords[4];
int nose_y = faces[i].ptsCoords[5];
int left_mouth_x = faces[i].ptsCoords[6];
int left_mouth_y = faces[i].ptsCoords[7];
int right_mouth_x = faces[i].ptsCoords[8];
int right_mouth_y = faces[i].ptsCoords[9];
//得到外扩100% 后图中关键点坐标(外扩的目的是为了防止对齐后出现黑边)
int new_left_eye_x = left_eye_x - new_x1;
int new_right_eye_x = right_eye_x - new_x1;
int new_nose_x = nose_x - new_x1;
int new_left_mouth_x = left_mouth_x - new_x1;
int new_right_mouth_x = right_mouth_x - new_x1;
int new_left_eye_y = left_eye_y - new_y1;
int new_right_eye_y = right_eye_y - new_y1;
int new_nose_y = nose_y - new_y1;
int new_left_mouth_y = left_mouth_y - new_y1;
int new_right_mouth_y = right_mouth_y - new_y1;
double M[6];
double enlargeFace_landmark[10] = { new_left_eye_x, new_right_eye_x, new_nose_x, new_left_mouth_x, new_right_mouth_x, new_left_eye_y, new_right_eye_y, new_nose_y, new_left_mouth_y, new_right_mouth_y };
//112x112
getAffineMatrix(enlargeFace_landmark, coord5point2, M);
Mat warp_mat_112x112 = (Mat_<float>(2, 3) << M[0], M[1], M[2], M[3], M[4], M[5]);
Mat alignFace_112x112 = Mat::zeros(112, 112, img.type());
warpAffine(enlargedFace, alignFace_112x112, warp_mat_112x112, alignFace_112x112.size());//裁剪图片
int position = picPath.find("/", 0);
imwrite("result/" + picPath.substr(position + 1, 4) + "_align_112x112.jpg", alignFace_112x112);
//112x96
getAffineMatrix(enlargeFace_landmark, coord5point1, M);
Mat warp_mat_112x96 = (Mat_<float>(2, 3) << M[0], M[1], M[2], M[3], M[4], M[5]);
Mat alignFace_112x96 = Mat::zeros(112, 96, img.type());
warpAffine(enlargedFace, alignFace_112x96, warp_mat_112x96, alignFace_112x96.size());//裁剪图片
imwrite("result/" + picPath.substr(position + 1, 4) + "_align_112x96.jpg", alignFace_112x96);
}
}
/对齐部分1/
return 0;
}
运行上述代码,效果如下所示:
注意事项:该工程通过Visual studio 2019编写,环境仅仅依赖OpenCV,下载到工程后,需要设置OpenCV的包含目录和库目录,并设置附加依赖项。然后直接打开工程运行即可得到上述结果过。
完整的工程下载点这里(code: face), 欢迎下载使用。
GitHub 加速计划 / opencv31 / opencv
77.38 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:2 个月前 )
c3747a68
Added Universal Windows Package build to CI. 7 天前
9b635da5 - 7 天前
更多推荐
已为社区贡献5条内容
所有评论(0)