今天想着把以前做过的一个Android的文字检测识别应用好好的回顾一下,因为以前写java程序,目的就是能用就行,不会仔细看每一个部分代码,也不会记他们的用法,不回会去查API,借鉴别人的例程,用过就忘了,现在想着要改变,于是就回顾了一番。

之前检测用到的是Tesseract_OCR,之所以能在Android的上运行,是因为黑暗伯爵大神已经把tess-two(为android写的tesseract-tools)编译好了,然后我直接用的。我还是小白,完全不懂编译那些,如果让我自己搞.... 反正最后编译成so文件(这个是linux平台下的动态链接库,可以类比dll),然后我用编译好的so文件,以及jar包导入到工程,照葫芦画瓢把文字识别部分和自己之前看论文写的文字检测部分合到一起,然后百度了怎么调用摄像头,然后写了一个摄像头拍照,然后检测文字所在区域,处理,然后识别的应用。以后有时间会详细的重新把应用梳理一遍,然后记录,当然这不是今天的重点。如果对Android上如何做OCR感兴趣,可以参考 这里 。

回到正题,前几天同学问我以前做的文字识别是咋搞得,他想用用,我于是就想把程序移回来到java上,结果我百度才发现原来还有另外一种思路,那就是执行exe进程。先在pc上安装好tesseract_orc,然后jvm运行命令行跑识别程序,完成识别后结果写入txt,最后读取txt把内容返回到java程序中。这么想想也行,于是便试了试。(PS:我是后来才发现也有Java的API tess4j,参考 这里

然后就是讲自己具体怎么实现:

工程也就两部分,一部分是GUI,反正我现在对于Java的基础知识薄弱,然后常用类也用的不多,所以借此机会正好熟悉。

GUI主要用到javax.swing包和java.awt包,swing主要写组件,awt是事件(其实awt也可以写组件),但是说swing是对awt中组建的优化,所以现在常用swing。GUI里面比较重要的概念还是容器,组件必须放到容器里面才能显示,常用frame和dialog。我这次写GUI用到jframe,jbutton,filedialog,JLabel,imageicon这几个类

界面如下

  • 其中的按钮用的JButton:"push" 按钮的实现,可以设置监听器。
  • 按钮设置了监听器,“打开图片”弹出Filedoalog,选择图片文件,“识别”新建文字识别类,进行识别返回结果:FileDialog 类显示一个对话框窗口,用户可以从中选择文件。
  • 图片显示和文字显示用的JLabel:JLabel 对象可以显示文本、图像或同时显示二者。可以通过设置垂直和水平对齐方式,指定标签显示区中标签内容在何处对齐。默认情况下,标签在其显示区内垂直居中对齐。默认情况下,只显示文本的标签是开始边对齐;而只显示图像的标签则水平居中对齐。
  • Jframe建立整个容器
  • Imageicon用来加载图像。Imageicon:一个 Icon 接口的实现,它根据 Image 绘制 Icon。可使用 MediaTracker 预载根据 URL、文件名或字节数组创建的图像,以监视该图像的加载状态。

界面的具体代码我就不贴上来了,值得注意的是图片压缩显示有一个小trick。

imagePath = new String(dirPath+fileName);
imageico = new ImageIcon(imagePath);
int w = imageico.getIconWidth();
int h = imageico.getIconHeight();
double ratio = (double)w/(double)h;
if(ratio>4/3){
h = (int)(640*h/w);
w = 640;
}else{
w = (int)(480*w/h);
h = 480;
}
imageico.setImage(imageico.getImage().getScaledInstance(w,h,imageico.getImage().SCALE_DEFAULT));

另外,就是文字识别的部分,主要还是一个执行进程的过程,那么首先得下载安装Tesseract_OCR:

安装下载的工作参考 这里

那么这边主要的挑战就是使用java执行进程和做文件io,主要分一下几点:

1.java操作命令行主要用到processbuilder & process 类,出自java.lang

一般都是ProcessBuilder.start() 和 Runtime.exec(ArrayList<String>) 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获得相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。

Runtime.getRuntime.exec(ArrayList<String> cmd)
processbuilder pb; pb.command(ArrayList<String> cmd);

这里就是用的processbuilder pb,新建一个实例,并且把运行参数保存到字符串表单cmd里,然后pb.command(ArrayList<String> cmd)执行,结果保存到指定txt中;

2.表示文件的类file类 出自java.io
它是文件和目录路径名的抽象表示形式。 
主要方法getName(),getPath(),getParentPath();

在执行命令行时,表示输入的图片,表示输出txt都可以用到file类。

3.读取字节流过程 出自java.io
FileInputStream 从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境,这里可以读取图片。
new FileInputStream(outputFile.getAbsolutePath()) 新建一个文件输入字节流
new InputStreamReader(new FileInputStream(outputFile.getAbsolutePath()),"UTF-8")。文件输入字节流变成文件输入字符流

BufferedReader从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

主要是两种用法还可以这么使用

BufferedReader in = new BufferedReader(new FileReader("foo.in"));

或者
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("foo.in"),"UTF-8"));

