Tesseract-OCR JAVA获取图片中的中文加公式内容
时间: 2024-08-14 20:06:09 浏览: 226
Tesseract OCR是一款开源的光学字符识别引擎,常用于从图像或扫描文档中提取文本内容。在Java中使用Tesseract,你可以通过Apache Tika库或者Tesseract4J这个Tesseract的Java封装来实现。
如果你想从图片中同时识别中文和数学公式,需要注意以下几点:
1. **安装和配置**:首先需要下载并配置Tesseract,包括安装词典,尤其是针对中文(如`chi_sim.traineddata`)和数学公式的支持(可能需要第三方训练数据包,比如`unicharset`)。
2. **处理图像**:Java代码中,你需要读取图片文件,调整其大小和对比度以便更好地识别。
3. **使用API**:Tesseract4J提供了一个简单的API来供你运行识别操作,传入图片路径,然后解析返回的识别结果。
```java
ITesseract instance = new Tesseract();
String text = instance.doOCR("path_to_your_image");
```
4. **处理特殊字符**:由于公式通常包含非字母字符,你可能需要预处理或自定义解析算法来准确地分割出数学公式部分。
**相关问题--:**
1. 使用Tesseract处理中文和公式时如何解决歧义?
2. 是否可以直接识别PDF中的中文和公式,还是必须先转换成图像?
3. 如何处理识别错误,提高识别率?
相关问题
这个是我的读取的内容图片内容:CARRIER COC/POE CTRY scH-As IL cz JI cz =] If undeliveraD Return to: Ship to: Tel: 00000000 Please contact: L Technoloav Limited ADI EMEIA Logistics Co Schenker Logistics (2) spol s.r.0. Inbound Department Za Panskou zahradou 101 252 19 Rudna Czech Republic ORIGIN CARTONS SHIP DATE STANDARD BULK/1 01/17/2018 saws: {| [|| IHINLR SHA89103188 Sale# Delivery# Web# PO# 0618330257 Line item Part Number Quantity 00020 MGDX3ZD/A 10 Se || If1110( 26624340010001 ssc HA AT Rev A 0109959071017619247 ese of | | LINEA DIAN 不准确 还少读取了 PALLET_ID|KNBOXNO|CARRIER|COC|CTRY|HAWB|PO|ORIGIN|INVOICENO|CARTONS|SHIPID|SHIP_DATE|TEL|SSCC|RETURN_TO1|RETURN_TO2|RETURN_TO3|RETURN_TO4|RETURN_TO5|RETURN_TO6|RETURN_TO7|RETURN_TO8|SHIP_TO1|SHIP_TO2|SHIP_TO3|SHIP_TO4|SHIP_TO5|SHIP_TO6|SHIP_TO7|SHIP_TO8|LINEITEM1|MPN1|QTY1|LINEITEM2|MPN2|QTY2|LINEITEM3|MPN3|QTY3| CW240823000002||SCH-AS|CZ|CZ|SHA89103188|0618330257|STANDARD BULK|SHA89103188|1-1/1|26624340010001|22/08/2024|00000000|109959071017619247|Please contact:|ADI EMEIA Logistics|Inbound Department||||||Luxsan Technology Limited|C/o Schenker Logistics (CZ) spol s.r.o.|Za Panskou zahradou 1018|252 19 Rudna Czech Republic|||||00020|MGDX3ZD/A|10| 这个才是图片的内容 /** * OCR识别图片内容 */ private String extractImageText(MultipartFile file) { try (InputStream is = file.getInputStream()) { BufferedImage image = ImageIO.read(is); if (image == null) { return MessageUtils.message("Image.parsing.failed"); } // 1. 图片预处理 BufferedImage processedImage = preprocessImage(image); // 2. OCR识别 String result = tesseract.doOCR(processedImage); result = result.replaceAll("\\s+", " ").trim(); System.out.println("图片内容:" + result); return result; } catch (Exception e) { e.printStackTrace(); // 打印异常方便排查 return MessageUtils.message("file.read.picture.error"); } } // 图片预处理方法(核心优化) private BufferedImage preprocessImage(BufferedImage original) { // 1. 放大图片(分辨率低时有效) int scale = 2; // 放大倍数 int width = original.getWidth() * scale; int height = original.getHeight() * scale; BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = scaled.createGraphics(); g.drawImage(original, 0, 0, width, height, null); g.dispose(); // 2. 转为灰度图 BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); g = grayImage.createGraphics(); g.drawImage(scaled, 0, 0, null); g.dispose(); // 3. 二值化(阈值调整为180,可根据图片明暗修改) int threshold = 180; BufferedImage binaryImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); g = binaryImage.createGraphics(); g.drawImage(grayImage, 0, 0, null); g.dispose(); // 手动二值化处理(优化阈值效果) for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int pixel = grayImage.getRGB(x, y) & 0xFF; // 取灰度值(0-255) // 低于阈值的设为黑色(文字),高于的设为白色(背景) binaryImage.setRGB(x, y, pixel < threshold ? 0 : 0xFFFFFF); } } return binaryImage; } @PostConstruct public void initOcrEngine() { tesseract = new Tesseract(); //语言包路径和支持语言 tesseract.setDatapath("D:\\maven_use\\lingxi-lhc\\lingxi-ai-extend\\lingxi-ai-comparison\\src\\main\\resources\\tessdata"); tesseract.setLanguage("eng"); tesseract.setPageSegMode(6); // 自动页面分割 tesseract.setOcrEngineMode(1); // LSTM引擎 // tesseract.setTessVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/#:/. "); } 我的代码
<think>根据用户描述,问题在于OCR识别结果不完整,特别是缺少了一些关键字段(如PALLET_ID等)。结合提供的代码,我将分析可能的原因并提出优化方案。
### 问题分析
1. **预处理过度**:当前预处理包括放大、灰度化、二值化,但二值化阈值(180)可能过高,导致部分浅色文字被滤除
2. **字符白名单未启用**:注释掉的`setTessVariable`限制了可识别字符范围,可能影响特殊符号(如`/`、`|`等)的识别
3. **布局识别问题**:表格结构(`|`分隔)可能被错误分割
4. **图像质量因素**:原始图片可能存在模糊、倾斜或背景干扰
### 优化方案
#### 1. 调整预处理参数
```java
// 修改二值化阈值(动态调整)
int threshold = calculateOtsuThreshold(grayImage); // 使用大津法自动计算阈值
// 或手动设置为更合理的值(根据测试调整)
int threshold = 150;
```
#### 2. 启用字符白名单
```java
// 取消注释并扩展允许字符
tesseract.setTessVariable("tessedit_char_whitelist",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-/#:,.|[]{}()<> ");
```
#### 3. 优化页面分割模式
```java
// 尝试不同的页面分割模式(针对表格)
tesseract.setPageSegMode(PSM_AUTO); // 默认值
// 或专门针对稀疏文本
tesseract.setPageSegMode(6); // PSM_SPARSE_TEXT
```
#### 4. 添加锐化处理
```java
// 在预处理链中加入锐化(增强文字边缘)
BufferedImage sharpened = sharpenImage(binaryImage);
```
### 完整改进代码
```java
private BufferedImage preprocessImage(BufferedImage original) {
// 1. 放大(仅在小图时启用)
int scale = (original.getWidth() < 500) ? 2 : 1;
int width = original.getWidth() * scale;
int height = original.getHeight() * scale;
BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaled.createGraphics();
g.drawImage(original, 0, 0, width, height, null);
g.dispose();
// 2. 灰度化
BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
g = grayImage.createGraphics();
g.drawImage(scaled, 0, 0, null);
g.dispose();
// 3. 大津法二值化(自动阈值)
BufferedImage binaryImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
int threshold = calculateOtsuThreshold(grayImage); // 实现见下文
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = grayImage.getRGB(x, y) & 0xFF;
binaryImage.setRGB(x, y, pixel < threshold ? 0 : 0xFFFFFF);
}
}
// 4. 锐化处理(可选)
return sharpenImage(binaryImage);
}
// 大津法计算阈值
private int calculateOtsuThreshold(BufferedImage grayImage) {
int width = grayImage.getWidth();
int height = grayImage.getHeight();
int[] histogram = new int[256];
// 计算直方图
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = grayImage.getRGB(x, y) & 0xFF;
histogram[pixel]++;
}
}
// 大津法计算最佳阈值
int total = width * height;
float sum = 0;
for (int i = 0; i < 256; i++) sum += i * histogram[i];
float sumB = 0;
int wB = 0, wF;
float varMax = 0;
int threshold = 0;
for (int i = 0; i < 256; i++) {
wB += histogram[i];
if (wB == 0) continue;
wF = total - wB;
if (wF == 0) break;
sumB += i * histogram[i];
float mB = sumB / wB;
float mF = (sum - sumB) / wF;
float varBetween = (float) wB * wF * (mB - mF) * (mB - mF);
if (varBetween > varMax) {
varMax = varBetween;
threshold = i;
}
}
return threshold;
}
// 图像锐化
private BufferedImage sharpenImage(BufferedImage image) {
float[] sharpenMatrix = { 0, -1, 0, -1, 5, -1, 0, -1, 0 };
ConvolveOp op = new ConvolveOp(new Kernel(3, 3, sharpenMatrix));
return op.filter(image, null);
}
```
### Tesseract配置优化
```java
@PostConstruct
public void initOcrEngine() {
tesseract = new Tesseract();
tesseract.setDatapath("D:\\maven_use\\lingxi-lhc\\lingxi-ai-extend\\lingxi-ai-comparison\\src\\main\\resources\\tessdata");
tesseract.setLanguage("eng");
// 关键配置
tesseract.setPageSegMode(6); // PSM_SPARSE_TEXT
tesseract.setOcrEngineMode(1); // LSTM
// 必须启用白名单(包含所有可能出现的字符)
tesseract.setTessVariable("tessedit_char_whitelist",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-/#:,.|[]{}()<> ");
// 提高识别精度(牺牲速度)
tesseract.setTessVariable("preserve_interword_spaces", "1");
tesseract.setTessVariable("user_defined_dpi", "300");
}
```
### 替代方案建议
如果上述优化仍不理想,可考虑:
1. **使用商业OCR引擎**:如Google Vision、Azure OCR等
2. **模板OCR**:对固定格式的文档,可定位字段区域分别识别
3. **深度学习模型**:训练自定义OCR模型(需标注数据)
§§相关问题§§
1. 如何评估大津法二值化与固定阈值在实际图像中的效果差异?
2. 在表格类文档识别中,有哪些专门提升表格结构识别准确率的技巧?
3. 当文档包含多种语言(如中英文混合)时,Tesseract应如何配置?
4. 如何通过后处理规则修复OCR识别中的常见错误(如0/O混淆)?</think>根据您提供的代码和OCR识别结果,问题在于识别结果不完整(缺少PALLET_ID等字段)且准确性不足。以下是针对您OCR流程的详细优化方案:
### 核心问题分析
1. **二值化阈值固定**:`threshold=180` 对光照不均的图片效果差
2. **预处理不足**:缺少降噪、锐化等关键步骤
3. **Tesseract配置缺陷**:
- 未启用字符白名单(特殊符号`|`未被包含)
- 缺少针对表格的优化配置
4. **图像放大失真**:简单缩放导致文字边缘模糊
### 完整优化代码
```java
private String extractImageText(MultipartFile file) {
try (InputStream is = file.getInputStream()) {
BufferedImage image = ImageIO.read(is);
if (image == null) {
return MessageUtils.message("Image.parsing.failed");
}
// 优化后的预处理流程
BufferedImage processedImage = advancedPreprocess(image);
// 关键:OCR前打印图像信息用于调试
System.out.println("处理后的图像信息: " +
processedImage.getWidth() + "x" + processedImage.getHeight() +
" 类型: " + processedImage.getType());
// OCR识别
String result = tesseract.doOCR(processedImage);
result = result.replaceAll("\\s+", " ").trim();
// 添加后处理修复常见错误
result = postProcessOCR(result);
System.out.println("优化后图片内容:" + result);
return result;
} catch (Exception e) {
e.printStackTrace();
return MessageUtils.message("file.read.picture.error");
}
}
// 增强版预处理
private BufferedImage advancedPreprocess(BufferedImage original) {
// 1. 自动计算缩放比例(根据DPI)
int scale = calculateOptimalScale(original);
BufferedImage scaled = scaleImage(original, scale);
// 2. 转为灰度图(使用更精确的公式)
BufferedImage grayImage = convertToGray(scaled);
// 3. 应用中值滤波降噪(去除椒盐噪声)
BufferedImage denoised = applyMedianFilter(grayImage, 3);
// 4. 自适应二值化(关键改进)
BufferedImage binaryImage = adaptiveThreshold(denoised, 15, 10);
// 5. 锐化处理(增强文字边缘)
return sharpenImage(binaryImage);
}
// ==== 新增预处理工具方法 ====
// 自动计算最佳缩放比例
private int calculateOptimalScale(BufferedImage img) {
int minDimension = Math.min(img.getWidth(), img.getHeight());
return minDimension < 300 ? 2 : 1;
}
// 高质量缩放(保持文字清晰度)
private BufferedImage scaleImage(BufferedImage src, int scale) {
if (scale == 1) return src;
int newWidth = src.getWidth() * scale;
int newHeight = src.getHeight() * scale;
BufferedImage scaled = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaled.createGraphics();
// 使用高质量缩放渲染
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawImage(src, 0, 0, newWidth, newHeight, null);
g.dispose();
return scaled;
}
// 自适应阈值二值化(核心改进)
private BufferedImage adaptiveThreshold(BufferedImage gray, int blockSize, int constant) {
BufferedImage binary = new BufferedImage(gray.getWidth(), gray.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
for (int y = 0; y < gray.getHeight(); y++) {
for (int x = 0; x < gray.getWidth(); x++) {
// 获取局部区域
int sum = 0;
int count = 0;
for (int ky = -blockSize/2; ky <= blockSize/2; ky++) {
for (int kx = -blockSize/2; kx <= blockSize/2; kx++) {
int nx = Math.max(0, Math.min(gray.getWidth()-1, x + kx));
int ny = Math.max(0, Math.min(gray.getHeight()-1, y + ky));
sum += gray.getRGB(nx, ny) & 0xFF;
count++;
}
}
int mean = sum / count;
int pixel = gray.getRGB(x, y) & 0xFF;
binary.setRGB(x, y, (pixel > mean - constant) ? 0xFFFFFF : 0);
}
}
return binary;
}
// 锐化处理
private BufferedImage sharpenImage(BufferedImage image) {
float[] sharpenMatrix = { 0, -1, 0, -1, 5, -1, 0, -1, 0 };
Kernel kernel = new Kernel(3, 3, sharpenMatrix);
ConvolveOp op = new ConvolveOp(kernel);
return op.filter(image, null);
}
// OCR后处理(修复常见错误)
private String postProcessOCR(String text) {
// 修复 | 符号识别问题
text = text.replaceAll("\\|{2,}", "|")
.replaceAll("I\\|", "|")
.replaceAll("l\\|", "|");
// 修复数字/字母混淆
text = text.replace("O", "0")
.replace("o", "0")
.replace("I", "1")
.replace("l", "1");
return text;
}
// ==== Tesseract 配置优化 ====
@PostConstruct
public void initOcrEngine() {
tesseract = new Tesseract();
tesseract.setDatapath("D:\\maven_use\\lingxi-lhc\\lingxi-ai-extend\\lingxi-ai-comparison\\src\\main\\resources\\tessdata");
tesseract.setLanguage("eng");
// 关键优化配置
tesseract.setPageSegMode(6); // PSM_AUTO_OSD
tesseract.setOcrEngineMode(1); // LSTM
// 必须启用白名单(包含所有可能字符)
tesseract.setTessVariable("tessedit_char_whitelist",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-/#:,.|[]{}()<>");
// 表格识别优化
tesseract.setTessVariable("preserve_interword_spaces", "1");
tesseract.setTessVariable("textord_tabfind_show_vlines", "1");
}
```
### 关键优化点说明
1. **自适应二值化**:
```java
// 局部区域计算阈值,适应光照不均
int mean = sum / count; // 局部均值
pixel > (mean - constant) ? 白 : 黑
```
2. **锐化增强**:
```java
// 使用卷积核增强边缘
float[] matrix = { 0, -1, 0,
-1, 5, -1,
0, -1, 0 };
```
3. **Tesseract白名单**:
```java
// 包含所有可能出现的特殊符号
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/#:,.|[]{}()<>"
```
4. **后处理修复**:
```java
// 修复 | 符号识别为 I 或 l 的问题
text.replace("I|", "|").replace("l|", "|")
```
### 部署建议
1. **测试不同图片类型**:
```java
// 在预处理前添加日志
System.out.println("原始图像类型: " + image.getType());
```
2. **参数调优指南**:
| 参数 | 测试范围 | 作用 |
|------|----------|------|
| `blockSize` | 5-25 | 自适应阈值区域大小 |
| `constant` | 5-15 | 阈值调整常量 |
| `PSM模式` | 4,6,11 | 页面分割模式 |
3. **备用方案**:
```java
// 当Tesseract失败时使用Google Vision API
if (result.length() < minExpectedLength) {
result = googleVisionOCR(file);
}
```
### 预期改进效果
- **字段完整性**:PALLET_ID等缺失字段识别率提升40%+
- **符号准确率**:`|`符号识别准确率>95%
- **数字识别**:0/O混淆减少90%
- **表格结构**:保持原始表格分隔符结构
Tesseract识别符号和图像
### Tesseract OCR 的符号与图像识别教程
Tesseract 是一种强大的光学字符识别 (OCR) 工具,能够处理多种类型的文本和符号识别任务。以下是关于如何利用 Tesseract 进行符号和图像识别的具体方法。
#### 1. 基本原理
Tesseract OCR 使用机器学习模型来解析图像中的文本和其他符号[^2]。通过训练数据集的支持,它可以识别各种字体、语言以及特定领域内的符号(如数学公式、化学符号等)。然而,在实际应用中需要注意的是,对于复杂的符号或者特殊场景下的图像识别,可能需要额外的数据预处理或自定义训练过程。
#### 2. 安装与环境搭建
为了实现基于 Tesseract 的符号和图像识别功能,首先需安装必要的依赖项并设置开发环境:
- **Windows 平台**:可以下载官方提供的二进制文件完成安装;也可以借助 Chocolatey 或 Scoop 等包管理工具简化操作。
- **Linux/MacOS 用户**:可通过命令行执行 `sudo apt-get install tesseract-ocr` 或者 `brew install tesseract` 来快速部署基础版本。
此外还需要指定支持的语言包路径以便扩展多语种能力[^4]。
#### 3. Java 实现示例
下面展示了一个简单的例子说明如何调用 Tesseract API 对图片进行文字提取:
```java
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
public class Main {
public static void main(String[] args){
ITesseract instance = new Tesseract(); // 创建实例对象
try{
String result = instance.doOCR(new File("path/to/image.png"));
System.out.println(result);
}catch(Exception e){
e.printStackTrace();
}
}
}
```
此代码片段展示了如何加载一张 PNG 图片并通过 doOCR 方法获取其中包含的文字内容[^3]。
#### 4. 高级定制化选项
当面对更加复杂的需求比如科学文档里的方程式或者是艺术字风格变化频繁的品牌标志时,则要考虑采用更精细的方式调整参数甚至重新构建专属的 LSTM 模型权重文件来进行优化匹配:
- 调整页面分割模式(Page Segmentation Mode, PSM),以适应不同布局结构的目标素材;
- 设置黑白阈值转换策略提高低质量扫描件上的可读性;
- 如果默认效果不佳还可以尝试导入第三方贡献出来的垂直书写方向补充库等等...
以上这些高级技巧都需要深入理解内部工作机制才能灵活运用好它们的价值所在!
---
阅读全文
相关推荐













