文档章节

Java 使用 Tess4J 进行 图片文字识别 笔记

周翔
 周翔
发布于 2013/09/16 09:26
字数 1457
阅读 17087
收藏 56

最近的工作中需要使用到从图片中识别文字的操作,就在网上找到到Tess4j.那么,现在来总结一下使用中遇到的问题.
关于Tess4J简价:
http://tess4j.sourceforge.net/ (需要翻墙)
很简洁的项目主页.一个从Java角度使用JNA封闭的针对 Tesseract ORC 的开源项目,使用  Apache License, v2.0 协议.支持TIFF, JPEG, GIF, PNG, and BMP image formats,Multi-page TIFF images,PDF document format.(支持Tiff是一个很大的亮点)


那就再了解一下   Tesseract ORC.
https://code.google.com/p/tesseract-ocr/  是一个Google支持的开源的OCR图文识别开源项目.去持多语言(当前3.02 版本支持包括英文,简体中文,繁体中文),支持Windows,Linux,Mac OSX 多平台.使用中Tesseract 的识别率非常高. ( 自己仅对数字,使用中图片清析的情况下没发生错误 )


网上传的代码示例大多是在Windows下安装Tesseract ORC后通过CMD命令操作进行图识别操作.而 Tess4j 针对Tesseract 提供了JNI支持,同时还提供了一些图片操作的工具类,提供比如图片放大,旋转,黑白处理,锐化 等用来提高识别率的操作.操作十分方便. Tess4j 简单到超乎想象,只是自己在使用环境比较特殊,遇到很多问题,这里一一道来.


1 依赖包.
tess4j.jar   Tess4j的本尊,用于Tesseract 的JNA支持,并提供相关操作工具类
jna.jar       看到Tesseract 的第一反应是要用cmd或JNI来操作它,了解了一下 Tess4j 使用的JNA,有点JNI高级版的感觉,CMD什么的,玩蛋蛋去吧.
jai_imageio.jar   图片操作的工具类,支持Tiff就靠它了. 它的 META-INF 里有文章,这个后面详说.
还有其它几个包,是用于操作PDF用的吧,没有引用,也没有发生错误.所以的包可以在 Tess4j 的文件目录里面找到.


2 操作代码.
官方的示例中给出了一个超级简单有效的示例,不足20行代码!!!我和小伙伴们都被震惊了!!!关键代码如下:

File imageFile = new File("eurotext.tif");
Tesseract instance = Tesseract.getInstance();  // JNA Interface Mapping
String result = instance.doOCR(imageFile);

实际使用中为了提高识别率还要对图片作一些处理来提高识别率,使用Tess4j 自带的工具类即可完成,这样识别率就大大的提高了.( 这里无法解决 验证码 中干扰线问题,干扰线的清理,网上有其它方式处理 )

// 这里对图片黑白处理,增强识别率.这里先通过截图,截取图片中需要识别的部分
BufferedImage textImage = ImageHelper.convertImageToGrayscale(ImageHelper.getSubImage(panel.image, startX, startY, endX, endY));
// 图片锐化,自己使用中影响识别率的主要因素是针式打印机字迹不连贯,所以锐化反而降低识别率
// textImage = ImageHelper.convertImageToBinary(textImage);
// 图片放大5倍,增强识别率(很多图片本身无法识别,放大5倍时就可以轻易识,但是考滤到客户电脑配置低,针式打印机打印不连贯的问题,这里就放大5倍)
textImage = ImageHelper.getScaledInstance(textImage, endX * 5, endY * 5);

3 使用中遇到的问题
3.1 相关DLL文件,相关字库文件
liblept168.dll,libtesseract302.dll 其中 liblept168.dll 要先加载.
tessdata 存放的是字库文件,如果需要数字,英文以外的支持需要 Tesseract 页面下载相关字库.
因为公司使用时是将文件打成Jar布署,然后提供客户端下载,所以就把以上两个文件一起打进tess4j.jar里面,然后客户端使用时 tessdata 直接可用,而 liblept168.dll,libtesseract302.dll 需要释放到临时目录然后加载.相关代码:

loadDLL("liblept168.dll");//注意加载先后顺序
loadDLL("libtesseract302.dll");//注意加载先后顺序

