楼主为武汉市某科技大学的机械小硕,由于某种原因,开始学习和使用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平凡之路下载。
请原谅我这种赚取积分的行为。毕竟,人生已经如此的艰难。