训练数据采集分为正样本和负样本
正样本:正脸、侧脸、抬头、低头、表情,4000张
负样本:平面照片、弯曲照片、褶皱照片、照片抠眼鼻嘴做简单面具、电子屏,4000张
分辨率为128*128,因为1米以内的人脸框大小在100多左右
保存格式为.xml
FileStorage fs(savename, FileStorage::WRITE);//savename表示保存的文件名 fs << "depth" << image2;//image2表示128*128的16位深度人脸框信息 cout << savename << " ,save successful" << endl; fs.release();然后开始训练模型
LBP.h #ifndef __LBP_H__ #define __LBP_H__ #include "opencv2/opencv.hpp" #include<vector> using namespace std; using namespace cv; class LBP { public: void elbp(const Mat &src, Mat &dst, int radius, int neighbors); }; #endif
//SVMTest.h #ifndef __SVMTEST__ #define __SVMTEST__ #include "opencv2/ml.hpp" //#include"../Utility/CommonUtility.h" //#include"../Utility/LogInterface.h" #include<fstream> #include"LBP.h" using namespace cv::ml; // if you do not need log,comment it,just like :#define LOG_WARN_SVM_TEST(...) //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", WARN_LOG_LEVEL, __VA_ARGS__) #define LOG_DEBUG_SVM_TEST(...) //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", DEBUG_LOG_LEVEL, __VA_ARGS__) #define LOG_ERROR_SVM_TEST(...) //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", ERROR_LOG_LEVEL, __VA_ARGS__) #define LOG_INFO_SVM_TEST(...) //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", INFO_LOG_LEVEL, __VA_ARGS__) #define LOG_WARN_SVM_TEST(...) //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", WARN_LOG_LEVEL, __VA_ARGS__) //#define CONFIG_FILE "./Resource/Configuration.xml" #define CELL_SIZE 16 class SVMTest { public: SVMTest(const string &_trainDataFileList, const string &_testDataFileList, const string &_svmModelFilePath, const string &_predictResultFilePath, SVM::Types svmType, // See SVM::Types. Default value is SVM::C_SVC. SVM::KernelTypes kernel, double c, // For SVM::C_SVC, SVM::EPS_SVR or SVM::NU_SVR. Default value is 0. double coef, // For SVM::POLY or SVM::SIGMOID. Default value is 0. double degree, // For SVM::POLY. Default value is 0. double gamma, // For SVM::POLY, SVM::RBF, SVM::SIGMOID or SVM::CHI2. Default value is 1. double nu, // For SVM::NU_SVC, SVM::ONE_CLASS or SVM::NU_SVR. Default value is 0. double p // For SVM::EPS_SVR. Default value is 0. ); bool Initialize(); virtual ~SVMTest(); void Train(); void Predict(); private: string trainDataFileList; string testDataFileList; string svmModelFilePath; string predictResultFilePath; string predictResultError; // SVM Ptr<SVM> svm; // feature extracting(HOG,LBP,Haar,etc) LBP lbp; }; #endif // SVMTEST
SVM训练模型主要参考了http://blog.csdn.net/qianqing13579,自己改了些东西,先表示感谢!
//LBP.cpp #include"LBP.h" void elbp(const Mat &src, Mat &dst, int radius, int neighbors) { CV_Assert(src.depth() == CV_16U&&src.channels() ==1); for (int n = 0; n < neighbors; n++) { //采样点的计算 float x = static_cast<float>(-radius * sin(2.0*CV_PI*n / static_cast<float>(neighbors))); float y = static_cast<float>(radius * sin(2.0*CV_PI*n / static_cast<float>(neighbors))); //上取整和下取整的值 int fx = static_cast<int>(floor(x)); int fy = static_cast<int>(floor(y)); int cx = static_cast<int>(ceil(x)); int cy = static_cast<int>(ceil(y)); //小数部分 float ty = y - fy; float tx = x - fx; //设置插值权重 float w1 = (1 - tx) * (1 - ty); float w2 = tx * (1 - ty); float w3 = (1 - tx) * ty; float w4 = tx * ty; //循环处理图像数据 for (int i = radius; i < src.rows - radius; i++) { for (int j = radius; j < src.cols - radius; j++) { //计算插值 float t = static_cast<float>(w1*src.at<ushort>(i + fy, j + fx) + w2 * src.at<ushort>(i + fy, j + cx) + w3 * src.at<ushort>(i + cy, j + fx) + w4 * src.at<ushort>(i + cy, j + cx)); //进行编码 dst.at<uchar>(i - radius, j - radius) += ((t > src.at<ushort>(i, j)) || (std::abs(t - src.at<ushort>(i, j)) < std::numeric_limits<float>::epsilon())) << n; } } } } //SVMTest.cpp #include"SVMTest.h" SVMTest::SVMTest(const string &_trainDataFileList, const string &_testDataFileList, const string &_svmModelFilePath, const string &_predictResultFilePath, SVM::Types svmType, // See SVM::Types. Default value is SVM::C_SVC. SVM::KernelTypes kernel, double c, // For SVM::C_SVC, SVM::EPS_SVR or SVM::NU_SVR. Default value is 0. double coef, // For SVM::POLY or SVM::SIGMOID. Default value is 0. double degree, // For SVM::POLY. Default value is 0. double gamma, // For SVM::POLY, SVM::RBF, SVM::SIGMOID or SVM::CHI2. Default value is 1. double nu, // For SVM::NU_SVC, SVM::ONE_CLASS or SVM::NU_SVR. Default value is 0. double p // For SVM::EPS_SVR. Default value is 0. ) : trainDataFileList(_trainDataFileList), testDataFileList(_testDataFileList), svmModelFilePath(_svmModelFilePath), predictResultFilePath(_predictResultFilePath) { // set svm param svm = SVM::create(); svm->setC(c); svm->setCoef0(coef); svm->setDegree(degree); svm->setGamma(gamma); svm->setKernel(kernel); svm->setNu(nu); svm->setP(p); svm->setType(svmType); //svm->setTermCriteria(TermCriteria(TermCriteria::EPS, 1000, FLT_EPSILON)); // based on accuracy svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6)); // based on the maximum number of iterations } bool SVMTest::Initialize() { // initialize log //InitializeLog("SVMTest"); return true; } SVMTest::~SVMTest() { } void SVMTest::Train() { // 读入训练样本图片路径和类别 std::vector<string> imagePaths; std::vector<int> imageClasses; string line; std::ifstream trainingData(trainDataFileList, ios::out); while (getline(trainingData, line)) { if (line.empty()) continue; stringstream stream(line); string imagePath, imageClass; stream >> imagePath; stream >> imageClass; imagePaths.push_back(imagePath); imageClasses.push_back(atoi(imageClass.c_str())); } trainingData.close(); printf("%d\n", imagePaths.size()); // extract feature Mat featureVectorsOfSample; Mat classOfSample; printf("get feature...\n"); LOG_INFO_SVM_TEST("get feature..."); for (int i = 0; i <= imagePaths.size() - 1; ++i) { //Mat srcImage = imread(imagePaths[i], -1); //读取xml文件中保存的数据 FileStorage fs(imagePaths[i], FileStorage::READ); Mat srcImage; fs["depth"] >> srcImage; fs.release(); if (srcImage.empty() || srcImage.depth() != CV_16U) { printf("%s srcImage.empty()||srcImage.depth()!=CV_16U!\n", imagePaths[i].c_str()); LOG_ERROR_SVM_TEST("%s srcImage.empty()||srcImage.depth()!=CV_8U!", imagePaths[i].c_str()); continue; } // extract feature //Mat featureVector; //lbp.ComputeLBPFeatureVector_Rotation_Uniform(srcImage, Size(CELL_SIZE, CELL_SIZE), featureVector); Mat featureVectorOfTestImage = Mat(srcImage.rows, srcImage.cols, CV_8UC1, Scalar(0)); lbp.elbp(srcImage, featureVectorOfTestImage,1,8); //lbp直方图归一化 const int channels[1] = { 0 }; int histSize[] = { 256 };//如果这里写成int histSize = 256; 那么下面调用计算直方图函数的时候,该变量需要写&histSize float midRanges[] = { 0,255 }; const float *ranges[] = { midRanges }; cv::Mat dstHist(256, 1, CV_32FC1); cv::calcHist(&featureVectorOfTestImage, 1, channels, Mat(), dstHist, 1, histSize, ranges, true, false); cv::Mat matResult(1, 256, CV_32FC1); transpose(dstHist, matResult); normalize(matResult, matResult, 0, 1, NORM_MINMAX, -1, Mat());//归一化结果存在dstHist if (matResult.empty()) continue; featureVectorsOfSample.push_back(matResult); classOfSample.push_back(imageClasses[i]); printf("get feature... %f% \n", (i + 1)*100.0 / imagePaths.size()); LOG_INFO_SVM_TEST("get feature... %f", (i + 1)*100.0 / imagePaths.size()); } printf("get feature done!\n"); LOG_INFO_SVM_TEST("get feature done!"); // train printf("training...\n"); LOG_INFO_SVM_TEST("training..."); double time1, time2; time1 = getTickCount(); //自动训练参数 Ptr<TrainData> td = TrainData::create(featureVectorsOfSample, SampleTypes::ROW_SAMPLE, classOfSample); ParamGrid c_grid(0.0001, 1000, 10); svm->trainAuto(td, 10, c_grid); //svm->train(featureVectorsOfSample, ROW_SAMPLE, classOfSample); time2 = getTickCount(); printf("训练时间:%f\n", (time2 - time1)*1000. / getTickFrequency()); LOG_INFO_SVM_TEST("训练时间:%f", (time2 - time1)*1000. / getTickFrequency()); printf("training done!\n"); LOG_INFO_SVM_TEST("training done!"); // save model svm->save(svmModelFilePath); } void SVMTest::Predict() { // predict std::vector<string> testImagePaths; std::vector<int> testImageClasses; string line; std::ifstream testData(testDataFileList, ios::out); while (getline(testData, line)) { if (line.empty()) continue; stringstream stream(line); string imagePath, imageClass; stream >> imagePath; stream >> imageClass; testImagePaths.push_back(imagePath); testImageClasses.push_back(atoi(imageClass.c_str())); } testData.close(); printf("predicting...\n"); LOG_INFO_SVM_TEST("predicting..."); int numberOfRight_0 = 0; int numberOfError_0 = 0; int numberOfRight_1 = 0; int numberOfError_1 = 0; svm = cv::ml::StatModel::load<cv::ml::SVM>("..\\Classifier_xml_elbp_auto_20190313.xml"); std::ofstream fileOfPredictResult(predictResultFilePath, ios::out); //最后识别的结果 std::ofstream fileOfPredictError(predictResultError, ios::out); //最后识别的结果 double sum_Predict = 0, sum_ExtractFeature = 0; char line2[256] = { 0 }; for (int i = 0; i < testImagePaths.size(); ++i) { //Mat srcImage = imread(testImagePaths[i], -1); //if (srcImage.empty() || srcImage.depth() != CV_8U) //{ // printf("%s srcImage.empty()||srcImage.depth()!=CV_8U!\n", testImagePaths[i].c_str()); // LOG_ERROR_SVM_TEST("%s srcImage.empty()||srcImage.depth()!=CV_8U!", testImagePaths[i].c_str()); // continue; //} extract feature //double time1_ExtractFeature = getTickCount(); //Mat featureVectorOfTestImage; //lbp.ComputeLBPFeatureVector_Rotation_Uniform(srcImage, Size(CELL_SIZE, CELL_SIZE), featureVectorOfTestImage); //if (featureVectorOfTestImage.empty()) // continue; //double time2_ExtractFeature = getTickCount(); //sum_ExtractFeature += (time2_ExtractFeature - time1_ExtractFeature) * 1000 / getTickFrequency(); FileStorage fs(testImagePaths[i], FileStorage::READ); Mat srcImage; fs["depth"] >> srcImage; fs.release(); if (srcImage.empty() || srcImage.depth() != CV_16U) { printf("%s srcImage.empty()||srcImage.depth()!=CV_16U!\n", testImagePaths[i].c_str()); LOG_ERROR_SVM_TEST("%s srcImage.empty()||srcImage.depth()!=CV_8U!", testImagePaths[i].c_str()); continue; } // extract feature //Mat featureVector; //lbp.ComputeLBPFeatureVector_Rotation_Uniform(srcImage, Size(CELL_SIZE, CELL_SIZE), featureVector); Mat featureVectorOfTestImage = Mat(srcImage.rows, srcImage.cols, CV_8UC1, Scalar(0)); lbp.elbp(srcImage, featureVectorOfTestImage, 1, 8); //lbp直方图归一化 const int channels[1] = { 0 }; int histSize[] = { 256 };//如果这里写成int histSize = 256; 那么下面调用计算直方图函数的时候,该变量需要写&histSize float midRanges[] = { 0,255 }; const float *ranges[] = { midRanges }; cv::Mat dstHist(256, 1, CV_32FC1); cv::calcHist(&featureVectorOfTestImage, 1, channels, Mat(), dstHist, 1, histSize, ranges, true, false); cv::Mat matResult(1, 256, CV_32FC1); transpose(dstHist, matResult); normalize(matResult, matResult, 0, 1, NORM_MINMAX, -1, Mat());//归一化结果存在dstHist if (matResult.empty()) continue; //对测试图片进行分类并写入文件 double time1_Predict = getTickCount(); int predictResult = svm->predict(matResult); float response = svm->predict(matResult, noArray(), StatModel::Flags::RAW_OUTPUT); float result = response * 1000000; cout << "result: " << result << endl; double time2_Predict = getTickCount(); sum_Predict += (time2_Predict - time1_Predict) * 1000 / getTickFrequency(); sprintf(line2, "%s %d\n", testImagePaths[i].c_str(), predictResult); fileOfPredictResult << line2; LOG_INFO_SVM_TEST("%s %d", testImagePaths[i].c_str(), predictResult); // 0 if ((testImageClasses[i] == 0) && (predictResult >= 0)) { ++numberOfRight_0; } if ((testImageClasses[i] == 0) && (predictResult < 0)) { ++numberOfError_0; fileOfPredictError << line2; } // 1 if ((testImageClasses[i] == 1) && (predictResult < 0)) { ++numberOfRight_1; } if ((testImageClasses[i] == 1) && (predictResult >= 0)) { ++numberOfError_1; fileOfPredictError << line2; } printf("predicting...%f%\n", 100.0*(i + 1) / testImagePaths.size()); } printf("predicting done!\n"); LOG_INFO_SVM_TEST("predicting done!"); printf("extract feature time:%f\n", sum_ExtractFeature / testImagePaths.size()); LOG_INFO_SVM_TEST("extract feature time:%f", sum_ExtractFeature / testImagePaths.size()); sprintf(line2, "extract feature time:%f\n", sum_ExtractFeature / testImagePaths.size()); fileOfPredictResult << line2; printf("predict time:%f\n", sum_Predict / testImagePaths.size()); LOG_INFO_SVM_TEST("predict time:%f", sum_Predict / testImagePaths.size()); sprintf(line2, "predict time:%f\n", sum_Predict / testImagePaths.size()); fileOfPredictResult << line2; // 0 double accuracy_0 = (100.0*(numberOfRight_0)) / (numberOfError_0 + numberOfRight_0); printf("0:%f\n", accuracy_0); LOG_INFO_SVM_TEST("0:%f", accuracy_0); sprintf(line2, "0:%f\n", accuracy_0); fileOfPredictResult << line2; // 1 double accuracy_1 = (100.0*numberOfRight_1) / (numberOfError_1 + numberOfRight_1); printf("1:%f\n", accuracy_1); LOG_INFO_SVM_TEST("1:%f", accuracy_1); sprintf(line2, "1:%f\n", accuracy_1); fileOfPredictResult << line2; // accuracy double accuracy_All = (100.0*(numberOfRight_1 + numberOfRight_0)) / (numberOfError_0 + numberOfRight_0 + numberOfError_1 + numberOfRight_1); printf("accuracy:%f\n", accuracy_All); LOG_INFO_SVM_TEST("accuracy:%f", accuracy_All); sprintf(line2, "accuracy:%f\n", accuracy_All); fileOfPredictResult << line2; fileOfPredictResult.close(); fileOfPredictError.close(); } //main.cpp #include"SVMTest.h" int main(int argc, char *argv[]) { string root = "/home/qq/Image2/Texture/SVMTest/"; SVMTest svmTest(root + "Train.txt", // train filelist root + "Test.txt", // test filelist root + "Classifier.xml", // classifier root + "PredictResult.txt", //predict result SVM::C_SVC, // svmType SVM::RBF, // kernel 1, // c 0, // coef 0, // degree 1, // gamma 0, // nu 0); // p if (!svmTest.Initialize()) { printf("initialize failed!\n"); //LOG_ERROR_SVM_TEST("initialize failed!"); return; } svmTest.Train(); svmTest.Predict(); return 0; }