这两天研究了一下关于OCR图文解析的技术。当然市场上已经有开源服务,比如百度的AI开放平台,就有OCR相关的API接口。我这里选用的是Tesseract开源框架,java封装版本是tess4j。结合网上公布的一些开源项目提供的demo,完成了身份证与营业执照的相关文字识别的处理。总体上来讲Tesseract其实还不错,简单应用其实还挺简单的(提供的图片质量可以靠前端做好限制,比如身份证识别,加上头像或国徽的框图限定,能提高识别率)。

  示例项目地址:https://github.com/git-simm/simm-framework

一、技术介绍

OCR(Optical Character Recognition):光学字符识别,是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程。

Tesseract:开源的OCR识别引擎,初期Tesseract引擎由HP实验室研发,后来贡献给了开源软件业,后由Google进行改进、修改bug、优化,重新发布。


  Tess4J:是对Tesseract OCR API.的Java JNA 封装。使java能够通过调用Tess4J的API来使用Tesseract OCR。支持的格式:TIFF,JPEG,GIF,PNG,BMP,JPEG,and PDF

Tess4J API 提供的功能:
1、直接识别支持的文件
2、识别图片流
3、识别图片的某块区域
4、将识别结果保存为 TEXT/ HOCR/ PDF/ UNLV/ BOX
5、通过设置取词的等级,提取识别出来的文字
6、获得每一个识别区域的具体坐标范围
7、调整倾斜的图片
8、裁剪图片
9、调整图片分辨率
10、从粘贴板获得图像
11、克隆一个图像(目的:创建一份一模一样的图片,与原图在操作修改上,不相 互影响)
12、图片转换为二进制、黑白图像、灰度图像
13、反转图片颜色

