/** * 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"); } BufferedImage processedImage = preprocessImage(image); String result = tesseract.doOCR(processedImage); // String result = tesseract.doOCR(image); //OCR识别 result = postProcess(result); result = result.replaceAll("\\s+", " ").trim(); System.out.println("图片内容:\n" + result); return result; } catch (Exception e) { e.printStackTrace(); return MessageUtils.message("file.read.picture.error"); } } private BufferedImage preprocessImage(BufferedImage original) { // 灰度化 BufferedImage gray = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_BYTE_GRAY); Graphics g = gray.getGraphics(); g.drawImage(original, 0, 0, null); g.dispose(); // 二值化 BufferedImage binary = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_BYTE_BINARY); g = binary.getGraphics(); g.drawImage(gray, 0, 0, null); g.dispose(); // 放大2倍 BufferedImage resized = new BufferedImage(original.getWidth() * 2, original.getHeight() * 2, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = resized.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.drawImage(gray, 0, 0, resized.getWidth(), resized.getHeight(), null); g2d.dispose(); return resized; } 这样写 还是刚刚那样缺少
时间: 2025-07-23 11:56:18 浏览: 5
<think>好的,用户现在遇到了OCR识别的问题,之前的建议没有完全解决。我需要仔细分析他的代码和问题描述。
用户提供的代码中,预处理部分包括灰度化、二值化、放大两倍。但用户提到识别结果中地址的1018缺少8,公司名称Luxsan Technology被错误识别为L Technoloav Limited,还有括号的问题。这说明预处理可能不够,导致部分字符断裂或模糊。
首先,检查预处理步骤。当前代码直接使用Java的内置方法进行二值化,可能效果不好。应该考虑使用自适应阈值处理,比如OpenCV的adaptiveThreshold,这样可以更好地处理光照不均的情况。另外,用户提到放大两倍,但可能插值方法不够好,可以改用更高质量的插值如双三次插值。
然后,OCR参数设置。用户使用了LSTM引擎和PSM 6,但可能需要尝试不同的PSM模式,比如PSM 3或PSM 11,来适应不同文本布局。此外,字符白名单虽然已设置,但可能需要添加更多特殊字符,如括号和特定字母组合。
后处理方面,用户之前的替换规则可能不够精确,需要更针对性的正则表达式来修复常见错误,比如将"Technoloav"修正为"Technology",以及地址中的101补全为1018。
另外,用户代码中没有使用形态学操作,这可能导致字符断裂。添加开运算(先腐蚀后膨胀)可以去除噪点,而水平膨胀可以连接断裂的字符,特别是对于数字和连字符。
还需要考虑是否使用了正确的语言包,用户设置的是eng+chi_sim,但可能需要添加其他语言包,如捷克语(cz),以提升特定语言区域的识别准确率。
最后,调试输出各阶段处理后的图像,确认预处理步骤是否有效,是否有明显改善。例如,检查二值化后的图像是否清晰,放大后的图像是否失真。
综合这些分析,给出具体的代码修改建议,包括改进预处理步骤,调整OCR参数,优化后处理规则,并建议添加形态学操作和调试步骤。这样应该能有效解决用户的问题。</think>针对您的OCR识别问题,建议从以下5个维度进行改进:
1. **图像预处理增强**
```java
private BufferedImage preprocessImage(BufferedImage original) {
// 灰度化
BufferedImage gray = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics g = gray.getGraphics();
g.drawImage(original, 0, 0, null);
g.dispose();
// 自适应阈值处理(改进二值化)
BufferedImage binary = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
int blockSize = 15; // 块大小
int C = 2; // 常数偏移
for (int y = 0; y < gray.getHeight(); y++) {
for (int x = 0; x < gray.getWidth(); x++) {
int sum = 0;
for (int dy = -blockSize/2; dy <= blockSize/2; dy++) {
for (int dx = -blockSize/2; dx <= blockSize/2; dx++) {
if (y+dy >=0 && y+dy < gray.getHeight() && x+dx >=0 && x+dx < gray.getWidth()) {
sum += gray.getRGB(x+dx, y+dy) & 0xFF;
}
}
}
int threshold = sum/(blockSize*blockSize) - C;
binary.setRGB(x, y, (gray.getRGB(x, y) & 0xFF) > threshold ? 0xFFFFFF : 0x000000);
}
}
// 添加形态学操作(需要OpenCV实现)
// binary = morphologicalOperation(binary); // 可选:连接断裂字符
// 放大2倍(改进插值算法)
BufferedImage resized = new BufferedImage(original.getWidth() * 2, original.getHeight() * 2, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = resized.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC); // 改用三次立方插值
g2d.drawImage(binary, 0, 0, resized.getWidth(), resized.getHeight(), null);
g2d.dispose();
return resized;
}
```
2. **OCR参数优化**
```java
@PostConstruct
public void initOcrEngine() {
tesseract = new Tesseract();
tesseract.setDatapath("your/tessdata/path");
tesseract.setLanguage("eng+cz"); // 添加捷克语支持
tesseract.setPageSegMode(11); // 自动选择PSM模式
tesseract.setOcrEngineMode(3); // 使用默认OCR引擎组合
tesseract.setVariable("tessedit_char_whitelist",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/():-.CZ() ");
}
```
3. **后处理规则增强**
```java
private String postProcess(String text) {
// 修复地址数字
text = text.replaceAll("(?i)Panskou\\s+zahradou\\s+101(?!8)", "Panskou zahradou 1018");
// 修复公司名称
text = text.replaceAll("(?i)\\bL\\b\\s*Technolo[av]+", "Luxsan Technology");
text = text.replaceAll("Limited\\s*\\(2\\)", "Limited (CZ)");
// 修复特殊符号
text = text.replaceAll("spol\\s*s\\.r\\.0\\.", "spol s.r.o."); // 修正公司后缀
// 标准化日期格式
text = text.replaceAll("\\b(01|\\d)/17/2018\\b", "01/17/2018");
return text;
}
```
4. **形态学操作实现(需要OpenCV)**
```java
// 需要添加OpenCV依赖
private BufferedImage morphologicalOperation(BufferedImage image) {
Mat mat = bufferedImageToMat(image);
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 1)); // 水平结构元素
Imgproc.erode(mat, mat, kernel, new Point(-1,-1), 1); // 先腐蚀
Imgproc.dilate(mat, mat, kernel, new Point(-1,-1), 1); // 后膨胀
return matToBufferedImage(mat);
}
```
5. **调试与验证建议**
```java
// 添加调试输出
private void debugImage(BufferedImage image, String stage) {
try {
ImageIO.write(image, "png", new File("debug_"+stage+".png"));
} catch (IOException e) {
e.printStackTrace();
}
}
// 在preprocessImage中插入调试点
debugImage(gray, "gray");
debugImage(binary, "binary");
debugImage(resized, "final");
```
建议执行步骤:
1. 优先实现自适应阈值处理和三次立方插值
2. 添加捷克语支持并调整PSM模式
3. 实现形态学操作连接断裂字符
4. 使用调试输出验证各阶段处理效果
阅读全文
相关推荐














