一块车牌、一张字符型验证码图片,我们人类看一眼,脑海中就已经有了答案,整个过程主要包括眼睛和大脑的协作:眼睛采集字符关键信息,通过大脑学习沉淀的知识进行比对,从而得出答案。那么对于机器识别,它是如何做的呢?本文将为大家提供一种类似于卷积神经网络算法的识别方案。

在文章开始前,先为大家简单介绍下数字图像处理的一些基础概念及数据结构。

一幅图像可以定义为一个二维数组f(x,y),这里x,y是空间坐标,而在任何一对空间坐标(x,y)上的幅值f称为该点图像的强度或灰度。当x,y和幅值f为有限的、离散的数值时,称该图像为数字图像。将图片二值化后其二维矩阵如下:(相信大家已经看出其中的内容了吧)

对于字符型图片,机器识别的完整流程跟人类读取信息基本一致,主要包括:

眼睛采集关键信息:图片预处理、字符切割,得到特征值;

大脑学习沉淀知识:数据模型训练,形成特征库;

大脑根据已学知识匹配得出结论:将待识别字符的特征值与特征库中的字符特征码进行类似卷积操作的计算,得出结果。

图片预处理

为了减少后面卷积比对的复杂度,同时增加识别率,很有必要对图片进行预处理,使其对机器识别更友好。预处理的主要包括:对图像进行灰度化、二值化、抑噪(滤波)等技术。

原始验证码图片:

图像灰度化

RGB系统中一个颜色值由3个分量组成,这样的图像称为彩色图像,RGB系统称为颜色空间模型。常见的颜色空间模型还有HSI、CMYK等。如果一幅图像的颜色空间是一维的(一个颜色值只有一个颜色分量),则这幅图像就是一副灰度图。在位图图像中,一般以R=G=B来显示灰度图像。常用的灰度化方法有以下三种:

(1.1)

(1.2)

(1.3)

其中,公式(1.1)的方法来源于I色彩空间中I分量的计算公式,公式(1.2)来源于NTSC色彩空间中Y分量的计算公式。公式(1.3)是基于采用保留最小亮度(黑色)的方法。本文主要以公式1.2算法为例,其核心实现如下:

public static Integer[][] getGrayMatrix (BufferedImage bi){Integer width = bi.getWidth();Integer height =bi.getHeight();Integer[][] matrix = new Integer[width][height];for(int i = 0;i < width;i ++){for(int j = 0;j < height;j ++){Color color = new Color(bi.getRGB(i,j));int red = color.getRed();int green = color.getGreen();int blue = color.getBlue();matrix[i][j] = (int)(0.3*red+0.6*green+0.1*blue);}}return matrix;
}
二值化

将灰度图按照设定阈值转化为二值图,二值图像中的数据全部是0或1。

public static Integer[][] binariazation(Integer[][] matrix) {Integer width = matrix.length;Integer height = matrix[0].length;for(int i=0;i<width;i++){for(int j = 0;j < height; j ++){if(matrix[i][j] < threshold){matrix[i][j] = 1;}else{matrix[i][j] = 0;}}}return  matrix;
}

经过灰度及二值化处理后的图片:

其二维矩阵样例,大家已经在文章开篇见识过了。

抑噪

在转化为二值图片后,就需要清除噪点。本文选择的素材比较简单,大部分噪点也是最简单的那种 孤立点,所以可以通过检测这些孤立点就能移除大量的噪点。

关于如何去除更复杂的噪点甚至干扰线和色块,有比较成熟的算法: 洪水填充法 Flood Fill ,后面有兴趣的时间可以继续研究一下。

本文主要采用九宫格降噪来解决掉这个问题:

  • 对某个 黑点 周边的九宫格里面的黑色点计数

  • 如果黑色点少于2个则证明此点为孤立点,然后得到所有的孤立点

  • 对所有孤立点一次批量移除。

九宫格降噪示意图:

核心代码实现:

// 定义九宫格
public static final Integer[][] BOX_9 = new Integer[3][3];
static {BOX_9[0] = new Integer[]{0, 0, 0};BOX_9[1] = new Integer[]{0, 1, 0};BOX_9[2] = new Integer[]{0, 0, 0};
}
/**
* 九宫格孤点降噪算法
* @param source
* @param nineBox
*/
public static void reducePiont(Integer[][] source, Integer[][] nineBox) {//去掉边缘燥点for (int i = 0; i < source.length; i++) {for (int j = 0; j < source[i].length; j++) {if (i == 0 || i == source.length - 1) {source[i][j] = 0;} else {if (j == 0 || j == source[0].length - 1) {source[i][j] = 0;}}}}int _sx = source[0].length;//列int _sy = source.length;//行int _tx = nineBox[0].length;int _ty = nineBox.length;int _deltax = _sx - _tx;//横轴卷积核平移次数int _deltay = _sy - _ty;//纵轴卷积核平移次数for (int dy = 0; dy <= _deltay; dy++) {for (int dx = 0; dx <= _deltax; dx++) {// 根据目标对待分析图片进行卷积求和int cn = 0; // 卷积for (int ty = 0; ty < _ty; ty++) {for (int tx = 0; tx < _tx; tx++) {int muti = nineBox[ty][tx] | source[ty + dy][tx + dx];cn += muti;}}if (cn == 1) {source[dy + 1][dx + 1] = 0;}}}
}

字符切割

如果采用统计特征匹配以及神经网络法识别,必须要先分割出单个的字符。简单的分割方法包括等距分割、投影法分割、交叉点分割、求连通区等。其中,粘连字符的分割是一个难点,复杂的粘连情况下分割比较困难,是一个硬人工智能问题。本文主要介绍投影法分割。

投影法

投影法的原理其实很简单,利用二值化图片的像素的分布直方图进行分析,从而找出相邻字符的分界点进行分割。(本文以左右布局的图片为例,就适合用垂直投影的方法,反之若是上下型,则做水平投影即可。)

上图其实已经看的很明白,投影所反应的就是在垂直方向上数字区域像素个数,而字与字之间的间隔(上图白色空隙)黑色像素点数为零,以此为依据分割。实现过程如下:

/**
* 投影
*
* @param source 二维矩阵
* @return
*/
public static Integer[] shadow(Integer[][] source) {Integer[] shadowResult = new Integer[source[0].length];for (int i = 0; i < source[0].length; i++) {int xn = 0;for (int k = 0; k < source.length; k++) {xn += source[k][i];}shadowResult[i] = xn;}return shadowResult;
}
/**
* 根据X投影坐标计算出字符分割边界
*
* @param source 投影后的权值矩阵
*/
public static List<Point> segmentX(Integer[] source) {List<Point> points_x = new ArrayList<Point>();for (int i = 0; i < source.length; i++) {if (source[i] > 0) {if (i == source.length - 1) {points_x.add(new Point(i, i));} else {for (int j = i + 1; j < source.length; j++) {if (source[j] == 0 || j == source.length - 1) {points_x.add(new Point(i, j - 1));i = j;break;}}}}}return points_x;
}

切割后的单个字符与二维矩阵:

大家可以看到在原始图片数字9后,还有两段干扰线,按投影法切割也会切成图片,在使用时候,只需设定单个字符像素点的最小阈值,小于阈值的舍弃即可。

模型训练

通过前面几步,已经完成了对单个图片的处理和分割,得到了每个字符的特征码——01二维矩阵,在展开卷积识别之前,机器是不具备任何字符观念的。所以需要预先建立特征库、为每个字符生成特征码,并人为对特征码进行打标,“告诉”机器什么样的图片内容是 A、什么样的图片内容是B等。

整个训练过程如下:

  1. 准备大量的图片素材,完成预处理并切割得到原子级(单个字符的01矩阵)的图片素材

  2. 对每个原子级素材图片进行人为分类打标

    0~9数字特征库分类示意图:

  3. 将图片旋转一定角度并分类(若目标图片中,字符有倾斜或旋转等情况需要)

    单个字符特征码示意图:

    4.将旋转后的单个字符素材转换为二维矩阵,便于后续卷积比对。

“卷积”识别

字符识别就是把处理后的图片还原回字符文本的过程。本文主要采用类似卷积神经网络的卷积操作,对分割后的单个字符进行识别。

将图片预处理并分割后,已经得到了待识别字符的特征码(01二维矩阵),同时经过模型训练,也已经得到每个字符的特征库(多组01二维矩阵),使用相似性度量将待识别字符和特征库的每组特征码进行“卷积操作”,将该字符识别为与其特征码相似性最高的字符。

卷积比对过程如下图所示:

本文所采用的类似卷积操作核心代码实现如下:

/**
* 二维矩阵卷积运算
* 考虑了位置因素,相当于卷积神经网络的一层卷积操作
*
* @param source 待卷积矩阵
* @param kernel 卷积核
* @return 待卷积矩阵与卷积核的重合度(简单粗暴的计算点相同的数量)
*/
public static Integer computeCN(Integer[][] source, Integer[][] kernel) {Integer num_kernel = MatrixUtil.pv(kernel);int _sx = source[0].length;//列int _sy = source.length;//行int _tx = kernel[0].length;int _ty = kernel.length;int _deltax = _sx - _tx;//横向移动次数int _deltay = _sy - _ty;//纵向移动次数Integer ref = 0;// 最大相似区域// 计算最大相似区域for (int dy = 0; dy <= _deltay; dy++) {for (int dx = 0; dx <= _deltax; dx++) {// 根据目标对待分析图片进行卷积求和int cn = 0; // 卷积for (int ty = 0; ty < _ty; ty++) {for (int tx = 0; tx < _tx; tx++) {int muti = kernel[ty][tx] & source[ty + dy][tx + dx];cn += muti;}}ref = Math.max(ref, cn);if (ref.doubleValue() / num_kernel.doubleValue() > 0.9) {return ref;}}}return ref;
}

通过“卷积操作”后,匹配到相似度较高的字符:0、2、6、9,拼接在一起即得到最终字符内容。


本文为大家介绍了一种字符型图片内容识别技术,同时业界也有很多成熟的ocr识别框架,如谷歌的tesseract等,不过作为技术,我们应当知其然知其所以然。在选择技术方案时,不管是自研、还是成熟的框架,最适合业务场景的才是最好的,比如我们的图片识别场景,采用自研算法,针对特定字符进行优化、模型训练后,单次识别可以做到100ms左右,远高于相同条件下tesseract平均1s左右的耗时,对用户端更加友好。

最后,技术是中立的、本文旨在为大家提供一些图文识别的思路,对于掌握OCR技术的人不要做违法的事。

ps:文中所提到的卷积神经网络识别,仅用到其卷积层的比对思想,实际整个神经网络是非常复杂的,感兴趣的同学可查找资料深入研究。

推荐阅读

阿里立秋:淘宝如何做智能化UI测试?

2021-08-03

李伟山:金融撮合架构

2021-05-31

Francisco: 构建前瞻性应用架构的优秀实践

2021-03-31

滕云:DDD实现之路

2021-03-25

DDD专家张逸:复杂与架构演进的关系

2021-03-29

领域驱动设计(DDD):领域和子域

2021-03-18

