码迷,mamicode.com
首页 > 其他好文 > 详细

使用MLP解决OCR问题(OpenCV)(下)

时间:2015-01-23 18:29:45      阅读:999      评论:0      收藏:0      [点我收藏+]

标签:opencv   神经网络   mlp   ocr   


分类模型:

       分类模型涉及的一个比较关键的问题就是输出的10维向量是如何与具体的类别挂钩的。实际上:10维向量的每一位都代表一类,在对于训练集的表达中,如果输入数据是0,则10维向量的第一位赋值为1,其余均为0。即0对应[1,0,0,0,0,0,0,0,0,0]。MLP模型训练完成后,就需要对用户输入的数据所属类别进行判定。这时得到的输出数据基本不可能是正好的所属类为1,其他位置为0。那具体的分类方法就是判断这10位中哪一位最大,则这个输入就属于哪一类。
test_sample = test_set.row(tsample);

		//分类器的输出

		nnetwork.predict(test_sample, classificationResult);
		//输出向量中最大的值即为样本所属的类

		// 以下的工作就是找到最大的数是哪个
		int maxIndex = 0;
		float value=0.0f;
		float maxValue=classificationResult.at<float>(0,0);
		for(int index=1;index<CLASSES;index++)
		{   
			value = classificationResult.at<float>(0,index);
			if(value>maxValue)
			{   
				maxValue = value;
				maxIndex=index;

			}
		}

		printf("Testing Sample %i -> class result (digit %d)\n", tsample, maxIndex);

测试集:

        测试集是用来测试训练好的模型是否有良好的泛化性,即是否能识别训练集以外的数据。所以这里就要求训练集与测试集最好不要有相同的图片。如果测试结果不满意,则需要增加训练集重新训练或者调整MLP的参数。
 
        文章的最后将整个CPP文件分享给大家
#include <opencv2/opencv.hpp>
#include <string.h>
#include <fstream>
#include <stdio.h>
using namespace std;
using namespace cv;

#define ATTRIBUTES 135  //每一个样本的像素总数.9X15
#define CLASSES 10 
#define TRAINING_SAMPLES 460
#define TEST_SAMPLES 200

//将int型转为string型
string convertInt(int number)
{
	stringstream ss;
	ss << number;
	return ss.str();
}
//将图像矩阵转为一个向量
void convertToPixelValueArray(Mat &img,int pixelarray[])
{
	int i =0;
	for(int x=0;x<15;x++)
	{  
		for(int y=0;y<9;y++)
		{
			pixelarray[i]=(img.at<uchar>(x,y)==255)?1:0;
			i++;

		}

	}
}
//读取样本集,并将样本集按照一个样本一行的形式写入一个文件
void readFile(string datasetPath,int samplesPerClass,string outputfile )
{
	fstream file(outputfile.c_str(),ios::out);
	for(int sample = 1; sample<=samplesPerClass;sample++)
	{
		for(int digit=0;digit<10;digit++)
		{   //构建图像路径
			string imagePath = datasetPath+convertInt(digit)+"\\"+convertInt(sample)+".bmp";
			
			Mat img = imread(imagePath,0);
			Mat output;
			
			int pixelValueArray[135];

			//图像矩阵转为向量
			convertToPixelValueArray(img,pixelValueArray);
			//将这个向量写入文件
			for(int d=0;d<135;d++){
				file<<pixelValueArray[d]<<",";
			}
			//将所属类别写入文件(行尾)
			file<<digit<<"\n";

		}
	}
	file.close();
}
//从样本集生成的文件中读取数据
void read_dataset(char *filename, Mat &data, Mat &classes,  int total_samples)
{

	int label;
	float pixelvalue;
	FILE* inputfile = fopen( filename, "r" );

	
	for(int row = 0; row < total_samples; row++)
	{
		
		for(int col = 0; col <=ATTRIBUTES; col++)
		{
			
			if (col < ATTRIBUTES){

				fscanf(inputfile, "%f,", &pixelvalue);
				data.at<float>(row,col) = pixelvalue;

			}
			else if (col == ATTRIBUTES){
				//输出向量的结构是应属类别的位置赋值为1,其余赋值为0
				fscanf(inputfile, "%i", &label);
				classes.at<float>(row,label) = 1.0;

			}
		}
	}

	fclose(inputfile);

}

int main( int argc, char** argv )
{

	readFile("E:\\workdir\\NN\\character_train\\",46,"E:\\workdir\\NN\\trainingset.txt");
	readFile("E:\\workdir\\NN\\character_test\\",20,"E:\\workdir\\NN\\testset.txt");

	//训练样本集构成的矩阵
	Mat training_set(TRAINING_SAMPLES,ATTRIBUTES,CV_32F);
	//训练样本集的标签(输出向量)构成的矩阵
	Mat training_set_classifications(TRAINING_SAMPLES, CLASSES, CV_32F,Scalar(-1));
	//测试样本集构成的矩阵
	Mat test_set(TEST_SAMPLES,ATTRIBUTES,CV_32F);
	//测试样本集的标签(输出向量)构成的矩阵
	Mat test_set_classifications(TEST_SAMPLES,CLASSES,CV_32F,Scalar(-1));

	//
	Mat classificationResult(1, CLASSES, CV_32F);
	
	read_dataset("E:\\workdir\\NN\\trainingset.txt", training_set, training_set_classifications, TRAINING_SAMPLES);
	read_dataset("E:\\workdir\\NN\\testset.txt", test_set, test_set_classifications, TEST_SAMPLES);

	// 定义MLP的结构
	// 神经网络总共有三层
	// - 135输入节点
	// - 16 隐藏节点
	// - 10 输出节点.

	cv::Mat layers(3,1,CV_32S);
	layers.at<int>(0,0) = ATTRIBUTES;//input layer
	layers.at<int>(1,0)=16;//hidden layer
	layers.at<int>(2,0) =CLASSES;//output layer

	//创建神经网络
	//for more details check http://docs.opencv.org/modules/ml/doc/neural_networks.html
	CvANN_MLP nnetwork(layers, CvANN_MLP::SIGMOID_SYM,2.0/3.0,1);

	CvANN_MLP_TrainParams params(                                  

		// 终止训练在 1000 次迭代之后
		// 或者神经网络的权值某次迭代
		// 之后发生了很小的改变
		cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, 0.000001),
		// 使用BP算法训练
		CvANN_MLP_TrainParams::BACKPROP,
		// BP算法的系数
		// recommended values taken from http://docs.opencv.org/modules/ml/doc/neural_networks.html#cvann-mlp-trainparams
		0.1,
		0.1);

	// 训练神经网络

	printf( "\nUsing training dataset\n");
	int iterations = nnetwork.train(training_set, training_set_classifications,cv::Mat(),cv::Mat(),params);
	printf( "Training iterations: %i\n\n", iterations);

	// 保存模型到一个XML文件
	CvFileStorage* storage = cvOpenFileStorage( "E:\\workdir\\NN\\param.xml", 0, CV_STORAGE_WRITE );
	nnetwork.write(storage,"DigitOCR");
	cvReleaseFileStorage(&storage);

	// 对生成的模型进行测试.
	cv::Mat test_sample;
	
	int correct_class = 0;
	
	int wrong_class = 0;

	//分类矩阵记录某个样本分到某类的次数.
	int classification_matrix[CLASSES][CLASSES]={{}};

	
	for (int tsample = 0; tsample < TEST_SAMPLES; tsample++) 
	{
		test_sample = test_set.row(tsample);

		//分类器的输出

		nnetwork.predict(test_sample, classificationResult);
		//输出向量中最大的值即为样本所属的类

		// 以下的工作就是找到最大的数是哪个
		int maxIndex = 0;
		float value=0.0f;
		float maxValue=classificationResult.at<float>(0,0);
		for(int index=1;index<CLASSES;index++)
		{   
			value = classificationResult.at<float>(0,index);
			if(value>maxValue)
			{   
				maxValue = value;
				maxIndex=index;

			}
		}

		printf("Testing Sample %i -> class result (digit %d)\n", tsample, maxIndex);

		//现在比较神经网络的预测结果与真实结果. 如果分类正确
		//test_set_classifications[tsample][ maxIndex] 应该是 1.
		//如果分类错误, 记录下来.
		if (test_set_classifications.at<float>(tsample, maxIndex)!=1.0f)
		{

			wrong_class++;

			//标记分类矩阵
			for(int class_index=0;class_index<CLASSES;class_index++)
			{
				if(test_set_classifications.at<float>(tsample, class_index)==1.0f)
				{

					classification_matrix[class_index][maxIndex]++;// A class_index sample was wrongly classified as maxindex.
					break;
				}
			}

		} 
		else 
		{
			correct_class++;
			classification_matrix[maxIndex][maxIndex]++;
		}
	}
	
	//输出测试结果
	printf( "\nResults on the testing dataset\n"
		"\tCorrect classification: %d (%g%%)\n"
		"\tWrong classifications: %d (%g%%)\n", 
		correct_class, (double) correct_class*100/TEST_SAMPLES,
		wrong_class, (double) wrong_class*100/TEST_SAMPLES);
	cout<<"   ";
	for (int i = 0; i < CLASSES; i++)
	{
		cout<< i<<"\t";
	}
	cout<<"\n";
	for(int row=0;row<CLASSES;row++)
	{
		cout<<row<<"  ";
		for(int col=0;col<CLASSES;col++)
		{
			cout<<classification_matrix[row][col]<<"\t";
		}
		cout<<"\n";
	}

	return 0;

}


参考文献:   http://www.nithinrajs.in/ocr-using-artificial-neural-network-opencv-part-1/


使用MLP解决OCR问题(OpenCV)(下)

标签:opencv   神经网络   mlp   ocr   

原文地址:http://blog.csdn.net/qq_18515405/article/details/43057545

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!