private static void loadDLL(String libFullName) {
        try {
            String nativeTempDir = System.getProperty("java.io.tmpdir");
            InputStream in = null;
            FileOutputStream writer = null;
            BufferedInputStream reader = null;
            File extractedLibFile = new File(nativeTempDir + File.separator + libFullName);
            if (!extractedLibFile.exists()) {
                try {
                    in = Tesseract.class.getResourceAsStream("/" + libFullName);
                    Tesseract.class.getResource(libFullName);
                    reader = new BufferedInputStream(in);
                    writer = new FileOutputStream(extractedLibFile);
                    byte[] buffer = new byte[1024];
                    while (reader.read(buffer) > 0) {
                        writer.write(buffer);
                        buffer = new byte[1024];
                    }
                    in.close();
                    writer.close();
                    System.load(extractedLibFile.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (in != null) {
                        in.close();
                    }
                    if (writer != null) {
                        writer.close();
                    }
                }
            } else {
                System.load(extractedLibFile.toString());
            }
        } catch (IOException e) {
            logger.error("初始化 " + libFullName + " DLL错误", e);
        }
 }

3.2 相关异常

错误信息:null
错误详细堆栈信息:java.util.NoSuchElementException: null
at: javax.imageio.spi.FilterIterator.next(ServiceRegistry.java:808)

这个错误在开发环境下没有报错,但是在使用环境下出错,网上说出错原因是因为  jai_imageio.jar 丢失.
如果在操作中遇到错误,很可能是这个原因,但是在前面的代码的工具类里使用了  jai_imageio.jar ,如果报错,可能会报某类找不到的错误
自己这里显然不是.查看JDK中关于报错位置的代码,大概问题是因为注册的类没找到的原因.根据JDK文档的说明在 jai_imageio.jar 的 META-INF 的 service 包里面找到了相关的注册代码.分析了下,可能是因为金蝶EAS客户端使用自定义的类文件加载器,导至 META-INF 中的注册信息未能读取.这里手动注册一下.代码如下:

        // FUCK,客户端加载jar的方式很特殊,所以第三方包注册的serve 无法生效,这里就行动注册了,事儿真多
        IIORegistry registry = IIORegistry.getDefaultInstance();
        // registry.registerServiceProvider(new ImageReadWriteSpi(), OperationRegistrySpi.class);//这个,注册不了
        registry.registerServiceProvider(new ChannelImageInputStreamSpi(), ImageInputStreamSpi.class);
        registry.registerServiceProvider(new ChannelImageOutputStreamSpi(), ImageOutputStreamSpi.class);
        // ---------
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReaderSpi(), ImageReaderSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.png.CLibPNGImageReaderSpi(), ImageReaderSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderSpi(), ImageReaderSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLibSpi(), ImageReaderSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.wbmp.WBMPImageReaderSpi(), ImageReaderSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.bmp.BMPImageReaderSpi(), ImageReaderSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.pnm.PNMImageReaderSpi(), ImageReaderSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.raw.RawImageReaderSpi(), ImageReaderSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.tiff.TIFFImageReaderSpi(), ImageReaderSpi.class);
        //
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.png.CLibPNGImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriterCodecLibSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.wbmp.WBMPImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.bmp.BMPImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.gif.GIFImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.pnm.PNMImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.raw.RawImageWriterSpi(), ImageWriterSpi.class);
        registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.tiff.TIFFImageWriterSpi(), ImageWriterSpi.class);


世界终于安静了.....

© 著作权归作者所有

共有 人打赏支持
周翔

周翔

粉丝 7
博文 48
码字总数 21994
作品 0
长宁
程序员
加载中

评论(8)

Y
YHUIWang
手动注册写在哪里?
周翔
周翔

引用来自“周翔”的评论

引用来自“niniwei”的评论

20为什么到处都是一样的文

Tesseract ORC 本身很简单,觉得像很正常.这篇是两年前写的,现在写也差不多是这个样子

引用来自“niniwei”的评论

那么你是作者咯
这里除了下厨房那个是因为爱好转发的,其它都是自己的工作笔记
niniwei
niniwei

引用来自“周翔”的评论

引用来自“niniwei”的评论

20为什么到处都是一样的文

Tesseract ORC 本身很简单,觉得像很正常.这篇是两年前写的,现在写也差不多是这个样子
那么你是作者咯
周翔
周翔

引用来自“niniwei”的评论

20为什么到处都是一样的文

Tesseract ORC 本身很简单,觉得像很正常.这篇是两年前写的,现在写也差不多是这个样子
niniwei
niniwei
20为什么到处都是一样的文
周翔
周翔

引用来自“木有”的评论

