Tess4J简介

Tesseract-OCR支持中文识别,并且开源和提供全套的训练工具,是快速低成本开发的首选。而Tess4J则是Tesseract在Java PC上的应用。在英文和数字识别中性能还是不错的,但是在中文识别中,无论速度还是识别率还是较弱,建议有条件的话,针对场景进行训练,会获得较好结果。
项目地址:https://github.com/tesseract-ocr
语言包下载地址:https://github.com/tesseract-ocr/tessdata

Demo

下面附上我自己的测试过程:
(1)新建一个SpringBoot工程,我用的版本是2.5.10。
(2)后端相关类和配置:

1、引入pom.xml配置:

Maven依赖

        <!-- ocr -->
        <dependency>
            <groupId>net.sourceforge.tess4j</groupId>
            <artifactId>tess4j</artifactId>
            <version>5.0.0</version>
        </dependency>
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna-platform</artifactId>
            <version>5.11.0</version>
        </dependency>

2、相关Utils工具类:

ImgFileUtils

package com.ocr.utils;

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

public class ImgFileUtils {
    
    /**
     * 存为PNG格式
     */
    public static void saveToFile(BufferedImage subimage, File file) throws IOException {
        ImageIO.write(subimage, "png", file);
    }
    
    /** 
     * 存为PNG格式 
     */
    public static void saveAsPNG(BufferedImage subimage, File file) throws IOException {
        ImageIO.write(subimage, "png", file);
    }
    
    /** 
     * 存为JPEG格式图像文件 
     */
    public static void saveAsJPEG(BufferedImage subimage, File file) throws IOException {
        ImageIO.write(subimage, "JPEG", file);
    }
    
    /** 
     * 写入一个OutputStream 
     */
    public static void write(BufferedImage subimage, OutputStream out) throws IOException {
        ImageIO.write(subimage, "png", out);
    }
    
}


ImgUtils

package com.ocr.utils;

import java.awt.image.BufferedImage;

public class ImgUtils {
    
    /**
     * 裁剪图片:去掉黑边
     */
    public static BufferedImage clipImage(BufferedImage srcImage) {
        return srcImage.getSubimage(8, 5, srcImage.getWidth() - 20, srcImage.getHeight() - 10);
    }
    
    /**
     * 灰度化
     */
    public static BufferedImage grayImage(BufferedImage srcImage) {
        return copyImage(srcImage, new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY));
    }
    
    /**
     * 二值化
     */
    public static BufferedImage binaryImage(BufferedImage srcImage) {
        return copyImage(srcImage, new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_BINARY));
    }
    
    public static BufferedImage copyImage(BufferedImage srcImage, BufferedImage destImage) {
        for (int y = 0; y < srcImage.getHeight(); y++) {
            for (int x = 0; x < srcImage.getWidth(); x++) {
                destImage.setRGB(x, y, srcImage.getRGB(x, y));
            }
        }
        
        return destImage;
    }
    
}


OCRUtils

package com.ocr.utils;

import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;

import java.awt.image.BufferedImage;
import java.io.File;

public class OCRUtils {
    
    public static String DEFAULT_LANG="eng";
    public static String DATA_PATH="D:/temp/test_data/";
    
    /**
     * 根据图片文件进行识别
     * 
     * @param imageFile 图片文件
     * @param lang 指定语言库
     * @return 识别文本信息
     */
    public static String doOCRFromFile(File imageFile,String lang) throws Exception {
        ITesseract instance = new Tesseract();
        instance.setDatapath(DATA_PATH); //指定语言库目录 
        instance.setTessVariable("user_defined_dpi", "300");
        instance.setLanguage(lang);
        String result = instance.doOCR(imageFile);
        return result;
    }
    
    public static String doOCRFromFile(File imageFile) throws Exception {
        return doOCRFromFile(imageFile,DEFAULT_LANG);
    }
    
    /**
     * 根据图片流进行识别
     */
    public static String doOCRFromImgBuffer(BufferedImage bufferedImage,String lang) throws Exception {
        ITesseract instance = new Tesseract();
        instance.setDatapath(DATA_PATH);
        instance.setTessVariable("user_defined_dpi", "300");
        instance.setLanguage(lang);
        String result = instance.doOCR(bufferedImage);
        
        return result;
    }
    
