OpenCV手写数字字符识别(基于k近邻算法)



本程序主要参照论文,《基于OpenCV的脱机手写字符识别技术》实现了,对于手写阿拉伯数字的识别工作。识别工作分为三大步骤:预处理,特征提取,分类识别。预处理过程主要找到图像的ROI部分子图像并进行大小的归一化处理,特征提取将图像转化为特征向量,分类识别采用k-近邻分类方法进行分类处理,最后根据分类结果完成识别工作。

程序采用Microsoft Visual Studio 2010与OpenCV2.4.4在Windows 7-64位旗舰版系统下开发完成。并在Windows xp-32位系统下测试可用。

主流程图

 

细化流程图:

 

 

 

1.   预处理

预处理的过程就是找到图像的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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV(Open Source Computer Vision Library)是一款开源的计算机视觉库,专门为图像和视频处理任务设计,广泛应用于学术研究、工业应用以及个人项目。以下是关于OpenCV的详细介绍: 历史与发展 起源:OpenCV于1999年由英特尔公司发起,旨在促进计算机视觉技术的普及和商业化应用。该项目旨在创建一个易于使用、高效且跨平台的库,为开发者提供实现计算机视觉算法所需的基础工具。 社区与支持:随着时间的推移,OpenCV吸引了全球众多开发者和研究人员的参与,形成了活跃的社区。目前,OpenCV由非盈利组织OpenCV.org维护,并得到了全球开发者、研究机构以及企业的持续贡献和支持。 主要特点 跨平台:OpenCV支持多种操作系统,包括但不限于Windows、Linux、macOS、Android和iOS,确保代码能够在不同平台上无缝运行。 丰富的功能:库包含了数千个优化过的函数,涵盖了计算机视觉领域的诸多方面,如图像处理(滤波、形态学操作、色彩空间转换等)、特征检测与描述(如SIFT、SURF、ORB等)、物体识别与检测(如Haar级联分类器、HOG、DNN等)、视频分析、相机校正、立体视觉、机器学习(SVM、KNN、决策树等)、深度学习(基于TensorFlow、PyTorch后端的模型加载与部署)等。 高效性能:OpenCV代码经过高度优化,能够利用多核CPU、GPU以及特定硬件加速(如Intel IPP、OpenCL等),实现高速图像处理和实时计算机视觉应用。 多语言支持:尽管OpenCV主要使用C++编写,但它提供了丰富的API绑定,支持包括C、Python、Java、MATLAB、JavaScript等多种编程语言,方便不同领域的开发者使用。 开源与免费:OpenCV遵循BSD开源许可证发布,用户可以免费下载、使用、修改和分发库及其源代码,无需担心版权问题。 架构与核心模块 OpenCV的架构围绕核心模块构建,这些模块提供了不同层次的功能: Core:包含基本的数据结构(如cv::Mat用于图像存储和操作)、基本的图像和矩阵操作、数学函数、文件I/O等底层功能。 ImgProc:提供图像预处理、滤波、几何变换、形态学操作、直方图计算、轮廓发现与分析等图像处理功能。 HighGui:提供图形用户界面(GUI)支持,如图像和视频的显示、用户交互(如鼠标事件处理)以及简单的窗口管理。 VideoIO:负责视频的读写操作,支持多种视频格式和捕获设备。 Objdetect:包含预训练的对象检测模型(如Haar级联分类器用于人脸检测)。 Features2D:提供特征点检测(如SIFT、ORB)与描述符计算、特征匹配与对应关系估计等功能。 Calib3d:用于相机标定、立体视觉、多视图几何等问题。 ML:包含传统机器学习算法,如支持向量机(SVM)、K近邻(KNN)、决策树等。 DNN:深度神经网络模块,支持导入和运行预训练的深度学习模型,如卷积神经网络(CNN)。 应用领域 OpenCV广泛应用于: 科研与教育:作为计算机视觉教学和研究的基础工具,OpenCV简化了算法原型开发与验证过程。 工业自动化:在视觉检测、机器人导航、产品质量控制等工业场景OpenCV用于实时图像分析与决策。 安防监控:用于人脸识别、行人检测、行为分析等智能监控系统。 医疗影像分析:在医疗领域,OpenCV用于医学图像处理、病灶检测、诊断辅助等应用。 自动驾驶:在车辆视觉感知系统OpenCV用于道路标志识别、障碍物检测、车道线识别等任务。 多媒体应用:如图像编辑软件、AR/VR应用、游戏开发等,利用OpenCV进行图像和视频处理。 物联网与嵌入式系统:在资源受限的嵌入式设备上,OpenCV提供轻量级的计算机视觉解决方案。 学习与社区资源 OpenCV拥有丰富的官方文档、教程、示例代码以及活跃的开发者社区,包括GitHub、StackOverflow、官方论坛等,为学习和使用OpenCV提供了有力支持。此外,有许多书籍、在线课程、博客文章和研讨会专门讲解OpenCV的使用和计算机视觉技术。 综上所述,OpenCV作为一款功能强大、高效、跨平台且开源的计算机视觉库,为开发者提供了实现各类图像和视频处理任务所需的工具箱,其广泛的应用领域和活跃的社区支持使之成为计算机视觉领域不可或缺的开发工具。
好的,这是一个非常有趣的问题。MNIST是一个非常著名的手写数字数据集,用于测试机器学习算法的性能。在C++,我们可以使用OpenCV库来读取和处理图像数据,并使用机器学习库(如TensorFlow)来构建数字识别模型。下面是一个基本的MNIST手写数字识别示例: 1. 首先,我们需要下载MNIST数据集,可以从官方网站下载:http://yann.lecun.com/exdb/mnist/ 2. 接下来,我们需要使用OpenCV库来读取图像数据。可以使用以下代码: ``` cv::Mat image = cv::imread("mnist_image.png", CV_LOAD_IMAGE_GRAYSCALE); ``` 这将读取图像数据并将其转换为灰度图像。 3. 然后,我们需要将图像数据转换为适合机器学习算法的格式。可以使用以下代码: ``` cv::Mat_<float> image_data = image.reshape(1, 1); image_data /= 255.0f; ``` 这将将图像数据转换为一个浮点数矩阵,并将其归一化为0到1之间的值。 4. 接下来,我们可以使用机器学习库来构建数字识别模型。这里假设我们使用TensorFlow库。可以使用以下代码: ``` tensorflow::GraphDef graph_def; tensorflow::Session* session; tensorflow::SessionOptions session_options; tensorflow::ReadBinaryProto(tensorflow::Env::Default(), "mnist_model.pb", &graph_def); session_options.config.mutable_gpu_options()->set_allow_growth(true); session = tensorflow::NewSession(session_options); tensorflow::Status status = session->Create(graph_def); ``` 这将读取预训练的数字识别模型,并创建一个TensorFlow会话。 5. 最后,我们可以使用以下代码来预测图像数字: ``` tensorflow::Tensor input_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, 784})); auto input_tensor_mapped = input_tensor.tensor<float, 2>(); for (int i = 0; i < 784; i++) { input_tensor_mapped(0, i) = image_data(0, i); } std::vector<tensorflow::Tensor> output_tensors; tensorflow::Status status = session->Run({{"input", input_tensor}}, {"output"}, {}, &output_tensors); float* prediction = output_tensors[0].flat<float>().data(); ``` 这将将图像数据输入到数字识别模型,并返回一个浮点数数组,表示每个数字的概率。我们可以选择具有最高概率的数字作为预测结果。 希望这个示例可以帮助你了解如何在C++基于OpenCV实现MNIST手写数字识别

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值