opencv SVM多分类 人脸识别
上一篇介绍了OPENCV中SVM的简单使用,以及自带的一个二分类问题。
例子中的标签是程序手动写的,输入也是手动加的二维坐标点。
对于复杂问题就必须使用数据集中的图片进行训练,标签使用TXT文件或程序设置好,下面以 IMM Face Database 中的人脸数据作为示例,
实现人脸的HOG特征提取及SVM识别人脸。
数据集参考我的http://www.cnblogs.com/chenzhefan/p/7624811.html;只选取其中5类人,每类5副图片作为训练。
提取人脸HOG特征的维数为1764,具体见代码设置。
1 void HogSVM() 2 { 3 int ImgWidht = 64; 4 int ImgHeight = 64; 5 vector<string> img_path; 6 vector<int> img_catg; 7 int nLine = 0; 8 string buf; 9 ifstream svm_data("E:\\vswork\\car3\\train\\train.txt"); 10 unsigned long n; 11 12 for (int catg = 0; catg < 5; catg++) 13 { 14 for (int num = 0; num < 5; num++) 15 { 16 if (getline(svm_data, buf)) 17 { 18 img_catg.push_back(catg);//图像类别 19 img_path.push_back(buf);//图像路径 20 nLine++; 21 } 22 } 23 24 } 25 26 svm_data.close();//关闭文件 27 28 Mat data_mat, res_mat; 29 int nImgNum = nLine; //读入样本数量 30 //样本矩阵,nImgNum:行数代表样本的数量,每一行就是由一张图片计算得到HOG的特征向量, 31 data_mat = Mat::zeros(nImgNum, 1764, CV_32FC1); 32 res_mat = Mat::zeros(nImgNum, 1, CV_32FC1); 33 34 Mat src; 35 Mat trainImg = Mat::zeros(ImgHeight, ImgWidht, CV_8UC3);//需要分析的图片 36 37 for (string::size_type i = 0; i != img_path.size(); i++) 38 { 39 src = imread(img_path[i].c_str(), 1); 40 41 cout << " processing " << img_path[i].c_str() << endl; 42 43 resize(src, trainImg, cv::Size(ImgWidht, ImgHeight), 0, 0, INTER_CUBIC); 44 HOGDescriptor *hog = new HOGDescriptor(cvSize(ImgWidht, ImgHeight), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9); //构造HOG,具体意思见参考文章1,2 45 vector<float>descriptors;//结果数组 46 hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0)); //调用计算函数开始计算 47 if (i == 0) 48 { 49 data_mat = Mat::zeros(nImgNum, descriptors.size(), CV_32FC1); //根据输入图片大小进行分配空间 50 } 51 cout << "HOG dims: " << descriptors.size() << endl; 52 n = 0; 53 for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++) 54 { 55 data_mat.at<float>(i, n) = *iter; 56 n++; 57 } 58 res_mat.at<float>(i, 0) = img_catg[i]; 59 cout << " end processing " << img_path[i].c_str() << " " << img_catg[i] << endl; 60 } 61 62 CvSVM svm; 63 CvSVMParams param; 64 CvTermCriteria criteria; 65 criteria = cvTermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON); 66 param = CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria); 67 68 svm.train(data_mat, res_mat, Mat(), Mat(), param); 69 svm.save("SVM_DATA.xml"); 70 71 return; 72 }
上述函数主要完成提取训练图片的HOG特征,并用SVM训练模型,保存为XML文件方便快速使用。
训练结果如图:
训练完成后即可以使用测试图片进行图片识别了:
1 void HogSVMPre() 2 { 3 //检测样本 4 vector<string> img_tst_path; 5 string buf; 6 unsigned long n; 7 int ImgWidht = 64; 8 int ImgHeight = 64; 9 Mat TestImg = Mat::zeros(ImgHeight, ImgWidht, CV_8UC3); 10 ifstream img_tst("E:\\vswork\\car3\\val\\val.txt"); 11 while (img_tst) 12 { 13 if (getline(img_tst, buf)) 14 { 15 img_tst_path.push_back(buf); 16 } 17 } 18 img_tst.close(); 19 CvSVM svm; 20 svm.load("SVM_DATA.xml"); 21 Mat test; 22 char line[512]; 23 ofstream predict_txt("SVM_PREDICT.txt"); 24 for (string::size_type j = 0; j != img_tst_path.size(); j++) 25 { 26 test = imread(img_tst_path[j].c_str(), 1);//读入图像 27 resize(test, TestImg, cv::Size(ImgWidht, ImgHeight), 0, 0, INTER_CUBIC);//要搞成同样的大小才可以检测到 28 HOGDescriptor *hog = new HOGDescriptor(cvSize(ImgWidht, ImgHeight), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9); //窗口大小,块大小,块滑动增量,cell的大小,bins的个数 29 vector<float>descriptors;//结果数组 30 hog->compute(TestImg, descriptors, Size(1, 1), Size(0, 0)); //调用计算函数开始计算 31 cout << "The Detection Result:" << endl; 32 cout << "HOG dims: " << descriptors.size() << endl; 33 Mat SVMtrainMat = Mat::zeros(1, descriptors.size(), CV_32FC1); 34 n = 0; 35 for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++) 36 { 37 SVMtrainMat.at<float>(0, n) = *iter; 38 n++; 39 } 40 41 int ret = svm.predict(SVMtrainMat); 42 std::sprintf(line, "%s %d\r\n", img_tst_path[j].c_str(), ret); 43 printf("%s %d\r\n", img_tst_path[j].c_str(), ret);//输出预测的结果,ret的值就代表类别 44 //getchar(); 45 predict_txt << line; 46 } 47 predict_txt.close(); 48 system("PAUSE"); 49 return; 50 }
预测结果:
小样本图片SVM的识别结果还是很不错的。本文的测试图片较少,也不能说明模型到底有多好,但基于opencv SVM的识别分类流程基本是这样了。
有问题欢迎讨论~
学学学~