八戒技术:徒手撸一套简易字符识别方案相关推荐

  1. 拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

    1.引言 老读者应该还记得我在去年国庆节前分享过一篇<技术干货:从零开始,教你设计一个百万级的消息推送系统>,虽然我在文中有贴一些伪代码,依然有些朋友希望能直接分享一些可以运行的源码.好吧 ...

  2. 八戒科技服务技术负责人鸿鹄真人:做好技术负责人的4个关键特质

    作者简介 猪八戒网后端技术委员成员&八戒科技服务技术负责人,中国商业联合会互联网协会智库顾问.国家软考高级系统架构师.国家软考高级系统分析师.TOGAF企业架构认证.国家软考系统集成项目经理. ...

  3. 徒手撸框架--实现 RPC 远程调用

    微服务,已经是每个互联网开发者必须掌握的一项技术.而 RPC 框架,是构成微服务最重要的组成部分之一.趁最近有时间.又看了看 dubbo 的源码.dubbo 为了做到灵活和解耦,使用了大量的设计模式和 ...

  4. spring boot 自动跳转登录页面_徒手撸一个扫码登录示例工程

    徒手撸一个扫码登录示例工程 不知道是不是微信的原因,现在出现扫码登录的场景越来越多了,作为一个有追求.有理想新四好码农,当然得紧跟时代的潮流,得徒手撸一个以儆效尤 本篇示例工程,主要用到以下技术栈 q ...

  5. 八戒帮扶V5v1.39 VUE任务系统微信公众平台任务系统完美运营

    版本说明:       八戒V5任务系统,微信公众平台任务系统,演示地址:https://www.pgyer.com/QPCf      这套程序的好处不用多说了,UE开发,懂的都懂,持久更新!!! ...

  6. 【独立版】帮扶极速版任务系统V3.1.3,八戒帮扶V5独立版

    应用介绍 帮扶极速版任务系统是八戒帮扶V5独立版,是一款拓客营销赚钱神器,打造私域流量池,是一套真正的微信赚钱神器系统. 帮扶极速版任务系统裂变粉丝原理: 1.全面解决兼容多平台,跨平台的任务体系 全 ...

  7. 八戒帮扶v5-1.3.8悬赏平台程序源码下载,打造私域流量池

    需要准备:服务器https://www.jyyidc.com/server/buy.html.linux宝塔面板https://www.jyyidc.com/linux/.程序源码https://do ...

  8. 重庆北大青鸟解放碑校区J12班 皮皮虾队【八戒租车平台】

    项目组名:皮皮虾队 项目名称:八戒租车平台 组内成员:重庆北大青鸟解放碑校区J12班王*.雷*.李骏.陈宏.管*明 (后台首页) (前端登陆页面) (前端首页) (前端租车指南) (后台公司运营界面) ...

  9. 搜索引擎大调整:百度出“惊雷算法”后360搜索又将上线“八戒算法”

    可能大家都也听说了百度在11月20日发出的算法预告"惊雷算法",而就在昨天,11月29日,360搜索站长平台发布"八戒算法"将在12月初上线,旨在打击低质量站群 ...

最新文章

  1. 普通域账号客户端计算无关机选项
  2. 在 Google Go Team 工作是一种怎样的体验?
  3. python迭代是什么意思_python中什么是迭代?
  4. HDU2136 Largest prime factor
  5. Debit and Credit Memo
  6. IT职场人生系列之四:怎样写简历
  7. 为什么要用SpringCloud alibaba作为微服务开发框架?
  8. 简单的java游戏编程代码_java游戏编程(1)线程
  9. mac下用ImageOptim压缩png图片
  10. 解决大部分win10软件字体模糊的问题
  11. How to create swiping gesture list items for Windows Phone 7
  12. 降维分析:人类发展指数法(IFI法)
  13. 小白也能懂的 Python 入门指南(1)——Python 的前世今生
  14. kubernetes之容器生命周期管理
  15. 19年深圳杯D题之爬取电视收视率排行榜
  16. 使用阿里云服务器三分钟搭建网站
  17. kali虚拟机连接网络设置/解决ping网站时域名解析错误/解决子网ip和子网掩码不一致
  18. 通往奥格瑞玛的道路(二分+迪杰斯特拉堆优化)
  19. 这些00后的“火星文”你都认识吗?证明自己是小鲜肉的时刻终于到了
  20. mysql根据出生日期,查询年月日,并且拼接

热门文章

  1. 3、mysql索引优化一:Explain关键字分析
  2. netty中实现双向认证的SSL连接
  3. java调用ecdh_java – BouncyCastle ECDH密钥协议失败
  4. [Verilog学习笔记] always@(*)语句是什么意思
  5. c语言黑洞数程序三位,C语言5位黑洞数
  6. 三年级信息技术用计算机打字教案,三年级上信息技术英文打字教案.pdf
  7. centos7安装tomcat步骤
  8. 2012年03月21日
  9. 武汉大学考研计算机录取名单,武汉大学考研拟录取名单2021公布在哪里?什么时候公布?...
  10. 华为HCIA鲲鹏云学习Linux指令|CSDN创作打卡