、环境准备(https://www.jianshu.com/p/ef60ef5395c5)

  2.1、我们需要安装tessdata语言包,用于图文识别。 tesseract-ocr语言包的下载地址,用于识别文字时进行匹配。链接: https://pan.baidu.com/s/1XAvPkTdUXuFq-q2InDREhQ 提取码: 6vjp

    

  2.2、项目引入maven依赖

<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.5.2</version>
</dependency>

、简单描述下图文解析的过程

  

、服务端关键代码的展示

private static int targetBrightness = 260;
private static int targetDifferenceValue = 15; /**
* 解析身份证信息
*
* @param inputStream
* @return
* @throws Exception
*/
@Override
public BizLicenseInfo getInfo(InputStream inputStream) throws Exception {
BizLicenseInfo bizLicenseInfo = new BizLicenseInfo();
String rootPath = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/tmp";
Tesseract tesseract = new Tesseract();
tesseract.setLanguage("chi_sim");
//读取网络图片
BufferedImage bufferedImage = ImageFilter.cloneImage(ImageIO.read(inputStream));
//不过滤部分颜色
//bufferedImage = ImageFilter.imageRGBDifferenceFilter(bufferedImage, targetDifferenceValue, null);
bufferedImage = ImageFilter.convertImageToGrayScale(bufferedImage);
//缩放到真实身份证大小
bufferedImage = ImageFilter.imageScale(bufferedImage, 3150, 1920);
try (OutputStream outputStream = new FileOutputStream(rootPath+"/bg.jpg")) {
saveImg(bufferedImage,outputStream);
getBufferedNameImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/nameImageBefore.jpg");
getBufferedCapitalImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/capitalImageBefore.jpg");
getBufferedBizTypeImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/bizTypeImageBefore.jpg");
getBufferedBuildOnImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/buildOnImageBefore.jpg");
getBufferedJuridicalImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/juridicalImageBefore.jpg");
getBufferedBizLimitImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/bizLimitImageBefore.jpg");
getBufferedBizScopeImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/bizScopeImageBefore.jpg");
getBufferedAddressImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/addressImageBefore.jpg");
getBufferedCreditCodeImage(tesseract, bufferedImage, bizLicenseInfo,rootPath+"/creditCodeImageBefore.jpg");
return bizLicenseInfo;
}catch (Exception e){
e.printStackTrace();
throw e;
}
}

/**
* 获取统一社会信用代码
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
* @throws IOException
* @throws TesseractException
*/
private void getBufferedCreditCodeImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
try (OutputStream outputStream = new FileOutputStream(path)) {
BufferedImage idImage = ImageFilter.subImage(bufferedImage, bufferedImage.getMinX() + 200
, 250, 550, 300);
System.out.println("creditCodeImage 辉度处理");
handBrightness(idImage, targetBrightness);
saveImg(idImage, outputStream);
// tesseract.setLanguage("eng");
tesseract.setLanguage("chi_sim");
// \W 可以配置 非字母和数字,等价于 [^a-zA-Z0-9] (\d \D 小写表示匹配数字,大写表示匹配非数字)
String idCardNumber = tesseract.doOCR(idImage).replaceAll("[\\W]", "");
bizLicenseInfo.setCreditCode(idCardNumber);
}catch (Exception e){
e.printStackTrace();
throw e;
}
} /**
* 获取名称
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
*/
private void getBufferedNameImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
BufferedImage buffered = ImageFilter.subImage(bufferedImage, 520, 700, 1200, 120);
getBufferedImage(tesseract,buffered,path,(img,content)->{
System.out.println("setName 辉度处理");
bizLicenseInfo.setName(content);
});
}
/**
* 获取类型
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
* @throws IOException
* @throws TesseractException
*/
private void getBufferedBizTypeImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
BufferedImage buffered = ImageFilter.subImage(bufferedImage, 520, 820, 1200, 130);
getBufferedImage(tesseract,buffered,path,(img,content)->{
System.out.println("setBizType 辉度处理");
bizLicenseInfo.setBizType(content);
});
}
/**
* 获取法人信息
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
* @throws IOException
* @throws TesseractException
*/
private void getBufferedJuridicalImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
BufferedImage buffered = ImageFilter.subImage(bufferedImage, 520, 950, 1200, 120);
getBufferedImage(tesseract,buffered,path,(img,content)->{
System.out.println("setJuridical 辉度处理");
bizLicenseInfo.setJuridical(content);
});
} /**
* 获取经营范围
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
* @throws IOException
* @throws TesseractException
*/
private void getBufferedBizScopeImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
BufferedImage buffered = ImageFilter.subImage(bufferedImage, 520, 1070, 1330, bufferedImage.getHeight() - 1200);
getBufferedImage(tesseract,buffered,path,(img,content)->{
System.out.println("setBizScope 辉度处理");
bizLicenseInfo.setBizScope(content);
});
} /**
* 获取注册资本
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
* @throws IOException
* @throws TesseractException
*/
private void getBufferedCapitalImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
BufferedImage buffered = ImageFilter.subImage(bufferedImage, 2170, 720, bufferedImage.getWidth()-2400, 120);
getBufferedImage(tesseract,buffered,path,(img,content)->{
System.out.println("setCapital 辉度处理");
bizLicenseInfo.setCapital(content);
});
} /**
* 获取成立日期
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
* @throws IOException
* @throws TesseractException
*/
private void getBufferedBuildOnImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
BufferedImage buffered = ImageFilter.subImage(bufferedImage, 2170, 850, bufferedImage.getWidth()-2400, 100);
getBufferedImage(tesseract,buffered,path,(img,content)->{
System.out.println("setBuildOn 辉度处理");
bizLicenseInfo.setBuildOn(content);
});
} /**
* 获取营业期限
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
* @throws IOException
* @throws TesseractException
*/
private void getBufferedBizLimitImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
BufferedImage buffered = ImageFilter.subImage(bufferedImage, 2170, 970, bufferedImage.getWidth()-2400, 100);
getBufferedImage(tesseract,buffered,path,(img,content)->{
System.out.println("setBizLimit 辉度处理");
bizLicenseInfo.setBizLimit(content);
});
} /**
* 获取住所
* @param tesseract
* @param bufferedImage
* @param bizLicenseInfo
* @param path
* @throws IOException
* @throws TesseractException
*/
private void getBufferedAddressImage(Tesseract tesseract, BufferedImage bufferedImage, BizLicenseInfo bizLicenseInfo, String path) throws IOException, TesseractException {
BufferedImage buffered = ImageFilter.subImage(bufferedImage, 2170, 1070, bufferedImage.getWidth()-2240, 270);
getBufferedImage(tesseract,buffered,path,(img,content)->{
System.out.println("setAddress 辉度处理");
bizLicenseInfo.setAddress(content);
});
}
/**
* 获取名称
* @param tesseract
* @param buffered
* @param path
* @param consumer
*/
private void getBufferedImage(Tesseract tesseract, BufferedImage buffered, String path, BiConsumer<BufferedImage,String> consumer) throws IOException, TesseractException {
try (OutputStream outputStream = new FileOutputStream(path)) {
// addressImage = ImageFilter.imageScale(addressImage, ((int) (addressImage.getWidth() * 2.4) + 1), ((int) (addressImage.getHeight() * 2.4) + 1));
handBrightness(buffered, targetBrightness);
saveImg(buffered, outputStream);
tesseract.setLanguage("chi_sim");
String result = tesseract.doOCR(buffered);
//留下中文字符、中文标点符号()【】、
String regexStr = "[^\\s\\u4e00-\\u9fa5\\(\\)\\uff08\\uff09\\u3001\\u3010\\u3011\\-0-9]+";
String content = result.replaceAll(regexStr, "")
.replaceAll("\\n", "")
.replaceAll(" ", "");
if(consumer!=null){
consumer.accept(buffered,content);
}
}catch (Exception e){
e.printStackTrace();
throw e;
}
}
/**
* 保存图片
* @param image
* @param outputStream
* @throws IOException
*/
private void saveImg(BufferedImage image,OutputStream outputStream) throws IOException {
ImageIO.write(image, "jpg", outputStream);
}
/**
* 处理图片辉度
*
* @param subImage
*/
private void handBrightness(BufferedImage subImage, int targetBrightness) {
int fixedBrightness;
int birthBrightness = ImageFilter.imageBrightness(subImage);
System.out.println("brightness = " + birthBrightness);
fixedBrightness = targetBrightness - birthBrightness;
//辉度处理
if (fixedBrightness != 0) {
subImage = ImageFilter.imageBrightness(subImage, fixedBrightness);
}
System.out.println("after brightness = " + ImageFilter.imageBrightness(subImage));
}

