您的位置:首页 > 编程语言 > C语言/C++

C/C++ 图像处理(18)------人脸检测

2018-02-01 18:00 357 查看

人脸识别包括人脸检测和识别两个部分

一般的逻辑是先检测人脸位置,然后再识别。

具体的流程是

准备要识别的人脸数据->检测人脸->学习人脸特征并生成模型

检测人脸->对比检测出来的人脸和模型的相识度->给出识别结果

本篇文章用OpenCV实现了这两个过程,具体的代码有参考网上的代码,如有雷同,绝非巧合

具体的检测和识别原理不在本篇文章的范畴之内,望见谅

人脸检测

#include <time.h>
#include <opencv2/opencv.hpp>
#include <vector>//容器头文件

using namespace std;
using namespace cv;

//关键函数
/*
void detectMultiScale(
const Mat& image,
CV_OUT vector<Rect>& objects,
double scaleFactor = 1.1,
int minNeighbors = 3,
int flags = 0,
Size minSize = Size(),
Size maxSize = Size()
);
*/
//参数1:image--待检测图片,一般为灰度图像加快检测速度;
//参数2:objects--被检测物体的矩形框向量组;
//参数3:scaleFactor--表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%;
//参数4:minNeighbors--表示构成检测目标的相邻矩形的最小个数(默认为3个)。
//如果组成检测目标的小矩形的个数和小于 min_neighbors - 1 都会被排除。
//如果min_neighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框
//参数5:flags--要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING
//CV_HAAR_DO_CANNY_PRUNING--函数将会使用Canny边缘检测来排除边缘过多或过少的区域,因为这些区域通常不会是人脸所在区域;
//参数6、7:minSize和maxSize用来限制得到的目标区域的范围。

void getfaceimg()//人脸图像获取
{
CascadeClassifier ccf;//创建脸部对象
string cascadeName = "haarcascade_frontalface_alt2.xml";//人脸检测模型,请在OpenCV文件夹中搜索
ccf.load(cascadeName);//读取opencv人脸检测模型
vector<Rect> faces;//容器,存放检测到的人脸
long time = clock();
string path;
for (size_t i = 0; i < 5; i++)
{
path = to_string(i + 1);
path.append(".jpg");
Mat img = imread(path, 0);
//imshow("原图", img);
equalizeHist(img, img);//直方图均衡化
//imshow("直方图均衡化", img);
//人脸检测
ccf.detectMultiScale(img, faces, 1.1, 3, CV_HAAR_DO_CANNY_PRUNING, Size(50, 50), Size(500, 500));//人脸检测
for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
rectangle(img, *iter, Scalar(0), 2, 8); //用矩形圈出人脸
}
//截取保存脸部图像
Mat faceimg;
for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
faceimg = img(*iter);
imshow("脸部图像", faceimg);
imwrite("faceImg//" + path, faceimg);
}
imshow("检测结果", img);
waitKey(1000);
}
cout << "花费时间:" << clock() - time << "ms" << endl;
}

void main()
{
getfaceimg();//人脸图像获取
}




分类器训练

//人脸分类器训练,数据库用的ORL人脸数据库,并加入了要识别的人脸放在"S0"文件夹中
void TrainFaceImg()
{
//定义保存图片和标签的向量容器
std::vector<Mat> images;
std::vector<int> labels;
//读取样本
for (size_t s = 0; s <= 40; s++)
{
String path = "att_faces//s"+ to_string(s)+"//";
for (size_t i = 1; i <= 10; i++)
{
String imgpath = path + to_string(i) + ".pgm";
Mat trainfaceimg = imread(imgpath, CV_LOAD_IMAGE_GRAYSCALE);
resize(trainfaceimg, trainfaceimg, Size(128, 128));
images.push_back(trainfaceimg);//加入图像
labels.push_back(s);//加入标签
}
}
//三种人脸识别方法,只用其中的一种也可以
Ptr<FaceRecognizer> faceClass = createEigenFaceRecognizer();
Ptr<FaceRecognizer> fisherClass = createFisherFaceRecognizer();
Ptr<FaceRecognizer> lpbhClass = createLBPHFaceRecognizer();
//训练
faceClass->train(images, labels);
fisherClass->train(images, labels);
lpbhClass->train(images, labels);
//保存训练的分类器
faceClass->save("faceClass.xml");
fisherClass->save("fisherClass.xml");
lpbhClass->save("lpbhClass.xml");
cout << "分类器训练完成"<< endl;
}


人脸识别(注意要放进去识别的图片是先经过检测、裁剪和尺度变换后的图片)

void FaceDetect()
{
Ptr<FaceRecognizer> faceClass = createEigenFaceRecognizer();
Ptr<FaceRecognizer> fisherClass = createFisherFaceRecognizer();
Ptr<FaceRecognizer> lpbhClass = createLBPHFaceRecognizer();
//加载分类器
faceClass->load("faceClass.xml");
fisherClass->load("fisherClass.xml");
lpbhClass->load("lpbhClass.xml");
//使用训练好的分类器进行预测。
Mat detectimg = imread("faceImg//14.pgm", 0);
resize(detectimg, detectimg, Size(128, 128));
//预测样本并获取标签和置信度
int faceResult = faceClass->predict(detectimg);
cout << String("faceClass标签类别:") << faceResult << endl;;
int fisherResult = -1;
double fisherConfidence = 0.0;
fisherClass->predict(detectimg, fisherResult, fisherConfidence);
cout << String("fisherClass标签类别:") << fisherResult << String("置信度:") << fisherConfidence << endl;
int lpbhResult = lpbhClass->predict(detectimg);
cout << String("lpbhResult标签类别:") << lpbhResult << endl;;
}


通过上面的步骤基本上就完成了一个普通的人脸识别流程,但其缺点是准确率还不是很高,要提高准确率可以考虑用深度学习的方法,后面研究到的话会写出来跟大家交流。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: