工作关系,这一周对ocr进行了一下研究。这里进行一下总结
目前主流的技术有:1、tesseract-ocr
2、sikulix(其底层是tesseract-ocr,只是他的封装用起来很方便)
3、百度-ocr
在这里比较一下他们各自的优缺点和使用场景。
一、tesseract-ocr
tesseract-ocr 主要用来解决英语,数字的文字识别。从3.0开始才加入中文,它对中文的支持相当的不靠谱。如果要用它来识别中文的话,业务场景需要被识别的图片中的文字有相当的规律。因为它提供了训练的功能,可以让ocr不断进行学习。所以也可以用来处理简单的干扰不大的数字加字母的验证码。他还有一个有点是,不需要任何网络请求,直接可以在本机进行处理。最后,他是开源的。
环境搭建:需要安装tesseract-ocr,然后引入jai_imageio.jar和javacsv.jar。
java demo代码,其实原理很简单,通过cmd调用命令即可
private final static String LANG_OPTION = "-l"; //英文字母小写l,并非数字1
private final static String EOL = System.getProperty("line.separator");
private final static String tessPath = "C:\\Program Files (x86)\\Tesseract-OCR";
public static String getString(File imageFile, String imageFormat) throws Exception {
//File tempImage = ImgUtil.createImage(imageFile,imageFormat);
File outputFile = new File(imageFile.getParentFile(),"output");
StringBuffer strB = new StringBuffer();
List cmd = new ArrayList();
if(OS.isWindowsXP()){
cmd.add(tessPath+"//tesseract");
}else if(OS.isLinux()){
cmd.add("tesseract");
}else{
cmd.add(tessPath+"//tesseract");
}
cmd.add("");
cmd.add(outputFile.getName());
cmd.add(LANG_OPTION);
cmd.add("eng");
//cmd.add("eng");
ProcessBuilder pb = new ProcessBuilder();
pb.directory(imageFile.getParentFile());
cmd.set(1, imageFile.getAbsolutePath());
pb.command(cmd);
pb.redirectErrorStream(true);
Process process = pb.start();
System.out.println(cmd);
//tesseract.exe 1.jpg 1 -l chi_sim
int w = process.waitFor();
//删除临时正在工作文件
//tempImage.delete();
imageFile.delete();
if(w==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 recongnize the image or its selected region.";
break;
case 31:
msg = "Unsupported image format.";
break;
default:
msg = "Errors occurred.";
}
//tempImage.delete();
imageFile.delete();
throw new RuntimeException(msg);
}
new File(outputFile.getAbsolutePath()+".txt").delete();
return strB.toString();
}
1、将需要用来训练的图片转换为tif格式,文件名改为[语言]
2、生成box文件 调用命令tesseract.exe eng.normal.exp0.tif eng.normal.exp0 -l eng batch.nochop makebox
4、纠正完后进行保存,将会保存box文件。
5、进行训练,调用命令tesseract.exe eng.normal.exp0.tif eng.normal.exp0 nobatch box.train
6、生成tr文件,可以批量指定box文件,调用命令 unicharset_extractor.exe eng.normal.exp0.box eng.normal.exp1.box
7、创建字体设置文件,font_properties,内容为 字体名 0 0 0 0 0,比如normal 0 0 0 0 0
8、生成unicharset文件,可以批量指定tr文件,调用命令mftraining.exe -F font_properties -U unicharset -O eng.unicharset eng.normal.exp0.tr eng.normal.exp1.tr
9、生成关键文件,可以批量指定tr文件,调用命令cntraining.exe eng.normal.exp0.tr eng.normal.exp1.tr
10、将生成的inttemp、pffmtable、normproto、shapetable文件修改文件名,加入前缀"字体名."
11、合并成语言包文件,调用命令combine_tessdata 语言名
二、sikulix
sikulix由于底层使用的是tesseract-ocr,所以优缺点都是一样的,sikulix相比于tesseract-ocr来说,优点在于封装了方便的api,而且提供了截图功能,并且直接采用字节流,不用创建文件。最后,它也是开源的。
关于sikulix使用tesseract-ocr的功能可以看我之前写的篇文章http://blog.csdn.net/guduyishuai/article/details/78331862,我就不赘述了。
三、百度-ocr
百度-ocr基于百度强大的人工智能,百度大脑,因此非常可靠。对于中文的识别也是相当精准的,同时提供了多种语言,包括android移动端的sdk,相当的方便。它的缺点是必须有网络,而且不是开源的,每天超过500次调用将收费。
我之前使用过android、和http api的方式,都很简单。这里来说一下python的方式,因为坑还是比较多的。
python版本提供了基于python2.7+和python3.+版本的模块。这里插一句,python2和python3的差异性很大,而且不兼容,这就造成很多人的机子上两个版本都有,这时候在pip的时候要注意是使用哪个版本的。
有两个方式来区分版本,方式一:修改python.exe文件名。方式二:使用py -2/-3 -m 命令。
我这里是使用python3.4版本来进行pip的,于是坑开始了。
首先,遇到了这个错误
这个错误实际上是python的一个bug,解决方案就是升级相应的安装工具
注意,不要用阿里的镜像,因为目前为止,阿里的镜像还没有更新最新的版本
最后就可以成功地调用pip获取百度的api了
到此为止,可以写相应的python代码了。如果最后能成功执行,就ok了。但是很可能还缺少不少模块,这时候就根据报错信息进行pip,我把我遇到的记录一下
在安装image时要注意,它提示的模块是PLT,而且很可能安装失败,这个时候需要重新安装pillow
下面我们来看一下python的demo
#! /usr/local/bin/python
# encoding: utf-8
'''
Created on 2017年9月26日
@author: wulinfeng
@date: 2017-09-30
'''
import sys
from aip import AipOcr
APP_ID = '你的APP_ID'
API_KEY = '你的API_KEY'
SECRET_KEY = '你的SECRET_KEY'
aipOcr = AipOcr(APP_ID, API_KEY, SECRET_KEY)
# 读取图片
def get_file_content(filePath):
with open(filePath, 'rb') as fp:
return fp.read()
# data = ''
# file = open(filePath)
# try:
# data = file.read()
# finally:
# file.close()
# return data
def cognize_text(filePath):
result = aipOcr.basicAccurate(get_file_content(filePath));
return result
# 调用通用文字识别接口
print(cognize_text(sys.argv[1]))
到目前为止jython还不支持python3,而且使用中非常不方便,而且也有一些坑。最新版的jython-2.7.0可能会报错如下
这必须在java中进行设置,python.import.site=false
static {
Properties props = new Properties();
props.put("python.home", "path to the Lib folder");
props.put("python.console.encoding", "UTF-8");
props.put("python.security.respectJavaAccessibility", "false");
props.put("python.import.site", "false");
Properties preprops = System.getProperties();
PythonInterpreter.initialize(preprops, props, new String[0]);
}
然后,还有一个坑是jython的环境路径和python并不是统一的,所以单独能运行的python脚本,并不能在java中调用成功,会报错,说某些module找不到,这时候需要执行sys的相关函数来进行设置
PythonInterpreter interpreter = new PythonInterpreter();
PySystemState sys = Py.getSystemState();
interpreter.exec("import sys");
interpreter.exec("sys.path.append('C:/Python34/Lib')");
interpreter.exec("sys.path.append('C:/Python34/Lib/site-packages')");
interpreter.exec("from aip import AipOcr");
如果是python2.7+,name就可以用如下的方法
public static String callFunction(String file, String fnName, String ... args) {
try {
PythonInterpreter interpreter = new PythonInterpreter();
PySystemState sys = Py.getSystemState();
interpreter.exec("import sys");
interpreter.exec("sys.path.append('C:/Python34/Lib')");
interpreter.exec("sys.path.append('C:/Python34/Lib/site-packages')");
interpreter.exec("from aip import AipOcr");
interpreter.execfile(PythonUtil.getUrl(file));
PyFunction func = (PyFunction)interpreter.get(fnName,PyFunction.class);
PyString[] ps = new PyString[args.length];
for(int i=0; i
PythonUtil.callFunction(Resource.PYTHON_BAIDU_OCR, "cognize_text", "D:/test666.png");
public static String execScript(String file, String ... args) {
StringBuffer result = new StringBuffer();
try {
StringBuffer cmd = new StringBuffer();
cmd.append("python "+file);
Arrays.asList(args)
.stream()
.forEach(arg -> {
cmd.append(" "+arg);
});
logger.log(Level.INFO, "cmd="+cmd.toString());
Process pr = Runtime.getRuntime().exec(cmd.toString());
BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream(), Charset.forName("GBK")));
String line = "";
while ((line = in.readLine()) != null) {
result.append(line);
}
in.close();
pr.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
return result.toString();
}
PythonUtil.execScript(PythonUtil.getUrl(Resource.PYTHON_BAIDU_OCR), "D:/test666.png");