考虑到产品未来可能需要对图片中的文字进行识别分析,所以抽空我做了一点初步的尝试。暂且写下来做个记录吧。

选型

经过一番寻找,锁定了tesseracttesseract是一个开源的OCR引擎,支持中文识别。Tess4J提供了tesseract面向java的api封装。

安装

  • 使用tess4j必须先安装tesseract,我的系统环境是centos,可以很方便的使用yum安装。为了识别中文还需要安装中文datafile。

    sudo yum install tesseract 
    sudo yum install tesseract-langpack-chi_sim.noarch //简体中文支持

    其他操作系统,需要参考tesseract的说明安装。

  • 然后在java项目中,通过maven引入tess4j。目前3.x版本里最新的是3.4

    <dependency>
    <groupId>com.sun.media</groupId>
    <artifactId>jai_imageio</artifactId>
    <version>1.1</version>
    </dependency>
    <dependency>
    <groupId>net.sourceforge.tess4j</groupId>
    <artifactId>tess4j</artifactId>
    <version>3.4.0</version>
    </dependency>

测试

  • 在word里用微软雅黑 小四 加粗写了一段文字 ,截成图片。说实话,考试难度已经很低了,真实场景很难有这么高质量的图片

    测试图片

  • 参考官网的示例源码写了测试代码。在这段测试代码里分别用了三种处理方式:第一个println方法打印的是官网的示例源码,直接doOCR的结果,第二个println方法是做了二值化处理后,再doOCR的结果,第三个println是截取一小块再doOCR的结果。后来还尝试过把png格式转成tiff格式再识别,识别率没有变化。

    import net.sourceforge.tess4j.ITesseract;
    import net.sourceforge.tess4j.Tesseract;
    import net.sourceforge.tess4j.util.ImageHelper;

    import javax.imageio.ImageIO;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.File;

    /**
    * @author fang
    * @creatdate 17-8-2
    */
    public class TesseractExample {

    public static void main(String[] args) {
    //读取图片
    File imageFile = new File("/home/fang/img/test4.png");
    ITesseract instance = new Tesseract(); // JNA Interface Mapping
    instance.setDatapath("/usr/share/tesseract/tessdata"); //必须设置,或者写到环境变量里
    //instance.setPageSegMode(1); //识别分页的模式,在我们这里用不到
    instance.setOcrEngineMode(0); //这个应该就是默认值,可以不设置
    instance.setLanguage("chi_sim+eng"); //中英文混检

    try {
    String result = instance.doOCR(imageFile);
    System.out.println(result);
    System.out.println("----------------------");
    //二值化
    BufferedImage grayImage = ImageHelper.convertImageToBinary(ImageIO.read(imageFile));
    ImageIO.write(grayImage, "png", new File("/home/fang/img/", "test41.png"));
    File imageFile2 = new File("/home/fang/img/test41.png");
    String result2 = instance.doOCR(imageFile2);
    System.out.println(result2);
    System.out.println("----------------------");
    //截取一小块
    Rectangle rectangle = new Rectangle(0, 0, 100, 20);
    String result3 = instance.doOCR(grayImage,rectangle)
    .replace(" ",".").replace(",","");
    System.out.println(result3);
    } catch (Exception e) {
    System.err.println(e.getMessage());
    }
    }
    }

    结果很囧。

    println 1

    软(懦必然要变化的′变化是常态;有变化就需要堆护′随盲时间的惟移′维护
    成本会远远超过才刃期开发的成本′占据成本的大头;因此′在钦件开发中′昌重
    要的昌要馏氏维沪成本 雌护成本正比于系统的复茅篝呈度 所以要降低维护咸本 ′
    系统的薏掰十就应当追求简单渲晰。 井

    println 2

    软(懦必然要变化的′变化是常态;有变化就需要堆护′随盲时间的惟移′维护
    成本会远远超过才刃期开发的成本′占据成本的大头;因此′在钦件开发中′昌重
    要的昌要馏氏维沪成本 雌护成本正比于系统的复茅篝呈度 所以要降低维护咸本 ′
    系统的薏掰十就应当追求简单渲晰。 \

    println 3

    蜱(缘「皂必俩菩

    识别率在70%左右。这个样本里全部都是中文,如果里面有英文,识别率会再降。不过,如果懂图像处理,比如把图像放大了再识别或者加粗,应该能提高识别率,或者找到自己应用场景下的样本去做训练。可以参考这篇文章

结论

由于图像处理这方面毫无经验,另考虑到我们的业务场景不仅图像质量参差不齐,而且还有医生手写体…我基本断了使用开源的心思,下次找一些商业的OCR API来试一下。

END