Tesseract5.4.0自定义LSTM训练

准备jTessBoxEditor,然后配置环境变量。

1、将图片转换成tif格式的,这里需要用画图工具另存为;

2、生成box文件

执行命令:

tesseract agv.normal.exp1.tif agv.normal.exp1 -l eng --psm 6 batch.nochop makebox

关于box文件的生成,对于Tesseract3可以使用makebox,但是对于Tesseract的lstm训练,需要使用lstmbox。否则再后面会报如下的错误。

生成lstmbox的命令如下:

D:\agvtest2>tesseract agv.normal.exp1.tif agv.normal.exp1 -l eng lstmbox

关于PSM的说明

0 = 仅方向和脚本检测 (OSD)。

1 = 自动页面分割,带 OSD。

2 = 自动页面分割,但无 OSD 或 OCR。(未执行)

3 = 完全自动页面分割,但无 OSD。(默认值)

4 = 假设一列文字大小可变。

5 = 假定垂直对齐的单个统一文本块。

6 = 假定单个统一的文本块。

7 = 将图像视为单一文本行。

8 = 将图像视为单个单词。

9 = 将图像视为圆圈中的单个单词。

10 = 将图像视为单个字符。

11 = 文本稀疏。不按特定顺序查找尽可能多的文本。

12 = 带 OSD 的稀疏文本。

13 = 原始行。将图像视为单行文本、

3、校正box文件中的信息

使用jTessBoxEditor打开tif文件。执行train.bat,打开jTexxBoxEditor.jar

校正完成后,一定要点保存。如下

关于box文件的内容,这里需要注意。它与tessera

