如何用opencv识别特定物体做银行卡号码识别

银行卡号识别(三) ---
基于k最近邻的数字识别测试 -
- ITeye技术网站
博客分类:
在进行完预处理之后,我们可以开始用算法识别数字了。首先我们不做那么复杂的、一连串银行卡数字的识别,而是做一个数字的测试。
一、机器算法的引入-----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/的博客上我看到了非常合适的解释图,在这里也分享给大家:
这里提取出来的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_
IplImage* prs_image = cvCreateImage(cvSize(new_width, new_height), 8, 1);
CvMat row,
CvMat rowb,
int c = 0;
int i,j,k;
CvMat* srcImg = cvCreateMat(32,32,CV_32FC1);
char filename[50];
char a[32][32];
for(m =0; m&m++)//总共10个数字
for(n = 0; n&train_n++)//每个数字50个样本
// 这里是读入图片样本
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.);
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* scaledR
CvMat dataA;
CvRect//bounding box
CvRect//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.
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 scaledR//直接返回处理后的图片
CvRect findBB(IplImage *img)
{//找模板图像有效图像的边框,方便抠下来
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,
rect = cvBoundingRect( contour, 0 );
有了上面代码的基础,我们就得到了trainData、trainClasses训练集,那么接下来我们要抠取待测图片的有效区域,并且生成相应的特征向量,当然这里生成特征向量的方法要和前面生成训练集时用的方法保持一致。
训练完之后我们就可以利用openCV函数对训练集和待测数据进行k最近邻计算具体函数见下:
int do_ocr(IplImage *img)
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.);
cvGetSubRect(image, &data,cvRect(0,0,new_width,new_height));
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)
按照我上文中说的思路很容易得到我们想要的结果:
测试图片:
测试结果:
浏览: 50760 次
来自: 上海
请问博主,大概在130行:Bitmap bmp = getRe ...
您好,我想请教一下关于银行卡识别的问题,您方便加一下我QQ吗? ...
闵大荒是什么?
写的很棒。加油&>&&>&&>&&>&图铭银行卡号识别
图铭银行卡号识别
上传大小:10.89MB
图铭Android平台银行卡号识别系统
随着智能终端(智能手机及平板电脑)及移动通信(3G)的发展,原来运行在PC上的信息系统(如邮件系统、即时通信、网页浏览、协同办公、网络购物、社交网站、博客等)逐渐转移到智能终端设备上。可以预见未来几年60%以上的业务将会逐渐转移到智能终端系统上来。在这种背景下,杭州图铭科技有限公司推出基于Android 平台的银行卡号识别系统。
通过拍照界面,指导用户拍出合格证件图像。
采用文字识别(OCR)技术,自动识别银行卡信息(如卡号,卡所属银行等).
通过调用 识别功能Activity,实现其他应用程序接口调用。
识别银行卡种类,主要是国内外20多家银行的印刷字体(平面黑色字体卡类)和凸面字体银行卡(包括字符间距类型为6-13、4-4-4-4-3、4-4-4-4等类型)。
对原图像进行倾斜矫正、抠图银行卡区域。
通过形态学和目前检测思路。对字符进行区域定位和单个字符分割。
对单个字符进行识别...展开收缩
综合评分:3.2(10位用户评分)
收藏((2))
所需积分:0
下载次数:185
审核通过送C币
创建者:xamhaha
创建者:qq
创建者:wty1009
课程推荐相关知识库
上传者其他资源上传者专辑
开发技术热门标签
VIP会员动态
android服务器底层网络模块的设计方法
所需积分:0
剩余积分:720
您当前C币:0
可兑换下载积分:0
兑换下载分:
兑换失败,您当前C币不够,请先充值C币
消耗C币:0
你当前的下载分为234。
图铭银行卡号识别
会员到期时间:
剩余下载次数:
你还不是VIP会员
开通VIP会员权限,免积分下载
你下载资源过于频繁,请输入验证码
你下载资源过于频繁,请输入验证码
您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:!
若举报审核通过,可奖励20下载分
被举报人:
zhubenfulovepoem
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:1961人阅读
银行卡的识别与车牌识别都是类似的,有了opencv方便了很多,许多函数都不要自己动手去写。
// #include &stdafx.h& &
#include &cv.h& &
#include &highgui.h& &
#include &cxcore.h& &
int main(int argc, char* argv[])
IplImage* imgQie=NULL;
IplImage* imgSrc = cvLoadImage(&D:\\1.jpg&, CV_LOAD_IMAGE_COLOR);//加载图像
IplImage* img_gray = cvCreateImage(cvGetSize(imgSrc), IPL_DEPTH_8U, 1);//创建灰度图,定义灰度图
cvCvtColor(imgSrc, img_gray, CV_BGR2GRAY);//灰度图的转换函数
cvThreshold(img_gray, img_gray, 50, 255, CV_THRESH_BINARY_INV);// CV_THRESH_BINARY_INV使得背景为黑色,字符为白色,这样找到的最外层才是字符的最外层 &
cvShowImage(&ThresholdImg&, img_gray);//显示灰度图像
CvSeq* contours = NULL;//可增长的序列,不是固定的序列,存储轮廓信息的链表头
CvSeq* contours1 = NULL;
CvMemStorage* storage = cvCreateMemStorage(0);//用来创建一个内存存储器,来统一管理各种动态对象的内存
// 上面源图片有瑕疵可以用腐蚀,膨胀来祛除 &
IplImage* imgPeng = cvCreateImage(cvGetSize(imgSrc), IPL_DEPTH_8U, 1);
IplImage* imgFu = cvCreateImage(cvGetSize(imgSrc), IPL_DEPTH_8U, 1);
cvErode(img_gray, imgFu, NULL, 1);//腐蚀函数
cvNamedWindow(&腐蚀&, CV_WINDOW_AUTOSIZE);
cvShowImage(&腐蚀&, imgFu);
cvDilate(imgFu,imgPeng,NULL,11);
cvNamedWindow(&膨胀&, CV_WINDOW_AUTOSIZE);
cvShowImage(&膨胀&, imgPeng);
int count = cvFindContours(imgPeng, storage, &contours, sizeof(CvContour), CV_RETR_EXTERNAL);//轮廓检验返回的是轮廓的个数
printf(&轮廓个数:%d&, count);
int idx = 0;
char szName[56] = { 0 };
int tempCount = 0;
for (CvSeq* c = c != NULL; c = c-&h_next)&
CvRect rc = cvBoundingRect(c, 0);
if (rc.width/rc.height&=5||rc.height&1||rc.width&1) & & &
& & & { & &
& & & & & & & //这里可以根据轮廓的大小进行筛选 &
cvDrawRect(imgSrc, cvPoint(rc.x-10, rc.y-3), cvPoint(rc.x + rc.width-6, rc.y + rc.height-3), CV_RGB(255, 0, 0));
IplImage* imgNo = cvCreateImage(cvSize(rc.width, rc.height), IPL_DEPTH_8U, 3);// //为分割后的单个字符分配一个存储空间
cvSetImageROI(imgSrc, rc); //基于给定的矩形设置图像的ROI(感兴趣区域)
cvCopyImage(imgSrc, imgNo);//将ROI复制到imgNo
cvResetImageROI(imgSrc);//释放基于给定的矩形设置图像的ROI
sprintf(szName, &wnd_%d&, idx++);
cvNamedWindow(szName);
cvShowImage(szName, imgNo); //如果想切割出来的图像从左到右排序,或从上到下,可以比较rc.x,rc.y; &
IplImage* imgQie = imgNo;
IplImage* imgQiegray = cvCreateImage(cvGetSize(imgQie), IPL_DEPTH_8U, 1);//创建灰度图,定义灰度图
cvCvtColor(imgQie, imgQiegray, CV_BGR2GRAY);//灰度图的转换函数
cvThreshold(imgQiegray, imgQiegray, 70, 255, CV_THRESH_BINARY_INV);// CV_THRESH_BINARY_INV使得背景为黑色,字符为白色,这样找到的最外层才是字符的最外层 &
cvShowImage(&灰度二&, imgQiegray);//显示灰度图像
int count1 = cvFindContours(imgQiegray, storage, &contours1, sizeof(CvContour), CV_RETR_EXTERNAL);//轮廓检验返回的是轮廓的个数
printf(&轮廓个数:%d&, count1);
//嵌套在里面再进行处理,在定位出后在处理。
int idx1 = 0;
//int i = 0;
char szName1[56] = { 0 };
int i = 0;
//int a[100];
CvRect rc1[100],
int tempCount1 = 0;
for (CvSeq* c1 = contours1; c1 != NULL; c1 = c1-&h_next)
rc1[i] = cvBoundingRect(c1, 0);//得到所有外部轮廓的
//a[i] = rc.x;
i++;
for (int j = 0; j &19; j++)
for (i = 0; i&19- i++)
if (rc1[i].x&rc1[i + 1].x)
temp = rc1[i];
rc1[i] = rc1[i + 1];//由小到小依次排序
rc1[i + 1] =
for (i = 0; i&count1; i++)
if (rc1[i].width&rc1[i].height)
& & //这里可以根据轮廓的大小进行筛选 &
cvDrawRect(imgQie, cvPoint(rc1[i].x, rc1[i].y), cvPoint(rc1[i].x + rc1[i].width, rc1[i].y + rc1[i].height), CV_RGB(255, 0, 0));
IplImage* imgNo1 = cvCreateImage(cvSize(rc1[i].width, rc1[i].height), IPL_DEPTH_8U, 3);// //为分割后的单个字符分配一个存储空间
cvSetImageROI(imgQie, rc1[i]); //基于给定的矩形设置图像的ROI(感兴趣区域)
cvCopyImage(imgQie, imgNo1);//将ROI复制到imgNo
cvResetImageROI(imgQie);//释放基于给定的矩形设置图像的ROI
sprintf(szName1, &wnd_%d&, idx1++);
cvNamedWindow(szName1);
cvShowImage(szName1, imgNo1); //如果想切割出来的图像从左到右排序,或从上到下,可以比较rc.x,rc.y; &
cvReleaseImage(&imgNo1);
cvReleaseImage(&imgNo);
cvNamedWindow(&src&);
cvShowImage(&src&, imgSrc);
cvWaitKey(0);
cvReleaseMemStorage(&storage);
cvReleaseImage(&imgSrc);
cvReleaseImage(&img_gray);
cvReleaseImage(&imgQie);
//cvReleaseImage(&imgQiegray);
cvDestroyAllWindows();
很多在吧字符切割后不知道怎么排序,上面有完整的代码,希望可以帮助大家,大家一起进步。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:45911次
排名:千里之外
原创:46篇
转载:47篇
评论:13条
(6)(6)(24)(34)(24)(1)(1)}

我要回帖

更多关于 opencv如何识别棋盘格 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信