使用Java实现OCR图片文字识别(Tesseract-OCR)

2019-05-07 17:29 阅读 343 次 评论 0 条

使用Tesseract-OCR这个工具需要在本地安装OCR工具:

下面一个是一定要安装的离线包,建议默认安装

上面一个是中文的语言包,如果网络可以FQ的童鞋可以在安装的时候就选择语言包在线安装,有多种语言可供选择,默认只有英文的

exe安装好之后,把上面一个文件拷到安装目录下tessdata文件夹下

如C:\Program Files (x86)\Tesseract-OCR\tessdata下

然后下面两个是可选包,如果图片不做临时文件处理的话,可以不需要带的。

首先是一个临时文件生成用的类以防源文件损坏

package org.ink.image.textrz;

import java.awt.image.BufferedImage;  
import java.io.File;  
import java.io.IOException;  
import java.util.Iterator;  
import java.util.Locale;  
  
import javax.imageio.IIOImage;  
import javax.imageio.ImageIO;  
import javax.imageio.ImageReader;  
import javax.imageio.ImageWriteParam;  
import javax.imageio.ImageWriter;  
import javax.imageio.metadata.IIOMetadata;  
import javax.imageio.stream.ImageInputStream;  
import javax.imageio.stream.ImageOutputStream;  
  
import com.sun.media.imageio.plugins.tiff.TIFFImageWriteParam;  
  
public class ImageIOHelper {
    private Locale locale=Locale.CHINESE;
    /**
     * user set locale Construct
     * @param locale
     */
    public ImageIOHelper(Locale locale){
        this.locale=locale;
    }
    
    /**
     * default construct using default locale Locale.CHINESE
     */
    public ImageIOHelper(){
        
    }
    /**
     * create tempFile of Image in order to prevent damaging original file
     * @param imageFile
     * @param imageFormat like png,jps .etc
     * @return TempFile of Image
     * @throws IOException
     */
    public File createImage(File imageFile, String imageFormat) throws IOException {    
        Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(imageFormat);    
        ImageReader reader = readers.next();    
        ImageInputStream iis = ImageIO.createImageInputStream(imageFile);    
        reader.setInput(iis);    
        IIOMetadata streamMetadata = reader.getStreamMetadata();    
        TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(Locale.CHINESE);    
        tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);    
        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("tiff");    
        ImageWriter writer = writers.next();    
        BufferedImage bi = reader.read(0);    
        IIOImage image = new IIOImage(bi,null,reader.getImageMetadata(0));    
        File tempFile = tempImageFile(imageFile);    
        ImageOutputStream ios = ImageIO.createImageOutputStream(tempFile);    
        writer.setOutput(ios);    
        writer.write(streamMetadata, image, tiffWriteParam);    
        ios.close();
        iis.close();
        writer.dispose();    
        reader.dispose();    
        return tempFile;    
    }    
    /**
     * add suffix to tempfile
     * @param imageFile
     * @return
     * @throws IOException 
     */
    private File tempImageFile(File imageFile) throws IOException {    
        String path = imageFile.getPath();    
        StringBuffer strB = new StringBuffer(path);    
        strB.insert(path.lastIndexOf('.'),"_text_recognize_temp");
        String s=strB.toString().replaceFirst("(?<=//.)(//w+)$", "tif");
        Runtime.getRuntime().exec("attrib "+"\""+s+"\""+" +H"); //设置文件隐藏
        return new File(strB.toString()); 
    }    
}

下面是真正识别的内容:

package org.ink.image.textrz;

import java.io.BufferedReader;    
import java.io.File;    
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;    
import java.util.ArrayList;    
import java.util.List;
import java.util.Locale;

import org.jdesktop.swingx.util.OS;    

/**
 * TEXT Recognize Utils
 * @author ink.Flower
 *
 */
public class OCRUtil { 
    private final String LANG_OPTION = "-l";  //英文字母小写l,并非数字1    
    private final String EOL = System.getProperty("line.separator");    
    private String tessPath = "C://Program Files (x86)//Tesseract-OCR";//ocr默认安装路径
    private String transname="chi_sim";//默认中文语言包,识别中文
    
    /**
     * Construct method of OCR ,set Tesseract-OCR install path
     * @param tessPath Tesseract-OCR install path
     * @param transFileName traningFile name like eng.traineddata
     */
    public OCRUtil(String tessPath,String transFileName){
        this.tessPath=tessPath;
        this.transname=transFileName;
    }
    /**
     * Construct method of OCR,default path is "C://Program Files (x86)//Tesseract-OCR"
     */
    public OCRUtil(){     }
    
