用Asprise的OCR包,处理验证码

今天要介绍Java的OCR(图片字符识别)包,由Asprise出品。它甚至可以读条形码。

请从下面的链接下载包含破解的zip文件。

 

Asprise-OCR-Java-Windows_XP_32bit-4.0.zip

 

 

这个包用起来非常简单。

解开上面的zip后,里面有demo-src.jar,把这个jar也解开,打开 com/asprise/util/ocr/demo/Demo.java 看看,就全明白了:

 

[java]  view plain  copy
  1. /* 
  2.  * $Id$ 
  3.  *  
  4.  */  
  5. package com.asprise.util.ocr.demo;  
  6. import java.awt.image.BufferedImage;  
  7. import java.io.File;  
  8. import java.io.IOException;  
  9. import javax.imageio.ImageIO;  
  10. import com.asprise.util.ocr.OCR;  
  11. public class Demo {  
  12.     public static void main(String[] args) throws IOException {  
  13.         if(("1.4").compareTo(System.getProperty("java.vm.version")) > 0) {  
  14.             System.err.println("Warining: /n/nYou need Java version 1.4 or above for ImageIO to run this demo.");  
  15.             System.err.println("Your current Java version is: " + System.getProperty("java.vm.version"));  
  16.             System.err.println("/nSolutions: /n");  
  17.             System.err.println("(1) Download JRE/JDK version 1.4 or above; OR /n");  
  18.             System.err.println("(2) Run DemoUI, which can run on your current Java virtual machine.");  
  19.             System.err.println("    Double click the 'runDemoUI' to invoke it./n");  
  20.             return;  
  21.         }  
  22.         System.out.println("Welcome to Asprise OCR v4.0 Demo!/n");  
  23.         if(args.length < 1) {  
  24.             System.err.println("Usage: java Demo PATH_TO_IMAGE [Description]");  
  25.             return;  
  26.         }  
  27.           
  28.         if(args.length >= 2) {  
  29.             System.out.println("-----------------------------------------------------------");  
  30.             for(int i=1; i<args.length; i++)  
  31.                 System.out.println(args[i]);  
  32.             System.out.println("-----------------------------------------------------------/n");  
  33.         }  
  34.       
  35.         File file = new File(args[0]);  
  36.       
  37.         System.out.println("Trying to perform OCR on image: " + file.getAbsolutePath());  
  38.           
  39.         //OCR.setLibraryPath("E:/Twain/OCR/OCR+i/Release/AspriseOCR.dll");  
  40.         BufferedImage image =  
  41.             ImageIO.read(file);  
  42.         String s = new OCR().recognizeEverything(image);  
  43.         System.out.println("/n---- RESULTS: ------- /n" + s);  
  44.     }  
  45.       
  46. }  

 

用ImageIO的read方法从File读入BufferedImage,然后把Image传个OCR类的recognizeEverything方法,这个方法会返回分析出来的字符串(英文和数字)。

 

核心的方法就是这些了,但是用它来处理大多数网站的验证码,都不太好使。

原因很简单,大多数网站的验证码都加入不同程度的噪音,以防止OCR软件的自动分析。

所谓的噪音就是,加入背景颜色,或者加入杂七杂八的点,或者加入横七竖八的线,然后就是扭曲文字等等。

 

那么怎么才能去掉这些噪音,从而让OCR可读呢?

这里以我以前做开心网外挂时用到的程序片段来做例子,给出点思路。

这个程序现在已经不能用了,因为开心网现在的验证码是由汉字组成的了,Asprise只能识别英文和数字。

 

 

 

[java]  view plain  copy
  1. BufferedImage image;  
  2.         image = ImageIO.read(new ByteArrayInputStream(buffer));  
  3.         int width = image.getTileWidth();  
  4.         int height = image.getTileHeight();  

 

首先,看一下上面的代码,其中 buffer是一个 byte[],它可以是用File打开的二进制文件,用InputStream的read方法读出的byte的全部,也可以是给出的网站的图片的URL,用HttpClient或者其他方法读入的图片二进制流。用ByteArrayInputStream转换后,被ImageIO的read方法转成Image。

 

 

