首页 > 代码库 > 使用MLP解决OCR问题(OpenCV)(下)

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


分类模型:

       分类模型涉及的一个比较关键的问题就是输出的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=http://www.mamicode.com/0.0f;>

测试集:

        测试集是用来测试训练好的模型是否有良好的泛化性,即是否能识别训练集以外的数据。所以这里就要求训练集与测试集最好不要有相同的图片。如果测试结果不满意,则需要增加训练集重新训练或者调整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=http://www.mamicode.com/0.0f;>

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


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