您的位置:首页 > 运维架构

opencv SVM多分类 人脸识别

2017-10-14 16:54 1361 查看
  上一篇介绍了OPENCV中SVM的简单使用,以及自带的一个二分类问题。

  例子中的标签是程序手动写的,输入也是手动加的二维坐标点。  

  对于复杂问题就必须使用数据集中的图片进行训练,标签使用TXT文件或程序设置好,下面以 IMM Face Database 中的人脸数据作为示例,

实现人脸的HOG特征提取及SVM识别人脸。

  数据集参考我的http://www.cnblogs.com/chenzhefan/p/7624811.html;只选取其中5类人,每类5副图片作为训练。

  提取人脸HOG特征的维数为1764,具体见代码设置。

void HogSVM()
{
int ImgWidht = 64;
int ImgHeight = 64;
vector<string> img_path;
vector<int> img_catg;
int nLine = 0;
string buf;
ifstream svm_data("E:\\vswork\\car3\\train\\train.txt");
unsigned long n;

for (int catg = 0; catg < 5; catg++)
{
for (int num = 0; num < 5; num++)
{
if (getline(svm_data, buf))
{
img_catg.push_back(catg);//图像类别
img_path.push_back(buf);//图像路径
nLine++;
}
}

}

svm_data.close();//关闭文件

Mat data_mat, res_mat;
int nImgNum = nLine;            //读入样本数量
//样本矩阵,nImgNum:行数代表样本的数量,每一行就是由一张图片计算得到HOG的特征向量,
data_mat = Mat::zeros(nImgNum, 1764, CV_32FC1);
res_mat = Mat::zeros(nImgNum, 1, CV_32FC1);

Mat src;
Mat trainImg = Mat::zeros(ImgHeight, ImgWidht, CV_8UC3);//需要分析的图片

for (string::size_type i = 0; i != img_path.size(); i++)
{
src = imread(img_path[i].c_str(), 1);

cout << " processing " << img_path[i].c_str() << endl;

resize(src, trainImg, cv::Size(ImgWidht, ImgHeight), 0, 0, INTER_CUBIC);
HOGDescriptor *hog = new HOGDescriptor(cvSize(ImgWidht, ImgHeight), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);  //构造HOG,具体意思见参考文章1,2
vector<float>descriptors;//结果数组
hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0)); //调用计算函数开始计算
if (i == 0)
{
data_mat = Mat::zeros(nImgNum, descriptors.size(), CV_32FC1); //根据输入图片大小进行分配空间
}
cout << "HOG dims: " << descriptors.size() << endl;
n = 0;
for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
{
data_mat.at<float>(i, n) = *iter;
n++;
}
res_mat.at<float>(i, 0) = img_catg[i];
cout << " end processing " << img_path[i].c_str() << " " << img_catg[i] << endl;
}

CvSVM svm;
CvSVMParams param;
CvTermCriteria criteria;
criteria = cvTermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON);
param = CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria);

svm.train(data_mat, res_mat, Mat(), Mat(), param);
svm.save("SVM_DATA.xml");

return;
}


上述函数主要完成提取训练图片的HOG特征,并用SVM训练模型,保存为XML文件方便快速使用。

训练结果如图:


训练完成后即可以使用测试图片进行图片识别了:

void HogSVMPre()
{
//检测样本
vector<string> img_tst_path;
string buf;
unsigned long n;
int ImgWidht = 64;
int ImgHeight = 64;
Mat TestImg = Mat::zeros(ImgHeight, ImgWidht, CV_8UC3);
ifstream img_tst("E:\\vswork\\car3\\val\\val.txt");
while (img_tst)
{
if (getline(img_tst, buf))
{
img_tst_path.push_back(buf);
}
}
img_tst.close();
CvSVM svm;
svm.load("SVM_DATA.xml");
Mat test;
char line[512];
ofstream predict_txt("SVM_PREDICT.txt");
for (string::size_type j = 0; j != img_tst_path.size(); j++)
{
test = imread(img_tst_path[j].c_str(), 1);//读入图像
resize(test, TestImg, cv::Size(ImgWidht, ImgHeight), 0, 0, INTER_CUBIC);//要搞成同样的大小才可以检测到
HOGDescriptor *hog = new HOGDescriptor(cvSize(ImgWidht, ImgHeight), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);  //窗口大小,块大小,块滑动增量,cell的大小,bins的个数
vector<float>descriptors;//结果数组
hog->compute(TestImg, descriptors, Size(1, 1), Size(0, 0)); //调用计算函数开始计算
cout << "The Detection Result:" << endl;
cout << "HOG dims: " << descriptors.size() << endl;
Mat SVMtrainMat = Mat::zeros(1, descriptors.size(), CV_32FC1);
n = 0;
for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
{
SVMtrainMat.at<float>(0, n) = *iter;
n++;
}

int ret = svm.predict(SVMtrainMat);
std::sprintf(line, "%s %d\r\n", img_tst_path[j].c_str(), ret);
printf("%s %d\r\n", img_tst_path[j].c_str(), ret);//输出预测的结果,ret的值就代表类别
//getchar();
predict_txt << line;
}
predict_txt.close();
system("PAUSE");
return;
}


预测结果:


小样本图片SVM的识别结果还是很不错的。本文的测试图片较少,也不能说明模型到底有多好,但基于opencv SVM的识别分类流程基本是这样了。

有问题欢迎讨论~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: