前言
《C OpenCV Contrib模块LBF人脸特征点检测》文章中已经介绍了人脸特征点的检测,本篇文章是在原代码的基础上实现人脸的提取。
实现效果
从上图上可以看到,左边蓝色方框里面是截取的人脸图像,然后在人脸图像的基础上针对特征点选定区域,最后生成右边圆框中的人脸图像。
# | 实现方式 |
---|---|
1 | 使用DNN检测到人脸并截取人脸部分区域 |
2 | 在截取的人脸区域中检测人脸68个特征点 |
3 | 针对68个特征点实现凸包检测形成图像掩膜 |
4 | 根据掩膜提取图像的人脸信息 |
关于人脸68个特征点
微卡智享
上图中介绍了人脸特征点的几个关键位置:
位置 | 点的范围 |
---|---|
左侧下巴轮廓 | 0-7 |
下巴 | 8 |
右侧下巴轮廓 | 9-16 |
左侧眉毛 | 17-21 |
右侧眉毛 | 22-26 |
鼻梁区域 | 27-30 |
鼻底区域 | 31-35 |
左眼 | 36-41 |
右眼 | 42-47 |
嘴唇外缘 | 48-59 |
嘴唇内缘 | 60-67 |
人脸关键点
- 鼻尖 30
- 鼻根 27
- 下巴 8
- 左眼外角 36
- 左眼内角 39
- 右眼外角 45
- 右眼内角 42
- 嘴中心 66
- 嘴左角 48
- 嘴右角 54
- 左脸最外 0
- 右脸最外 16
核心代码
微卡智享
代码语言:javascript复制//初始化模版人脸
void InitFaceMarkModel(Mat& frame, Rect rect, Mat& dst, vector<Point2f>& dstfacemarkmodel)
{
vector<int> faceid = { 30,27,8,36,39,45,42,66,48,54,0,16 };
vector<int>::iterator it;
dst = Mat(frame, rect);
Mat tmpmodel;
dst.copyTo(tmpmodel);
Rect tmprect = Rect(0, 0, dst.cols, dst.rows);
vector<Rect> tmprects;
tmprects.push_back(tmprect);
vector<vector<Point2f>> tmpfacemodels;
facemarkdetect.facemarkdetector(dst, tmprects, tmpfacemodels);
Mat tmpdst = Mat::zeros(dst.size(), CV_8UC1);
if (tmpfacemodels.size() > 0) {
facemarkmodel = tmpfacemodels[0];
//将vector<Point2f>转为vector<Point>用于做凸包检测
vector<Point> facemarkcontour;
for (int i = 0; i < facemarkmodel.size(); i) {
facemarkcontour.push_back(Point(facemarkmodel[i].x, facemarkmodel[i].y));
//it = find(faceid.begin(), faceid.end(), i);
//if (it != faceid.end()) {
// putText(tmpmodel, to_string(i), facemarkmodel[i], FONT_HERSHEY_PLAIN, 1, Scalar(255, 0, 0));
//}
cout << "模版特征点"<< i <<":" << facemarkmodel[i] << endl;
}
//凸包检测
vector<Point> contourhull;
convexHull(facemarkcontour, contourhull);
//存入二维数组vector<vector<Point>>中用于画轮廓处理
vector<vector<Point>> contours;
contours.push_back(contourhull);
//画轮廓并添充
drawContours(tmpdst, contours, -1, Scalar(255, 255, 255), -1);
}
dst = Mat::zeros(tmpmodel.size(), CV_8UC3);
tmpmodel.copyTo(dst, tmpdst);
imshow("dst", dst);
//resize(tmpmodel, tmpmodel, Size(0, 0), 5, 5);
imshow("srcmodel", tmpmodel);
imshow("tmpdst", tmpdst);
}
划重点
上面的代码还是比较简单的,两个需要注意的点:
- 人脸关键点检测出来的数据是vector<vector<Point2f>>,而做凸包检测的时候需要将vector<vector<Point2f>>转换成vector<vector<Point>>。
- 做区域掩膜时先生成一张相同大小的全黑的图片,然后把要截取的区域全部填充为白色,再通过copyto的方式生成即可。
结语
源码下一篇会再提交上去,现在的源码在处理人脸的Delaunay三角形的
提取,正好遇到了问题。等下篇的时候一起说一下。
完