<think>好的,用户之前已经尝试过我的建议但效果不佳,现在需要进一步帮助。首先,我需要回顾之前的对话,了解用户的问题和提供的解决方案。用户提到OCR识别时,图片内容与其他元素紧挨着导致错误,之前的回复中我提供了字符级分割、形态学处理以及参数调整等方法,但用户反馈无效。 现在用户再次提问,说明之前的方案没有解决他的问题。我需要更深入分析可能的原因。可能用户遇到的粘连情况比较复杂,或者预处理步骤不够彻底。例如,连通域分析可能没有正确分割某些粘连字符,或者形态学操作参数需要调整。此外,OCR的参数设置可能仍不理想,比如PSM模式或OCR引擎模式选择不当。 接下来,我需要考虑其他可能的解决方案。例如,使用投影分析来分割字符,或者采用更复杂的分割算法如分水岭算法。另外,可能需要调整二值化的阈值,或者使用不同的结构元素进行形态学操作。还可以建议用户检查图像分辨率,因为低分辨率可能导致字符粘连更严重。 另外,用户可能没有正确应用提供的代码,或者图像有特殊噪声需要不同的预处理步骤。例如,某些情况下需要先去除表格线或背景噪声,再进行字符分割。或者用户的图像中存在倾斜,需要先进行透视矫正。 还需要考虑用户的代码实现是否有误。例如,在增加间距时是否正确计算了新图像的尺寸,或者保存的调试图像是否确实显示了预期的处理效果。用户可能没有正确集成代码,或者某些步骤被遗漏。 此外,Tesseract训练数据可能不适用于用户的特定字体,建议用户进行自定义训练。或者,用户需要更精确地调整OCR参数,如设置字符白名单、调整页面分割模式等。 最后,可能需要建议用户尝试其他OCR引擎或工具,如Google Keep、Adobe Scan等,或者结合深度学习模型如CNN进行字符分割和识别。 总结来说,用户需要更全面的解决方案,可能包括改进预处理、调整OCR参数、验证中间结果、甚至使用替代工具。需要分步骤指导用户逐一排查问题,并提供具体的代码调整和验证方法。</think>根据您反馈的“效果不佳”问题,我们需要系统性地排查并优化处理流程。以下是 **深度优化方案**,包含 **图像预处理增强**、**字符分割优化** 和 **OCR 参数调优** 三部分: --- ### 🔍 问题深度分析(关键矛盾点) | 问题层级 | 具体表现 | 修复方向 | |---------|----------|----------| | **图像预处理不足** | 粘连字符未完全断开、噪声干扰 | 增加投影分析 + 自适应二值化 | | **字符分割失败** | 连通域分析误判粘连区域 | 改用投影分析 + 分水岭算法 | | **OCR 参数不匹配** | LSTM 模式对特定字体效果差 | 切换 OCR 引擎模式 + 添加白名单 | | **图像分辨率过低** | 小字符模糊导致分割失败 | 图像超分放大 + 边缘增强 | --- ### ✅ 终极修复方案(分步骤优化) #### 1. **增强预处理(自适应二值化 + 投影分析)** ```java // 自适应二值化(比固定阈值更鲁棒) public static BufferedImage adaptiveBinarize(BufferedImage image, int windowSize, double k) { int width = image.getWidth(); int height = image.getHeight(); BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); // 计算积分图 long[][] integral = new long[height+1][width+1]; for (int y=0; y<height; y++) { long rowSum = 0; for (int x=0; x<width; x++) { int gray = (image.getRGB(x, y) >> 16) & 0xFF; rowSum += gray; integral[y+1][x+1] = integral[y][x+1] + rowSum; } } // 自适应阈值计算 for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { int window = Math.min(Math.min(x, y), windowSize/2); int x1 = Math.max(0, x - window); int y1 = Math.max(0, y - window); int x2 = Math.min(width-1, x + window); int y2 = Math.min(height-1, y + window); int area = (x2 - x1) * (y2 - y1); long sum = integral[y2+1][x2+1] - integral[y1][x2+1] - integral[y2+1][x1] + integral[y1][x1]; double mean = sum / (double)area; double threshold = mean * (1 + k*( (y - height/2)/ (double)height )); int gray = (image.getRGB(x, y) >> 16) & 0xFF; result.setRGB(x, y, gray < threshold ? 0 : 0xFFFFFF); } } return result; } ``` #### 2. **投影分析分割粘连字符** ```java // 水平投影分析(检测字符间隔) public static List<int[]> horizontalProjection(BufferedImage image) { int width = image.getWidth(); int height = image.getHeight(); int[] projection = new int[height]; for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { if ((image.getRGB(x, y) & 0xFF) < 0x80) projection[y]++; } } // 寻找字符行边界 List<int[]> textLines = new ArrayList<>(); boolean inText = false; int startY = 0; for (int y=0; y<height; y++) { if (projection[y] > 0 && !inText) { startY = y; inText = true; } else if (projection[y] == 0 && inText) { textLines.add(new int[]{startY, y}); inText = false; } } return textLines; } // 垂直投影分析(分割单个字符) public static List<int[]> verticalProjection(BufferedImage image, int startY, int endY) { int width = image.getWidth(); int[] projection = new int[width]; for (int x=0; x<width; x++) { for (int y=startY; y<endY; y++) { if ((image.getRGB(x, y) & 0xFF) < 0x80) projection[x]++; } } List<int[]> charRegions = new ArrayList<>(); boolean inChar = false; int startX = 0; for (int x=0; x<width; x++) { if (projection[x] > 0 && !inChar) { startX = x; inChar = true; } else if (projection[x] == 0 && inChar) { charRegions.add(new int[]{startX, x}); inChar = false; } } return charRegions; } ``` #### 3. **OCR 参数调优(关键修正)** ```java private String extractImageText(MultipartFile file) { try (InputStream is = file.getInputStream()) { BufferedImage image = ImageIO.read(is); if (image == null) return "Image read failed"; // 多阶段预处理 image = adaptiveBinarize(image, 15, 0.15); // 自适应二值化 image = enhanceEdges(image); // 边缘增强 image = removeLines(image); // 移除表格线干扰 // 投影分析分割 List<int[]> lines = horizontalProjection(image); List<Rectangle> charRegions = new ArrayList<>(); for (int[] line : lines) { List<int[]> chars = verticalProjection(image, line[0], line[1]); for (int[] c : chars) { charRegions.add(new Rectangle(c[0], line[0], c[1]-c[0], line[1]-line[0])); } } // 添加间距并重组图像 image = addSpacingBetweenCharacters(image, charRegions, 15, 15); saveDebugImage(image, "final_processed.png"); // OCR 参数优化 tesseract.setPageSegMode(7); // 单行文本模式 tesseract.setOcrEngineMode(1); // LSTM + 传统混合模式 tesseract.setVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"); // 白名单 String result = tesseract.doOCR(image); return postProcess(result); } catch (Exception e) { e.printStackTrace(); return "Error"; } } ``` --- ### 🛠️ 关键参数调优建议 | 参数 | 推荐值 | 说明 | |------|--------|------| | `tessedit_char_whitelist` | 根据文本内容限定 | 极大提升识别准确率 | | `tess_psm_config_only` | 7(单行文本) | 避免自动分割干扰 | | `image_resolution` | ≥ 300 DPI | 低分辨率会导致粘连 | | `morphology_kernel_size` | 3x3 十字形 | 调整结构元素大小 | --- ### 🧪 验证步骤 1. **检查调试图像**: - 打开 `final_processed.png` 验证字符是否完全断开 - 使用图像编辑器测量字符间距是否大于 `15px` 2. **手动测试 Tesseract 命令行**: ```bash tesseract final_processed.png stdout -c tessedit_char_whitelist="0123456789" --psm 7 -c load_system_dawg=false ``` > 关键参数说明:`load_system_dawg=false` 可避免词典干扰单字符识别 3. **日志输出验证**: ```java System.out.println("检测到字符数量: " + charRegions.size()); System.out.println("最终图像尺寸: " + image.getWidth() + "x" + image.getHeight()); ``` --- ### 🚫 常见失败场景修复 | 现象 | 诊断 | 修复方案 | |------|------|----------| | **字符仍粘连** | 投影分析未正确分割 | 增加 `removeLines()` 步骤移除干扰线 | | **识别结果错位** | 间距添加计算错误 | 检查 `addSpacingBetweenCharacters` 的坐标逻辑 | | **小字符模糊** | 图像分辨率不足 | 添加超分放大(如 `imgscalr` 库放大2x) | | **特定字符错误** | 字体不在训练数据中 | 使用 [jTessBoxEditor](https://github.com/sriyegna/jtessboxtool) 训练自定义字体 | --- ### 📦 依赖建议 ```xml <!-- 图像增强推荐依赖 --> <dependency> <groupId>org.imgscalr</groupId> <artifactId>imgscalr-lib</artifactId> <version>4.2</version> </dependency> <!-- Tesseract 最新版 --> <dependency> <groupId>net.sourceforge.tess4j</groupId> <artifactId>tess4j</artifactId> <version>5.4.0</version> </dependency> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值