SVM样本训练步骤
转自:http://blog.csdn.net/xw20084898/article/details/21389885
1、引言
近期在做飞形体目标识别的研究,需要做SVM训练来生成识别的分类器。从网上找了大量的参考文章,但是发现很多文章都讲的比较零散。鉴于此原因,本文对SVM训练过程做一个较为系统的总结,希望对广大初学者有所帮助。
2、步骤
(1)生成SVM描述文件;
将需要训练的样本文件的路径和对应的分类类别号写入txt文档,如:
plane/飞机训练正样本Normalize/0.jpg
1
plane/飞机训练正样本Normalize/1.jpg 命名为:SVM_DATA.txt
1
plane/飞机训练正样本Normalize/1.jpg 命名为:SVM_DATA.txt
1
(2)将描述文件读入容器中;
定义两个容器,用于保存样本路径和分类标号,如:
vector<string> img_path;
vector<int> img_catg;
读入数据:
int nLine = 0;
string buf;
ifstream svm_data( "SVM_DATA.txt" );
- while( svm_data )
- {
- if( getline( svm_data, buf) )
- /*原型
- istream& getline ( istream &is , string &str , char delim ); istream& getline ( istream& , string& );
- 参数 is 进行读入操作的输入流 str 存储读入的内容 delim 终结符 返回值 与参数is是一样的
- 功能 将输入流is中读到的字符存入str中,直到遇到终结符delim才结束。
- 对于第一个函数delim是可以由用户自己定义的终结符;对于第二个函数delim默认为 '\n'(换行符)。
- 函数在输入流is中遇到文件结束符(EOF)或者在读入字符的过程中遇到错误都会结束。
- 在遇到终结符delim后,delim会被丢弃,不存入str中。在下次读入操作时,将在delim的下个字符开始读入。*/
- {
- nLine ++;
- if( nLine % 2 == 0 )
- {
- img_catg.push_back( atoi( buf.c_str() ) );//atoi将字符串转换成整型,值为0或1 用0,1区分正负样本
- //功 能: 把字符串转换成整型数。 名字来源:array to integer 的缩写。
- //原型: int atoi(const char *nptr);
- //函数说明: 参数nptr字符串,如果第一个非空格字符不存在或者不是数字也不是正负号则返回零,否则开始做类型转换,
- //之后检测到非数字(包括结束符 \0) 字符时停止转换,返回整型数。
- // 函数声明:const char *c_str(); c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.
- }
- else
- {
- img_path.push_back( buf );//图像路径
- }
- }
- }
- svm_data.close();//关闭文件
(3)读入样本数量,生成样本矩阵和类型矩阵
- CvMat *data_mat, *res_mat;
- int nImgNum = nLine / 2; //读入样本数量
- 样本矩阵,nImgNum:横坐标是样本数量, WIDTH * HEIGHT:样本特征向量,即图像大小
- data_mat = cvCreateMat( nImgNum, 144, CV_32FC1 );
- cvSetZero( data_mat );
- //类型矩阵,存储每个样本的类型标志
- res_mat = cvCreateMat( nImgNum, 1, CV_32FC1 );
- cvSetZero( res_mat );
(4)读入样本图像
- IplImage* src;
- IplImage* trainImg=cvCreateImage(cvSize(64,64),8,3);//需要分析的图片
- for( string::size_type z = 0; z != img_path.size(); z++ ) //整体循环为z
- {
- src=cvLoadImage(img_path[z].c_str(),1);
- // 函数声明:const char *c_str();c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.
- if( src == NULL )
- {
- cout<<" can not load the image: "<<img_path[z].c_str()<<endl;
- continue;
- }
- cout<<" processing "<<img_path[z].c_str()<<endl;
(5)提取HOG特征
- //以下为提取Hog特征
- cvResize(src,trainImg); //读取图片,归一化大小
- HOGDescriptor *hog=new HOGDescriptor(cvSize(64,64),cvSize(16,16),cvSize(16,16),cvSize(16,16),9);
- vector<float>descriptors;//结果数组
- hog->compute(trainImg, descriptors,Size(8,8), Size(0,0)); //调用计算函数开始计算
- cout<<"HOG dims: "<<descriptors.size()<<endl;
- //CvMat* SVMtrainMat=cvCreateMat(descriptors.size(),1,CV_32FC1);
- n=0;
- for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++) //迭代器
- {
- cvmSet(data_mat,z,n,*iter); //将HOG特征 存入data_mat矩阵中
- x=cvmGet(data_mat,z,n);
- cout<<"hog"<<x<<endl;
- n++;
- }
(6)将HOG特征写入txt文件
- FILE *fp1;
- int i,j;
- if((fp1=fopen("Hog.txt","ab"))==NULL)// 读写打开一个二进制文件,允许读或在文件末追加数据。
- {
- printf("can not open the hu file\n");
- exit(0);//正常退出程序
- }
- for (i = 0; i <144; ++i)
- {
- fprintf(fp1,"%lf ",descriptors[i]);
- }
- //fprintf(fp1,"\r\n");
- fclose(fp1);
- cvmSet( res_mat, z, 0, img_catg[z] ); //将正负样本标记存入矩阵res_mat中
- cout<<" end processing "<<img_path[z].c_str()<<" "<<img_catg[z]<<endl;
- }
(7)进行SVM训练
- CvSVM svm = CvSVM();
- 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种类:CvSVM::C_SVC
- Kernel的种类:CvSVM::RBF
- degree:10.0(此次不使用)
- gamma:8.0
- coef0:1.0(此次不使用)
- C:10.0
- nu:0.5(此次不使用)
- p:0.1(此次不使用)
- 然后对训练数据正规化处理,并放在CvMat型的数组里。
- */
- //SVM学习
- svm.train( data_mat, res_mat, NULL, NULL, param );
- //利用训练数据和确定的学习参数,进行SVM学习
- svm.save( "SVM_DATA1.xml" );
- cvReleaseImage(&src);
- cvReleaseMat( &data_mat );
- cvReleaseMat( &res_mat );
- return 0;
在以上训练过程中,要特别注意的是在创建样本矩阵的时候,其矩阵大小由样本数量和样本提取的特征维数决定的。比如上面创建的样本矩阵大小为:
- int nImgNum = nLine / 2; 行,144列; 144是由提取HOG特征时,由窗口大小、块大小、胞元大小和每个抱怨大小中的特征数共同决定的。