这种情况怎么处理?
java.lang.UnsatisfiedLinkError: 由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题。

  at com.sun.jna.Native.open(Native Method)
  at com.sun.jna.Native.open(Native.java:1759)
  at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:260)
  at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:398)
  at com.sun.jna.Native.register(Native.java:1396)
  at com.sun.jna.Native.register(Native.java:1156)
  at net.sourceforge.tess4j.TessAPI1.<clinit>(Unknown Source)
  at Tesseract1Test.setUp(Tesseract1Test.java:56)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMe

没遇到过,JNA报错的话多半可能跟DLL文件方面有关.看一下电脑上有没有安装Tesseract ORC
木有
这种情况怎么处理?
java.lang.UnsatisfiedLinkError: 由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题。

  at com.sun.jna.Native.open(Native Method)
  at com.sun.jna.Native.open(Native.java:1759)
  at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:260)
  at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:398)
  at com.sun.jna.Native.register(Native.java:1396)
  at com.sun.jna.Native.register(Native.java:1156)
  at net.sourceforge.tess4j.TessAPI1.<clinit>(Unknown Source)
  at Tesseract1Test.setUp(Tesseract1Test.java:56)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMe
ALOSIN
ALOSIN
好东西,值得推荐
Java 验证码识别库 Tess4j 学习

Java 验证码识别库 Tess4j 学习 【在用java的Jsoup做爬虫爬取数据时遇到了验证码识别的问题(基于maven),找了网上挺多的资料,发现Tess4j可以自动识别验证码,在这里简单记录下学习过程及遇...

_TBHacker
08/01
0
0
深入学习Tesseract-ocr识别中文并训练字库的方法

  上篇文章简单的学习了tesseract-ocr识别图片中的英文(链接地址如下:https://www.cnblogs.com/wj-1314/p/9428909.html),看起来效果还不错,所以这篇文章继续深入学习tesseract-ocr识别...

战争热诚
08/14
0
0
Windows下Tesseract4.0识别与中文手写字体训练

一 、 tesseract 4.0 安装及使用 1. tesseract 4.0 安装 安装包下载地址: http://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-setup-4.00.00dev.exe exe可执行文件直接安装,选择安装...

qq_37674858
05/16
0
0
腾讯 AI-Java 客户端 TAip 新增加手写体、车牌识别

TAIP 是调用腾讯 AI 接口的 Java 客户端,为调用腾讯 AI 功能的开发人员提供了一系列的交互方法。 目前版本已经更新至4.2.5,Java开发者们无需再各种百度了。 新特性 文字识别模块新增手写体...

小帅帅丶
06/13
0
0
腾讯 AI-Java 客户端 TAip 升级至4.3.2 版本

腾讯 AI-Java 客户端 TAip 升级至4.3.2 版本 Ronny 3分钟前暂无评论 阅读 3 次 TAIP 是调用腾讯 AI 接口的 Java 客户端,为调用腾讯 AI 功能的开发人员提供了一系列的交互方法。 目前版本已经...

Ronny
07/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

arts-week10

Algorithm 905. Sort Array By Parity - LeetCode Review Who’s Afraid of the Big Bad Preloader? 一文读懂前端缓存 一个网络请求3个步骤:请求,处理,响应,而前端缓存主要在请求处响应这两步...

yysue
今天
4
0
00.编译OpenJDK-8u40的整个过程

前言 历经2天的折腾总算把OpenJDK给编译成功了,要说为啥搞这个,还得从面试说起,最近出去面试经常被问到JVM的相关东西,总感觉自己以前学的太浅薄,所以回来就打算深入学习,目标把《深入理...

凌晨一点
今天
5
0
python: 一些关于元组的碎碎念

初始化元组的时候,尤其是元组里面只有一个元素的时候,会出现一些很蛋疼的情况: def checkContentAndType(obj): print(obj) print(type(obj))if __name__=="__main__": tu...

Oh_really
昨天
6
2
jvm crash分析工具

介绍一款非常好用的jvm crash分析工具,当jvm挂掉时,会产生hs_err_pid.log。里面记录了jvm当时的运行状态以及错误信息,但是内容量比较庞大,不好分析。所以我们要借助工具来帮我们。 Cras...

xpbob
昨天
158
0
Qt编写自定义控件属性设计器

以前做.NET开发中,.NET直接就集成了属性设计器,VS不愧是宇宙第一IDE,你能够想到的都给你封装好了,用起来不要太爽!因为项目需要自从全面转Qt开发已经6年有余,在工业控制领域,有一些应用...

飞扬青云
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部