利用openCV的PCA+SVM实现人脸识别,即用PCA对数据集进行降维,保留主要的成分,然后送至SVM进行训练,对于当训练数据特别庞大时,可以达到缩小SVM模型提升分类速度的目的。
欢迎一起学习交流!
软件开发平台:visual studio 2013
opencv version:3.3.0
请注意上面两个的版本要匹配才行,opencv3.3.0有VC12的lib库,可以在网上查一下visual studio和VC的对应版本,这里visual studio 2013对应的就是VC12
目录
- 准备和读取数据
- 数据前处理
- 数据分类
- PCA降维
- SVM分类
- 预测
- 关于非训练类别预测结果随机的处理办法
- 参考链接
1. 准备和读取数据
1.1 目录介绍
首先给大家看一下我的VS目录结构,DataBase中就是存放的数据集,其中的图像都是未经处理过的含有人脸的图片。
DataBase文件夹如下图:
1.2 数据读取
本文采用读取TXT文件的方式,依次读入所需图片数据:
PathForTrain.txt包含了训练集的路径:
PathForTest.txt包含了测试机的路径:
1.3 图像读取程序
首先实现一个根据TXT文件路径读取所以图片的函数:
vector<vector<String> > getImgPath(string s,int& num){
ifstream path(s);
vector<string> ipath;//多少个文件夹
string buf;
while (path){
if (getline(path, buf)){
ipath.push_back(buf);//图像所在的文件夹
}
}
path.close();
vector<vector<String> > allpath;//所有文件夹下的图片(*.jpg)文件的路径
for (size_t i = 0; i < ipath.size(); i++){
string pattern_jpg = ipath[i];
vector<String> files;
cv::glob(pattern_jpg, files);
if (files.size() == 0) {
std::cout << "No image files[jpg]" << std::endl;
}
num += files.size();//每个文件夹下的图片数量之和
allpath.push_back(files);
}
return allpath;
}
然后调用这个函数,举个例子:
//1. 通过path.txt确定需要读取的图片文件夹和类别
vector<vector<String> > imgByDir;//按文件夹存储图片路径的向量,每个文件夹代表不同的label
int nImgNum = 0; //nImgNum是样本数量
imgByDir = getImgPath("PathForTrain.txt", nImgNum);
cout << "共有样本个数为:" << nImgNum <<
2. 数据前处理
本文的目的是实现人脸识别,所以首先需要进行人脸检测,把人脸数据送去降维和分类,这里用opencv自带的人脸检测模型,这里分两步:
第一步加载人脸检测分类器
//0. 加载人脸检测模型
String face_cascade_name = "src/haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;
if (!face_cascade.load(face_cascade_name)){
printf("--(!)Error loading\n"); return -1; };
第二步对人脸区域图像裁剪
Mat getFaceImg(Mat src, CascadeClassifier cascade){
//人脸检测
std::vector<Rect> faces;
Mat face = src;
//equalizeHist(src,src);//直方图均衡化
cascade.detectMultiScale(src, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
//裁剪出人脸
for (size_t f = 0; f < faces.size(); f++)