代码改变世界

【技术原创】探讨一下京东商城价格图片解析算法的优化,附演示程序下载

2011-11-15 14:08  Brush  阅读(3344)  评论(11编辑  收藏  举报

     以下是我发布在个人独立博客的原创技术文章(源地址),放到园子里来供大家讨论。 

 

     发现咱博客开启后技术性的文章写的并不多,这貌似违背当时的初衷啊。文章不多并不表示咱一直都闲着,尤其是在技术方面咱是因为太忙了才没时间写一写,总结总结的。今晚趁还有些精力赶紧将前段日子自己捣鼓的小东西(之一)给大家分享一下。

      前不久我不是扬言说要做两款小软件么,这次我们说到的话题就跟这个有关。我说的那个软件之一就是京东商城的相关软件--我想抓取价格做分析(京东不会提供这个接口),我相信这个肯定是对大家有所帮助的。京东商城的价格展示方式,除了书籍外,基本上都是通过图片来展示的--这个好处是防止有人过于轻易地抓取到价格信息。于是咱想准确地获取到价格的话就只能老实地分析图片喽(其实有的页面里,比如列表页面商品价格是有字符串表示形式的,但那个只用于无目标采集时有用,要是关注某个商品价格变动情况的话,作用就不大了,所以咱无法避免图像分析这一步)。

      图片分析一般有两种思路,一种是与样本库对比,这种方法简单有效,缺点是适应性较差,样本可能要跟着图片不停地变动;另一种就是形状分析,也就是判断图片中数字的形状来判断是哪个字,这种方法效率比前者低,但适应性强;以前我在看验证码识别相关文章时还找到过这种算法,但眼下要用的时候就再也找不着了,方便起见咱也只能用第一种,也就是样本库的方法识别了。

      这里我要先插播一下,之所以我能采取样本库的算法,是因为京东商城的价格显示很有特点(希望京东商城的人看到后表改掉哦,否则我又得重新找算法了),就是几个数字拼在一起然后再随机绘制了一条细线挡了一下,其中0~9这9个数字的字体样式和大小是始终不变的,也就是我们能将价格图片分割成单独的数字,然后去掉无效的坐标(也就是被细线挡住的部分),就创造了样本库对比的先前基础了。

      样本库对比如何做呢,最简单来讲,我们拿到一串数字,首先要把每个数字独立分割开来,图片中有几个数字就分割成几张图片,然后再针对每个图片进行分析处理。这样我们就需要针对每个数字建立一个样本,然后分析时将每个分割出来的图片与样本采集的点进行对比,命中最高的数字就是我们要的答案喽,但按实际运行效率来看,这种做法并不高效。假设我们每个数字图片采集8个点做样本,这样的话每个图片要比对10次(0~9每个数字一次),然后找出配对率最高的作为最终结果。事实上我这样做的结果也有很高的出错率(大概在5%的样子),为什么呢,因为8和0很像,3和8很像,6和8也很像,这样如果样本正好挡住关键位置或者其它位置使两者匹配点相等或者非正确值大于正确值的数量,这就使结果出错。说简单一点就是本来是要匹配8的,但如果正好8中间的点被划线了,很可能就被判断为3。想要提高准确率只能加大样本库,最后我将样本库加大到极限,也就是整个数字的所有像素都做样本比对,发现还是不能保证百分百识别正确。这种做法显然行不通。

      上面的样本库对比有些死板,因为他非要一个一个去对比,等对比完了找匹配数量最高的为最终结果,效率不高,可信度也不高。后来我就想有没有更好的样本库算法呢,我就从尽量减少比对次数上考虑,发现我们可以这样去判断:我们先去找带有个性的数字的特征,然后以此为基础否决或者确定一个个的数字,最终就能得到我们想要的结果。具体怎么说呢,就是我先找出0~9这9个数字,也就是9张图片中每个数字独具的特色(比如说1号数字,只有它这里在坐标(7,1)处是白色,只有它在坐标(3,4)处是红色),写这样一个算法计算每个数字的特色并不复杂,于是我很轻松地就把样本库统计出来了:

1:W(7,1), R(5,2), R(6,3), R(5,4), R(6,4), R(6,9)
2:R(3,9), R(1,11), R(9,11)
4:W(5,1), W(6,1), R(4,4), R(3,8), R(7,8), R(10,8), W(3,11), W(4,11)
5:R(3,4)
7:R(1,1), R(9,2), R(4,10)
9:R(4,7)

   解释一下上面表示的意思:第一个数字表示数字几的对比结果,W表示白色,R表示红色,第一行表示:只有数字1,才会在坐标(7,1)处出现白色,才会在坐标(5,2)处出现红色,才会在……这样我们就可以根据这些特征值直接判断是否是当前这个数字。考虑到有时特征值正好被细线经过成为无效数据(即不是W也不是R),每个数字要有至少三个不在同一条线上的点才能保证能被准确判断(是或者不是)。比如1这个数字,在坐标(7,1)处正好是无效点,(6,3)也是无效,那(5,4)跟前两者不在一条线上,就不大可能也无效了(除非京东价格图片改划曲线了),也就是说有这三个点作为依据,肯定能判断此数字是不是1了。根据这个理论,数字1、2、4、7能保证被正确识别,5,9则需要进一步验证。

      上面已经解决了至少有三个独特的点的数字识别问题,接下来我们就考虑5、9以及剩下的数字如何识别的问题。其实按我们的思路,前面已经可以准确识别数字1、2、4、7了,那么也就是说我们若到此时还没判断出数字是多少,但我们已经坚决否定了前面四个数字,那样的话,两个数字共享的特征,就可能有准确的判断结果了---因为其中一个已经有结果了嘛。于是我们再将与其它数字共享一个特征的数字找出来:

0:R(9,5)-9, R(1,6)-6, W(7,6)-1, R(9,6)-9
1:W(4,1)-4, R(4,2)-6, R(6,2)-4, R(5,3)-4, W(7,6)-0, R(5,9)-7, R(5,10)-7, R(6,10)-9
2:R(1,2)-3, R(4,8)-4, R(4,9)-7
3:R(1,2)-2, R(4,6)-8, R(1,10)-5
4:W(4,1)-1, R(6,2)-1, R(5,3)-1, R(7,3)-7, R(7,4)-7, R(4,8)-2, R(7,9)-9, W(5,11)-7, W(6,11)-7
5:R(9,1)-7, R(3,3)-6, R(4,5)-6, R(1,10)-3
6:R(4,2)-1, R(3,3)-5, R(4,5)-5, R(1,6)-0
7:R(9,1)-5, R(7,3)-4, R(7,4)-4, R(4,9)-2, R(5,9)-1, R(5,10)-1, W(5,11)-4, W(6,11)-4, W(7,11)-9
8:R(4,6)-3, R(3,7)-9
9:R(9,5)-0, R(9,6)-0, R(3,7)-8, R(7,9)-4, R(6,10)-1, W(7,11)-7

      上面第一行的意思是:数字0的共享特征是,它与数字9在坐标(9,5)上都是红色的,与数字6在坐标(1,6)上都是红色的,与数字1…… 依次往下,就形成了上面这张表。我们能得到什么呢,首先我们能判断1、2、4、7,如果成功了就是四者之一了,否则我们看共享表中数字1的特征,为什么这么看呢,因为前面的数字都被否决了,那么这些数字对应的共享特征表里的坐标,就变成了“独享”的。如数字1与数字6共享R(4,2),当否决了数字1时,那么R(4,2)这个条件就可以来直接判断是否是数字6。归纳一下,也就是说前面已经否决的数字,其共享的特征则成为另一方独享的特征(说得比较绕口),归纳算法如下:

1:W(7,1), R(5,2), R(6,3), R(5,4), R(6,4), R(6,9)
2:R(3,9), R(1,11), R(9,11)
7:R(1,1), R(9,2), R(4,10)
4:W(5,1), W(6,1), R(4,4), R(3,8), R(7,8), R(10,8), W(3,11), W(4,11)
9:R(4,7), R(7,9)|4, R(6,10)|1, W(7,11)|7
0:R(9,5)|9, W(7,6)|1, R(9,6)|9
5:R(3,4), R(9,1)|7, R(3,3)|6, R(1,10)|3, R(4,5)|6
6:R(4,2)|1, R(3,3)|5, R(4,5)|5, R(1,6)|0
3:R(1,2)|2, R(4,6)|8, R(1,10)|5
8:R(4,6)|3, R(3,7)|9

    上面便是最后算法依据的推导公式了,我来给大家解释一下:

    算法每行可断定某一个数字(成立或者不成立),第1行表示数字1的判断成立条件(也就是数字1的独享特征),本来三个就足够,我这里顺便将它的6个特征全部列上了;算法依次判断下去,直到判断条件成立,便找到当前数字;

     前四行不用多说,1、2、4、7列举的都是独享的特征,能一次性判断是否成立;第5行,也就是数字9的判断特征里写,第一个是R(4,7)独享特征,第二个是R(7,9)|4,表示与数字4共享的特征(如果判断到这一步了已经表示前面第四行的4已经被否决掉了,所以这个点成为它的独享特征了),再下一个是R(6,10)|1,到这里已经够三个不在一条直线上的点了,数字9也就可识别了。然后数字9的共享特征点又可以为剩下的点做判断依据,于是就有了上面的这个识别算法公式。这个公式要确保的条件是:

     每一行至少有三个不在同一直线上的特征点 ;

     本行若存在共享特征,则需共享方数字已经在本行之前被推导(如数字4的共享特征方1、4、7均已在之前被推导);

     说了这么多,我的算法终于介绍完了,不知道大家有何看法或者想讨论的,可以直接留言。

附件:点击这里下载演示程序

 

     后来我又写了篇文章将源代码放出,具体请参考文章《【技术原创】京东商城价格图片分析解析源代码下载(C#),附演示程序