前者不能指定编码,而后者可以。

在最后把txt中文本读取到java程序,进而显示在GUI中用到

识别的代码如下

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List; public class textRecognizer{ private String textResult;
/**
* 输出的结果
*/
private final String EOL = System.getProperty("line.separator");
//回车
private String tessPath = "D:\\Tesseract-OCR";
//tessocr程序所在目录
public textRecognizer(String path)
{
try
{
File imagefile = new File(path);
textResult = this.recognizeText(imagefile);
} catch (Exception e)
{
e.printStackTrace();
}
} public String getResult(){
return textResult;
} private String recognizeText(File imageFile) throws Exception
{
/**
* 设置输出文件的保存的文件目录
*/
File outputFile = new File(imageFile.getParentFile(),"output");
StringBuffer strB = new StringBuffer(); //设置cmd命令行字符串形式
List<String> cmd = new ArrayList<String>();
cmd.add(tessPath + "\\tesseract");
cmd.add(imageFile.getName());
cmd.add(outputFile.getName());
cmd.add("-l");
cmd.add("eng"); //启动exe进程
ProcessBuilder pb = new ProcessBuilder();
pb.directory(imageFile.getParentFile());
pb.command(cmd);
pb.redirectErrorStream(true);
Process process = pb.start();
//等待此进程完成
int w = process.waitFor();
if (w == 0){// 0代表正常退出
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(outputFile.getAbsolutePath()+ ".txt"),"UTF-8"));
String str;
while ((str = in.readLine()) != null)
{
strB.append(str).append(EOL);
}
in.close();
} else{
String msg;
switch (w){
case 1:
msg = "Errors accessing files. There may be spaces in your image's filename.";
break;
case 29:
msg = "Cannot recognize the image or its selected region.";
break;
case 31:
msg = "Unsupported image format.";
break;
default:
msg = "Errors occurred.";
}
throw new RuntimeException(msg);
}
new File(outputFile.getAbsolutePath()+ ".txt").delete();
/**
* 如果做验证码
* return strB.toString().replaceAll("\\s*", "");
*/
return strB.toString();
}
}

可惜的是最后检测的结果一般。

今天写程序期间还有其他的有意思的地方我也有记录。

  • java foreach 遍历,for(File file :testDataDir.listFiles()),jdk1.6后支持。
  • private final String EOL = System.getProperty("line.separator"); 回车换行的字符串表示

