最近学习了opencv,然后想通过其对图片上的数字进行识别,参考了网上几篇关于opencv数字识别的博客,我自己也写了一个程序玩玩。我是在vs2017和opencv3.4.1环境下实现的。

这里先说一下我的思路和步骤:

  1. 加载需要识别的图片,然后将其转化为二值图
  2. 寻找数字的外轮廓,切记不可以找全部轮廓,否则一个数字将会有多个轮廓,识别起来就很麻烦了
  3. 对轮廓进行排序,因为使用findcontours函数寻找到的轮廓顺序不一定是我们想要的,因此需要对找到的数字轮廓根据输入的图片进行排序
  4. 按顺序将数字轮廓分割,一个一个提取出来
  5. 进行识别和匹配,将提取出来的数字与模板数字(需要自己创建)进行比较,这里采用两幅图片像素相减的方法,寻找出差值最小的图片即为最匹配的数字

一、图片预处理

将输入的图片转化为二值图以便寻找轮廓

        //输入要识别的图片,并显示Mat srcImage = imread("number.jpg");imshow("原图", srcImage);//对图像进行处理,转化为灰度图然后再转为二值图Mat grayImage;cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);Mat binImage;//第4个参数为CV_THRESH_BINARY_INV是因为我的输入原图为白底黑字//若为黑底白字则选择CV_THRESH_BINARY即可threshold(grayImage, binImage, 100, 255, CV_THRESH_BINARY_INV);

二、寻找数字轮廓

        //寻找轮廓,必须指定为寻找外部轮廓,不然一个数字可能有多个轮廓组成,比如4,6,8,9等数字Mat conImage = Mat::zeros(binImage.size(), binImage.type());vector<vector<Point>> contours;vector<Vec4i> hierarchy;//指定CV_RETR_EXTERNAL寻找数字的外轮廓findContours(binImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//绘制轮廓drawContours(conImage, contours, -1, 255);

三、对轮廓进行排序

在排序之前呢,我们需要定义一个类,用来存放轮廓的外接矩阵以及方便后续的排序

class myRect
{
public:myRect(){}~myRect(){}myRect(Rect &temp):myRc(temp){}//比较矩形左上角的横坐标,以便排序bool operator<(myRect &rect){if (this->myRc.x < rect.myRc.x){return true;}else{return false;}}//重载赋值运算符myRect operator=(myRect &rect){this->myRc = rect.myRc;return *this;}//获取矩形Rect getRect(){return myRc;}
private:Rect myRc;//存放矩形
};

有了这个类之后,我们可以将一个一个轮廓外接矩阵保存于该类中。而且类中重载了比较操作符,很容易对轮廓进行排序。

        //将每个数字,分离开,保存到容器中vector<myRect> sort_rect;for (int i = 0; i < contours.size(); i++){//boundingRect返回轮廓的外接矩阵Rect tempRect = boundingRect(contours[i]);sort_rect.push_back(tempRect);}

排序算法的话,采用比较简单的冒泡法

        //对矩形进行排序,因为轮廓的顺序不一定是数字真正的顺序for (int  i = 0; i < sort_rect.size(); i++){for (int j = i + 1; j < sort_rect.size(); j++){if (sort_rect[j] < sort_rect[i]){myRect temp = sort_rect[j];sort_rect[j] = sort_rect[i];sort_rect[i] = temp;}}}

这样,sort_rect容器中的轮廓矩形是按我们输入的图片中的数字顺序存放的。

四、加载(新建)数字模板

我们在进行数字匹配时,需要先加载模板进行比较。如果没有就要先新建一个。新建模板需要输入的是0-9的数字模板,不用修改程序,只需要添加以下代码。

        /*加载模板,若没有则需自己新建一个*///新建,运行一次就好,不过制作模板的材料为0-9十个数字的图像for (int i = 0; i < 10; i++){Mat ROI = conImage(sort_rect[i].getRect());Mat dstROI;resize(ROI, dstROI, Size(40, 50),0, 0, INTER_NEAREST);char name[64];sprintf(name, "C:/Users/Administrator/Desktop/number_recognition/number_recognition/image/%d.jpg", i);//imshow(str, dstROI);imwrite(name, dstROI);}

制作模板其实就是将我们需要的ROI区域保存为图片,代码中的路径是我的路径,可以根据自己情况修改。

然后是加载模板,也就是从文件中将各个模板图片读入,路径根据自己的情况修改。

        //加载模板vector<Mat> myTemplate;for (int i = 0; i < 10; i++){char name[64];sprintf(name, "C:/Users/Administrator/Desktop/number_recognition/number_recognition/image/%d.jpg", i);Mat temp = imread(name, 0);myTemplate.push_back(temp);}

五、分割数字

分割数字比较容易,即通过轮廓外接矩形在二值图片上寻找我们要使用的ROI,然后分别保存下来,以供识别。根据排好序的sort_rect可以分割出待识别的数字。

        //按顺序取出和分割数字vector<Mat> myROI;for (int i = 0; i < sort_rect.size(); i++){Mat ROI;ROI = conImage(sort_rect[i].getRect());Mat dstROI = Mat::zeros(myTemplate[0].size(),myTemplate[0].type());resize(ROI, dstROI, myTemplate[0].size(), 0, 0, INTER_NEAREST);myROI.push_back(dstROI);}

六、比较和匹配

我采用的比较和匹配方法是,将absdiff计算模板和待识别数字的差值,然后比较出差值最小的即为最匹配的数字,从而实现匹配。在匹配前我们需要定义一个getPiexSum函数以计算两幅图片的差值的像素之和。

//求图片的像素和
int getPiexSum(Mat &image)
{int sum = 0;for (int i = 0; i < image.cols; i++){for (int j = 0; j < image.rows; j++){sum += image.at<uchar>(j, i);}}return sum;
}

下面进行匹配和输出

        //进行比较,将图片与模板相减,然后求全部像素和,和最小表示越相似,进而完成匹配vector<int> seq;//顺序存放识别结果for (int i = 0; i < myROI.size(); i++){Mat subImage;int sum = 0;int min = 100000;int min_seq = 0;//记录最小的和对应的数字for (int j = 0; j < 10; j++){//计算两个图片的差值absdiff(myROI[i], myTemplate[j], subImage);sum = getPiexSum(subImage);if (sum < min){min = sum;min_seq = j;}sum = 0;}seq.push_back(min_seq);}//输出结果cout << "识别结果为:";for (int i = 0; i < seq.size(); i++){cout << seq[i];}cout << endl;

七、总结

识别的结果图片:

存在的不足:这种识别方式有个不好的点就是,模板的数字大小(比如我用的是48号字体大小)不能与待识别的数字的大小相差太多,否则会降低识别准确率。如果相差不是很大的话是可以准确识别的。然后该程序也只能识别单行数字,暂时还不能识别多行。但是可以在本程序的基础上做点修改就可以了。等以后有时间了再回来解决这两个问题。

附上程序源码下载:https://download.csdn.net/download/m0_37543178/10662148

基于opencv的数字识别相关推荐

  1. 基于OpenCV的数字识别系统

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 综述 2012年iOS应用商店中发布了一个名为FuelMate的G ...

  2. 基于OpenCV的人脸识别自助商店(源码&部署视频)

    1.模块功能介绍 实现人脸识别模块.人脸登录与注册功能.商店显示和用户余额页显示功能 用GUl图形界面实现(pyqt)语言python windows下软件pycharm 1.用户登录模块:刷脸登录 ...

  3. Python基于OpenCV的人脸识别自助商店(源码&部署视频)

    1.模块功能介绍 实现人脸识别模块.人脸登录与注册功能.商店显示和用户余额页显示功能 用GUl图形界面实现(pyqt)语言python windows下软件pycharm 1.用户登录模块:刷脸登录 ...

  4. OpenCV车牌/数字识别

    opencv 数字识别 附完整代码 Opencv的应用之车牌识别       用的支持向量机 使用opencv进行数字识别       对学习还是有点帮助的 Tensorflow 实现 MNIST 手 ...

  5. 基于OpenCV实现人脸识别--Python

    目录 前言 第一章 OpenCV介绍 第二章 功能描述 2.1 对已有的数据进行检测 2.2 陌生人检测并发出警告 2.3 保存陌生人的视频 2.4 输入图片进行检测 2.5 现场录用信息 第三章 功 ...

  6. 基于FPGA的数字识别实现

    前言 数字识别在我们生活中很常见,比如车牌识别.本篇博客就将介绍数字识别的方法,由于只是研究数字识别的方法,我们就不用硬件平台,而是用Modelsim和Matlab来仿真验证. 具体方法如下: 我们用 ...

  7. 基于MATLAB手写体数字识别程序设计

    基于MATLAB手写体数字识别程序设计 手写体识别由于其实用性,一直处于研究进步的阶段,本文主要针对的是对0-9十个手写数字体脱机识别,在Matlab中对样本部分为进行16特征的提取,分别采用最小距离 ...

  8. Android:基于OpenCV实现身份证识别(C++)——移植图像算法

    系列文章目录 第一章 Android:基于OpenCV实现身份证识别(C++)--图像处理 第二章 Android:基于OpenCV实现身份证识别(C++)--移植图像算法 文章目录 系列文章目录 前 ...

  9. 基于pynq的数字识别神经网络加速器设计

    文章目录 基于pynq的数字识别神经网络加速器设计 软件部分 1. 全连接神经网络: 2. 卷积神经网络搭建: 3. 文件格式转换: 硬件部分 1. MNIST的硬件实现思路 2. 代码编写与硬件综合 ...

  10. 基于MNIST手写体数字识别--含可直接使用代码【Python+Tensorflow+CNN+Keras】

    基于MNIST手写体数字识别--[Python+Tensorflow+CNN+Keras] 1.任务 2.数据集分析 2.1 数据集总体分析 2.2 单个图片样本可视化 3. 数据处理 4. 搭建神经 ...

最新文章

  1. OSChina 周二乱弹 ——同意,我的元首大人
  2. Python-OpenCV学习--电脑外接摄像头实时采集FAST角点并显示
  3. mysql get one_Ecshop 数据库操作方法getRow、getAll、getOne区别
  4. 初识canvas,使用canvas做一个百分比加载进度的动画
  5. pytorch慢到无法安装,该怎么办?
  6. 容器编排技术 -- Kubernetes kubectl rollout pause 命令详解
  7. Flutter 随机颜色 颜色处理工具类
  8. mac mysql-share_mac下安装mysql
  9. Feign 超时设置
  10. AMD完成对赛灵思的收购
  11. 打印机如何共享多台电脑_多台电脑打印机共享的方法
  12. BZOJ3527 推出卷积公式FFT求值
  13. 前端开发工程师如何在2013年里提升自己
  14. NDCG、AUC介绍
  15. 淘宝客APP源码 社交电商uniapp开发源码 前端源码自营商城
  16. chm 打不开 解决办法
  17. windows服务器连接教程-手机连接电脑连接
  18. word文档打钩记录快捷键
  19. Excel 地址 行列转换
  20. java.io.IOException: Unable to establish loopback connection

热门文章

  1. 实用工具SDelete
  2. Python 自带slic代码分析
  3. kindle DXG 安装多看
  4. JS实现自定义右键菜单
  5. Android-更改字体(LED液晶数字字体)
  6. 有哪些免费且比较好用的数据可视化工具?
  7. 服务器项目管理软件,项目管理软件-Microsoft Project.pdf
  8. 紧密中心性(closeness centrality)
  9. TSINSEE青犀视频/海康合作的RTMP推流安防摄像头的移动侦测功能介绍
  10. 微信模拟地理位置_微信伪装地理位置是什么个原理