`
java-大神
  • 浏览: 34995 次
  • 性别: Icon_minigender_1
  • 来自: 大山东
社区版块
存档分类
最新评论

机器学习:支持向量机实现手写识别

阅读更多

    不知不觉,学习脑与科学已经将近3个月了,虽然对上课老师讲的纯理论提不起一点兴趣,但是不得不说,这玩意儿确实有它吸引人的地方,比如计算机视觉,比如今天的机器学习。

    机器学习可以说是人工智能的核心,是它使计算机拥有了智能,简单说,它使计算机有了学习的能力。MS李

给了五种机器学习算法实现手写识别(否则挂科):

    自适应增强;

    支持向量机;

    贝叶斯分类器;

    人工神经网络;

    决策树;

    

    支持向量机是啥?跑去百科转了一圈,不懂。又借了本导论,很快就看完了,伤感是没怎么看懂,高兴的是字我都认识。乱起八糟看了一堆,用几个关键词来形容吧,大量样本-->hog特征处理-->训练产生分类器-->预测。

   

    处理样本数据。

    现在有0~9的样本图片60000张(如下),可以用一个for循环来一次读入每张图片,这里介绍一另一种
              
方法,读入文件(本质也是循环),楼主用bat批处理器把所用图片路径存到一个"hb.txt"中,突然发现不知道怎么说批处理了,这里暂时略过,容楼主再去仔细看下汇编(尴尬)~~

    HOG特征处理

    其实就是提取图片、灰度化(三维化)、划分成一个个cells、统计。

 

            cvResize(src,trainImg); //读取图片,归一化处理    
            HOGDescriptor *hog=new HOGDescriptor(cvSize(28,28),cvSize(14,14),cvSize(7,7),cvSize(7,7),9); //实例化一个hog对象     
            vector<float>descriptors;//存放结果,数组     
            hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算

   

 

    训练形成分类器

    这就简单啦,新建一个SVM,直接调用train(),

	svm.train( data_mat, res_mat, NULL, NULL, param ); 
//data_mat样本矩阵存储上面提取到的HOG特征,存储 m 个样本的 n 个特征, res_mat 是标签矩阵
//训练数据,利用训练数据和确定的学习参数,进行SVM学习 
//F:\OpenCV-2.4.5\opencv\modules\ml\src\svm.cpp-------P1584-P1647   

只能说opencv太强大,好吧,还是源代码最直接,其实在我们用着系统早已封装好的方法时,我们似乎渐渐忽视了源代码重要性,若不是之前就已经知道算法原理,光是一个train()根本不能就绝问题,下面贴出源码仅供有兴趣的同学参考:

 

bool CvSVM::train( const CvMat* _train_data, const CvMat* _responses,
    const CvMat* _var_idx, const CvMat* _sample_idx, CvSVMParams _params )
{
    bool ok = false;
    CvMat* responses = 0;
    CvMemStorage* temp_storage = 0;
    const float** samples = 0;

    CV_FUNCNAME( "CvSVM::train" );

    __BEGIN__;

    int svm_type, sample_count, var_count, sample_size;
    int block_size = 1 << 16;
    double* alpha;

    clear();
    CV_CALL( set_params( _params ));

    svm_type = _params.svm_type;

    /* Prepare training data and related parameters */
    CV_CALL( cvPrepareTrainData( "CvSVM::train", _train_data, CV_ROW_SAMPLE,
                                 svm_type != CvSVM::ONE_CLASS ? _responses : 0,
                                 svm_type == CvSVM::C_SVC ||
                                 svm_type == CvSVM::NU_SVC ? CV_VAR_CATEGORICAL :
                                 CV_VAR_ORDERED, _var_idx, _sample_idx,
                                 false, &samples, &sample_count, &var_count, &var_all,
                                 &responses, &class_labels, &var_idx ));


    sample_size = var_count*sizeof(samples[0][0]);

    // make the storage block size large enough to fit all
    // the temporary vectors and output support vectors.
    block_size = MAX( block_size, sample_count*(int)sizeof(CvSVMKernelRow));
    block_size = MAX( block_size, sample_count*2*(int)sizeof(double) + 1024 );
    block_size = MAX( block_size, sample_size*2 + 1024 );

    CV_CALL( storage = cvCreateMemStorage(block_size + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
    CV_CALL( temp_storage = cvCreateChildMemStorage(storage));
    CV_CALL( alpha = (double*)cvMemStorageAlloc(temp_storage, sample_count*sizeof(double)));

    create_kernel();
    create_solver();

    if( !do_train( svm_type, sample_count, var_count, samples, responses, temp_storage, alpha ))
        EXIT;

    ok = true; // model has been trained succesfully

    __END__;

    delete solver;
    solver = 0;
    cvReleaseMemStorage( &temp_storage );
    cvReleaseMat( &responses );
    cvFree( &samples );

    if( cvGetErrStatus() < 0 || !ok )
        clear();

    return ok;
}

    生成分类器

svm.save( "HOG_SVM_DATA.xml" );  //保存训练好的分类器

   

#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "windows.h"
#include "fstream"
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
    vector<string> img_path;//输入文件名变量   
    vector<int> img_catg;  //标签  
    int nLine = 0;    
    string buf;    
    ifstream svm_data( "D:\\nums\\hb.txt" );//训练样本图片的路径都写在这个txt文件中,bat批处理
    unsigned long n;     
    while( svm_data )//将训练样本文件依次读取进来    
    {    
        if( getline( svm_data, buf ) )    //将输入流svm_data中读到的字符存入buf中
        {    
            nLine ++;    
            if( nLine % 2 == 0 )//注:奇数行是图片全路径,偶数行是标签 
            {    
                 img_catg.push_back( atoi( buf.c_str() ) );
				 //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:横坐标是样本数量,只有文本行数的一半,另一半是标签  
       
    data_mat = cvCreateMat( nImgNum, 324, CV_32FC1 );  //样本矩阵
	//第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,
	//且对于不同大小的输入训练图片,这个值是不同的  
    cvSetZero( data_mat );     
    //类型矩阵,存储每个样本的类型标志    
    res_mat = cvCreateMat( nImgNum, 1, CV_32FC1 );    
    cvSetZero( res_mat );   
     
    IplImage* src;    
    IplImage* trainImg=cvCreateImage(cvSize(28,28),8,3);
	//需要分析的图片,这里默认设定图片是28*28大小,所以上面定义了324,如果要更改图片大小,
	//可以先用debug查看一下descriptors是多少,然后设定好再运行    
    
    //处理HOG特征  
    for( string::size_type i = 0; i != img_path.size(); i++ )    
    {    
            src=cvLoadImage(img_path[i].c_str(),1);    
            if( src == NULL )    
            {    
                cout<<" can not load the image: "<<img_path[i].c_str()<<endl;    
                continue;    
            }    
    
            cout<<" 处理: "<<img_path[i].c_str()<<endl;    
                   
            cvResize(src,trainImg); //读取图片,归一化处理    
            HOGDescriptor *hog=new HOGDescriptor(cvSize(28,28),cvSize(14,14),cvSize(7,7),cvSize(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;    
            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] );    
            cout<<" 处理完毕: "<<img_path[i].c_str()<<" "<<img_catg[i]<<endl;    
    }    
        
                 
    CvSVM svm = CvSVM();//新建一个SVM      
    CvSVMParams param;//SVM训练相关参数  
    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型的数组里。     */  
                                                                 
	//data_mat样本矩阵存储上面提取到的HOG特征,存储 m 个样本的 n 个特征, res_mat 是标签矩阵
	svm.train( data_mat, res_mat, NULL, NULL, param );  //训练数据,利用训练数据和确定的学习参数,进行SVM学习 
	//F:\OpenCV-2.4.5\opencv\modules\ml\src\svm.cpp-------P1584-P1647   
	svm.save( "HOG_SVM_DATA.xml" );  //保存训练好的分类器 
	   
   //检测样本    
	IplImage *test;  
    char result[512]; 
	vector<string> img_tst_path;
	ifstream img_tst( "D:\\SVM_TEST.txt" );  //加载需要预测的图片集合,这个文本里存放的是图片全路径,不要标签
	while( img_tst )  
	{  
		if( getline( img_tst, buf ) )  
		{  
			img_tst_path.push_back( buf );  
		}  
	}  
	img_tst.close(); 

    ofstream predict_txt( "SVM_PREDICT.txt" );//把预测结果存储在这个文本中   
	for( string::size_type j = 0; j != img_tst_path.size(); j++ )//依次遍历所有的待检测图片    
	{    
		test = cvLoadImage( img_tst_path[j].c_str(), 1);    
		if( test == NULL )    
		{    
			cout<<" can not load the image: "<<img_tst_path[j].c_str()<<endl;    
			continue;    
		}
		//读入需要计算特征的图像
		IplImage* trainTempImg=cvCreateImage(cvSize(28,28),8,3);
        cvZero(trainTempImg);    
        cvResize(test,trainTempImg);    
        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)); 
            
        cout<<"HOG dims: "<<descriptors.size()<<endl;    
        CvMat* SVMtrainMat=cvCreateMat(1,descriptors.size(),CV_32FC1);    
         int n=0;    
        for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)    
        {    
               cvmSet(SVMtrainMat,0,n,*iter);    
               n++;    
        }    
        int ret = svm.predict(SVMtrainMat);//检测结果
        sprintf( result, "%s  %d\r\n",img_tst_path[j].c_str(),ret );
        predict_txt<<result;  //输出检测结果到文本
	}
		predict_txt.close();    
		cvReleaseMat( &data_mat );    
		cvReleaseMat( &res_mat );  
		cvReleaseImage(&test);
		cvReleaseImage(&trainImg);
	  return 0;
}

 

 

    不管是手写识别,还是以后要研究的人脸识别,车牌识别,分类器都是必不可少的,又了它,接下来的工作就容易了。

 

    用画图板保存一张jpg,读入图片并加载已经训练好的分类器"HOG_SVM_DATA.xml",显示结果,OK。

 

 

// SVMmain.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "windows.h"
#include "fstream"
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
    CvSVM svm = CvSVM();
    svm.load("HOG_SVM_DATA.xml");//加载训练好的分类器xml文件
	//检测样本    
    IplImage *test;  
    char result[300]; //存放预测结果 
    test = cvLoadImage("5.jpg", 1); //待预测图片,用系统自带的画图工具随便手写,最好用粗体
    if (!test)
     {
	  MessageBox(NULL,TEXT("待预测图像不存在!"),TEXT("提示"),MB_ICONWARNING);
	  return -1;
     }
	IplImage* trainTempImg=cvCreateImage(cvSize(128,128),8,3);
     cvZero(trainTempImg);    
     cvResize(test,trainTempImg);     
     HOGDescriptor *hog=new HOGDescriptor(cvSize(128,128),cvSize(64,64),cvSize(32,32),cvSize(32,32),9);      
     vector<float>descriptors;//存放结果       
     hog->compute(trainTempImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算      
     cout<<"HOG dims: "<<descriptors.size()<<endl;  //打印Hog特征维数  ,这里是324
     CvMat* SVMtrainMat=cvCreateMat(1,descriptors.size(),CV_32FC1);   
     int n=0;    
     for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)    
     {    
           cvmSet(SVMtrainMat,0,n,*iter);   
           n++;    
      }   
    
      int ret = svm.predict(SVMtrainMat);//检测结果
	  //cout<<ret;
      sprintf(result, "%d\r\n",ret );
      cvNamedWindow("dst",1);
      cvShowImage("dst",test);
      //MessageBox(NULL,TEXT("5"),TEXT("预测结果"),MB_OK);	//(LPCWSTR)result
	  MessageBoxA(NULL,result,"预测结果",MB_OK);
      cvReleaseImage(&test);
      cvReleaseImage(&trainTempImg);
      return 0;
}

    附件里上传楼主的分类器,图片太大就不传了,需要的话说一下。

    有时间打算把其它几种算法都实现一遍,一起讨论吧。

 

 

    

 

 


    

 

 
 

 

 

 

 

 

 

    

  • 大小: 792 Bytes
  • 大小: 917 Bytes
  • 大小: 593 Bytes
  • 大小: 794 Bytes
  • 大小: 792 Bytes
  • 大小: 442 Bytes
  • 大小: 31.6 KB
分享到:
评论
1 楼 HeyGirl 2014-12-28  
  

相关推荐

    Python 支持向量机SVM手写数字识别

    SVM手写数字识别,使用scikit-learn库的数据库

    matlab:基于支持向量机的手写数字识别

    《基于支持向量机的手写数字识别:MATLAB实现与深度探索》 手写数字识别是一种广泛应用的人工智能技术,广泛应用于自动邮戳识别、银行支票读取、电子白板系统等领域。在这个主题中,我们将深入探讨如何利用MATLAB...

    机器学习实验:使用mnist与usps数据集,采用BP神经网络与SVM支持向量机的方式实现手写数字的识别.zip

    采用BP神经网络与SVM支持向量机的方式实现手写数字的识别.zip机器学习实验:使用mnist与usps数据集,采用BP神经网络与SVM支持向量机的方式实现手写数字的识别.zip机器学习实验:使用mnist与usps数据集,采用BP神经...

    支持向量机手写体数字识别系统

    ### 支持向量机手写体数字识别系统的关键知识点 #### 1. 工程背景与重要性 - **核心需求**:本研究聚焦于手写体阿拉伯数字的识别,这是字符识别技术中的一个重要分支。传统的识别方法,如人工分类、神经网络、决策...

    支持向量机的手写字符识别

    支持向量机(Support Vector Machine,SVM)是一种在机器学习领域广泛应用的监督学习模型,尤其在模式识别、分类和回归分析中表现出色。在这个场景中,我们将关注它在手写字符识别上的应用。 手写字符识别是计算机...

    机器学习SVM(支持向量机)实验报告.pdf

    支持向量机(Support Vector Machine,简称SVM)是一种监督学习模型,尤其在二分类问题上表现突出。它的核心思想是在特征空间中找到一个能够最大程度地将两类样本分开的超平面。这个超平面是由支持向量决定的,这些...

    机器学习SVM(支持向量机)实验报告(带源代码)

    ### 机器学习SVM(支持向量机)实验报告知识点解析 #### 一、实验目的与要求 **实验目的:** - 验证支持向量机(Support Vector Machine, SVM)机器学习算法的学习情况。 **要求:** - 学员需要自主完成整个实验过程...

    基于支持向量机的手写体相似字识别

    支持向量机(Support Vector Machine, SVM)是一种强大的机器学习算法,在模式识别、分类和回归分析中展现出优秀的性能,尤其在小样本和高维空间问题中。本文将深入探讨如何利用支持向量机来解决手写体相似字的识别...

    基于mnist与usps数据集,采用BP神经网络与SVM支持向量机的方式实现手写数字识别算法开发源码(机器学习实战).zip

    基于mnist与usps数据集,采用BP神经网络与SVM支持向量机的方式实现手写数字识别算法开发源码(机器学习实战).zip基于mnist与usps数据集,采用BP神经网络与SVM支持向量机的方式实现手写数字识别算法开发源码(机器...

    支持向量机指南.doc

    支持向量机(SVM)是一种基于统计学习理论的机器学习算法,广泛应用于模式识别、回归分析、分类等领域。下面是支持向量机指南的知识点总结: 1. 支持向量机的基本思想 支持向量机的基本思想是将输入空间转换到高维...

    SVM实现手写数字识别

    **SVM实现手写数字识别**是机器学习领域的一个经典应用,主要利用支持向量机(Support Vector Machine, SVM)的分类能力来识别手写字符。SVM是一种强大的监督学习模型,尤其在处理小样本、高维数据时表现出色。在本...

    svm手写数字识别_手写数字识别_支持向量机分类_

    支持向量机(SVM,Support Vector Machine)是一种在机器学习领域广泛应用的监督学习模型,尤其在模式识别、数据分类和回归分析等方面表现出强大的能力。本文将深入探讨如何利用SVM进行手写数字识别,以及如何对SVM...

    支持向量机手写体识别matlab

    支持向量机(Support Vector Machine,SVM)是一种在机器学习领域广泛应用的监督学习模型,尤其在模式识别、分类和回归分析中表现出色。在这个"支持向量机手写体识别matlab"项目中,我们将深入探讨如何使用MATLAB这...

    【手写数字识别】基于支持向量机SVM实现手写数字识别matlab源码含GUI.zip

    【手写数字识别】基于支持向量机SVM实现手写数字识别的MATLAB源码是一种常见的机器学习项目,用于训练模型以识别手写数字。这个项目的核心是使用支持向量机(Support Vector Machine,简称SVM)算法,这是一种强大的...

    基于mnist与usps数据集,采用BP神经网络与SVM支持向量机的方式实现手写数字识别算法源码(机器学习实战).zip

    项目旨在通过两个经典数据集,深入探讨并应用两种重要的机器学习算法——反向传播神经网络(BP神经网络)和SVM支持向量机,以实现手写数字的准确识别。项目中包含完整的源代码,经过严格测试验证,确保可正常运行。...

    手写汉字识别中的机器学习.pdf

    1. 支持向量机(SVM):SVM 是一种常用的机器学习算法,能够对高维空间中的数据进行分类。在手写汉字识别中,SVM 可以用于分类手写汉字图像。 2. Random Forest:Random Forest 是一种基于决策树的机器学习算法,...

Global site tag (gtag.js) - Google Analytics