Java实现OCR识别

日期 版本 作者 说明
2024-10-26 V-1.0 孔留锋 文档新建。

需求

​ 项目需求做身份认证,用户注册时候收集用户手机号、身份证号。用户认证的时候,上传身份证号正反面,对比身份证号基于认证标识。

方案一基于Tesseract+Opencv

​ 思路,基于Tesseract 对身份证进行识别,实际测试识别的效果不是很多,故利用opencv 库对图片预处理,从而提高 Tesseract 的识别准确度。图像预处理通常包括:灰度化、二值化、去噪、旋转和倾斜校正等操作。

  • Tesseract :是一个开源的光学字符识别(OCR,Optical Character Recognition)引擎。它被广泛用于从图像中提取文本,支持多种语言,并且能够处理不同类型的文本图像,包括打印文本、手写文本以及结构化的文档。
  • opencv:(Open Source Computer Vision Library,开源计算机视觉库)是一个开源的计算机视觉和机器学习软件库。它提供了丰富的功能,用于图像处理、视频分析、物体检测、人脸识别、机器学习等任务。OpenCV 是由 Intel 开发并发布的,后续由社区和组织进行维护和扩展。它支持多种编程语言,包括 C++、Python、Java 和 MATLAB/Octave。

Tesseract

官网地址

https://github.com/tesseract-ocr/tesseract

下载地址

https://github.com/UB-Mannheim/tesseract/wiki

安装

安装包:tesseract-ocr-w64-setup-5.5.0.20241111.exe

安装目录可以选择 D:\Mac\ai\tessearct-ocr

点击下一步即可。

语言模型下载

https://tesseract-ocr.github.io/tessdoc/Data-Files.html

下载对应的语言包,下载下来后,移动到安装目录D:\Mac\ai\tessearct-ocr\tessdata 下。

tesseract –list-langs 查看是否识别

命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#参考文档:https://tesseract-ocr.github.io/tessdoc/
#更多帮助
tesseract -h
# 常看版本
tesseract -v
#查看语言模型
tesseract --list-langs
chi_sim 简体中文
chi_tra 繁体中文
eng 英文

#基本语法
tesseract imagename outputbase [-l lang] [--oem ocrenginemode] [--psm pagesegmode] [configfiles...]

# -l 语言
#英语作为默认语言,其他语言数据文件(用于英语)应位于安装目录下 “tessdata” 目录中
# 单独试用中文
-l chi_sim
# 多语言试用
-l chi_sim+eng

# --oem(OCR Engine Mode)用于指定 OCR 引擎的工作模式。
# Tesseract 提供了几种不同的 OCR 引擎模式,以便在不同的场景下优化识别性能。
#值 描述
#0 使用传统的 Tesseract 引擎(基于基于图像的字符识别)。这种模式使用 Tesseract 的传统 OCR 引擎,适合文本比较规整、无噪点的图像。
#1 使用 LSTM(长短期记忆)引擎。这是 Tesseract 在 v4 中引入的神经网络引擎,能够识别复杂的文本和字符,尤其在处理噪声较多或手写文本时表现更好。
#2 使用 Tesseract + LSTM 引擎的组合模式。这种模式将传统的 Tesseract 引擎与 LSTM 引擎结合使用,适合大多数场景,兼顾传统和深度学习模型的优点。
#3 自动选择最合适的引擎。Tesseract 会自动根据图像的特征选择使用传统引擎还是 LSTM 引擎,适用于大多数文档的自动识别。

# --psm (Page segmentation modes:页面分割模式)
# 用于指定 Tesseract 处理页面时如何分割文本区域。不同的模式适用于不同类型的文档布局,从而影响 OCR 的效果。
#值 描述
#0 自动页面分割(默认模式)。这个模式下,Tesseract 自动决定如何分割页面,适用于一般的文本识别任务。
#1 自动页面分割,但不进行 OCR。Tesseract 会尝试自动分割页面,但不会执行实际的 OCR 识别。
#2 自动页面分割,但假设是单列文本。适用于文本格式清晰、每行内容仅占一列的情况。
#3 自动页面分割,但假设是单列文本,并进行 OCR。这个模式假设页面只有一个文本块,因此适合像文章、简报等较为简洁的布局。
#4 假设页面是一个单一的文本块。适用于没有明显分隔的单一文本块的页面。
#5 假设页面是一个单一的文本块,但进行 OCR。与模式 4 相似,但会进行 OCR 识别。适合扫描的页面内容较为整齐的情况。
#6 假设页面是一个单列文本块。适用于只有一列的文本(比如单列的报纸文章、纯文本文件等)。
#7 假设页面是单列文本,并进行 OCR 识别。与模式 6 相似,但会进行 OCR 识别。适用于文档只有一列内容的情况。
#8 假设页面是多列文本。适用于多列报纸或杂志样式的布局。
#9 假设页面是多列文本,并进行 OCR 识别。与模式 8 相似,但会进行 OCR 识别。适用于报纸、杂志等具有多列文本的页面。
#10 单字行(Ocr can output text line by line, useful for recognizing handwritten or handwritten-like text)。适用于每行只有一个字符或字母的情况。
#11 默认的自动页面分割,适用于复杂的文档布局,Tesseract 会自动选择合适的页面分割方式。

#使用 -c preserve_interword_spaces=1 保留空格
tesseract images/toc.png - --psm 6 -c preserve_interword_spaces=1

opencv

官网地址

https://opencv.org

下载地址

https://opencv.org/releases/

安装

安装包:opencv-4.10.0-windows.exe

点击安装即可

1
2
3
4
D:\Mac\ai\opencv\opencv\
├── build\
├── opencv\
└── opencv_contrib\

环境变量配置

1
2
3
4
将 D:\Mac\ai\opencv\opencv\build\x64\vc15\bin 路径添加到系统环境变量 PATH 中
将 D:\Mac\ai\opencv\opencv\build\bin 路径添加到系统环境变量 PATH 中
将 D:\Mac\ai\opencv\opencv\build\java 路径添加到系统环境变量 PATH 中
将 D:\Mac\ai\opencv\opencv\build\java\x64 路径添加到系统环境变量 PATH 中

命令行使用Tesseract

1
2
3
# cmd 进入 D:/data 目录
tesseract b.jpg result -l chi_sim --oem 3 --psm 4
#生成结果文件 D:/data/result.txt 文件打开即可

Java使用Tesseract

POM安装

1
2
3
4
5
 <dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.5.5</version>
</dependency>

Java 使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) {
String IdCardPath = "D:\\data\\b.jpg"
// 创建 Tesseract 实例
ITesseract instance = new Tesseract();
// 设置 Tesseract 数据路径
instance.setDatapath("D:\\Mac\\ai\\tessearct-ocr\\tessdata\\");
// 设置语言(例如简体中文)
instance.setLanguage("chi_sim");
// 设置 OCR 引擎模式
instance.setOcrEngineMode(3);
// 设置分页模式
instance.setPageSegMode(4);
try {
// 识别图片文本
String result = instance.doOCR(new File("IdCardPath"));
System.out.println(result);
} catch (TesseractException e) {
e.printStackTrace();
}
}

Java使用Tesseract+opencv

POM安装

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.5.5</version>
</dependency>

<dependency>
<groupId>org.opencv</groupId>
<artifactId>opencv</artifactId>
<version>4.10.0</version>
</dependency>

Java 使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package com.imalt.ai.api;

import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.awt.image.BufferedImage;

