在进行完预处理之后,我们可以开始用算法识别数字了。首先我们不做那么复杂的、一连串银行卡数字的识别,而是做一个数字的测试。
一、机器算法的引入-----K近邻算法
K最近邻(k-Nearest Neighbour,KNN)分类算法是一个理论上比较成熟的算法,也是最简单的机器学习算法之一。顾名思义,k最近邻实际上就是取和待分类物最相似的k个模板,然后这k个模板中所占比例最高的类别就是最后决定的类别。
思路就是这么简单,那么这个最近的距离如何计算呢?往往用欧氏距离等经典距离来衡量模板和待分类物的“距离”。
KNN很适合在有大量样本的情况下进行使用,当然,这也带来了速度较慢的问题。
于是KNN就非常简单了。
二、准备工作----模板准备
我们只做单个数字的检测,来检验我们所写的算法的正确性,所以类似单片机中串口自发自收的测试方法,我们可以用模板来识别模板,从而检测算法的正确性。
我们在画图板中写入0-9十个数字(大小并没有特殊要求,后面程序会进一步处理),并一一截图保存变成我们的样本,并放在工程目录下:
模板准备完毕。
三、整体思路
1>读取模板:我们这里有10个类别,即0-9十个数字,每个类别有一个样本,一共十个模板,我们需要读入程序中,用IplImage或者cvMat进行存储;
2>模板调整(示模板情况而定需不需要该步骤):也可以说是提取特征区域吧,因为模板是手动截图的,每个模板打大小不是严格一样的,但是作为模板匹配来说,我们需要的是统一的尺寸标准,所以我们需要将导入的模板图片调整到统一的、合适的尺寸。
在http://blog.csdn.net/wangyaninglm/article/details/17091901的博客上我看到了非常合适的解释图,在这里也分享给大家:
这里提取出来的ROI是模板的有效部分,但是大小还是不一定符合统一尺寸的要求,所以,我们要进行适当的放缩
3>训练数据:这是我认为的算法最关键的部分。这里有几个参数:
Classes:类型数量
Train_simples:每个类型的样本数量
trainData:模板的训练集,
trainClasses:训练集所对应的类别标号
接下来我想解释一下trainData,trainClasses是个啥,但是感觉说太多也并不一定能够说得清楚,所以,请见下图所示:
trainData:
trainClasses:
看了上图之后,相信大家对k最近邻算法会有自己的想法了。可以看出,得到训练集的关键就是得到样本的特征向量。有很多特征向量的提取方法,详细的会在后面阐述,这里只介绍最简单的一种方法:
当模板不大的时候,我们可以将模板(可以看做一个n*m的矩阵)展开成一个n*m的一维向量,这就是这个模板的特征。事实上,有了第二步的预处理(ROI的提取),模板几乎就只有数字那么大了,所以模板是很小的,要想得到全部的信息,该方法再好也再简单不过了。
4>得到了trainData、trainClasses后,就可以利用openCV的函数进行k最近邻的算法求解了
所有步骤结束,是不是很简单呢?
接下来看看实际的实现过程和结果------关键函数代码:
void getData()
{//得到训练数据
IplImage* src_image;
IplImage* prs_image = cvCreateImage(cvSize(new_width, new_height), 8, 1); ;
CvMat row,data;
CvMat rowb,datab;
int x,y;
int c = 0;
int i,j,k;
int m,n;
m=0;
k=0;
CvMat* srcImg = cvCreateMat(32,32,CV_32FC1);
ifstream file;
char filename[50];
char a[32][32];
string s;
for(m =0; m<classes;m++)//总共10个数字
{
c = 0;
for(n = 0; n<train_samples;n++)//每个数字50个样本
{
c++;
// 这里是读入图片样本
sprintf(file, "%d%d.bmp", i, j);
src_image = cvLoadImage(file);
if(!src_image)
{
printf("Error: Cant load image %s\n",file);
}
IplImage* gray_image = cvCreateImage(cvGetSize(src_image), 8, 1);
IplImage* binary_image = cvCreateImage(cvGetSize(src_image), 8, 1);
cvCvtColor(src_image, gray_image, CV_BGR2GRAY);
cvThreshold(gray_image, binary_image, 100, 255, CV_THRESH_BINARY);
//process file
//将模板按照尺寸大小将有效部分放缩
prs_image = preprocessing(prs_image);
//生成训练矩阵,每个图像作为一个向量
cvGetRow(trainClasses, &row,m*train_samples +n);//y
cvSet(&row,cvRealScalar(m));
//Set data
cvGetRow(trainData, &rowb,m*train_samples +n);//x
IplImage *img = cvCreateImage(cvGetSize(prs_image),IPL_DEPTH_32F, 1 );
//转换换 8 bits image to 32位浮点数图片取值区间为[0,1]
//将模板图像转换成一个一维向量作为特征向量
//scale = 0.0039215 = 1/255;
cvConvertScale(prs_image,img, 0.0039215, 0);
cvGetSubRect(img, &data,cvRect(0,0,new_width,new_height));
CvMat row_header, *row1;
//convert data matrix sizexsize to vecor
row1 =cvReshape( &data, &row_header, 0, 1 );
cvCopy(row1, &rowb,NULL);
}
}
}
IplImage *preprocessing(IplImage*imgSrc)
{//放缩模板图像的有效部分
IplImage* result;
IplImage* scaledResult;
CvMat data;
CvMat dataA;
CvRect bb;//bounding box
CvRect bba;//boundinb box maintain aspect ratio
//Find bounding box找到边界框
bb=findBB(imgSrc);
cvGetSubRect(imgSrc, &data,cvRect(bb.x,bb.y,bb.width,bb.height));
int size=(bb.width>bb.height)?bb.width:bb.height;
result=cvCreateImage( cvSize( size, size ), 8, 1 );
cvSet(result,CV_RGB(255,255,255),NULL);
//将图像放中间,大小归一化
int x=(int)floor((float)(size-bb.width)/2.0f);
int y=(int)floor((float)(size-bb.height)/2.0f);
cvGetSubRect(result, &dataA,cvRect(x,y,bb.width,bb.height));
cvCopy(&data, &dataA, NULL);
//Scale result
scaledResult=cvCreateImage( cvSize( new_width, new_height ), 8, 1 );
cvResize(result, scaledResult, CV_INTER_NN);
//Return processed data
return scaledResult;//直接返回处理后的图片
}
CvRect findBB(IplImage *img)
{//找模板图像有效图像的边框,方便抠下来
CvSeq *contour;
CvMemStorage *storage = cvCreateMemStorage(0);
IplImage* temp = cvCreateImage(cvGetSize(img), 8, 1);
cvCopy(img, temp);
int a = cvFindContours(temp, storage, &contour, sizeof(CvContour),CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
CvRect rect, tprect;
rect = cvBoundingRect( contour, 0 );
return rect;
}
有了上面代码的基础,我们就得到了trainData、trainClasses训练集,那么接下来我们要抠取待测图片的有效区域,并且生成相应的特征向量,当然这里生成特征向量的方法要和前面生成训练集时用的方法保持一致。
训练完之后我们就可以利用openCV函数对训练集和待测数据进行k最近邻计算具体函数见下:
int do_ocr(IplImage *img)
{
IplImage* pimage;
CvMat data;
pimage = preprocessing(img);
IplImage *image = cvCreateImage(cvGetSize(pimage),IPL_DEPTH_32F, 1 );
//转换换 8 bits image to 32位浮点数图片取值区间为[0,1]
//scale = 0.0039215 = 1/255;
cvConvertScale(pimage,image, 0.0039215, 0);
cvGetSubRect(image, &data,cvRect(0,0,new_width,new_height));
CvMat mathdr;
CvMat *vec;
vec = cvReshape(&data, &mathdr, 0, 1);
//SumMat(*vec);
CvMat* nearest = cvCreateMat( 1, K, CV_32FC1);
float ret = knn->find_nearest(vec, K, 0, 0, nearest, 0);
return (int)ret;
}
按照我上文中说的思路很容易得到我们想要的结果:
测试图片:
测试结果:
相关推荐
KNN算法是一种基于实例的学习方法,它根据训练集中最接近(即最近邻)的K个样本来预测未知样本的类别。 **k-近邻算法原理** 1. **距离度量**:在KNN中,我们首先需要定义一个距离函数来衡量样本之间的相似性。通常...
在手写字符识别领域,K-NN被广泛应用于自动识别数字,如OCR(光学字符识别)系统。本项目是用C语言实现的K-NN算法,通过Visual Studio 2010编译环境进行了验证,对于初学者理解K-NN的工作原理和应用具有很高的参考...
K-最近邻算法是一种基于实例的学习方法,主要用于分类和回归问题。该算法的基本思想是根据输入实例在特征空间中的K个最近邻居的信息来进行预测。 ##### 原理介绍 1. **计算距离**:对于一个新的输入实例,计算其与...
在本项目中,我们主要探讨的是如何利用图像处理技术和机器学习中的K近邻(K-Nearest Neighbor,简称KNN)算法实现车牌号码的自动识别。这个过程涉及到多个步骤,包括图像预处理、特征提取、车牌字符分割以及分类预测...
在人脸识别技术领域,基于Singular Value Decomposition(奇异值分解,简称SVD)和K-Nearest Neighbor(K-最近邻,简称KNN)算法的系统是一种常见的解决方案。本项目提供的MATLAB代码实现了这一方法,使得研究者和...
标签"matlab_最近邻 nearest_neighbor 最近邻 最近邻_识别 最近邻分类"涵盖了与主题相关的关键词,这些标签有助于理解压缩包中的内容是关于MATLAB编程,特别是与最近邻算法相关的部分,包括识别和分类任务。...
利用K-最近邻算法进行高识别率的信号特征五分类
以图像打开、保存、几何变换、形态学处理、阈值分割、边缘检测和滤波等基本操作为基础,对手写数字图片进行处理,提取有效特征,采用K最近邻算法识别,获得了较高的准确率。训练与测试图片位于Data文件夹中。
然后计算最近邻样本的距离权重,并用该权重描述最近邻和其他近邻对预测结果的影响;最后使用新的目标函数为待测样本分类。通过在图片、Web页面文本数据等数据集上的实验表明,所提算法得到了更好的分类结果,并且...
字符识别模块使用 MATLAB 的模式识别工具箱对字符进行识别,使用最近邻法实现字符识别。 数字图像处理 数字图像处理是车牌识别技术的基础,包括图像预处理、图像分割、图像识别等方面的内容。数字图像处理技术可以...
基于k-最近邻图的小样本KNN分类算法 KNN(K-Nearest Neighbors)分类算法是一种典型的非参数、有效、较流行的惰性学习方法,其思路简单且易于实现。该算法的核心思想是根据训练样本集中的模式来对未知样本进行分类...
常用的分类器有SVM(支持向量机)、KNN(K最近邻)或神经网络。唐宇迪老师的课程可能会介绍如何使用这些算法构建模型并进行训练。 6. 预测与识别:最后,将预处理后的图像输入到训练好的分类器,预测出每个数字。...
### 基于K近邻的手写数字识别 #### 一、绪论 ##### 1.1 手写数字识别的基本概念 手写数字识别属于图像识别领域的一部分,其主要研究如何利用电子计算机自动识别手写的阿拉伯数字。与其他类型的字符识别相比,手写...
其次,项目利用了sklearn(Scikit-learn)库来实现三种不同的机器学习模型:K-最近邻(KNN)、多层感知器(MLP,也称为神经网络)和支持向量机(SVM)。这些模型被用于数字识别任务。在`KNN.py`、`MLP train.py`和`...
在距离法中,通常是最近邻分类(K-Nearest Neighbor,KNN)或单近邻分类(Nearest Neighbor,NN)。对于KNN,我们需要找到测试样本与训练集中最接近的K个样本,然后根据这K个样本的类别决定测试样本的类别。MATLAB的...
- KNN(K最近邻)算法:这是一种基于实例的学习,通过找到训练集中与新样本最接近的K个邻居来预测其类别。 3. 数据集: 实现手写数字识别通常使用MNIST数据集,它包含60,000个训练样本和10,000个测试样本,每个...
k-最近邻搜索(KNNS) 在高维空间中应用非常广泛,但目前很多KNNS算法是基于欧氏距离对数据进行索引和搜索,不适合采用角相似性的应用。提出一种基于角相似性的k-最近邻搜索算法(BA-KNNS)。该算法先提出基于角相似性的...
然而,回归树对噪声数据敏感,稳定性欠佳,预测精度可能低于K-最近邻(K-NN)方法。K-NN则以其非参数特性、良好的适应性和无需事先假设数据分布而闻名,但计算复杂度较高,尤其是在大数据集上。 本文提出了一种结合...
k最近邻算法是一种有效快速的分类算法,包括源代码和测试数据