概述
之前的刚学习OpenCV的时候,对人脸识别感兴趣,觉得能够实现识别自己的脸感觉很棒。通过一段时间的学习之后,发现其实并不难。网上较多的都是PCA算法的人脸识别,这是相对来说比较老的算法了,多数的东西OpenCV都是自带的,借助该算法来学习也比较方便。
下面来具体说一下从制作样本到训练样本,再到最后调用摄像头识别自己人脸的整个过程。
1.图像的采集及预处理
要想识别指定的人,则需要将被识别人的照片做成数据集,也就是训练模型。传统获得照片的途径就是通过手机拍照、自拍。一个人需要20张不同角度和表情的照片,要实现几个人的训练模型,手机拍照显得比较麻烦,而且效果不佳,倒不如通过电脑摄像头实现。通过查阅资料,利用OpenCV写了一个拍照的小程序,并将图片提前进行了灰度处理以及中值滤波处理。然后将图片缩小到指定的120*120的大小,拍出来的照片能达到样本级的水平,省去了很多二次处理的过程。
代码如下:
#include <opencv2opencv.hpp>
using namespace cv;
int main()
{
VideoCapture cap(0);
Mat frame;
int i=0;
while (1)
{
char key = waitKey(100);
cap >> frame;
imshow("frame", frame);
Mat out;
Mat out1;
Mat out2;
cvtColor(frame, out1, CV_BGR2GRAY);//灰度化
medianBlur(out1,out,7);//中值滤波
resize(out, out2, Size(120, 120));//尺寸缩减
imshow("out", out2);
string filename = format("D:\pic\pic%d.jpg", i);//存入文件路径
switch (key)
{
case'p': //按'P'拍照
i++;
imwrite(filename, out2);
imshow("photo", out2);
waitKey(500);
destroyWindow("photo");
break;
default:
break;
}
}
}
这样得到的图片已经是经过处理之后的,可以当做样本使用。效果如图所示:
这样初步的样本就制作好了。
2.csv文件的生成
当我们写人脸模型的训练程序的时候,我们需要读取人脸和人脸对应的标签。直接在数据库中读取显然是低效的。所以我们用csv文件读取。csv文件中包含两方面的内容,一是每一张图片的位置所在,二是每一个人脸对应的标签,也就是每一个人编号。这个at.txt就是我们需要的csv文件。如图所示:
在图中,前面所显示的路径是图片的位置,后面的数字是该图片所对应人的的标签。如果你用于学习,只制作几个人的样本集来试验的话,可以直接手动创建复制路径,工作量不大,三个人的几分钟搞定。如果你是要做多个人的可以利用OpenCV自带的脚本自动生成,(可以网上搜一下,我这里忘了)最后就能得到既有路径又有标签的csv文件。
3.训练模型
数据集和csv文件都已经准备好了,接下来就可以进行模型训练。首先,需要先将之前的图片和标签提取出来,这个时候就需要用到at.txt。使用csv文件去读图像和标签,主要会用到stringstream和getline方法。Stringstream主要是将一个字符串分割,在将个别内容分开输出;getline则是从输入流中读入字符存到指定的地方。通过stringstream和getline两个方法,将csv文件中的图像和标签分别存到images和labels连个容器中。
注意的是,这里的at.txt文件内容及是将CSV文件的内容复制过来,需要放入到训练模型代码的文件夹中,否则加载不到会报错。
训练模型代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
using namespace cv;
using namespace std;
static Mat norm_0_255(InputArray _src) {
Mat src = _src.getMat();
// 创建和返回一个归一化后的图像矩阵:
Mat dst;
switch (src.channels()) {
case1:
cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
break;
case3:
cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
break;
default:
src.copyTo(dst);
break;
}
return dst;
}
//使用CSV文件去读图像和标签,主要使用stringstream和getline方法
static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
std::ifstream file(filename.c_str(), ifstream::in);
if (!file) {
string error_message = "No valid input file was given, please check the given filename.";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
while (getline(file, line)) {
stringstream liness(line);
getline(liness, path, separator);
getline(liness, classlabel);
if (!path.empty() && !classlabel.empty()) {
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));
}
}
}
int main()
{
//读取你的CSV文件路径.
//string fn_csv = string(argv[1]);
string fn_csv = "at.txt";
// 2个容器来存放图像数据和对应的标签
vector<Mat> images;
vector<int> labels;
// 读取数据. 如果文件不合法就会出错
// 输入的文件名已经有了.
try
{
read_csv(fn_csv, images, labels);
}
catch (cv::Exception& e)
{
cerr << "Error opening file "" << fn_csv << "". Reason: " << e.msg << endl;
// 文件有问题,我们啥也做不了了,退出了
exit(1);
}
// 如果没有读取到足够图片,也退出.
if (images.size() <= 1) {
string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
}
// 下面的几行代码仅仅是从你的数据集中移除最后一张图片
//[gm:自然这里需要根据自己的需要修改,他这里简化了很多问题]
// 下面几行创建了一个特征脸模型用于人脸识别,
// 通过CSV文件读取的图像和标签训练它。
// T这里是一个完整的PCA变换
//如果你只想保留10个主成分,使用如下代码
// cv::createEigenFaceRecognizer(10);
//
// 如果你还希望使用置信度阈值来初始化,使用以下语句:
// cv::createEigenFaceRecognizer(10, 123.0);
//
// 如果你使用所有特征并且使用一个阈值,使用以下语句:
// cv::createEigenFaceRecognizer(0, 123.0);
Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
model->train(images, labels);
model->save("MyFacePCAModel.xml");
return 0;
}
这样一来,你就能在你的训练模型代码的文件夹下生成MyFacePCAModel.xml这个东西,这个就是你经行人脸识别的基准。
4.人脸识别
前面的工作都做好了,这步就很简单了,将MyFacePCAModel.xml和haarcascade_frontalface_alt(haar人脸检测器是OpenCV自带的,在OpenCV自带的人脸识别代码文件夹里面能找到)放入指定代码的文件夹中,运行就好。
代码如下:
#include<opencv2opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap(0); //打开默认摄像头
if (!cap.isOpened())
{
return -1;
}
Mat frame;
Mat edges;
Mat gray;
CascadeClassifier cascade;
bool stop = false;
//训练好的文件名称,放置在可执行文件同目录下
cascade.load("haarcascade_frontalface_alt.xml");
Ptr<FaceRecognizer> modelPCA = createEigenFaceRecognizer();
modelPCA->load("MyFacePCAModel.xml");
while(!stop)
{
cap >> frame;
//建立用于存放人脸的向量容器
vector<Rect> faces(0);
cvtColor(frame, gray, CV_BGR2GRAY);
//改变图像大小,使用双线性差值
//resize(gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR);
//变换后的图像进行直方图均值化处理
equalizeHist(gray, gray);
cascade.detectMultiScale(gray, faces,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
| CV_HAAR_SCALE_IMAGE,
Size(30, 30));
Mat face;
Point text_lb;
for (size_t i = 0; i < faces.size(); i++)
{
if (faces[i].height > 0 && faces[i].width > 0)
{
face = gray(faces[i]);
text_lb = Point(faces[i].x, faces[i].y);
rectangle(frame, faces[i], Scalar(255, 0, 0), 1, 8, 0);
}
}
Mat face_test;
int predictPCA = 0;
if (face.rows >= 120)
{
resize(face, face_test, Size(92, 112));
}
//Mat face_test_gray;
//cvtColor(face_test, face_test_gray, CV_BGR2GRAY);
if (!face_test.empty())
{
//测试图像应该是灰度图
predictPCA = modelPCA->predict(face_test);
}
cout << predictPCA << endl;
if (predictPCA == 1)
{
string name = "ZBR";
putText(frame, name, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
}
else
{
string name = "No Person!";
putText(frame, name, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
}
imshow("face", frame);
if (waitKey(50) >= 0)
stop = true;
}
return 0;
}
文件夹中有:
最终效果图:
到此就全部结束了,过程并不,重要的是要学会方法和原理。
如果感兴趣的也可以去了解下PCA算法,还有OpenCV机器学习的相关内容
最后
以上就是无聊心情为你收集整理的基于PCA算法的人脸识别制作自己的样本实现识别自己的人脸1.图像的采集及预处理2.csv文件的生成3.训练模型4.人脸识别的全部内容,希望文章能够帮你解决基于PCA算法的人脸识别制作自己的样本实现识别自己的人脸1.图像的采集及预处理2.csv文件的生成3.训练模型4.人脸识别所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复