java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot图片OCR文字识别

SpringBoot集成Tess4J实现图片OCR文字识别

作者:bst@微胖子

本教程详细介绍了如何在SpringBoot项目项目中集成TesseractOCR引擎进行图片文字识别,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

一、环境准备

1.安装Tesseract OCR 引擎

2.下载语言数据包(tessdata)

Tesseract 需要语言数据包才能识别特定语言。你需要下载chi_sim.traineddata(简体中文)和eng.traineddata(英文) 等文件。

重要:路径中不要包含中文或空格。 将这些文件放在一个固定的目录中,

例如:D:/tessdata (Windows) 或 /usr/local/share/tessdata(Linux/macOS)。

二、Maven项目依赖引入(pom.xml)

在你的pom.xml文件中添加 Tess4J 的依赖。如果你使用的是 Spring Boot 3 (JDK 17+),建议使用 4.5.6 或更高版本以获得更好的兼容性。

<dependencies>
    <!-- Tess4J 依赖 -->
    <dependency>
        <groupId>net.sourceforge.tess4j</groupId>
        <artifactId>tess4j</artifactId>
        <version>5.3.0</version> <!-- 推荐使用较新版本 -->
    </dependency>
</dependencies>

三、配置Tess4J

创建一个配置类,将Tesseract 实例定义为 Spring Bean,方便在项目中注入使用。通过配置文件来管理数据路径和识别语言,使配置更灵活。

1.配置文件(application.yml)

tess4j:
  data-path: D:/tessdata # 替换为你存放语言数据包的绝对路径
  language: chi_sim+eng # 设置识别语言,chi_sim为中文,eng为英文

2.Tesseract配置类(TesseractConfig.java)

package com.example.ocr.config;

import net.sourceforge.tess4j.Tesseract;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
publicclass TesseractConfig {

    @Value("${tess4j.data-path}")
    private String dataPath;

    @Value("${tess4j.language}")
    private String language;

    @Bean
    public Tesseract tesseract() {
        Tesseract tesseract = new Tesseract();
        tesseract.setDatapath(dataPath); // 设置tessdata目录路径
        tesseract.setLanguage(language); // 设置识别语言
        return tesseract;
    }
}

四、核心代码

接下来创建Service和Controller来提供图片识别功能。

1.服务层(OcrService.java)

该服务负责接收图片文件,并将其转换为BufferedImage后交给Tesseract处理。

package com.example.ocr.service;

import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;

@Service
publicclass OcrService {

    privatefinal Tesseract tesseract;

    public OcrService(Tesseract tesseract) {
        this.tesseract = tesseract;
    }

    /**
     * 识别图片中的文字
     * @param imageFile 上传的图片文件
     * @return 识别出的文本
     */
    public String recognizeText(MultipartFile imageFile) throws IOException, TesseractException {
        // 将 MultipartFile 转换为 BufferedImage
        BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageFile.getBytes()));
        if (image == null) {
            thrownew IOException("无法读取图片,请检查图片格式是否支持 (如PNG, JPG)");
        }
        // 调用 Tesseract 进行识别
        return tesseract.doOCR(image);
    }
}

2.接口层OcrController

提供一个 REST 接口,用于接收前端上传的图片并返回识别结果。

package com.example.ocr.controller;

import com.example.ocr.service.OcrService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("/ocr")
publicclass OcrController {

    privatefinal OcrService ocrService;

    public OcrController(OcrService ocrService) {
        this.ocrService = ocrService;
    }

    @PostMapping("/recognize")
    public String recognizeImage(@RequestParam("file") MultipartFile file) throws Exception {
        return ocrService.recognizeText(file);
    }
}

五、扩展识别精度优化

Tesseract 的识别效果与图片质量密切相关。通过预处理图片可以显著提升识别准确率。

图像预处理: 在调用doOCR之前,可以对BufferedImage进行以下处理:

