• 拍照怎么搜题?(下)


    /*

     *上一篇,我们讲到了怎样对图像进行处理

     *接下来。我们聊聊怎样对图像进行识别

     *没看过上一篇的同学。请微信关注:simplemain


     */


    ====图像的识别 ====

     

    我们已经拿到一个个的字符的图案了,如今要做的。就是怎样把这些图案转化成计算机可认知的二进制编码。由于这次仅仅涉及到英文和标点,所以实际要做的。就是将图案转化为asc码。

     

    识别的方法有许多。接下来我给大家介绍一下我用的几种方法。为了使得识别率提升。一般还会有其它更好或者更有效的方法,假设这里没讲述到。请大家谅解~

     

    对于每个待识别的字符图案。都有他自己的特征(比方:i长的非常瘦,O长的非常圆,T横竖都有等等),识别的时候,就能够借助他们的特征,从而抽丝剥茧的把他们认出来。

     

    问:那详细怎么做呢?

    答:我们将多种字体的全部英文和标点生成标准图案,再将待识别的图案和他们进行比对,看这些待匹配的图案和哪个标准图案最像,那就能找出最有可能的asc码。

     

    那就開始吧!

     

    步骤一:生成模板图案

    我们用多种常见字体,将全部英文和标点生成标准图案。这里简称模板图案。

    为什么要多种字体呢?由于对于同一个字符,在不同字体下,可能长的全然不一样,比方相同是gal,不同字体效果例如以下:


    拿到这些标准模板图案以后。我们就有了例如以下图的这些位图:


    可是有了这些位图还不够,我们还要做一些其它工作,来保证后面的匹配工作能正常进行。接下来我们就看看还要做什么工作。

     

    步骤二:归一化 +记录meta信息

    我们将模板图案先去掉上下左右空白的背景,让前景图案顶格。

    接着再统一宽高,将图案压缩或拉伸为p*q大小的图案(比方都压缩或者拉伸到50像素*50像素)。这样我们才干非常好比对。

    说白了,就是大家都用统一的标准,否则你穿XL号的衣服。我穿S号的。我们的衣服就根本没有可比性。

     

    好了,有了统一的比对标准,是不是一切就都好了呢?

     

    大家一看这样的问题,基本就能够条件反射的判定:回答是否定的(就跟读书那会儿做推断题一样^_^)。那问题出在哪儿呢?

     

    有些图案做了归一化以后。就失真了。比方逗号[,]和引號[’],去掉周围的白边。最后就都长成例如以下图像了:


    另一些字符就会长的非常像了,比方大写的Z和小写的z。归一化以后,就变成例如以下这样了,人看都恼火。让计算机怎么来推断,对吧。



    所以,除了归一化,我们还要记录图案本身的信息,比方原始的长宽,原始的位图等等,这些信息在匹配的时候,能够提供额外的信息,来帮助算法推断有效性。

     

    好了。做完上面两步。我们就得到了标准图案的归一化位图和meta信息。同一时候,我们对上一篇文章中做完垂直分割的待匹配图案也做归一化和meta信息记录的工作。有了这两样东西。我们就能够开展以下的匹配工作了。

     

    步骤三:模板图案和待匹配图案的匹配

    接下来,就用我们的匹配算法,对待匹配的图案和标准图案进行匹配了。

    图像的识别算法有非常多非常多,依据不同的应用场景,会有非常多不同的选择,包含直接匹配的。也有通过数据挖掘来识别。每一种方法没有绝对的好坏,仅仅有看是否更适合。

     

    我以前看过一篇文章,是讲验证码识别的。验证码为了防止机器识别,会对字符进行旋转、扭曲、干扰等处理。为了识别这些变态的字符,那篇文章列举了多达10几种的识别算法。当时看得我不断的惊叹:我擦……。假设以后有时间,我尝试看看能不能把那篇文章找出来分享给大家。

     

    我们这里由于仅仅涉及到英文和标点,所以用了下面几种方法:

    1、字符像素匹配

    2、投影区块匹配

    3、九宫格匹配

    4、重心匹配

    5、宽高比匹配

     

    每个匹配算法都有自身的优缺点(稍后会讲到),因此他们都能得出一个谁跟谁最像。待匹配图案是谁的可能性最大的推断。

    尽管这个推断绝大多数情况下是对的,可是也有bad case的情况。

    所以,我们要综合来看全部的推断,将每个算法的匹配值进行加权求和。得出最后的一个相似度的值。这个相似度有可能就是终于的一个结果。只是这个结果可能也是有错误的(bad case),所以假设继续往后做的时候,我们要不断去给我们的评价推断系统以反馈。丰富我们识别的样本。同一时候对识别算法和加权參数进行修正(这个会比較花时间,我这次就没做了^_^

     

    通过上面的算法,我们就将待匹配的图案和每个标准图案进行算法比对的相似度值求出来。做个排序。取相似度最大的那个,基本就得到我们终于想要的那个。

     

    后来出于好奇。我专门问了作业帮的朋友,想看看他们怎么做的。

    大体方法类似。同一时候他们还用了其它的一些手段,比方:卷积神经网络(CNN)等。后面有时间了,我再专门去研究研究。

     

    好了,大体上的步骤,老王是不是都讲清楚了呢?接下来,就是详细讲讲这几个匹配算法,做完这几个算法。我们的识别工作就基本告一段落。来吧,跟着老王一起往下看。

     

     

    方法一:字符像素匹配

    这是最直观也最easy想到的方法。

    我们将待匹配图案和标准的每个图案进行一个像素一个像素的比对,假设位图都是0或者都是1,则计数加一,终于得到计数数值k。用k除以像素个数w * h就得到了一个相似值 d = k / (w * h)。假设d越大,则相似度越高(为了描写叙述起来easy些,后面我都用一些简单的位图来做示意):

     

    模板图案:


    待匹配图案:


    我们的模板图案和待匹配图案都被归一化到10*10的尺寸。他们有99个点是重合的,有一个点不重合:(0,0)那个点。

    这种话,他们的相似度就是d = 99 / 100 = 99%

     

    理想情况下,假设全部点都匹配的话,他们的就会有100点重合,那d = 100 / 100 = 100%。另外一个极端,就是一个点都不重合,那么d = 0 / 100 = 0%。对吧。

    所以。我们这个算法的值域就是[0,1]

    对于99%的相似度,我们觉得已经非常高了,所以他俩匹配的可能性就非常高。

     

    如此这样,我们将待匹配的图案和模板图案一一计算,得到d1 d2 ... dn这样一个结果序列,降序排列的第一个,就是这个算法觉得最有可能的图案。

     

    这个算法直观。实现简单,只是这个算法有一个问题:就是待匹配图案假设略微有一些偏差或者干扰,对算法本身的影响就会很大。

    比方,我们在图像处理的时候,某一行里多了一个干扰点。就有可能造成这一行的匹配度下降。例如以下图:



    我们在图像处理的时候,最后一行多了一个噪点。然后做图像归一化以后,整个图像的最右边就往左边挤占了一个像素。这样和模板图案进行算法对照的时候,匹配值就变成了90。整个匹配度就变成d = 90 / 100 = 90%

     

    因此,这个算法对图像精确度要求非常高,抗干扰能力弱。只是,在图像处理比較好的绝大多数情况下,他的匹配度还是不错的。

     

    方法二:投影区块匹配

    上一种方法就是对图像的信息太过敏感。略微一点干扰就会造成影响。所以,我们有一个新的方法。将信息做汇聚。然后再比較信息的相似性。

     

    我们将图像在x轴上做投影,累加位图为1的值。然后再将x轴等分成n份(比方n=5)。分别将这等分的n份里全部的值累加,得到k1 k2 ... kn,然后将标准图案和待匹配图案的这nk值进行求差。差值越小,则相似度越高。同理,在y轴也做相同的投影和求差值。

     

    我们还是对这个10 * 10的位图进行分析,将这个位图分别往xy轴上投影。将位图中为1的累加,因此得到在x轴上的10个数字和y轴上的10个数字,例如以下:

     

    模板图案:


    待匹配图案1


    待匹配图案2


    然后我们把x轴和y轴上的数字。分别分成连续的5组(每两个一组),组内的数字累加:

    模板图案:

    x轴:(8 8) (66) (6 6) (6 6) (8 8) -> 16 12 12 12 16

    y轴:(10 10) (22) (10 10) (2 2) (10 10) -> 20 4 20 4 20

    我们将上面的值命名为:

    x0[1] x0[2] ... x0[5] = 16 12 12 12 16

    y0[1] y0[2] ... y0[5] = 20 4 20 4 20

     

    待匹配图案1

    x轴:(7 8) (66) (6 6) (6 6) (8 8) -> 15 12 12 12 16

    y轴:(9 10) (22) (10 10) (2 2) (10 10) -> 19 4 20 4 20

    我们将上面的值命名为:

    x1[1] x1[2] ... x1[5] = 15 12 12 12 16

    y1[1] y1[2] ... y1[5] = 19 4 20 4 20

     

    待匹配图案2

    x轴:(7 8) (66) (6 6) (6 8) (8 1) -> 15 12 12 14 9

    y轴:(8 9) (22) (9 9) (2 2) (9 10) -> 17 4 18 4 19

    x2[1] x2[2] ... x2[5] = 15 12 12 14 9

    y2[1] y2[2] ... y2[5] = 17 4 18 4 19

     

    然后。我们将相应的值做下面操作:

    待匹配图案1和标准图案对照:

    adx1 =Σ((x1[i] - x0[i]) / 20) ^ 2 = 0.0025

    bdy1 =Σ((y1[i] - y0[i]) / 20) ^ 2 = 0.0025

    cd1  = 1 - (dx1 + dy1) / 2 = 99.75%

    (当中i=15, 20是每一组点的个数)

     

    待匹配图案2和标准图案对照:

    adx2 =Σ((x2[i] - x0[i]) / 20) ^ 2 = 0.1325

    bdy2 =Σ((y2[i] - y0[i]) / 20) ^ 2 = 0.035

    cd2  = 1 - (dx2 + dy2) / 2 = 91.6%

     

    从绝对差值来看。这样的方案要比前一种对于图像的敏感度要小,特别是假设每组的个数很多其它的时候,这样的敏感度就越弱。

     

    这个算法主要是在做图像有效信息分布的比对,信息相对要粗放一些,抗干扰度要好一些。

    只是可是带来的问题,就是信息是统计信息。比較粗,有些图案比对会不准确,比方:ao

     

    方法三:九宫格匹配

    我们将图案划分成3*3的格子,然后在每一个格子里统计位图值为1的个数,得到k1 k2 ... k9一共9个值。然后再将标准图案和待匹配图案对k值求差。差值越小,则相似度越高。

    这个算法类似上一种。不同的是。他将x轴和y轴的信息做了汇聚。鉴于计算方法类似,我们这里就不再赘述。

     

    方法四:重心匹配

    还记得我们之前说的一个case吗?逗号[,]和引號[’]事实上除了位置不一样以外。事实上长的很像。我最先做匹配的时候,匹配出来的结果就是要么都是逗号,要么都是引號。类似的还有横线[-]和下划线[_]等。

    那我们要做的,事实上就能够计算位图中1值的重心在x方向和y方向的分布。一比对就能够轻松的判别了。

    比方逗号的重心在y轴上的分布是更以下一些,而引號则是更上面一些。

     

    详细重心的计算方式有非常多,最简单的就是:

    x轴:将每一个1点的x坐标分别相加,然后除以1点的个数,再除以宽度做归一化。

    y轴:将每一个1点的y坐标分别相加,然后除以1点的个数。再除以高度做归一化。

    for (int x = 0; x < width; x++)

    {

       for (int y = 0; y < height; y++)

        {

          if (data[x][y] == 1)

           {

               yValue += y;

               count++;

           }

        }

    }

    double avg = count > 0 ? yValue / count : 0;

    avg = avg / height;

     

     

    方法五:宽高比匹配

    为什么要做这样一个匹配呢?我们先看一个case

     

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1

     

    请问。这个10*10的图案,是什么字符?


    这可能是一个句号[.],也可能是一个竖线[|]。还有可能是某些字体的逗号[,]。由于在做归一化的时候,都变成了一个全是1的图案。而逗号和句号的重心有可能还差点儿相同。这个时候,我们就能够用原始信息中的宽高比来做比对。比方,句号[.]的宽高比接近1:1,竖线[|]的宽高比可能是1:20,逗号[,]的宽高比可能是1:2等等。

    有了这个推断。就能够将相似的这些图案区分开来了。

     

    通过以上几种算法,我们就会拿到每一个算法计算出来的每一个待识别图案和标准图案的相似值。

    对于每一个待识别图案,我们将每一个算法的相似值做一个加权合并,就得到了终于的相似度值,从而来确定这个待识别的图案和哪个标准图案最相似,找出最有可能的asc码值。


    好了,最后我们再来看看文章開始的时候。给大家展示的效果:


    最后识别出来以后,没有做不论什么的单词校正工作:

    ===================================

    Three months after [he government stopped issulng (&%) or renewing permits for In[ernet cafes because of security (%#) concerns, some cafe owners are having flnanclal (ff%%) concerns of their own.

    ===================================

     

    大家肉眼看。识别率还是不错的。只是有一些字符比方(Ili)(t[)等这些字符组内的图案特别easy识别错误。为了解决这些问题,能够增加单词的校正算法。

    经常使用的LCS(最长公共子序列)或者BKTree等等。

    由于须要做全字典匹配,所以,BKTree的效率会更好一些。(这些基础算法就临时不在这里细讲。有兴趣的同学能够查阅baidu

     

    有了纠错算法,基本能非常好的将图案识别出来。

     

     

    ====总结 ====

     

    以上仅仅是一个主要的拍照识图的算法。除了上述说的这些方法。事实上在实际应用中。还会对数据做反馈训练。

    比方有些字符会引发错误。我们会将这些图案反馈给系统,下次遇到类似的图案的时候,系统就会匹配到更精准的信息。

    同一时候,对于參数的调整。也能够引入反馈和修正。

     

    而假设要增加中文的话。整个难度和复杂度还会提升不少,使用的方法可能都还有不一样。鉴于这次调研的时间,老王同志就没有再做深入的研究了。

    再等一段时间。老王可能会把这个做的更深入仔细。这次就先到这里吧~ ^o^

     

    最后还是老规矩,上美图:


    void next()
    {
        大家能够关注老王的微信公众号:simplemain

        老王近期写的技术干货都在里面,也能够提问题一起探讨~
        不愿意打字的盆友们,能够长按一下二维码关注哈~


    }

  • 相关阅读:
    【云栖社区001-数据结构】如何实现一个高效的单向链表逆序输出(Java版)
    全球疫情爬取及展示
    两个命令配置云服务器web开发环境
    云服务器的两类系统特点整理介绍
    团队介绍和项目简介
    Navicat连接阿里云服务器上MySQL数据库
    Android_bilibili式评论及回复的简单实现
    人月神话阅读笔记02
    每日进度博客_2
    每日进度博客_1
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7273872.html
Copyright © 2020-2023  润新知