基于OpenCV性别识别

描述

所谓性别识别就是判断检测出来的脸是男性还是女性,是个二元分类问题。识别所用的算法可以是SVM,BP神经网络,LDA,PCA,,PCA+LDA等等。OpenCV官网给出的文档是基于Fisherfaces检测器(LDA)方法实现的。链接: 。这篇博文()中也是采用OpenCV官网的方法,据称有98%的正确率,我在百度图片找了一些数据测试了下,只有大概50%多的识别率。原因是他的数据集是经过严格标定的,好像是眼睛的是对齐的。实际应用中不太可能会遇到这种情况吧。CSDN还有两篇博客也介绍到这个性格识别( )文章写得很好,一看就是大牛。博文中也是测试了LDA的方法,正确率也是出奇的低。采用的是PCA+LDA的方法。通过改进能达到接近90%的正确率。博文指出PCA+LDA比单纯的LDA和PCA识别率都高,但我对博文中的PCA+LDA程序和官网的PCA程序测试了下,发现PCA的正确率会高那么一两个点。难道又是数据的问题?

数据

采集数据一方面可以采用开源的人脸库,另一方面可以自己去百度图片下载图片。去百度或谷歌图片分别搜索“男明星头像”“女明星头像”的关键字批量下载,这里当然需要批量下载利器。然后利用人脸检测器过滤检测出头像,然后归一化检测出来的图像,保存在本地。这样基本的数据集就有了。当然我也会附上我采集的数据和工程文件(特此声明,所有图片均来自网络)

测试程序

创建CSV文件的python代码:

import sysimport os.pathif __name__ == “__main__”:if len(sys.argv) != 3:print “usage: create_csv <base_path> <SAVE_FILE_NAME>”sys.exit(1)BASE_PATH=sys.argv[1]FILE_NAME = sys.argv[2]SEPARATOR=”;”fh = open(FILE_NAME,’w’)label = 0for 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)##print “%s %s” % (dirname, subject_path)fh.write(abs_path)fh.write(SEPARATOR)if dirname.find(“female”) > 0 :label = 1else:label = 0fh.write(str(label))fh.write(“\n”)fh.close()

测试性别识别的程序