1. 基础预处理类

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class ImagePreprocessor {
    
    /**
     * 灰度化处理
     */
    public static BufferedImage grayScale(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();
        BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
        
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb = image.getRGB(x, y);
                int r = (rgb >> 16) & 0xff;
                int g = (rgb >> 8) & 0xff;
                int b = rgb & 0xff;
                
                // 使用加权平均法,人眼对绿色最敏感
                int gray = (int) (0.299 * r + 0.587 * g + 0.114 * b);
                int newPixel = (gray << 16) | (gray << 8) | gray;
                grayImage.setRGB(x, y, newPixel);
            }
        }
        return grayImage;
    }
    
    /**
     * 二值化处理(Otsu算法)
     */
    public static BufferedImage binary(BufferedImage image) {
        BufferedImage grayImage = grayScale(image);
        int width = grayImage.getWidth();
        int height = grayImage.getHeight();
        BufferedImage binaryImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
        
        // 计算灰度直方图
        int[] histogram = new int[256];
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int gray = grayImage.getRGB(x, y) & 0xff;
                histogram[gray]++;
            }
        }
        
        // Otsu算法计算最佳阈值
        float sum = 0;
        for (int i = 0; i < 256; i++) {
            sum += i * histogram[i];
        }
        
        float sumB = 0;
        int wB = 0;
        int wF = 0;
        float varMax = 0;
        int threshold = 0;
        
        int total = width * height;
        for (int t = 0; t < 256; t++) {
            wB += histogram[t];
            if (wB == 0) continue;
            
            wF = total - wB;
            if (wF == 0) break;
            
            sumB += t * histogram[t];
            float mB = sumB / wB;
            float mF = (sum - sumB) / wF;
            
            float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);
            if (varBetween > varMax) {
                varMax = varBetween;
                threshold = t;
            }
        }
        
        // 应用阈值
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int gray = grayImage.getRGB(x, y) & 0xff;
                int newPixel = (gray > threshold) ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
                binaryImage.setRGB(x, y, newPixel);
            }
        }
        return binaryImage;
    }
    
    /**
     * 降噪处理(领域检测法)
     */
    public static BufferedImage denoise(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();
        BufferedImage denoisedImage = new BufferedImage(width, height, image.getType());
        
        // 边界处理
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                denoisedImage.setRGB(x, y, image.getRGB(x, y));
            }
        }
        
        // 降噪核心算法
        for (int y = 1; y < height - 1; y++) {
            for (int x = 1; x < width - 1; x++) {
                if (isBlack(image.getRGB(x, y))) {
                    int blackCount = 0;
                    
                    // 检查周围8个像素
                    if (isBlack(image.getRGB(x-1, y-1))) blackCount++;
                    if (isBlack(image.getRGB(x, y-1))) blackCount++;
                    if (isBlack(image.getRGB(x+1, y-1))) blackCount++;
                    if (isBlack(image.getRGB(x-1, y))) blackCount++;
                    if (isBlack(image.getRGB(x+1, y))) blackCount++;
                    if (isBlack(image.getRGB(x-1, y+1))) blackCount++;
                    if (isBlack(image.getRGB(x, y+1))) blackCount++;
                    if (isBlack(image.getRGB(x+1, y+1))) blackCount++;
                    
                    // 如果周围黑色像素少于5个,则认为是噪点
                    if (blackCount < 5) {
                        denoisedImage.setRGB(x, y, Color.WHITE.getRGB());
                    } else {
                        denoisedImage.setRGB(x, y, image.getRGB(x, y));
                    }
                } else {
                    denoisedImage.setRGB(x, y, image.getRGB(x, y));
                }
            }
        }
        return denoisedImage;
    }
    
    /**
     * 调整DPI(通过缩放实现)
     */
    public static BufferedImage adjustDPI(BufferedImage image, int targetDPI) {
        int width = image.getWidth();
        int height = image.getHeight();
        int currentDPI = 72; // 默认DPI
        
        // 计算缩放比例
        double scale = (double) targetDPI / currentDPI;
        int newWidth = (int) (width * scale);
        int newHeight = (int) (height * scale);
        
        BufferedImage scaledImage = new BufferedImage(newWidth, newHeight, image.getType());
        for (int y = 0; y < newHeight; y++) {
            for (int x = 0; x < newWidth; x++) {
                int srcX = (int) (x / scale);
                int srcY = (int) (y / scale);
                if (srcX < width && srcY < height) {
                    scaledImage.setRGB(x, y, image.getRGB(srcX, srcY));
                }
            }
        }
        return scaledImage;
    }
    
    /**
     * 设置PSM模式
     */
    public static void setPSM(ITesseract tesseract, String mode) {
        tesseract.setTessVariable("tessedit_pageseg_mode", mode);
    }
    
    // 辅助方法
    private static boolean isBlack(int color) {
        Color c = new Color(color);
        return (c.getRed() + c.getGreen() + c.getBlue()) <= 300;
    }
    
    private static boolean isWhite(int color) {
        Color c = new Color(color);
        return (c.getRed() + c.getGreen() + c.getBlue()) > 300;
    }
}

2. 完整OCR处理流程

import net.sourceforge.tess4j.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

public class OCRProcessor {
    
    public static String recognizeText(File imageFile) {
        try {
            // 读取图像
            BufferedImage image = ImageIO.read(imageFile);
            
            // 1. 灰度化
            BufferedImage grayImage = ImagePreprocessor.grayScale(image);
            
            // 2. 二值化
            BufferedImage binaryImage = ImagePreprocessor.binary(grayImage);
            
            // 3. 降噪
            BufferedImage denoisedImage = ImagePreprocessor.denoise(binaryImage);
            
            // 4. 调整DPI到300
            BufferedImage highDPIImage = ImagePreprocessor.adjustDPI(denoisedImage, 300);
            
            // 5. 初始化Tesseract
            ITesseract tesseract = new Tesseract();
            tesseract.setDatapath("C:/Program Files/Tesseract-OCR/tessdata");
            tesseract.setLanguage("eng"); // 或 "chi_sim" 用于中文
            
            // 6. 设置PSM模式
            // PSM 6: 假设单行文本
            // PSM 7: 假设文本在单个 uniform 块中
            // PSM 3: 完全自动页面分割,但适合具有明显文本区域的页面
            ImagePreprocessor.setPSM(tesseract, "6");
            
            // 7. 执行OCR
            String result = tesseract.doOCR(highDPIImage);
            return result.trim();
            
        } catch (Exception e) {
            e.printStackTrace();
            return "识别失败: " + e.getMessage();
        }
    }
    
    public static void main(String[] args) {
        String imagePath = "your_image.jpg";
        String result = recognizeText(new File(imagePath));
        System.out.println("识别结果: " + result);
    }
}

 到此这篇关于SpringBoot集成Tess4J实现图片OCR文字识别的文章就介绍到这了,更多相关SpringBoot图片OCR文字识别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文