opencv +数字识别

您所在的位置:网站首页 麒麟鼠标键盘同步器-v623破解版 opencv +数字识别

opencv +数字识别

2024-07-13 00:56:39| 来源: 网络整理| 查看: 265

现在很多场景需要使用的数字识别,比如银行卡识别,以及车牌识别等,在AI领域有很多图像识别算法,大多是居于opencv 或者谷歌开源的tesseract 识别.

由于公司业务需要,需要开发一个客户端程序,同时需要在xp这种老古董的机子上运行,故研究了如下几个数字识别方案:

ocr 识别的不同选择方案 tesseract 放弃:谷歌的开源tesseract ocr识别目前最新版本不支持xp系统 云端ocr 识别接口(不适用) 费用比较贵: 场景不同,我们的需求是可能毫秒级别就需要调用一次ocr 识别 opencv 概念:OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

以上几种ocr 识别比较,最后选择了opencv 的方式进行ocr 数字识别,下面讲解通过ocr识别的基本流程和算法.

opencv 数字识别流程及算法解析

要通过opencv 进行数字识别离不开训练库的支持,需要对目标图片进行大量的训练,才能做到精准的识别出目标数字;下面我会分别讲解图片训练的过程及识别的过程.

opencv 识别算法原理 比如下面一张图片,需要从中识别出正确的数字,需要对图片进行灰度、二值化、腐蚀、膨胀、寻找数字轮廓、切割等一系列操作.

原图

image

灰度化图

image

二值化图

image

寻找轮廓

image

识别后的结果图

image

以上就是简单的图片进行灰度化、二值化、寻找数字轮廓得到的识别结果(这是基于我之前训练过的数字模型下得到的识别结果) 有些图片比较赋值,比如存在背景斜杠等的图片则需要一定的腐蚀或者膨胀等处理,才能寻找到正确的数字轮廓.

上面的说到我这里使用的是opencv 图像处理库进行的ocr 识别,那我这里简单介绍下C# 怎么使用opencv 图像处理看;

为了在xp上能够运行 我这里通过nuget 包引用了 OpenCvSharp-AnyCPU 第三方库,它使用的是opencv 2410 版本,你们如果不考虑xp系统的情况下开源使用最新的版本,最新版本支持了更多的识别算法.

右击你的个人项目,选择“管理Nuget程序包”。在包管理器页面中,点击“浏览”选项,然后在搜索框中键入“OpenCvSharp-AnyCPU”。选择最顶端的正确项目,并在右侧详情页中点击“安装”,等待安装完成即可。

以上的核心代码如下:

private void runSimpleOCR(string pathName) { //构造opcvOcr 库,这里的是我单独对opencv 库进行的一次封装,加载训练库模板 var opencvOcr = new OpencvOcr($"{path}Template\\Traindata.xml", opencvOcrConfig: new OCR.Model.OpencvOcrConfig() { ErodeLevel = 2.5, ThresholdType = OpenCvSharp.ThresholdType.Binary, ZoomLevel = 2, }); var img = new Bitmap(this.txbFilaName.Text); var mat = img.ToMat(); //核心识别方法 var str = opencvOcr.GetText(mat, isDebug: true); this.labContent.Content = str; }

opencvOcr 的核心代码如下

#region Constructor const double Thresh = 80; const double ThresholdMaxVal = 255; const int _minHeight = 35; bool _isDebug = false; CvKNearest _cvKNearest = null; OpencvOcrConfig _config = new OpencvOcrConfig() { ZoomLevel = 2, ErodeLevel = 3 }; #endregion /// /// 构造函数 /// /// 训练库完整路径 /// OCR相关配置信息 public OpencvOcr(string path, OpencvOcrConfig opencvOcrConfig = null) { if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path is not null"); if (opencvOcrConfig != null) _config = opencvOcrConfig; this.LoadKnearest(path); } /// /// 加载Knn 训练库模型 /// /// /// private CvKNearest LoadKnearest(string dataPathFile) { if (_cvKNearest == null) { using (var fs = new FileStorage(dataPathFile, FileStorageMode.Read)) { var samples = fs["samples"].ReadMat(); var responses = fs["responses"].ReadMat(); this._cvKNearest = new CvKNearest(); this._cvKNearest.Train(samples, responses); } } return _cvKNearest; } /// /// OCR 识别,仅仅只能识别单行数字 /// /// 训练库 /// 要识别的图片路径 public override string GetText(Mat src, bool isDebug = false) { this._isDebug = isDebug; #region 图片处理 var respMat = MatProcessing(src, isDebug); if (respMat == null) return ""; #endregion #region 查找轮廓 var sortRect = FindContours(respMat.FindContoursMat); #endregion return GetText(sortRect, respMat.ResourcMat, respMat.RoiResultMat); } /// /// 查找轮廓 /// /// /// private List FindContours(Mat src) { try { #region 查找轮廓 Point[][] contours; HierarchyIndex[] hierarchyIndexes; Cv2.FindContours( src, out contours, out hierarchyIndexes, mode: OpenCvSharp.ContourRetrieval.External, method: OpenCvSharp.ContourChain.ApproxSimple); if (contours.Length == 0) throw new NotSupportedException("Couldn't find any object in the image."); #endregion #region 单行排序(目前仅仅支持单行文字,多行文字顺序可能不对,按照x坐标进行排序) var sortRect = GetSortRect(contours, hierarchyIndexes); sortRect = sortRect.OrderBy(item => item.X).ToList(); #endregion return sortRect; } catch { } return null; } /// /// 获得切割后的数量列表 /// /// /// /// private List GetSortRect(Point[][] contours, HierarchyIndex[] hierarchyIndex) { var sortRect = new List(); var _contourIndex = 0; while ((_contourIndex >= 0)) { var contour = contours[_contourIndex]; var boundingRect = Cv2.BoundingRect(contour); //Find bounding rect for each contour sortRect.Add(boundingRect); _contourIndex = hierarchyIndex[_contourIndex].Next; } return sortRect; } /// /// 是否放大 /// /// /// private bool IsZoom(Mat src) { if (src.Height (EnumMatAlgorithmType)Convert.ToInt32(item)) .ToList(); if (!IsZoom(src)) result.Remove(EnumMatAlgorithmType.Zoom); return result; } } catch { } #endregion #region 默认算法 if (IsZoom(src)) { result.Add(EnumMatAlgorithmType.Zoom); } if (this._config.ThresholdType == ThresholdType.Binary) { //result.Add(EnumMatAlgorithmType.Blur); result.Add(EnumMatAlgorithmType.Gray); result.Add(EnumMatAlgorithmType.Thresh); if (this._config.DilateLevel > 0) result.Add(EnumMatAlgorithmType.Dilate); result.Add(EnumMatAlgorithmType.Erode); return result; } //result.Add(EnumMatAlgorithmType.Blur); result.Add(EnumMatAlgorithmType.Gray); result.Add(EnumMatAlgorithmType.Thresh); if (this._config.DilateLevel > 0) result.Add(EnumMatAlgorithmType.Dilate); result.Add(EnumMatAlgorithmType.Erode); return result; #endregion } /// /// 对查找的轮廓数据进行训练模型匹配,这里使用的是KNN 匹配算法 /// private string GetText(List sortRect, Mat source, Mat roiSource) { var response = ""; try { if ((sortRect?.Count ?? 0) { try { #region 绘制矩形 if (this._isDebug) { Cv2.Rectangle(source, new Point(boundingRect.X, boundingRect.Y), new Point(boundingRect.X + boundingRect.Width, boundingRect.Y + boundingRect.Height), new Scalar(0, 0, 255), 1); Cv2.Rectangle(roiSource, new Point(boundingRect.X, boundingRect.Y), new Point(boundingRect.X + boundingRect.Width, boundingRect.Y + boundingRect.Height), new Scalar(0, 0, 255), 1); } #endregion #region 单个ROI var roi = roiSource.GetROI(boundingRect); //Crop the image roi = roi.Compress(); var result = roi.ConvertFloat(); #endregion #region KNN 匹配 var results = new Mat(); var neighborResponses = new Mat(); var dists = new Mat(); var detectedClass = (int)this._cvKNearest.FindNearest(result, 1, results, neighborResponses, dists); var resultText = detectedClass.ToString(CultureInfo.InvariantCulture); #endregion #region 匹配 var isDraw = false; if (detectedClass >= 0) { response += detectedClass.ToString(); isDraw = true; } if (detectedClass == -1 && !response.Contains(".")) { response += "."; resultText = "."; isDraw = true; } #endregion #region 绘制及输出切割信息库 try { //if (this._isDebug) //{ Write(contourIndex, detectedClass, roi); //} } catch { } if (this._isDebug && isDraw) { Cv2.PutText(dst, resultText, new Point(boundingRect.X, boundingRect.Y + boundingRect.Height), 0, 1, new Scalar(0, 255, 0), 2); } #endregion result?.Dispose(); results?.Dispose(); neighborResponses?.Dispose(); dists?.Dispose(); contourIndex++; } catch (Exception ex) { TextHelper.Error("GetText ex", ex); } }); #region 调试模式显示过程 source.IsDebugShow("Segmented Source", this._isDebug); dst.IsDebugShow("Detected", this._isDebug); dst.IsDebugWaitKey(this._isDebug); dst.IsDebugImWrite("dest.jpg", this._isDebug); #endregion } } catch { throw; } finally { source?.Dispose(); roiSource?.Dispose(); } return response; } /// /// 图片处理算法 /// /// /// /// public ImageProcessModel MatProcessing(Mat src, bool isDebug = false) { src.IsDebugShow("原图", isDebug); var list = GetAlgoritmList(src); var resultMat = new Mat(); src.CopyTo(resultMat); var isZoom = IsZoom(src); list?.ForEach(item => { switch (item) { case EnumMatAlgorithmType.Dilate: resultMat = resultMat.ToDilate(Convert.ToInt32(this._config.DilateLevel)); resultMat.IsDebugShow(EnumMatAlgorithmType.Dilate.GetDescription(), isDebug); break; case EnumMatAlgorithmType.Erode: var eroderLevel = isZoom ? this._config.ErodeLevel * this._config.ZoomLevel : this._config.ErodeLevel; resultMat = resultMat.ToErode(eroderLevel); resultMat.IsDebugShow(EnumMatAlgorithmType.Erode.GetDescription(), isDebug); break; case EnumMatAlgorithmType.Gray: resultMat = resultMat.ToGrey(); resultMat.IsDebugShow(EnumMatAlgorithmType.Gray.GetDescription(), isDebug); break; case EnumMatAlgorithmType.Thresh: var thresholdValue = this._config.ThresholdValue x.ImageGroupId).ToArray(); var responses = new Mat(labels.Length, 1, MatType.CV_32SC1, labels); var tmp = responses.Reshape(1, 1); //make continuous var responseFloat = new Mat(); tmp.ConvertTo(responseFloat, MatType.CV_32FC1); // Convert to float return responses; }

到这里ocr 训练模型以及建立好了,会在目录中生成一个Traindata.xml 的训练模型库,我们来打开这个训练模型库文件探索它的神秘的容颜. image image

到这里opencv + 数字识别分享已经完成,它的神秘面纱也就到此结束了



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