OpenCV手写数字字符识别(基于k近邻算法)
摘要
本程序主要参照论文,《基于OpenCV的脱机手写字符识别技术》实现了,对于手写阿拉伯数字的识别工作。识别工作分为三大步骤:预处理,特征提取,分类识别。预处理过程主要找到图像的ROI部分子图像并进行大小的归一化处理,特征提取将图像转化为特征向量,分类识别采用k-近邻分类方法进行分类处理,最后根据分类结果完成识别工作。
程序采用Microsoft Visual Studio 2010与OpenCV2.4.4在Windows 7-64位旗舰版系统下开发完成。并在Windows xp-32位系统下测试可用。
主流程图:
细化流程图:
预处理的过程就是找到图像的ROI区域的过程,如下图所示:
首先找到数字的边界框,然后大小归一化数字图片,主要流程如下图所示:
主要代码:
IplImagepreprocessing(IplImage*imgSrc,intnew_width,intnew_height)
{
IplImage* result;
IplImage* scaledResult;
CvMat data;
CvMat dataA;
CvRectbb;//bounding box
CvRectbba;//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;//直接返回处理后的图片
}
2. 特征提取
在拿到ROI图像减少了信息量之后,就可以直接用图片作为向量矩阵作为输入:
voidbasicOCR::getData()
{
IplImage* src_image;
IplImage prs_image;
CvMat row,data;
char file[255];
int i,j;
for(i =0; i<classes;i++)//总共10个数字
{
for(j = 0;
j<train_samples;j++)//每个数字50个样本
{
//加载所有的样本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 =cvLoadImage(file,0);
if(!src_image)
{
printf("Error: Cant load image %s\n",file);
//exit(-1);
}
//process file
prs_image =preprocessing(src_image,size,size);
//生成训练矩阵,每个图像作为一个向量
cvGetRow(trainClasses, &row,i*train_samples
+j);
cvSet(&row,cvRealScalar(i));
//Set data
cvGetRow(trainData, &row,i*train_samples
+j);
IplImage*img =
cvCreateImage(cvSize(
size, size ),
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,size,size));
CvMatrow_header, *row1;
//convert data matrix sizexsize to vecor
row1 =cvReshape( &data, &row_header,
0, 1 );
cvCopy(row1, &row,NULL);
}
}
}
3. 分类识别
识别方法采用knn近邻分类法。这个算法首先贮藏所有的训练样本,然后通过分析(包括选举,计算加权和等方式)一个新样本周围K个最近邻以给出该样本的相应值。这种方法有时候被称作“基于样本的学习”,即为了预测,我们对于给定的输入搜索最近的已知其相应的特征向量。
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 KNN方法虽然从原理上也依赖于极限定理,但在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
识别工作主要有以下几个步骤:
1. 初始化机器学习算法,及其训练
knn=new CvKNearest( trainData, trainClasses, 0, false, K );
因为trainData, trainClasses数据已得到。训练在CvKNearest算法初始化中已经完成
2. 识别
获取识别测试的数据,testData
result=knn->find_nearest(testData,K,0,0,nearest,0);
result为返回的识别的结果
4. 实验结果
在knn参数k=5,子图像向量大小选取128*128像素,训练样本50副图片,测试样本50副图片,系统误识率为7.4%。对于用户手写阿拉伯数字2的识别结果为2,识别比较准确。
5. 未来的工作
本程序主要参照网上的一些实例完成了部署跟实验工作,虽然仅仅完成了手写阿拉伯数字的识别工作,但是字符识别的一些原理工作都是相同的,未来能够从一下几个方面进行提高:
1. 提高程序的识别准确率,从一些文献实现的结果来看,简单的模型结合大量的训练样本,往往效果比复杂的模型结合少量训练样本实现的效果好。
2. 扩展程序的功能,从实现简单的字符到最终实现识别手写汉字等。
3. 提高识别速度,改进算法为并行算法,实现如联机在线识别等。
6.主要参考文献:
http://blog.csdn.net/jackmacro/article/details/7026211
http://blog.damiles.com/2008/11/basic-ocr-in-opencv/
http://blog.csdn.net/zhubenfulovepoem/article/details/6803150
http://blog.csdn.net/firehood_/article/details/8433077
http://blog.csdn.net/viewcode/article/details/7943341
7.项目打包下载
http://download.csdn.net/detail/wangyaninglm/6631953
8.手写字符识别的复杂版本,这个增加了一些OpenGL技术,程序比较复杂
http://blog.csdn.net/wangyaninglm/article/details/41848019
OpenCV手写数字字符识别(基于k近邻算法)的更多相关文章
- linux-基于tensorflow2.x的手写数字识别-基于MNIST数据集
数据集 数据集下载MNIST 首先读取数据集, 并打印相关信息 包括 图像的数量, 形状 像素的最大, 最小值 以及看一下第一张图片 path = 'MNIST/mnist.npz' with np. ...
- 手写数字识别——基于LeNet-5卷积网络模型
在<手写数字识别——利用Keras高层API快速搭建并优化网络模型>一文中,我们搭建了全连接层网络,准确率达到0.98,但是这种网络的参数量达到了近24万个.本文将搭建LeNet-5网络, ...
- 手写数字识别的k-近邻算法实现
(本文为原创,请勿在未经允许的情况下转载) 前言 手写字符识别是机器学习的入门问题,k-近邻算法(kNN算法)是机器学习的入门算法.本文将介绍k-近邻算法的原理.手写字符识别问题分析.手写字符识别的k ...
- 基于opencv的手写数字字符识别
摘要 本程序主要参照论文,<基于OpenCV的脱机手写字符识别技术>实现了,对于手写阿拉伯数字的识别工作.识别工作分为三大步骤:预处理,特征提取,分类识别.预处理过程主要找到图像的ROI部 ...
- TensorFlow实战之Softmax Regression识别手写数字
关于本文说明,本人原博客地址位于http://blog.csdn.net/qq_37608890,本文来自笔者于2018年02月21日 23:10:04所撰写内容(http://blog.c ...
- BP神经网络的手写数字识别
BP神经网络的手写数字识别 ANN 人工神经网络算法在实践中往往给人难以琢磨的印象,有句老话叫“出来混总是要还的”,大概是由于具有很强的非线性模拟和处理能力,因此作为代价上帝让它“黑盒”化了.作为一种 ...
- 一看就懂的K近邻算法(KNN),K-D树,并实现手写数字识别!
1. 什么是KNN 1.1 KNN的通俗解释 何谓K近邻算法,即K-Nearest Neighbor algorithm,简称KNN算法,单从名字来猜想,可以简单粗暴的认为是:K个最近的邻居,当K=1 ...
- 基于OpenCV的KNN算法实现手写数字识别
基于OpenCV的KNN算法实现手写数字识别 一.数据预处理 # 导入所需模块 import cv2 import numpy as np import matplotlib.pyplot as pl ...
- KNN (K近邻算法) - 识别手写数字
KNN项目实战——手写数字识别 1. 介绍 k近邻法(k-nearest neighbor, k-NN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法.它的工作原理是:存在一个 ...
随机推荐
- ROS_Kinetic_x 基於ROS和Gazebo的RoboCup中型組仿真系統(多機器人協作)
國防科學技術大學發布了RoboCup中型組仿真平臺,基於ROS和Gazebo設計. 該平臺可以用於多機器人協作研究.參考資料如下: ROS新聞:1 http://www.ros.org/news ...
- 高仿腾讯QQ即时通讯IM项目
前言:其实这个项目早就开发完成了,在本人的github上,本来没打算写成博客的形式,因为一个项目要写出来要花很久,但是最近看到很多 人在我的github上download后随意发布到网上,本来上传到g ...
- API创建员工Element
DECLARE ln_element_link_id PAY_ELEMENT_LINKS_F.ELEMENT_LINK_ID%TYPE; ld_effective_start_date DATE; l ...
- xml特殊字符处理 如&
写了个request2XML的方法,每当数据中有'<'.'&'符号时,封装的XML就无法解析.发现了XML里的CDATA属性,问题迎刃而解!在XML文档中的所有文本都会被解析器解析 ...
- JavaScript实现的网页放大镜效果
今天在观看视频学习的时候,学到了一个小技巧.就拿过来与大家进行分享一下啦. 实现的原理 分析需求:需要两张图,一大一小.然后根据鼠标的动作显示出不同的区域块的图像. 核心:鼠标事件的获取和处理.图片显 ...
- 初次见面 你好EF
EF(yif),第一次听到这个名字的时候,以为是一个帅帅的魔术师,在小编的傻傻的梦想里,就是有一天,有一个魔术师站在小编面前,变出一大捧的玫瑰花,然后,然后不要钱`(*∩_∩*)′,然而在我们的编程世 ...
- K-均值聚类算法(K-means)
K-means是一种无监督的学习,将相似的对象归到同一个簇中.可以将一批数据分为K个不同的簇,并且每个簇的中心采用簇中所含样本的均值计算而成. K-means算法的K值需要由用户指定, ...
- 如何回滚请求<复制系统初始的数据>所处理的数据
一. 问题提出 请求名称:复制系统初始的数据 参数:空 问题: 今天早上财务实施人员新配置了一个OU,然后在跑复制系统初始的数据报表的时候,不小心,不输入参数就直接跑. 报表先是报错. 接下来的 ...
- JAVA之旅(十七)——StringBuffer的概述,存储,删除,获取,修改,反转,将缓存区的数据存储到数组中,StringBuilder
JAVA之旅(十七)--StringBuffer的概述,存储,删除,获取,修改,反转,将缓存区的数据存储到数组中,StringBuilder 讲完String,我们来聊聊他的小兄弟 一.StringB ...
- 数据从oracle转换到mysql
因为项目变更,需要把数据从oracle里转到mysql里. 第一个想法,自己写代码. 20分钟后,算了,还是找找工具吧. 第二步: 下了一个工具,二十分钟后,师兄发现,表的结构是倒完了,但是有的表数据 ...