[java]  view plain  copy
  1. Map<Integer, Integer> mapColor = new HashMap<Integer, Integer>();  
  2. for (int i = 0; i < width; i++)  
  3.     for (int j = 0; j < height; j++) {  
  4.         int color = image.getRGB(i, j);  
  5.         Integer count = mapColor.get(color);  
  6.         if (count == null)  
  7.             count = 0;  
  8.         count++;  
  9.         mapColor.put(color, count);  
  10.     }  

 

上面的代码是对Image进行处理。一个二重循环,用image.getRGB方法来取得每个点的颜色,然后对颜色计数,并放到一个HashMap里去。

这是为后面的去噪音做准备。

 

后面的代码,针对不同的噪音,要用同的方法。这里只是给个思路。

[java]  view plain  copy
  1. List<Map.Entry<Integer, Integer>> list = new ArrayList<Map.Entry<Integer, Integer>>(  
  2.         mapColor.entrySet());  
  3. Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {  
  4.     @Override  
  5.     public int compare(Entry<Integer, Integer> o1,  
  6.             Entry<Integer, Integer> o2) {  
  7.         return o2.getValue() - o1.getValue();  
  8.     }  
  9. });  
  10. list = list.subList(05);  

上面是把,已经处理过的HashMap(key是颜色,value该颜色的点的个数)进行排序得到 list。

开心网的验证码是4位,然后每个的颜色不同。那么取list的前5项,必然是背景色和4位验证码的颜色。

 

list = list.subList(0, 5);

 

然后再来个二重循环,把不属于这5种颜色的点,全变成背景色,也就是去噪音了。

[java]  view plain  copy
  1. int intBack = list.get(0).getKey();  
  2. Set<Integer> setColor = new HashSet<Integer>();  
  3. for (Map.Entry<Integer, Integer> entry : list) {  
  4.     setColor.add(entry.getKey());  
  5. }  
  6. for (int i = 0; i < width; i++)  
  7.     for (int j = 0; j < height; j++) {  
  8.         int color = image.getRGB(i, j);  
  9.         if (setColor.contains(color))  
  10.             continue;  
  11.         image.setRGB(i, j, intBack);  
  12.     }  

上面的程序,首先取出list的第一项(背景)的颜色:int intBack = list.get(0).getKey();

循环体中,如果是背景色或者验证码的颜色(if (setColor.contains(color))),那么继续循环;否则,该点为噪音,要设置成背景色(image.setRGB(i, j, intBack))。

 

最后,当然就是把处理过的Image交个OCR了。

[java]  view plain  copy
  1. String strCode = ocr.recognizeEverything(image).trim().toLowerCase()  
  2.                 .replaceAll(" """);  

由于分析的来的字符里出现空格的可能很大,所以要删除。

 

以上的程序,对加入横七竖八的别的颜色的线的加噪音方法比较有效,加别的颜色的点,也可以处理。

 

然后对于别的噪音,这里只给点思路,就不给出算法实现了。

 

比方说,对于那些加入和验证码颜色一致的杂七杂八的点的处理。前面的方法不能去除这种噪音。

我们可以做这么个二重循环,分析每个点,如果这个点颜色的四周(上下左右4个点,或者包括斜角共8个点)的颜色不同,而四周的颜色都一致,那么就判定这个点是噪音点,把它设置成和四周颜色一致。

当然,这个噪音未必是一个点,也许是个块,比方说2*2个点,或者3*3个点。如果这样,处理稍微麻烦点。可以用围棋博弈算法里的分块算法,取得每个小块,那些特别小的就判定为噪音。

 

然后说说关于扭曲,通常是把字母的上下往左右拉升。如果要其归位,比较难,未必一定可以实现。

可以考虑,用分块算法,取得的每一块,一个一个处理。处理时,把最左上和最左下画连线,算斜率;最右上和最右下也算斜率。取平均值,然后以平均斜率为base进行纠正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值