今天想着把以前做过的一个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. [BZOJ4316]小C的独立集 仙人掌?

    题目链接 因为xls让我每周模拟一次,然后学习模拟中没有学过的东西.所以就来学圆方树. 本来这道题用不着圆方树,但是圆方树是看yyb的博客学的,他在里面讲一下作为一个引子,所以也来写一下. 首先来Ta ...

  2. ftp 上传文件时报 cant open output connection for file "ftp://129.28.149.240/shop/web/index.html". Reason: "550 Permission denied.".

    原因:没有写入权限 修改权限即可 vsftpd.conf vim /etc/vsftpd.conf write_enable=YES #加入这句

  3. 【leetcode】636. Exclusive Time of Functions

    题目如下: 解题思路:本题和括号匹配问题有点像,用栈比较适合.一个元素入栈前,如果自己的状态是“start”,则直接入栈:如果是end则判断和栈顶的元素是否id相同并且状态是“start”,如果满足这 ...

  4. paper 149:Deep Learning 学习笔记(一)

     1. 直接上手篇 台湾李宏毅教授写的,<1天搞懂深度学习> slideshare的链接: http://www.slideshare.net/tw_dsconf/ss-62245351? ...

  5. AcWing 260. 买票 (树状数组+二分)打卡

    题目:https://www.acwing.com/problem/content/description/262/ 题意:给定一个队伍,每个人过来的时候可以插队,每个人会输入一个插入到哪个位置,但是 ...

  6. 'Error Domain=NSURLErrorDomain Code=-999' AFNetworking请求报错

    早上请求app请求登录接口发现了下面的错误信息: Error Domain=NSURLErrorDomain Code=-999 "已取消" UserInfo={NSErrorFa ...

  7. 【已转移】【Java架构:基础技术】一篇文章搞掂:SVN

    一个例子: 公司的SVN代码中,含有target等文件夹,每次生成运行后,有很多文件打扰签入 处理方案: 1.CheckOut时,点击ChooseItems选项,不要选择这些target文件夹(有点麻 ...

  8. 20175203 2018-2019-2 实验一《Java开发环境的熟悉》实验报告

    20175203 2018-2019-2 实验一<Java开发环境的熟悉> 实验内容及步骤 使用JDK编译.运行简单的Java程序 此代码较为基础,主要是为了让我们熟悉JDK编程环境及如何 ...

  9. Linux 学习 (五) DNS配置

    没有配置DNS会引起的问题 yum命令 ssh命令等不能进行 错误: Could not resolve host: centos.ustc.edu.cn; 本文例子: CentOS7 下DNS配置 ...

  10. phpredis报错信息:protocol error, got 'o' as reply type byte解决方案

    今天在前端调用PHP的接口时,有报错信息为:protocol error, got 'o' as reply type byte另外此错误有几率会重现,并不是必现的.十分疑惑,遂百度一下,发现是red ...