g_howManyPhotoForTraining = 260;//每个人取出8张作为训练int g_photoNumberOfOnePerson = 279;cv;;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;}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()));}}}void train_and_test_lda(){string fn_csv = string(“at.txt”);//string fn_csv = string(“feret.txt”);vector<Mat> allImages,train_images,test_images;vector<int> allLabels,train_labels,test_labels;try {read_csv(fn_csv, allImages, allLabels);} catch (cv::Exception& e) {cerr <<“Error opening file “<< fn_csv <<“. Reason: “<< e.msg << endl;// 文件有问题,我们啥也做不了了,退出了exit(1);}if(allImages.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);}for(int i=0 ; i<allImages.size() ; i++)equalizeHist(allImages[i],allImages[i]);int photoNumber = allImages.size();for(int i=0 ; i<photoNumber ; i++){if((i%g_photoNumberOfOnePerson)<g_howManyPhotoForTraining){train_images.push_back(allImages[i]);train_labels.push_back(allLabels[i]);}else{test_images.push_back(allImages[i]);test_labels.push_back(allLabels[i]);}}/*Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型model->train(train_images, train_labels);//训练pca模型,这里的model包含了所有特征值和特征向量,没有损失model->save(“eigenface.yml”);//保存训练结果,供检测时使用 */Ptr<FaceRecognizer> fishermodel = createFisherFaceRecognizer();fishermodel->train(train_images,train_labels);//用保存的降维后的图片来训练fishermodel,后面的内容与原始代码就没什么变化了 fishermodel->save(“fisherlda.yml”);int iCorrectPrediction = 0;int predictedLabel;int testPhotoNumber = test_images.size();for(int i=0;i<testPhotoNumber;i++){predictedLabel = fishermodel->predict(test_images[i]);if(predictedLabel == test_labels[i])iCorrectPrediction++;}string result_message = format(“Test Number = %d / Actual Number = %d.”, testPhotoNumber, iCorrectPrediction);cout << result_message << endl;cout<<“accuracy = “<<float(iCorrectPrediction)/testPhotoNumber<<endl;}void train_and_test_pca(){string fn_csv = string(“at.txt”);//string fn_csv = string(“feret.txt”);vector<Mat> allImages,train_images,test_images;vector<int> allLabels,train_labels,test_labels;try {read_csv(fn_csv, allImages, allLabels);} catch (cv::Exception& e) {cerr <<“Error opening file “<< fn_csv <<“. Reason: “<< e.msg << endl;// 文件有问题,我们啥也做不了了,退出了exit(1);}if(allImages.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);}for(int i=0 ; i<allImages.size() ; i++)equalizeHist(allImages[i],allImages[i]);int photoNumber = allImages.size();for(int i=0 ; i<photoNumber ; i++){if((i%g_photoNumberOfOnePerson)<g_howManyPhotoForTraining){train_images.push_back(allImages[i]);train_labels.push_back(allLabels[i]);}else{test_images.push_back(allImages[i]);test_labels.push_back(allLabels[i]);}}Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型 model->train(train_images, train_labels);//训练pca模型,这里的model包含了所有特征值和特征向量,没有损失 model->save(“eigenfacepca.yml”);//保存训练结果,供检测时使用 int iCorrectPrediction = 0;int predictedLabel;int testPhotoNumber = test_images.size();for(int i=0;i<testPhotoNumber;i++){predictedLabel = model->predict(test_images[i]);if(predictedLabel == test_labels[i])iCorrectPrediction++;}string result_message = format(“Test Number = %d / Actual Number = %d.”, testPhotoNumber, iCorrectPrediction);cout << result_message << endl;cout<<“accuracy = “<<float(iCorrectPrediction)/testPhotoNumber<<endl;}void train_and_test(){string fn_csv = string(“at.txt”);//string fn_csv = string(“feret.txt”);vector<Mat> allImages,train_images,test_images;vector<int> allLabels,train_labels,test_labels;try {read_csv(fn_csv, allImages, allLabels);} catch (cv::Exception& e) {cerr <<“Error opening file “<< fn_csv <<“. Reason: “<< e.msg << endl;// 文件有问题,我们啥也做不了了,退出了exit(1);}if(allImages.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);}for(int i=0 ; i<allImages.size() ; i++)equalizeHist(allImages[i],allImages[i]);int photoNumber = allImages.size();for(int i=0 ; i<photoNumber ; i++){if((i%g_photoNumberOfOnePerson)<g_howManyPhotoForTraining){train_images.push_back(allImages[i]);train_labels.push_back(allLabels[i]);}else{test_images.push_back(allImages[i]);test_labels.push_back(allLabels[i]);}}Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型 model->train(train_images, train_labels);//训练pca模型,这里的model包含了所有特征值和特征向量,没有损失 model->save(“eigenface.yml”);//保存训练结果,供检测时使用 Mat eigenvalues = model->getMat(“eigenvalues”);//提取model中的特征值,该特征值默认由大到小排列 Mat W = model->getMat(<Mat> reduceDemensionimages;//降维后的图像矩阵 vector<Mat> testreduceDemensionimages;Mat evs = Mat(W, Range::all(), Range(0, xth));//选择前xth个特征向量,其余舍弃Mat mean = model->getMat(“mean”);for(int i=0;i<train_images.size();i++){Mat projection = subspaceProject(evs, mean, train_images[i].reshape(1,1));//做子空间投影 reduceDemensionimages.push_back(projection.reshape(1,sqrt(xth*1.0)));//将获得的子空间系数表示映射成2维图像,并保存起来 }for(int i=0;i<test_images.size();i++){Mat projection = subspaceProject(evs, mean, test_images[i].reshape(1,1));//做子空间投影 testreduceDemensionimages.push_back(projection.reshape(1,sqrt(xth*1.0)));//将获得的子空间系数表示映射成2维图像,并保存起来 }Ptr<FaceRecognizer> fishermodel = createFisherFaceRecognizer();fishermodel->train(reduceDemensionimages,train_labels);//用保存的降维后的图片来训练fishermodel,后面的内容与原始代码就没什么变化了 fishermodel->save(“fisher.yml”);int iCorrectPrediction = 0;int predictedLabel;int testPhotoNumber = test_images.size();for(int i=0;i<testPhotoNumber;i++){predictedLabel = fishermodel->predict(testreduceDemensionimages[i]);if(predictedLabel == test_labels[i])iCorrectPrediction++;}string result_message = format(“Test Number = %d / Actual Number = %d.”, testPhotoNumber, iCorrectPrediction);cout << result_message << endl;cout<<“accuracy = “<<float(iCorrectPrediction)/testPhotoNumber<<endl;}void test_pca(){string fn_csv = string(“test.txt”);vector<Mat> allImages;vector<int> allLabels;try {read_csv(fn_csv, allImages, allLabels);} catch (cv::Exception& e) {cerr <<“Error opening file “<< fn_csv <<“. Reason: “<< e.msg << endl;// 文件有问题,我们啥也做不了了,退出了exit(1);}if(allImages.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);}Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型 model->load(“eigenfacepca.yml”);//保存训练结果,供检测时使用 int iCorrectPrediction = 0;int predictedLabel;int testPhotoNumber = allImages.size();for(int i=0;i<testPhotoNumber;i++){predictedLabel = model->predict(allImages[i]);if(predictedLabel == allLabels[i])iCorrectPrediction++;}string result_message = format(“Test Number = %d / Actual Number = %d.”, testPhotoNumber, iCorrectPrediction);cout << result_message << endl;cout<<“accuracy = “<<float(iCorrectPrediction)/testPhotoNumber<<endl; }void test(){string fn_csv = string(“test.txt”);vector<Mat> allImages;vector<int> allLabels;try {read_csv(fn_csv, allImages, allLabels);} catch (cv::Exception& e) {cerr <<“Error opening file “<< fn_csv <<“. Reason: “<< e.msg << endl;// 文件有问题,我们啥也做不了了,退出了exit(1);}if(allImages.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);}Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型 model->load(“eigenface.yml”);//保存训练结果,供检测时使用 Mat eigenvalues = model->getMat(“eigenvalues”);//提取model中的特征值,该特征值默认由大到小排列 Mat W = model->getMat(<Mat> reduceDemensionimages;//降维后的图像矩阵 Mat evs = Mat(W, Range::all(), Range(0, xth));//选择前xth个特征向量,其余舍弃Mat mean = model->getMat(“mean”);for(int i=0;i<allImages.size();i++){Mat projection = subspaceProject(evs, mean, allImages[i].reshape(1,1));//做子空间投影 reduceDemensionimages.push_back(projection.reshape(1,sqrt(xth*1.0)));//将获得的子空间系数表示映射成2维图像,并保存起来 }Ptr<FaceRecognizer> fishermodel = createFisherFaceRecognizer();fishermodel->load(“fisher.yml”);int iCorrectPrediction = 0;int predictedLabel;int testPhotoNumber = allImages.size();for(int i=0;i<testPhotoNumber;i++){predictedLabel = fishermodel->predict(reduceDemensionimages[i]);if(predictedLabel == allLabels[i])iCorrectPrediction++;}string result_message = format(“Test Number = %d / Actual Number = %d.”, testPhotoNumber, iCorrectPrediction);cout << result_message << endl;cout<<“accuracy = “<<float(iCorrectPrediction)/testPhotoNumber<<endl; }int main() {cout<<“lda = “<<endl;train_and_test_lda();cout<<“pca = “<<endl;train_and_test_pca();cout<<“pca+lda = “<<endl;train_and_test();/*test();test_pca();*/return 0 ;}

整个工程文件和数据下载链接

奋斗令我们的生活充满生机,责任让我们的生命充满意义!

基于OpenCV性别识别

相关文章:

你感兴趣的文章:

标签云: