赞
踩
在人脸识别之前需要获取人脸的训练集,这里利用的是The ORL Database of Faces’数据库,也可以自己采集人脸图像进行检测然后调整大小,具体的过程可以参照:http://blog.csdn.net/wanghz999/article/details/78751406
人脸识别的过程就是对人脸图像进行训练然后读取人脸并进行识别。在训练时,计算机会对每张人脸的多张图像进行特征提取,然后根据特征值来区分不同的人脸。然而计算机并不知道两种不同的人脸彼此是哪张,因此需要告诉预先告诉计算机一个标签——区分不同的人脸。cvs文件就是包含人脸图像路径和标签的文件,格式如下:
D:/workspace/VS/opencv/face_recg/face_recg/face/s1/1.pgm;0
D:/workspace/VS/opencv/face_recg/face_recg/face/s1/10.pgm;0
D:/workspace/VS/opencv/face_recg/face_recg/face/s1/2.pgm;0
D:/workspace/VS/opencv/face_recg/face_recg/face/s1/3.pgm;0
D:/workspace/VS/opencv/face_recg/face_recg/face/s1/4.pgm;0
...
;
之前的表示人脸图像的路径,;
之后的0
表示标签。opencv官方提供了create_cvs.py,该文件位于源码目录(OPENCV_SOURCE_DIR
)的opencv_contrib模块目录下:
OPENCV_SOURCE_DIR/opencv_contrib/modules/face/samples/etc
也可以直接从github上获取:https://github.com/opencv/opencv_contrib/tree/master/modules/face/samples/etc
这里给出我使用的(python3.*适用):
#!/usr/bin/env python
import sys import os.path # This is a tiny script to help you creating a CSV file from a face # database with a similar hierarchie: # # philipp@mango:~/facerec/data/at$ tree # . # |-- README # |-- s1 # | |-- 1.pgm # | |-- ... # | |-- 10.pgm # |-- s2 # | |-- 1.pgm # | |-- ... # | |-- 10.pgm # ... # |-- s40 # | |-- 1.pgm # | |-- ... # | |-- 10.pgm # if __name__ == "__main__": #if len(sys.argv) != 2: # print "usage: create_csv <base_path>" # sys.exit(1) #BASE_PATH=sys.argv[1] BASE_PATH="D:/workspace/VS\opencv/face_recg/face_recg/face/" SEPARATOR=";" fh = open("at.txt",'w') label = 0 for dirname, dirnames, filenames in os.walk(BASE_PATH): for subdirname in dirnames: subject_path = os.path.join(dirname, subdirname) for filename in os.listdir(subject_path): abs_path = "%s/%s" % (subject_path, filename) print ("%s%s%d" % (abs_path, SEPARATOR, label)) fh.write(abs_path) fh.write(SEPARATOR) fh.write(str(label)) fh.write("\n") label = label + 1 fh.close()
其中,BASE_PATH
表示存放人脸图像的文件夹,在该文件夹下,每个文件夹代表一个人脸,一个人脸应该有多张大小一样的图。该文件夹如下:
opencv支持3种人脸识别的算法,分别是:
自opencv3.0开始,人脸识别的模块也有许多变动,实现跟以前一些很多不一样。上述的3种算法在opencv3.*中对应三个类:EigenFaceRecognizer
、FisherFaceRecognizer
和LBPHFaceRecognizer
,它们都是从BasicFaceRecognizer
继承过来的子类。这三个类有相似的API函数(以EigenFaceRecognizer
为例):
/*创建人脸识别的模型,若该两个参数为空,会以默认值创建
@param num_components:进行训练的人脸图片数
@param threshold: 阈值*/
Ptr<EigenFaceRecognizer> EigenFaceRecognizer::create(int num_components,
double threshold);
/*对模型进行训练
@param src:进行训练的人脸图像
@param labels:标签值,每张相同的人脸都有标签值来区分*/
void train(InputArrayOfArrays src, InputArray labels);
/*利用训练好的模型进行人脸识别,返回标签值
@param src:需要进行识别的图像/
CV_WRAP_AS(predict_label) int predict(InputArray src) const;
#include<iostream> #include<fstream> #include<sstream> #include<math.h> #include<opencv2\opencv.hpp> #include<opencv2\highgui.hpp> #include<cv.h> #include<objdetect.hpp> #include<opencv2/face.hpp> using namespace cv::face; using namespace std; using namespace cv; vector<Mat> faces; vector<int> labels; //使用CVS文件读取图片和标签 void read_cvs(const string& filename, vector<Mat>& img, vector<int>& lable, char separator = ';') { Mat tmp_img; ifstream cvs_file(filename.c_str()); assert(cvs_file); string line, path, tag; while (getline(cvs_file, line)) { stringstream lines(line); getline(lines, path, separator); getline(lines, tag); if (!path.empty() && !tag.empty()) { tmp_img = imread(path, IMREAD_GRAYSCALE); //读入图像时转成灰度图 assert(!tmp_img.empty()); img.push_back(tmp_img); lable.push_back(atoi(tag.c_str())); } } tmp_img.release(); } int main() { string cvs_path = "./face/at.txt"; Mat test_face; int test_label,p_label; int sample_num = 0; try { read_cvs(cvs_path, faces, labels); //读取人脸图像和标签 } catch (cv::Exception& e) { cerr << "Error opening file.Reason:" << e.msg << endl; exit(1); } if (faces.size() <= 1) { cout << "Too few face images" << endl; return -1; } /*从训练集中取出一张图片作为测试图*/ sample_num = faces.size(); test_face = faces[sample_num - 1]; test_label = labels[sample_num - 1]; faces.pop_back(); labels.pop_back(); /* 创建人脸识别的模型,并进行训练,之后保存训练结果*/ Ptr<EigenFaceRecognizer> eigen_model = EigenFaceRecognizer::create(); eigen_model->train(faces, labels); eigen_model->save("my_eigen_face_model.xml"); Ptr<FisherFaceRecognizer> fisher_model = FisherFaceRecognizer::create(); fisher_model->train(faces, labels); fisher_model->save("my_fisher_face_model.xml"); Ptr<LBPHFaceRecognizer> lbph_model = LBPHFaceRecognizer::create(); lbph_model->train(faces, labels); lbph_model->save("my_lbph_face_model.xml"); /*对人脸进行测试,查看是否能够识别*/ p_label = eigen_model->predict(test_face); cout << "Test label is:" << test_label << ",predict label is:"<< p_label << endl; p_label = fisher_model->predict(test_face); cout << "Test label is:" << test_label << ",predict label is:" << p_label << endl; p_label = lbph_model->predict(test_face); cout << "Test label is:" << test_label << ",predict label is:" << p_label << endl; return 0; }
训练和测试使用灰度图。EigenFaceRecognizer
、 FisherFaceRecognizer
两个类在调用train
训练时可以使用BGR图像,但是训练结果中保存的是单通道的灰度图结果。可以查看生成的训练结果文件my_eigen_face_model.xml
:
可以看到在训练结果中保存的训练集是1*10304大小的图片,而我训练集图片大小为92 * 112(92 * 112 = 10304)。在对测试图进行人脸识别时,必须确保测试图大小与保存的训练集大小一致,否则会报错。而LBPHFaceRecognizer
类必须使用灰度图进行训练,不然也会报错。
可以看到程序可以对人脸进行识别,正确给出标签值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。