、解析效果展示

  5.1、身份证信息识别示例:

  

  5.2、营业执照信息识别示例:

  

参考资料:

https://github.com/firefoxmmx2/IDCardIDentify

https://www.jianshu.com/p/e7915ba6f0e7

https://kefeng.wang/2017/04/22/tess4j/

使用tess4j完成身份证和营业执照图片的文字识别的更多相关文章

  1. 电脑端的全能扫描王:图片转文字识别、识别pdf、图片中的文字,图片提取txt

    手机中有全能扫描王,但PC端没有.所以需要另外找. 发现微软的oneNode有提供类似的功能. 第一步.下载Microsoft OneNode http://www.onenote.com/downl ...

  2. 用百度AI的OCR文字识别结合JAVA实现了图片的文字识别功能

    第一步可定要获取百度的三个东西 要到百度AI网站(http://ai.baidu.com/)去注册 然后获得 -const APP_ID = '请填写你的appid'; -const API_KEY ...

  3. JAVA的图片文字识别技术

    从2013年的记录看,JAVA中图片文字识别技术大部分采用ORC的tesseract的软件功能,后来渐渐开放了java-api调用接口. 图片文字识别技术,还是采用训练的方法.并未从根本上解决图片与文 ...

  4. 刚破了潘金莲的身份信息(图片文字识别),win7、win10实测可用(免费下载)

    刚破了潘金莲的身份信息(图片文字识别),win7.win10实测可用 效果如下: 证照,车牌.身份证.名片.营业执照 等图片文字均可识别 电脑版 本人出品 大小1.3MB 下载地址:https://p ...

  5. 腾讯云OCR图片文字识别

    一. OCR OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然后用字符识别 ...

  6. 百度OCR文字识别-身份证识别

    简介 一.介绍 身份证识别 API 接口文档地址:http://ai.baidu.com/docs#/OCR-API/top 接口描述 用户向服务请求识别身份证,身份证识别包括正面和背面. 请求说明 ...

  7. Android ORC文字识别之识别身份证号等(附源码)

    项目地址https://github.com/979451341/OrcTest 我们说说实现这个项目已实现的功能,能够截图手机界面的某一块,将这个某一块图片的Bitmap传给tess-two的代码来 ...

  8. Delphi百度文字识别【支持通用文字识别、身份证识别、银行卡识别、驾驶证识别、行驶证识别、车牌识别等功能】

    作者QQ:(648437169) 点击下载➨Delphi百度文字识别          百度api文档 [Delphi百度文字识别]支持 通用文字识别.通用文字识别(高精度版).通用文字识别(含位置信 ...

  9. 基于Tesseract实现图片文字识别

    一.简介  Tesseract是一个开源的文本识别[OCR]引擎,可通过Apache 2.0许可获得.它可以直接使用,或者使用API从图像中提取打印的文本,支持多种语言.该软件包包含一个ORC引擎[l ...

随机推荐

  1. 安装fiddler 谷歌插件

    移动 .crx 插件无法安装问题 解决方案: 修改后缀名为 .zip 文件 进行解压后,使用浏览器扩展程序加载已解压的文件进行扩展 添加插件 2020-06-20

  2. Python os.lchflags() 方法

    概述 os.lchflags() 方法用于设置路径的标记为数字标记,类似 chflags(),但是没有软链接.高佣联盟 www.cgewang.com 只支持在 Unix 下使用. 语法 lchfla ...

  3. PHP password_verify() 函数

    password_verify() 函数用于验证密码是否和散列值匹配. PHP 版本要求: PHP 5 >= 5.5.0, PHP 7高佣联盟 www.cgewang.com 语法 bool p ...

  4. PHP unpack() 函数

    实例 从二进制字符串对数据进行解包: <?php$data = "PHP";print_r(unpack("C*",$data));?>高佣联盟 w ...

  5. PHP substr_replace() 函数

    实例 把 "Hello" 替换成 "world": <?php高佣联盟 www.cgewang.comecho substr_replace(" ...

  6. 使用pdf.js实现前端页面预览pdf文档,解决了跨域请求

    pdf.js主要包含两个库文件,一个pdf.js和一个pdf.worker.js,,一个负责API解析,一个负责核心解析 官网地址:http://mozilla.github.io/pdf.js/ 下 ...

  7. C/C++编程笔记:C语言入门知识点(一),请收藏C语言最全笔记!

    C语言简介 C 语言是一种通用的高级语言,最初是由丹尼斯·里奇在贝尔实验室为开发 UNIX 操作系统而设计的.C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现. 原文链接: ...

  8. JAVA设计模式 5【结构型】代理模式的理解与使用

    今天要开始我们结构型 设计模式的学习,设计模式源于生活,还是希望能通过生活中的一些小栗子去理解学习它,而不是为了学习而学习这些东西. 结构型设计模式 结构型设计模式又分为 类 结构型 对象 结构型 前 ...

  9. Python实现图片滑动式验证识别

    1 abstract 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的知识.那么针对这三类 ...

  10. Java日志框架(二)

    最流行的日志框架解决方案 按笔者理解,现在最流的日志框架解决方案莫过于SLF4J + LogBack.其有以下几个优点: LogBack 自身实现了 SLF4J 的日志接口,不需要 SLF4J 去做进 ...