Opencv做人脸关键点可视化
本文所用的文件和项目源码都已存放在百度云:
链接:https://pan.baidu.com/s/1V6mJ7khatTWfj8inNEH5xw
提取码:b50p
Opencv做人脸关键的可视化主要包括三部分,人脸的检测,关键点的检测,关键点的绘制。首先人脸检测可以根据自己的需要选择,我这里只是做一个示范,所以用的是Haar级联的人脸检测,如果需要更精准的检测,还是建议用深度学习的模型,关键点的检测用的是LBF的训练模型。
首先需要导入这几个头文件,opencv的hpp文件就不用说了,face.hpp是opencv_contrib库中的文件,如果使用的是windows简单版的opencv是不行的,这个一定要自己编译,如果不会编译,请参考我的另一篇博客,名字和连接如下:
Windows10+VS2017+cmake 编译opencv4.1.0 + opencv_contrib4.1.0
https://blog.csdn.net/weixin_45081640/article/details/104754568
最后一个头文件是自己写的。代码如下:
drawLandmarks.hpp
#pragma once
// Summary: 绘制人脸关键点和多边形线
// Author: Amusi
// Date: 2018-03-20
#ifndef _renderFace_H_
#define _renderFace_H_
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#define COLOR Scalar(255, 200, 0)
// drawPolyline通过连接开始和结束索引之间的连续点来绘制多边形线。
void drawPolyline
(
Mat &im,
const vector<Point2f> &landmarks,
const int start,
const int end,
bool isClosed = false
)
{
// 收集开始和结束索引之间的所有点
vector <Point> points;
for (int i = start; i <= end; i++)
{
points.push_back(cv::Point(landmarks[i].x, landmarks[i].y));
}
// 绘制多边形曲线
polylines(im, points, isClosed, COLOR, 2, 16);
}
// 绘制人脸关键点
void drawLandmarks(Mat &im, vector<Point2f> &landmarks)
{
// 在脸上绘制68点及轮廓(点的顺序是特定的,有属性的)
if (landmarks.size() == 68)
{
drawPolyline(im, landmarks, 0, 16); // Jaw line
drawPolyline(im, landmarks, 17, 21); // Left eyebrow
drawPolyline(im, landmarks, 22, 26); // Right eyebrow
drawPolyline(im, landmarks, 27, 30); // Nose bridge
drawPolyline(im, landmarks, 30, 35, true); // Lower nose
drawPolyline(im, landmarks, 36, 41, true); // Left eye
drawPolyline(im, landmarks, 42, 47, true); // Right Eye
drawPolyline(im, landmarks, 48, 59, true); // Outer lip
drawPolyline(im, landmarks, 60, 67, true); // Inner lip
}
else{
// 如果人脸关键点数不是68,则我们不知道哪些点对应于哪些面部特征。所以,我们为每个landamrk画一个圆圈。
for (int i = 0; i < landmarks.size(); i++)
{
circle(im, landmarks[i], 3, COLOR, FILLED);
}
}
}
#endif // _renderFace_H_
下面的是faceMarkTest.cpp源文件的代码:
这几个路径记得改成自己的文件路径,文件可以在本文开始提供的百度云路径下下载,MP4文件自行搞定。随便一个有人脸正脸的就可以。
faceMarkTest.cpp:
#include <opencv2/opencv.hpp>
#include <opencv2/face.hpp>
#include "drawLandmarks.hpp"
#include <iostream>
using namespace std;
using namespace cv;
using namespace cv::face;
int main(int argc, char** argv)
{
// 加载人脸检测器(Face Detector)
// [1]Haar Face Detector
//CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml");
// [2]LBP Face Detector
CascadeClassifier faceDetector("F:\\BaiduNetdiskDownload\\Facemark_LBF\\lbpcascade_frontalface.xml");
// 创建Facemark类的对象
Ptr<Facemark> facemark = FacemarkLBF::create();
// 加载人脸检测器模型
facemark->loadModel("F:\\BaiduNetdiskDownload\\Facemark_LBF\\lbfmodel.yaml");
// 设置网络摄像头用来捕获视频
VideoCapture cam("F:\\BaiduNetdiskDownload\\Facemark_LBF\\2.mp4");
// 存储视频帧和灰度图的变量
Mat frame, gray;
// 读取帧
while (cam.read(frame))
{
// 存储人脸矩形框的容器
vector<Rect> faces;
// 将视频帧转换至灰度图, 因为Face Detector的输入是灰度图
cvtColor(frame, gray, COLOR_BGR2GRAY);
// 人脸检测
faceDetector.detectMultiScale(gray, faces);
// 人脸关键点的容器
vector< vector<Point2f> > landmarks;
// 运行人脸关键点检测器(landmark detector)
bool success = facemark->fit(frame, faces, landmarks);
if (success)
{
// 如果成功, 在视频帧上绘制关键点
for (int i = 0; i < landmarks.size(); i++)
{
// 自定义绘制人脸特征点函数, 可绘制人脸特征点形状/轮廓
drawLandmarks(frame, landmarks[i]);
// OpenCV自带绘制人脸关键点函数: drawFacemarks
drawFacemarks(frame, landmarks[i], Scalar(0, 0, 255));
}
}
// 显示结果
imshow("Facial Landmark Detection", frame);
// 如果按下ESC键, 则退出程序
if (waitKey(1) == 27) break;
}
return 0;
}
展示下效果: