opencv 数字识别详细教程

article/2025/7/19 7:43:46

 

最近要做数字识别这块,但是自己又完全不懂这个,网上搜资料搜了好多,但是都没找到完整代码。只有自己慢慢搞,下面写下自己的过程以及代码有不好的地方希望大神可以指出,大家相互交流下。有需要完整代码的可以自行下载(源码里面 是需要自己做一个图片的,没有图片,不能直接运行)

 

git 源码

 

我是在VS2013 和opencv 2.4.9 环境下实现的。关于环境的搭建和配置以及软件的下载可以可以参考,http://blog.csdn.net/ltg01/article/details/50433386

我要做的是把0123456789 印刷体数字识别出来。

一、首先对图片进行预处理

对图片进行灰度化二值化

 

        Mat src = imread("D:\\b.png", CV_LOAD_IMAGE_GRAYSCALE);//读取图片并进行灰度化处理threshold(src, src, 100 , 255, CV_THRESH_BINARY);//二值化imshow("origin", src);//显示图片

原图经过灰度二值化的图

Mat imread(const string& filename, int flags);

filename:文件地址 flags:标志,读取什么样(灰度,彩色)图像hdrtype:传入的为载入什么类型(enum {LOAD_CVMAT=0,LOAD_IMAGE=1, LOAD_MAT=2 };这三个中的一个。) Mat :保存图像的Mat对象了。
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type) 
参数信息:
第一个参数,InputArray类型的src,输入数组,填单通道 , 8或32位浮点类型的Mat即可。
第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放输出结果,且和第一个参数中的Mat变量有一样的尺寸和类型。
第三个参数,double类型的thresh,阈值的具体值。
第四个参数,double类型的maxval,当第五个参数阈值类型type取 THRESH_BINARY 或THRESH_BINARY_INV阈值类型时的最大值.
第五个参数,int类型的type,阈值类型,。
其它参数很好理解,我们来看看第五个参数,第五参数有以下几种类型
0: THRESH_BINARY  当前点值大于阈值时,取Maxval,也就是第四个参数,下面再不说明,否则设置为0
1: THRESH_BINARY_INV 当前点值大于阈值时,设置为0,否则设置为Maxval
2: THRESH_TRUNC 当前点值大于阈值时,设置为阈值,否则不改变
3: THRESH_TOZERO 当前点值大于阈值时,不改变,否则设置为0
4: THRESH_TOZERO_INV  当前点值大于阈值时,设置为0,否则不改变

 

 

二、对图片上的数字进行切割
 

   图片经过二值化后每个像素点的值只有1和0两种,在这里黑色部分的像素点的值为0白色字体部分的值为1.
对图片

 

先进行列扫描求每列的和。刚开始是都是黑色所以每列的和都是0,知道扫描到3的左边缘的那列的时候因为有白色所以这列的和大于0,这时候记下当前位置left,然后接着扫描,接下来每列的和都大于0,直到3的右边缘时候这列和右等于0,记下当前位置right,则right减去left则是3的宽度,高度仍为原图的高度,这样通过函数

 

        int width = right - left;Rect rect(left, 0, width, src.rows);leftImg = src(rect);

 

就可以把3截取出来了,如图

但是3的上下部分没有截取,同样对图片进行行扫描,截取上下部分,如下图

就这样循环截取图片就可以吧其他数字截取下来了,但是每次截取的原图是不一样的,第二次截取的时候原图上就没有3 是从6开始的如图

 

int cutLeft(Mat& src, Mat& leftImg, Mat& rightImg)//左右切割
{int left, right;left = 0;right = src.cols;int i;for (i = 0; i < src.cols; i++){int colValue = getColSum(src, i);//cout <<i<<" th "<< colValue << endl;if (colValue>0){left = i;break;}}if (left == 0){return 1;}for (; i < src.cols; i++){int colValue = getColSum(src, i);//cout << i << " th " << colValue << endl;if (colValue == 0){right = i;break;}}int width = right - left;Rect rect(left, 0, width, src.rows);leftImg = src(rect).clone();Rect rectRight(right, 0, src.cols - right, src.rows);rightImg = src(rectRight).clone();cutTop(leftImg, leftImg);return 0;
}void cutTop(Mat& src, Mat& dstImg)//上下切割
{int top, bottom;top = 0;bottom = src.rows;int i;for (i = 0; i < src.rows; i++){int colValue = getRowSum(src, i);//cout <<i<<" th "<< colValue << endl;if (colValue>0){top = i;break;}}for (; i < src.rows; i++){int colValue = getRowSum(src, i);//cout << i << " th " << colValue << endl;if (colValue == 0){bottom = i;break;}}int height = bottom - top;Rect rect(0, top, src.cols, height);dstImg = src(rect).clone();
}
int main()
{Mat src = imread("D:\\s.png", CV_LOAD_IMAGE_GRAYSCALE);threshold(src, src, 100 , 255, CV_THRESH_BINARY_INV);imshow("origin", src);Mat leftImg,rightImg;int res = cutLeft(src, leftImg, rightImg);	int i = 0; while (res == 0){ 		char nameLeft[10];sprintf(nameLeft, "%dLeft", i);char nameRight[10];sprintf(nameRight, "%dRight", i);i++;//stringstream ss;//ss << nameLeft;//imwrite("D:\\" + ss.str() + ".jpg", leftImg);//ss >> nameLeft;Mat srcTmp = rightImg;//getSubtract(leftImg, 10);res = cutLeft(srcTmp, leftImg, rightImg);	}waitKey(0);return 0;
}


最后截取结果如下图

 

 

(截取的很清楚只是拖动的时候留下的划痕)

 

三、制作模板

 

 

模板的制作和步骤二完全一样,首先你要切割的图片的字体样式和大小要和模板的样式和大小一样(比如都是宋体,10号)要不然匹配的结果就不准确,而且把0123456789最好按顺序这样匹配的时候可以知道是匹配到那个数字,比如你切割下的数字和模板匹配的时候,匹配到第三个模板则知道是匹配的数字3(模板从第0个开始)。只需要改主函数

 

 

 

int main()
{Mat src = imread("D:\\s.png", CV_LOAD_IMAGE_GRAYSCALE);threshold(src, src, 100 , 255, CV_THRESH_BINARY_INV);imshow("origin", src);Mat leftImg,rightImg;int res = cutLeft(src, leftImg, rightImg);	int i = 0; while (res == 0){ 		char nameLeft[10];sprintf(nameLeft, "%dLeft", i);char nameRight[10];sprintf(nameRight, "%dRight", i);i++;imshow(nameLeft, leftImg);<strong>stringstream ss;ss << nameLeft;imwrite("D:\\" + ss.str() + ".jpg", leftImg);//保存截取图片做为模板ss >> nameLeft;</strong>Mat srcTmp = rightImg;//getSubtract(leftImg, 10);res = cutLeft(srcTmp, leftImg, rightImg);	}waitKey(0);return 0;
}


四、数字识别

 

 

 

 

 

 

 

把你切割的数字图片大小调整到和模板一样的大小,然后让需要匹配的图和分别和10个模板相减,(让两个图片对应像素点值相减)然后求返回图片的整个图片的像素点值得平方和,和哪个模板匹配时候返回图片的平方和最小则就可以得到结果。只需要改主函数

 

 

void getPXSum(Mat &src, int &a)//获取所有像素点和
{ threshold(src, src, 100, 255, CV_THRESH_BINARY);a = 0;for (int i = 0; i < src.rows;i++){for (int j = 0; j < src.cols; j++){a += src.at <uchar>(i, j);}}
}int  getSubtract(Mat &src, int TemplateNum) //两张图片相减
{Mat img_result;int min = 1000000;int serieNum = 0;for (int i = 0; i < TemplateNum; i++){char name[20];sprintf_s(name, "D:\\%dLeft.jpg", i);Mat Template = imread(name, CV_LOAD_IMAGE_GRAYSCALE);threshold(Template, Template, 100, 255, CV_THRESH_BINARY);threshold(src, src, 100, 255, CV_THRESH_BINARY);resize(src, src, Size(32, 48), 0, 0, CV_INTER_LINEAR);resize(Template, Template, Size(32, 48), 0, 0, CV_INTER_LINEAR);//调整尺寸		//imshow(name, Template);absdiff(Template, src, img_result);//getPXSum(img_result, diff);if (diff < min){min = diff;serieNum = i;}}printf("最小距离是%d ", min);printf("匹配到第%d个模板匹配的数字是%d\n", serieNum,serieNum);return serieNum;
}int main()
{Mat src = imread("D:\\s.png", CV_LOAD_IMAGE_GRAYSCALE);threshold(src, src, 100 , 255, CV_THRESH_BINARY_INV);imshow("origin", src);Mat leftImg,rightImg;int res = cutLeft(src, leftImg, rightImg);	int i = 0; while (res == 0){ 		//	char nameLeft[10];//	sprintf(nameLeft, "%dLeft", i);//	char nameRight[10];//	sprintf(nameRight, "%dRight", i);//	i++;imshow(nameLeft, leftImg);//	stringstream ss;//	ss << nameLeft;//	imwrite("D:\\" + ss.str() + ".jpg", leftImg);//	ss >> nameLeft;Mat srcTmp = rightImg;getSubtract(leftImg, 10);//数字识别res = cutLeft(srcTmp, leftImg, rightImg);	}waitKey(0);return 0;
}

 

 

 

 

 

运行最终结果如下图

 

 

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

http://chatgpt.dhexx.cn/article/jY5VmDUV.shtml

相关文章

FPGA实现mnist手写数字识别(软件部分)

文章目录 FPGA实现mnist手写数字识别① 环境配置② 数据集及代码下载③ 代码操作&#xff08;1&#xff09;训练模型&#xff08;2&#xff09;权重输出&#xff08;3&#xff09;关于灰度转换 FPGA实现mnist手写数字识别 ① 环境配置 使用的环境&#xff1a;tf1.12&#xff…

pyqt5手写板+pytorch卷积神经网络,实现手写数字识别软件

卷积神经网络的结构 #定义网络结构 #不是le-net5的结构 class Net(nn.Module):def __init__(self):super(Net, self).__init__()# Sequential表示在搭建网络模型中要执行的一系列的步骤# Dropout中,p0.5表示50%的神经元不工作# layer3:输出层 一般输出层中不需要加Dropout# Co…

使用Dl4j训练的一个手写数字识别软件

DL4J使用之手写数字识别 最近一直在学习深度学习&#xff0c;由于我是Java程序员出身&#xff0c;就选择了一个面向Java的深度学习库—DL4J。为了更加熟练的掌握这个库的使用&#xff0c;我使用该库&#xff0c;以MNIST(http://yann.lecun.com/exdb/mnist/)手写数字数据集作为…

识别数字的软件有哪些?这几款识别数字工具安利给你

嘿&#xff0c;朋友们&#xff0c;你们有没有遇到过需要处理大量数字的情况&#xff0c;要是一个一个手动输入感觉十分麻烦&#xff0c;还会耗费大量时间和精力&#xff1f;别着急&#xff0c;现在数字识别的软件已经非常发达了&#xff0c;只需要一款好用的数字识别软件&#…

这款数字识别软件你知道吗

识别数字技术是指通过计算机自动识别数字的能力&#xff0c;通常采用数字图像处理和模式识别等技术进行实现。你别看这个技术好像很高大上&#xff0c;实际上现在已经有很多软件可以做到识别数字了&#xff0c;你知道识别数字的软件有哪些吗&#xff1f;今天我就为大家科普这项…

基于TensorFlow深度学习框架,运用python搭建LeNet-5卷积神经网络模型和mnist手写数字识别数据集,设计一个手写数字识别软件。

本软件是基于TensorFlow深度学习框架&#xff0c;运用LeNet-5卷积神经网络模型和mnist手写数字识别数据集所设计的手写数字识别软件。 具体实现如下&#xff1a; 1.读入数据&#xff1a;运用TensorFlow深度学习框架&#xff0c;下载并读入mnist手写数字识别数据集。 2.构建模型…

OCR手写数字识别什么软件好用?介绍一种

OCR是指用电子设备检查文本上的资料&#xff0c;然后对图像文件进行分析处理&#xff0c;从而获取文字及版面信息的过程。那OCR手写数字识别有好用的软件吗&#xff1f;当我们需要整理大量手写资料需要整理时&#xff0c;下面这两款软件就派上用场了。 软件一、我们可以使用识别…

识别数字的软件有哪些?自动识别数字的方法并不难

每个月月初时&#xff0c;作为销售助理的同事经常要整理一大堆数据&#xff0c;密密麻麻的数字看得他头晕眼花&#xff0c;特别是有些图片里的数字&#xff0c;一不小心就容易出错&#xff0c;酿成严重的数据错误。像平时我也会处理到一些数据图片&#xff0c;为了准确及时的整…

Unity 渲染YUV数据 ---- 以Unity渲染Android Camera数据为例子

1 背景 一般Unity都是RGB直接渲染的&#xff0c;但是总有特殊情况下&#xff0c;需要渲染YUV数据。比如&#xff0c;Unity读取Android的Camera YUV数据&#xff0c;并渲染。本文就基于这种情况&#xff0c;来展开讨论。 Unity读取Android的byte数组&#xff0c;本身就耗时&am…

图形学之Unity渲染管线流程分析

文章来源&#xff1a; 学习通http://www.bdgxy.com/ 普学网http://www.boxinghulanban.cn/ 智学网http://www.jaxp.net/ 表格制作excel教程http://www.tpyjn.cn/ 学习通http://www.tsgmyy.cn/ 下图是《Unity Shader 入门精要》一书中的渲染流程图&#xff1b; ApplicationS…

Unity渲染(二):Shader着色器基础入门之渲染Image图片

Unity渲染(二):图片渲染 通过这里&#xff0c;你会学习到怎么将一张图片渲染到UI的Image组件或者SpriteRenderer上&#xff0c;以及透明物体的渲染。 上一章:Unity渲染(一):着色器基础入门之纯色Shader 开发环境&#xff1a;Unity5.0或者更高 透明与不透明的最终效果 概述 1…

unity 渲染性能分析工具

目标 既然要优化&#xff0c;肯定要有个目标&#xff1a; pc上一般要求&#xff1a;一秒渲染60帧 移动端&#xff1a;一秒渲染30帧 这应该是最低的要求&#xff0c;如果游戏运行时&#xff0c;游戏帧率有变化&#xff0c;人眼能够明显的感觉到帧率下降。 优化的首要规则是找到…

unity 渲染环境设置

环境光分为两种&#xff0c;一种是环境光漫反射SH&#xff08;球谐光照&#xff09;&#xff0c;另一种是环境光的镜面反射IBL&#xff08;基于图像的渲染&#xff09;。 光照的配置位置可以在 窗口 -> 渲染 -> 光照 打开。 环境照明对应的就是环境漫反射&#xff0c;环…

【流程向】模型复原与Unity渲染

项目简述 简单记录下学校里的一个项目&#xff0c;涉及到对/何家村遗宝/的模型复原&#xff0c;记录一下模型制作的全流程&#xff0c;同时涉及到Unity中一些优化画面的技术点。项目中渲染效果优先&#xff0c;没有怎么考虑性能。 流程&#xff1a;Blender高低模与展UV ->…

Unity中的物体渲染顺序

big seven 文章目录 前言 一、摄像机渲染 二、划分渲染队列 三、不透明物体的渲染 四、透明物体的渲染 五、UGUI元素的渲染 总结 前言 Unity中物体的渲染顺序 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、摄像机渲染 Unity中的渲染顺序首先是…

Unity渲染流程概述

本篇的任务是回答&#xff1a;在Untiy的渲染流程中CPU和GPU分别做了什么。 渲染到设备屏幕显示的每一帧的画面&#xff0c;都经历几个阶段的加工过程&#xff1a; 应用程序阶段&#xff08;CPU&#xff09;&#xff1a;识别出潜在可视的网格实例&#xff0c;并把他们及其材质…

Unity_渲染_灯光_前向渲染

前向渲染路径 前向渲染的作用和意义场景内有多个灯光,如何渲染每个灯光对物体的影响 前向渲染的作用和意义 前向渲染的作用:处理多光源的渲染,多光源渲染在unity 有2中渲染方式 前向渲染和延时渲染 .延时渲染主要用于主机,PC平台,不在本次讨论范围.主要来研究前向渲染前向渲染…

【Unity渲染】前向渲染和延迟渲染的区别及切换

前向渲染和延迟渲染通道的区别&#xff0c;主要在对于光源的处理上。 Unity默认是前向渲染通道&#xff0c;如果光源特别多&#xff0c;可以使用延迟渲染。 前向渲染 使用前向渲染路径时&#xff0c;被照亮的对象将在单独的通道中进行渲染。根据场景中的光源数量以及它们是否…

从FrameDebugger看Unity渲染

从FrameDebugger看Unity渲染(一) Unity如何渲染一个3D2D的游戏画面&#xff0c;今天通过FrameDebugger来看下Unity内置渲染管线的渲染策略, 后续再出一些URP渲染管线相关的文章。 对啦&#xff01;这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白&#xff0c…

UnityShader入门精要——Unity中的渲染优化技术(二)

减少DrawCall数目 最常见的优化技术——批处理。实现原理为减少渲染每一帧所需的drawcall数目。使用同一个材质的物体可以一起处理。 优点缺点动态批处理切处理都是Unity 自动完成的&#xff0c;不需要我们自己做任何操作&#xff0c;而且物体是可以移动的限制很多&#xff0c…