opencv 基于KNN的手写数字字符识别

楼主为武汉市某科技大学的机械小硕,由于某种原因,开始学习和使用opencv,所以算是半路出家和非科班出身,如有描述的不够专业地方,还请多多包涵和批评指正。

本文主要实现对手写数字字符的识别,主要用到的方法为k-近邻分类方法,用到opencv提供的KNearest类。

也是在网上看到的代码,觉得很好玩,然后下载了工程,原工程是opencv2早期版本,还是cvmat的时代,看起来很不方便和习惯。

楼主花了点儿时间,好好学习了下,然后修改成了opencv2后期mat时代的代码,opencv2.4.9-2.4.13应该都可以跑起来。


先讲下原理吧

1、得到训练的数据,一般都会是两个矩阵,一个矩阵存放着数据,另一个矩阵存放数据对应的标记(如数字0,1,2,3....)

2、训练数据,这一步,很简单,一个函数就可以搞定

3、根据需要识别的图片,预测其属于哪一类。


总结来讲:既然opencv都为我们封装好了算法,提供了一个可供调用的类,使用起来,必然是比较简单的。大部分的精力和代码,都花在得到标准化的数据上。


话不多说,先上一部分代码吧

class basicOCR
{
public:
	float classify(Mat img, int showResult);
	basicOCR();
	void test();
private:
	char file_path[255];
	int train_samples;
	int classes;
	Mat trainData;
	Mat trainClasses;
	int size;
	static const int K = 5;//最大邻居个数
	KNearest *knn;
	void getData();
	void train();
	void preprocessing(Mat &srcimage, int new_width, int new_height);
};
封装成一个类

</pre><pre name="code" class="cpp">basicOCR::basicOCR()//构造函数
{

	//initial
	sprintf(file_path, "OCR/");
	train_samples = 50;//训练样本,总共100个,50个训练,50个测试
	classes = 10;//暂时识别十个数字

	size = 128;//

	trainData.create(train_samples*classes, size*size, CV_32FC1);//训练数据的矩阵
	trainClasses.create(train_samples*classes, 1, CV_32FC1);

	//Get data (get images and process it)
	getData();

	//train	
	train();
	//Test	
	test();

	printf(" ------------------------------------------------------------------------\n");
	printf("|\t识别结果\t|\t 测试精度\t|\t  准确率\t|\n");
	printf(" ------------------------------------------------------------------------\n");
}
类的构造函数,可以看到,存放训练数据的矩阵trainData和存放对应标记的矩阵trainClasses


void basicOCR::getData()
{
	Mat src_image;
	char file[255];
	int i, j;
	for (i = 0; i<classes; i++)
	{
		for (j = 0; j< train_samples; j++)
		{

			//加载pbm格式图像,作为训练
			if (j<10)
				sprintf(file, "%s%d/%d0%d.pbm", file_path, i, i, j);
			else
				sprintf(file, "%s%d/%d%d.pbm", file_path, i, i, j);
			src_image = imread(file, 0);
			if (src_image.empty())
			{
				printf("Error: Cant load image %s\n", file);
				//exit(-1);
			}
			//process file
			preprocessing(src_image, size, size);

			//Set data 
			float* data1 = trainData.ptr<float>(i*train_samples+j);
			float* data2 = src_image.ptr<float>(0);
			for (int k = 0; k < src_image.cols; k++)
			{
				data1[k] = data2[k];
			}

			//Set class label
			trainClasses.at<float>(i*train_samples + j, 0) = i;
		}
	}
}

得到数据矩阵和相应的标记矩阵。

好了,只贴部分代码吧,如需要完整的工程,可以到hust平凡之路下载。

请原谅我这种赚取积分的行为。毕竟,人生已经如此的艰难。



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值