    public static String doOCRFromImgBuffer(BufferedImage bufferedImage) throws Exception {
        return doOCRFromImgBuffer(bufferedImage,DEFAULT_LANG);
    }
    
}


WindowsUtils

package com.ocr.utils;

import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.RECT;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;

public class WindowsUtils {
    
    /**
     * 截图:指定屏幕区域 
     * 参数为截图左上角坐标(x1,y1)+右下角坐标(x2,y2)
     */
    public static BufferedImage captureImg(int x1, int y1, int x2, int y2) throws Exception {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Rectangle screenRectangle = new Rectangle(screenSize);
        Robot robot = new Robot();
        BufferedImage image = robot.createScreenCapture(screenRectangle);
        BufferedImage subimage = image.getSubimage(x1, y1, x2, y2);
        return subimage;
    }
    
    /**
     * 截图:指定窗口(使用AWT)
     */
    public static BufferedImage captureWindowAndActive(HWND hWnd) throws AWTException, IOException {
        RECT r = new RECT();
        Rectangle rect;
        User32.INSTANCE.GetWindowRect(hWnd, r);
        User32.INSTANCE.ShowWindow(hWnd, User32.INSTANCE.SW_SHOWNORMAL); //如果最小化,恢复显示
        User32.INSTANCE.SetForegroundWindow(hWnd); //激活显示
        rect = r.toRectangle();
        Robot robot = new Robot();
        BufferedImage image = robot.createScreenCapture(rect);
        return image;
    }
    
}

3、测试Demo

Demo

package com.ocr;

import com.ocr.utils.ImgFileUtils;
import com.ocr.utils.ImgUtils;
import com.ocr.utils.OCRUtils;
import com.ocr.utils.WindowsUtils;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;

import java.io.File;

public class DemoOCR {
    private static String WIN_TITLE="测试OCR.txt - 记事本";
    private static String PICTURE_PATH = System.getProperty("user.dir")+"/picture";

    /**
     * 测试OCR:指定窗口截图&OCR识别
     */
    public static void testCapture() throws Exception {
        // 截图保存的路径
        File imgFile = new File(PICTURE_PATH + "/capture.png");
        if (!imgFile.getParentFile().exists()) {
            imgFile.getParentFile().mkdirs();
        }

        // 第一个参数是Windows窗体的窗体类,第二个参数是窗体的标题。
        WinDef.HWND hWnd = User32.INSTANCE.FindWindow(null, WIN_TITLE);
        System.out.println("找到窗体:"+hWnd);

        if(hWnd==null){
            System.out.println("未找到窗口");
        }else{
            // 保存截图
            ImgFileUtils.saveAsPNG(ImgUtils.clipImage(WindowsUtils.captureWindowAndActive(hWnd)), imgFile); //Active解决有些窗口截图不正常
            //String ocrRs = OCRUtils.doOCRFromFile(imgFile);
            String ocrRs = OCRUtils.doOCRFromImgBuffer(ImgUtils.clipImage(ImgUtils.grayImage(WindowsUtils.captureWindowAndActive(hWnd)))); // 灰化效果
            System.out.println("识别窗体文本信息:"+ocrRs); //OCR识别,图像转文本。
        }
    }

    /**
     * main method
     */
    public static void main(String[] args) {
        System.out.println("OCR文字识别已启动!");
        try {
            //设置训练库的位置
            OCRUtils.DATA_PATH=System.getProperty("user.dir")+"/config";
            OCRUtils.DEFAULT_LANG="chi_sim"; //eng :英文  chi_sim :简体中文

            //测试OCR:指定窗口截图&OCR识别
            WIN_TITLE="测试OCR.txt - 记事本"; //用记事本打开测试文本
            testCapture();

            //测试识别图片
            String ocrText = OCRUtils.doOCRFromFile(new File(PICTURE_PATH+"/capture1.png")); // 灰化效果
            System.out.println("识别文本信息:"+ocrText); //OCR识别,图像转文本

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


在项目根目录新建两个文件夹:
1.picture用于存放用于识别的图片;
2.config用来存放你下载的语言包;

最后修改:2022 年 04 月 11 日
给我一点小钱钱也很高兴啦!o(* ̄▽ ̄*)ブ