【Java程序】tesseract_orc java上的一种实现方法的更多相关文章

  1. 我的第一个Java程序和Java简介

    public calss HelloWorld{ public static void main(String[] args){ System.out.println("Hello Worl ...

  2. 执行Asp.net应用程序在Linux上的3种托管方式

    执行Asp.net应用程序在Linux上的3种托管方式 想要执行Asp.net应用程序在Linux上.我们有3种选择: 1.使用Apache作为Webserver.使用mod_mono:http:// ...

  3. Java 微信公众号上传永久素材的方法

    Java 微信公众号上传永久素材的方法 学习了:http://blog.csdn.net/u013791374/article/details/53258275 膜拜一下,源码如下: @Request ...

  4. redis(Springboot中封装整合redis,java程序如何操作redis的5种基本数据类型)

    平常测试redis操作命令,可能用的是cmd窗口 操作redis,记录一下 java程序操作reids, 操作redis的方法 可以用Jedis ,在springboot 提供了两种 方法操作 Red ...

  5. 将Java程序作成exe文件的几种方法【转载】

    看到网上有同志的介绍将Java程序作成exe文件的方法,写的不错,但是也许是这篇文章完成的时间比较早,许多内容已经不合适了.我在这里补充几条: 一.exe4j 说明:exe4j可以将Jar文件制作成e ...

  6. java 程序从linux 上接收不可见字符

    近期在写一个简单的小java程序,希望在运行java 程序时,从shell 中接收参数,并且参数的内容为不可见字符. 开始时还觉得可以使用"\"之类的转义符来写,后来发现java程 ...

  7. java程序在一个电脑上只启动一次,只开一个进程

    方案1: 单进程程序可以用端口绑定.程序启动的时候可以尝试看该端口是否已经被占用,如果占用则程序已经启动. 方案2:你可以在java程序中创建一个隐藏文件,程序退出的时候删除这个文件.这样在程序启动的 ...

  8. 第一个java程序以及java的运行机制

    课堂要点: 编写第一个java程序以及理解java的运行机制. 1.基本命令介绍: javac命令: 编译java文件得到.class字节码文件 -encoding 参数:指定编译的编码 java命令 ...

  9. Java程序在Linux上运行虚拟内存耗用很大

    突然集群的2个节点挂了,通过top查看, 虚拟内存22G, 通过 pmap -x 8 | grep anon 一大堆64M Linux下glibc的内存管理机制用了一个很奇妙的东西,叫arena.在g ...

随机推荐

  1. 第05章 AOP细节

    第05章 AOP细节 1.切入点表达式 1.1 作用 通过表达式的方式定位一个或多个具体的连接点. 1.2 语法细节 ①切入点表达式的语法格式 execution([权限修饰符] [返回值类型] [简 ...

  2. Java调用明华RF读写器DLL文件的方法

    首先jdk必须得是32位的,IDE也必须是32位的(我用的idea,所以为了使用32位的,下载了2018年1月版本的). 明华RF读写器演示文件提供了一份名为mwrf32.dll的动态链接库文件 ja ...

  3. Java Web学习总结(3)Servlet(二)

    一,Servlet访问URL映射配置 由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml ...

  4. APP开发者如何从应用程序中赚钱?

    付费应用程序,这是应用程序最基本的赚钱方式之一,也是拥有巨大潜力的赚钱方式之一.但有一个问题开发者必须扪心自问,您的程序用户是否有一批粉丝级用户的认可,或对您应用程序品牌的认可   蝉大师APP推广工 ...

  5. AcWing 244. 谜一样的牛 (树状数组+二分)打卡

    题目:https://www.acwing.com/problem/content/245/ 题意:有n只牛,现在他们按一种顺序排好,现在知道每只牛前面有几只牛比自己低,牛的身高是1-n,现在求每只牛 ...

  6. (转)df命令

    转:http://man.linuxde.net/df df命令用于显示磁盘分区上的可使用的磁盘空间.默认显示单位为KB.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 语法 d ...

  7. 解决Flutter boost模块化加入到原有android项目后,首次加载过慢的问题

    由于Flutter boost目前还没有很好的解决方案,所以只能魔改了,大致的思路就是在刚打开app的时候就初始化一个不可见的Flutter页面,让其自动注册&初始化. 先编写一个Flutte ...

  8. hive中not in优化

    比如:A,B两表,找到ID字段中,存在A表,但不存在B表的数据. A表共13w,去重后3w,B表共2W,且有索引 方法一 not in,易理解,效率低,时间:1.395s )

  9. 重新认识Maven

    PS:第一次接触maven大约是两年前吧,隐约记得之前都是人工寻找并下载很多jar,放在项目的lib中(表示太年轻,没有接触过Ant或者其他类似的工具,就不找别人写的比较了).懒人永远有着自己的小聪明 ...

  10. c++全局变量,局部变量,内存布局,默认初始化

    全局变量 定义在所有函数之外的变量,main函数之内的变量也是局部变量,Globle variable  未显示初始化时执行默认初始化 局部变量 定义在函数之内的变量,Local variable 未 ...