    public String getTessPath() {
        return tessPath;
    }
    public void setTessPath(String tessPath) {
        this.tessPath = tessPath;
    }
    public String getTransname() {
        return transname;
    }
    public void setTransname(String transname) {
        this.transname = transname;
    }
    public String getLANG_OPTION() {
        return LANG_OPTION;
    }
    public String getEOL() {
        return EOL;
    }
    
    /**
     * recognize text in image
     * @param imageFile
     * @param imageFormat
     * @return text recognized in image
     * @throws Exception
     */
    public String recognizeText(File imageFile,String imageFormat)throws Exception{    
        File tempImage = new ImageIOHelper().createImage(imageFile,imageFormat);    
        return ocrImages(tempImage, imageFile);   
    }    
    
    /**
     * recognize text in image
     * @param imageFile
     * @param imageFormat
     * @param locale
     * @return text recognized in image
     * @throws Exception
     */
    public String recognizeText(File imageFile,String imageFormat,Locale locale)throws Exception{    
        File tempImage = new ImageIOHelper(locale).createImage(imageFile,imageFormat);
        return ocrImages(tempImage, imageFile);
           
    }
    /**
     * 
     * @param tempImage
     * @param imageFile
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    private String ocrImages(File tempImage,File imageFile) throws IOException, InterruptedException{
        File outputFile = new File(imageFile.getParentFile(),"output");
        Runtime.getRuntime().exec("attrib "+"\""+outputFile.getAbsolutePath()+"\""+" +H"); //设置文件隐藏
        StringBuffer strB = new StringBuffer();    
        List<String> cmd = new ArrayList<String>();    
        if(OS.isWindowsXP()){    
            cmd.add(tessPath+"//tesseract");    
        }else if(OS.isLinux()){    
            cmd.add("tesseract");    
        }else{    
            cmd.add(tessPath+"//tesseract");    
        }    
        cmd.add("");    
        cmd.add(outputFile.getName());    
        cmd.add(LANG_OPTION);    
        cmd.add(transname);    
        ProcessBuilder pb = new ProcessBuilder();    
        pb.directory(imageFile.getParentFile());    
        cmd.set(1, tempImage.getName());    
        pb.command(cmd);    
        pb.redirectErrorStream(true);    
        Process process = pb.start();    
        int w = process.waitFor();    
        tempImage.delete();//删除临时正在工作文件         
        if(w==0){    
            BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(outputFile.getAbsolutePath()+".txt"),"UTF-8"));    
            String str;    
            while((str = in.readLine())!=null){    
                strB.append(str).append(EOL);    
            }    
            in.close();    
        }else{    
            String msg;    
            switch(w){    
            case 1:    
                msg = "Errors accessing files.There may be spaces in your image's filename.";    
                break;    
            case 29:    
                msg = "Cannot recongnize the image or its selected region.";    
                break;    
            case 31:    
                msg = "Unsupported image format.";    
                break;    
            default:    
                msg = "Errors occurred.";    
            }    
            tempImage.delete();    
            throw new RuntimeException(msg);    
        }    
        new File(outputFile.getAbsolutePath()+".txt").delete();    
        return strB.toString(); 
    }
}

在实验中发现,如果对有多个文字的大图进行直接识别的话,效果可能比较差,所以可以参考另一篇切图的博文,将图片取一块之后再识别。http://www.cnblogs.com/inkflower/p/6642089.html  这样成功率会提高很多。

以上为离线识别版本,效率因图而已,具体使用的时候可以总结分析。

此外,为提高准确率,可以对字体库进行相应的训练,可以参考以下文章。

Tesseract-OCR 简单的中文数字混合训练——https://blog.csdn.net/majiahuicsdn/article/details/81312026

Tesseract-OCR识别中文与训练字库实例——https://www.cnblogs.com/wzben/p/5930538.html

转载自:https://www.cnblogs.com/inkflower/p/6642264.html

版权声明:本文著作权归原作者所有,欢迎分享本文,谢谢支持!
转载请注明:使用Java实现OCR图片文字识别(Tesseract-OCR) | 猿笔记
分类:JAVA, 程序笔记 标签:, ,

发表评论


表情