您的位置:首页 > 移动开发 > 微信开发

SVM手写字符识别小程序

2016-12-17 10:54 232 查看
该程序是基于opencv3.1写的,自己的训练样本图片,图片大小都是32X32,主要思路是利用灰度图在行和列方向上的投影得到的64(32+32)个标签进行数据分类

主函数如下:

#include"LetterDet.h"

int main()
{
image_read();
image_SVMClassify();
cv::waitKey();
return 0;
}


对应的头文件:

/***********************************************************
*为什么变成 D:\testImages\ 就会出错
*转义序列 \" 表示双引号,而不是字符串的结尾
*http://blog.csdn.net/holybin/article/details/17751063
**********************************************************/
#ifndef LETTERDET_H
#define LETTERDET_H

#include<opencv2\opencv.hpp>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<sstream>
#include<fstream>

using namespace std;

#define source_path    "D:\testImages"
#define feature_path   "features.txt"

//cv::Mat FeatureMat = cv::Mat::zeros( 860 , 64 , CV_32FC1 );
//cv::Mat LabelMat = cv::Mat::zeros( 1 , 860 , CV_32SC1 );

void image_read();
void image_feature_write( cv::Mat& image , int label );
void getTrainingDataAndLabel();
void image_SVMClassify();

#endif


具体的函数实现:

#include"LetterDet.h"

cv::Mat sampleFeatureMat = cv::Mat::zeros( 850 , 64 , CV_32FC1 );       // SVM训练数据是行向量
cv::Mat sampleLabelMat = cv::Mat::zeros( 850 , 1 , CV_32SC1 );          // SVM标签是列向量

void image_read()
{
for( int i = 0; i < 10; i++ )
{
for( int j = 0; j < 85; j++ )
{
stringstream str;                          // 读取一系列图片
str << "D:\\testImages\\" << i << "_" << j << ".jpg";
cv::Mat srcImage = cv::imread( str.str() , 0 );
if( !srcImage.data )
{
cout << "读取失败,请检查该图片是否存在!!!" << endl;
exit( 0 );
}
else
{
//				cout << str.str() << "\t读取成功!" << endl;
}
image_feature_write( srcImage , i );
}
}
}

void image_feature_write( cv::Mat& image , int label )
{
FILE* file;

if( fopen_s( &file , feature_path , "a+" ) )  // 以可附加的方式打开只写文件,若文件不存在则建立
{
cout << "Can't open file!" << endl;
exit( 0 );
}
else
{
//	getFeature();
for( int i = 0; i < image.rows; i++ )   //投影到X轴的所有像素和
{
int sum = 0;
uchar* ptr = image.ptr( i );
for( int j = 0; j < image.cols; j++ )
{
sum += ptr[j];
}
fprintf( file , " %d" , sum );
}

for( int j = 0; j < image.cols; j++ )   //投影到Y轴的所有像素和
{
int sum = 0;
for( int i = 0; i < image.rows; i++ )
{
sum += image.at<uchar>( i , j );
}
fprintf( file , " %d" , sum );
}
}
fprintf( file , " %d" , label );
fprintf( file , "\n" );
fclose( file );             // 一定要记得关闭文件
}

void getTrainingDataAndLabel()
{
FILE* file;
//	if( fopen_s( &file , feature_path , "a+" ) )
file=fopen( feature_path , "r" );
/*if( fopen_s( &file , feature_path , "r" ) )
{
cout << "打开features.txt文件成功!" << endl;
}
else
{
cout << "打开features.txt文件失败!" << endl;
}*/

//	ifstream fr;          // 记得包含库文件<fstream>
//	fr.open( feature_path , ios::in );
sampleLabelMat.setTo( 0 );     // 850,1
sampleFeatureMat.setTo( 0 );   // 850,64

cout << "开始读取features.txt文件中的数据" << endl;
for( int i = 0; i < 850; i++ )
{
for( int j = 0; j < 65; j++ )
{
if( j == 64 )
{
fscanf( file , "%d" , &sampleLabelMat.at<int>( i , 0 ) );
continue;
}
else
{
fscanf( file , "%f" , &sampleFeatureMat.at<float>( i , j ) );
}
}
}
fclose( file );
}

void image_SVMClassify()
{
getTrainingDataAndLabel();
cout << "开始训练Auto分类器..." << endl;
cv::Ptr<cv::ml::SVM> m_SVM = cv::ml::SVM::create();
m_SVM->setType( cv::ml::SVM::C_SVC );     // SVM类型为C_SVM,可以进行2类以上的分类
m_SVM->setKernel( cv::ml::SVM::LINEAR );  // 核函数径向基函数,线性的不可分没法用
m_SVM->setC( 0.01 );			          // 应该是松弛因子的惩罚系数C ?
m_SVM->setTermCriteria( cv::TermCriteria( CV_TERMCRIT_ITER + CV_TERMCRIT_EPS , 1000 , FLT_EPSILON ) );//设定终止条件为迭代1000次或者误差小于FLT_EPSILON

cv::Ptr<cv::ml::TrainData> trainDataSet = cv::ml::TrainData::create( sampleFeatureMat , cv::ml::ROW_SAMPLE , sampleLabelMat );
m_SVM->trainAuto( trainDataSet , 10 ,
cv::ml::SVM::getDefaultGrid( cv::ml::SVM::C ) ,
cv::ml::SVM::getDefaultGrid( cv::ml::SVM::GAMMA ) ,
cv::ml::SVM::getDefaultGrid( cv::ml::SVM::P ) ,
cv::ml::SVM::getDefaultGrid( cv::ml::SVM::NU ) ,
cv::ml::SVM::getDefaultGrid( cv::ml::SVM::COEF ) ,
cv::ml::SVM::getDefaultGrid( cv::ml::SVM::DEGREE ) ,
true );

//	m_SVM->train( sampleFeatureMat , cv::ml::SampleTypes::ROW_SAMPLE , sampleLabelMat );

cv::Mat image = cv::imread( "8_90.jpg" , 0 );
//	cv::imshow( "Image" , image );
cv::Mat test( 1 , 64 , CV_32FC1 );

for( int i = 0; i < image.rows; i++ )   //投影到X轴的所有像素和
{
int sum = 0;
uchar* ptr = image.ptr( i );
for( int j = 0; j < image.cols; j++ )
{
sum += ptr[j];
}
test.at<float>( 0 , i ) = sum;
}

for( int j = 0; j < image.cols; j++ )   //投影到Y轴的所有像素和
{
int sum = 0;
for( int i = 0; i < image.rows; i++ )
{
sum += image.at<uchar>( i , j );
}
test.at<float>( 0 , image.rows + j ) = sum;
}

int response = ( int ) m_SVM->predict( test );
printf( "response:%d\n" , response );

}


最后的结果输出类似如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  SVM 字符识别