/**
* @author kongliufeng
* @create 2024-12-26
*/
public class TesseractOCR {
static {
// 加载 OpenCV 库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}

/**
* 图像预处理
* @param imagePath 图片路径
* @return 处理后的图像
*/
public static Mat preprocessImage(String imagePath) {
// 读取图片
Mat img = Imgcodecs.imread(imagePath);

// 1. 转为灰度图
Mat gray = new Mat();
Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY);

// 2. 二值化处理
Mat binary = new Mat();
Imgproc.threshold(gray, binary, 0, 255, Imgproc.THRESH_BINARY_INV + Imgproc.THRESH_OTSU);

// 3. 去噪处理(高斯模糊)
Mat denoised = new Mat();
Imgproc.GaussianBlur(binary, denoised, new Size(5, 5), 0);

// 4. 旋转和倾斜校正
Mat rotated = correctTilt(denoised);

return rotated;
}

/**
* 旋转和倾斜校正
* @param img 待处理的图像
* @return 处理后的图像
*/
public static Mat correctTilt(Mat img) {
// 查找图像中的轮廓(找出旋转角度)
Mat edges = new Mat();
Imgproc.Canny(img, edges, 50, 150);

// 找到轮廓
MatOfPoint2f approxCurve = new MatOfPoint2f();
Mat hierarchy = new Mat();
java.util.List<MatOfPoint> contours = new java.util.ArrayList<>();
Imgproc.findContours(edges, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

// 假设轮廓是矩形的,计算旋转角度并校正
double angle = 0.0;
for (MatOfPoint contour : contours) {
RotatedRect rect = Imgproc.minAreaRect(new MatOfPoint2f(contour.toArray()));
angle = rect.angle;
if (Math.abs(angle) > 45) {
angle = 90 - Math.abs(angle);
}
break;
}

// 旋转矩阵
Mat rotated = new Mat();
Point center = new Point(img.width() / 2, img.height() / 2);
Mat rotationMatrix = Imgproc.getRotationMatrix2D(center, angle, 1.0);
Imgproc.warpAffine(img, rotated, rotationMatrix, img.size());

return rotated;
}

/**
* 使用 Tesseract 进行 OCR 识别
* @param processedImage
* @return
*/
public static String recognizeText(Mat processedImage) {
// 将 Mat 转换为 BufferedImage
BufferedImage bufferedImage = matToBufferedImage(processedImage);

// 创建 Tesseract 实例
ITesseract instance = new Tesseract();
// 设置 Tesseract 数据路径
instance.setDatapath("D:\\Mac\\ai\\tessearct-ocr\\tessdata\\");
// 设置语言(例如简体中文)
instance.setLanguage("chi_sim");
// 设置 OCR 引擎模式
instance.setOcrEngineMode(3);
// 设置分页模式
instance.setPageSegMode(4);

try {
// 识别图片文本
String result = instance.doOCR(bufferedImage);
System.out.println(result);
return result;
} catch (TesseractException e) {
e.printStackTrace();
}
return null;
}

/**
* 将 Mat 转换为 BufferedImage
* @param mat Mat 对象
* @return BufferedImage 对象
*/
public static BufferedImage matToBufferedImage(Mat mat) {
// 将 OpenCV Mat 转换为 BufferedImage
int width = mat.width();
int height = mat.height();
int channels = mat.channels();
byte[] sourcePixels = new byte[width * height * channels * 10];
mat.get(0, 0, sourcePixels);

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
image.getRaster().setDataElements(0, 0, width, height, sourcePixels);
return image;
}

public static void main(String[] args) {
String imagePath = "D:\\data\\b.jpg";

// 图像预处理
Mat preprocessedImage = preprocessImage(imagePath);

// 使用 Tesseract 进行 OCR 识别
String result = recognizeText(preprocessedImage);

// 输出结果
System.out.println("识别结果: " + result);
}
}

方案二基于RapidOcr-Java

mymonstercat

官网地址

https://github.com/MyMonsterCat/RapidOcr-Java

简介

POM安装

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>io.github.mymonstercat</groupId>
<artifactId>rapidocr</artifactId>
<version>0.0.7</version>
</dependency>
<dependency>
<groupId>io.github.mymonstercat</groupId>
<artifactId>rapidocr-onnx-platform</artifactId>
<version>0.0.7</version>
</dependency>

Java 使用

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
ParamConfig paramConfig = ParamConfig.getDefaultConfig();
paramConfig.setDoAngle(true);
paramConfig.setMostAngle(true);
InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V4);
OcrResult ocrResult = engine.runOcr( "D:\\data\\b.jpg", paramConfig);
String strRes=ocrResult.getStrRes();
System.out.println(strRes);
}

Linux 环境风险

文档参考

https://github.com/MyMonsterCat/RapidOcr-Java/blob/main/docs/CentOS7.md

Linux环境要求

  • 确保gcc>=9.1.0
  • 确保cmake>=4
  • 确保GLIBC>=2.26

使用建议

  • 建议方案二:简单、方便。