一、提取方法的修正
上回说道,我们使用cvFindContours函数来找银行卡上的数字的外包矩形,从而从银行卡上将数字抠下来进行识别,但是,使用后会发现有如下两个问题:
(1)不好筛选
提供的图片大小不一样,那么数字的外包矩形框的大小也就不一样,如果简单地采用面积的办法进行筛选,那么这种方法的适应性是非常的差的。
(2)外包矩形框的不确定性
我们来看看数字8的外包矩形框
不看不知道,一看吓一跳,一个数字八竟然有四个外包矩形框,这个我们的提取工作带来了非常大的不便,所以我们考虑换一种提取方式。
基于灰度变化的数字提取方法:
数字与数字的间隔往往是背景颜色或者是背景像素点个数和的一个波峰,即前景像素点个数和的一个波谷,我们利用这样的特点来分割图片。这里考虑到银行卡类型比较单一,如果将卡大小控制在一定的范围内,那么两数字之间一般会出现大部分背景像素点,即这里暂时不考虑数字与数字相连的情况。
那么首先,我们通过获得有效区域(见“再预处理”一文),得到了数字的高度,接下来,我们用上述方法得到每个数字的宽度,于是乎就能将数字抠取下来了。
二、样本模板修正
从网上下了一个手写数字的样本,天真地以为应该是可以的,随便打开一个看看,如下图所示:
大家可能觉得形状扭曲或者其他什么,而我注意到的是它的填充情况,可以发现,这个样本上下基本与图像边框相切,但是两边却非常空余,结合一下我们所采取的数字抠取得办法,得到的数字一定是上下左右都是切和图像边框的,我不禁冷汗直冒。为什么呢?因为k最近邻是通过距离来计算相似度的,那么,如下图,可以想象得到,红色的0和黑色的0在距离计算后得到的结果一定是差个十万八千里的:
所以,根据我们数字抠取得方法特点来看,我决定自己制作简单的样本,这个样本完全模拟抠取后的数字图片来,包括大小、胖瘦、粗细、上下左右切合图像边框等等,因为考虑到银行卡号是比较单一的,所以,我相信这样做是合理的!
三、关键函数实现及其结果
(1)数字分割
IplImage *Filter(IplImage*imgSrc, IplImage*src)
{//过滤图像
int a = 0, b = 0;//保存有效行号
int h = 0;
int state = 0;//标志位,0则表示还未到有效行,1则表示到了有效行,2表示搜寻完毕
for (int y = 0; y < imgSrc->height; y++)
{
int count = 0;
for (int x = 0; x < imgSrc->width; x++)
{
if (cvGet2D(imgSrc, y, x).val[0] == 0)
count = count + 1;
}
if (state == 0)//还未到有效行
{
if (count >= 10)//找到了有效行
{//有效行允许十个像素点的噪声
a = y;
state = 1;
}
}
else if (state == 1)
{
if (count <= 10)//找到了有效行
{//有效行允许十个像素点的噪声
b = y;
state = 2;
}
}
}
numX1 = a;
numX2 = b;
CvRect roi = cvRect(0, a, src->width, b - a);
IplImage *res = cvCreateImage(cvSize(roi.width, roi.height), 8, 1);
IplImage *orig = cvCreateImage(cvSize(roi.width, roi.height), 8, 1);
cvSetImageROI(src, roi);
cvCopy(src, res);
cvThreshold(res, res, 30, 255, CV_THRESH_BINARY);//24
cvErode(res, res, NULL, 1);
return res;
}
void findRect(IplImage* srcA)
{//将银行数字分割,黑点为前景点,白点为背景点。
int count = 0;
int judgeA = 0;//0代表当前要判断有效列,1代表当前要判断无效列
int i = 0;
IplImage* src = cvCreateImage(cvGetSize(srcA), 8, 1);
cvSmooth(srcA, src, CV_MEDIAN);
for (int x = 0; x < src->width; x++)
{
count = 0;
for (int y = 0; y < src->height; y++)
{
int q = ((uchar*)(src->imageData + y*src->widthStep))[x];
if (q == 0)//遇到前景点就加1
{
//cout << q << endl;
count ++;
}
}
if (judgeA == 0)
{
if (count >= 5)//有效行到了
{
judgeA = 1;
aa[i] = x;
}
}
else if(judgeA == 1)
{
if (count < 5)
{
judgeA = 0;
bb[i] = x;
i++;
}
}
}
cout << " i = " << i << endl;
for (int m = 0; m < i; m++)
{
cvLine(src, cvPoint(aa[m], 0), cvPoint(aa[m], src->height), cvScalar(0, 0, 0));
cvLine(src, cvPoint(bb[m], 0), cvPoint(bb[m], src->height), cvScalar(0, 0, 0));
}
/*cvNamedWindow("img");
cvShowImage("img", src);
cvWaitKey(0);
*/
}
分割结果:
注意:过程中灵活使用中值滤波可以有效减少噪声的干扰,特别是不可见噪声
(2)外包矩形框查找修正成resize
在上一回我们这样实现的,即先得到外包矩形框,然后再讲外包矩形框resize得到模板的尺寸。现在为了更简便和准确,我们直接resize(因为考虑到我们前面做了一系列操作,数字已经在一个合适的范围内了,不会出现大部分空白现象)
(3)顺序调整
算法实现的顺序并不是从上到下,从左到右的,而是随机的,所以我们需要在识别数字的时候讲数字的位置记录下来,最后根据位置进行数字排序,再进行显示
void sortBankNum()//对银行卡进行排序
{
int i,j,temp;
for(j=0;j<=18;j++)
{
for (i=0;i<19-j;i++)
if (bankX[i]>bankX[i+1])
{
temp=bankX[i];
bankX[i]=bankX[i+1];
bankX[i+1]=temp;
temp=bankNum[i];
bankNum[i]=bankNum[i+1];
bankNum[i+1]=temp;
}
}
}
最后银行卡识别结果:
问题:适应性,这里的适应性主要指两方面:(1)预处理适应性:不同光线情况下得到的图片处理效果截然不同,也直接影响到了识别效果;(2)样本适应性:样本是否能适应所有的银行卡,虽然理论上数字都是一样的,但是处理过后的数字特征发生了一定的变换
这将在后面进行完善!!!!!
相关推荐
在人脸识别技术领域,基于Singular Value Decomposition(奇异值分解,简称SVD)和K-Nearest Neighbor(K-最近邻,简称KNN)算法的系统是一种常见的解决方案。本项目提供的MATLAB代码实现了这一方法,使得研究者和...
在本项目中,我们主要探讨的是如何利用图像处理技术和机器学习中的K近邻(K-Nearest Neighbor,简称KNN)算法实现车牌号码的自动识别。这个过程涉及到多个步骤,包括图像预处理、特征提取、车牌字符分割以及分类预测...
标签"matlab_最近邻 nearest_neighbor 最近邻 最近邻_识别 最近邻分类"涵盖了与主题相关的关键词,这些标签有助于理解压缩包中的内容是关于MATLAB编程,特别是与最近邻算法相关的部分,包括识别和分类任务。...
在手写字符识别领域,K-NN被广泛应用于自动识别数字,如OCR(光学字符识别)系统。本项目是用C语言实现的K-NN算法,通过Visual Studio 2010编译环境进行了验证,对于初学者理解K-NN的工作原理和应用具有很高的参考...
K-最近邻算法是一种基于实例的学习方法,主要用于分类和回归问题。该算法的基本思想是根据输入实例在特征空间中的K个最近邻居的信息来进行预测。 ##### 原理介绍 1. **计算距离**:对于一个新的输入实例,计算其与...
利用K-最近邻算法进行高识别率的信号特征五分类
这种分区方式可以是基于空间划分,如k-d树或四叉树等,也可以是基于密度或距离等其他特征。 - **分区内的聚类过程**:对于每个子集,独立应用NNAF算法进行聚类。这样可以在较小的范围内更精确地识别出簇的边界。 - *...
然后计算最近邻样本的距离权重,并用该权重描述最近邻和其他近邻对预测结果的影响;最后使用新的目标函数为待测样本分类。通过在图片、Web页面文本数据等数据集上的实验表明,所提算法得到了更好的分类结果,并且...
基于k-最近邻图的小样本KNN分类算法 KNN(K-Nearest Neighbors)分类算法是一种典型的非参数、有效、较流行的惰性学习方法,其思路简单且易于实现。该算法的核心思想是根据训练样本集中的模式来对未知样本进行分类...
KNN算法是一种基于实例的学习方法,它根据训练集中最接近(即最近邻)的K个样本来预测未知样本的类别。 **k-近邻算法原理** 1. **距离度量**:在KNN中,我们首先需要定义一个距离函数来衡量样本之间的相似性。通常...
不确定数据上的概率相互最近邻查询具有重要的实际应用,针对目前关于这方面的研究尚少,提出了不确定数据上的概率相互最近邻的top-k查询算法。首先对问题进行描述与定义,其次总结可行的裁剪规则,从而裁剪查询对象中...
k-最近邻搜索(KNNS) 在高维空间中应用非常广泛,但目前很多KNNS算法是基于欧氏距离对数据进行索引和搜索,不适合采用角相似性的应用。提出一种基于角相似性的k-最近邻搜索算法(BA-KNNS)。该算法先提出基于角相似性的...
K-NNR,即K最近邻分类器,是一种基于实例的学习方法。其基本思想是:一个未知样本最有可能属于与其最近的K个已知样本类别中最常见的那个类别。K-NNR算法简单易懂,无需事先训练模型,但计算复杂度较高,特别是在...
3. 测试与识别:新图像同样经过K-L变换得到参数向量,与库中所有图像的参数向量比较,使用某种距离度量(如欧氏距离)找到最近邻,从而确定识别结果。 总结来说,K-L变换是图像处理和人脸识别领域中一种强大的工具...
- 人脸识别算法:可以使用Eigenfaces、Fisherfaces或最近邻算法等。这些算法将人脸特征向量与预先构建的模型进行比较,以识别身份。 - OpenCV的`cv2.face.LBPHFaceRecognizer_create()`、`cv2.face....
k最近邻算法是一种有效快速的分类算法,包括源代码和测试数据
哈工大的模式识别的k均值算法,当K=1时为k最近邻算法,