svm+hog的手写体识别

svm训练.xml文件

#include "opencv2/opencv.hpp"
#include "iostream"
#include "fstream"  
using namespace cv;
using namespace std;
void getdata()
{

vector<string> img_path;//输入文件名变量     
    vector<int> img_catg;  //标签 
int nLine = 0;     
int i;
    string buf;     
char c[20];
    ifstream svm_data( "bh.txt" );//训练样本图片的路径都写在这个txt文件中,bat批处理, ifstream从已有的文件读
unsigned long n;       
    while( svm_data )//将训练样本文件依次读取进来      
    {      
        if( getline( svm_data, buf ))    //将输入流svm_data中读到的字符存入buf中,getline把svm_data中的文件输出到buf字符串  
        {      
            nLine ++;      
            if( nLine % 2 == 0 )//注:奇数行是图片全路径,偶数行是标签 ---一半训练一半测试  
            {      
strcpy(c,buf.c_str());
img_catg.push_back(c[0]-'0');
//sscanf( buf.c_str(), "%d", &i );  
                // img_catg.push_back( atoi( buf.c_str() ) );  //int atoi(const char *nptr);atoi函数遇到字符开始转换遇到非字符停止转换
                 //atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错    
                 // 函数声明:const char *c_str(); c_str()函数返回一个指向正规字符串的指针, 内容与本字符串相同  
            }      
            else      
            {      
                img_path.push_back( buf );//图像路径      
            }      
        }      
    }      
    svm_data.close();  //关闭文件  
//CvMat *data_mat, *res_mat;  //定义样本矩阵,类型矩阵    
    int nImgNum = nLine / 2; //nImgNum:横坐标是样本数量,只有文本行数的一半,另一半是标签
Mat data_mat=Mat::zeros(nImgNum, 324, CV_32FC1);  //样本矩阵
Mat res_mat=Mat::zeros(nImgNum, 1, CV_32FC1);  //类型矩阵,存储每个样本的类型标志 
Mat trainImg=cvCreateImage(Size(28,28),8,3);  
Mat src;
for(int i = 0; i<img_path.size()-1; i++ )      
    {      
if(img_path[i].c_str()==NULL)
break;
            src=imread(img_path[i].c_str(),1);      
if( src.empty() == 1 )      
            {      
                cout<<" can not load the image: "<<img_path[i].c_str()<<endl;      
                break;      
            }      
      
            cout<<" 处理: "<<img_path[i].c_str()<<endl;      
                     
            resize(src,trainImg,Size(28,28)); //读取图片,归一化处理,   
            HOGDescriptor *hog=new HOGDescriptor(Size(28,28),Size(14,14),Size(7,7),Size(7,7),9);        
            vector<float>descriptors;//存放结果,数组       
            hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算        
            /*cout<<"HOG dims: "<<descriptors.size()<<endl;  */        
            n=0;
Mat descriptors_mat=Mat(descriptors);
Mat row1=descriptors_mat.reshape(0,1);//矩阵转置成行
for(int j=0;j<row1.cols;j++)//把每一个数字的特征存储为Mat矩阵的一行
{
data_mat.at<float>(i,j)=row1.at<float>(0,j);//存储HOG特征到data_mat矩阵中 at(row,cols)=at(y,x)  
}
//res_mat.at<int>(i,0)=row2.at<int>(0,i); //为每一个数字创建一个标签
/*cout<<"data_mat"<<data_mat.cols<<endl;
cout<<"res_mat"<<res_mat.cols<<endl;*/
            //for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++) //迭代器     
            //{      
            //    cvmSet(data_mat,i,n,*iter);//存储HOG特征到data_mat矩阵中   
            //    n++;      
            //}         
            //cvmSet( res_mat, i, 0, img_catg[i] ); //输出矩阵,第i行第j列,输入需转置的vector    
            //cout<<" 处理完毕: "<<img_path[i].c_str()<<" "<<img_catg[i]<<endl;      
    }  
Mat img_catg_mat=Mat(img_catg);
Mat row2=img_catg_mat.reshape(0,1);//矩阵转置成行
res_mat = row2.t(); //把第i行变成第j列



CvSVM svm;
CvSVMParams params;
params.svm_type    = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
svm.train(data_mat,res_mat,Mat(),Mat(),params);
svm.save( "HOG_SVM_DATA.xml" );
}
void main()
{
getdata();
/*Mat src=imread("\0\1.jpg");
imshow("src",src);*/
waitKey(0);
}

我训练的过程中遇到过几个问题

1.svm.train报错,原因是由于svm必须要有大于两个的标签

2.矩阵转置问题:由于svm训练时监督式学习,需要给计算机标签和训练样本,svm的训练样本是把一副图片通过hog提取特征,然后把一副图片的特征保存为矩阵的一行,那么有多少图片就有多少的列,转置成行的函数是reshape函数,标签是0,1,,2,3,4,5,6,7,8,9对应图片数字,标签矩阵是1列,以图片数量为行,转置成列的方法是先把矩阵转置成行,然后用Mat.t()函数行列互换


利用训练好的.xml文件识别数字


#include "opencv2/opencv.hpp"
#include "iostream"
using namespace cv;
using namespace std;
void main()
{
CvSVM svm;
CvSVMParams params;
params.svm_type    = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
Mat test=imread("2.jpg");
Mat trainTempImg=Mat::zeros(28,28,CV_8UC3);
resize(test,trainTempImg,Size(28,28));
HOGDescriptor *hog=new HOGDescriptor(cvSize(28,28),cvSize(14,14),cvSize(7,7),cvSize(7,7),9);         
vector<float>descriptors;//结果数组    
//计算hog特征      
hog->compute(trainTempImg, descriptors,Size(1,1), Size(0,0));   
Mat descriptors_Mat=Mat(descriptors);
Mat data=descriptors_Mat.reshape(0,1);
svm.load("HOG_SVM_DATA.xml");
int ret = svm.predict(data);
cout<<ret<<endl;
imshow("rest",test);
waitKey(0);
}

相比较与我上次写的knn手写体识别svm的离线学习方式有更大的效率


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值