Tesseract識別圖片提取文字&字庫訓練


   文中測試了3.0和4.0兩個版本。發現3.0識別效率不准確,需要訓練詞庫。4.0識別效率就比較高了,而且支持結果生成pdf、txt等格式。所以推薦使用4.0版本。

  這個工具可以用在爬蟲的時候獲取驗證碼進行識別且自動輸入驗證碼的功能。

  git地址:https://github.com/tesseract-ocr/tesseract

  下載地址:https://digi.bib.uni-mannheim.de/tesseract/

1.下載安裝

  我下載的是 3.05.01,自帶了中文詞庫。

下載完成后目錄結構:

 

2.測試識別

0.准備一張文字圖片

1.添加環境變量到path中,可以直接使用tesseract命令。檢查是否配置成功

C:\Users\Administrator\Desktop\新建文件夾>tesseract -v
tesseract 3.05.01
 leptonica-1.74.1
  libgif 4.1.6(?) : libjpeg 8d (libjpeg-turbo 1.5.0) : libpng 1.6.20 : libtiff 4.0.6 : zlib 1.2.8 : libwebp 0.4.3 : libopenjp2 2.1.0

 

查看命令可以攜帶的參數:

PS C:\Users\Administrator\Desktop\新建文件夾> tesseract
Usage:
  E:\tesseract\Tesseract-OCR\tesseract.exe --help | --help-psm | --help-oem | --version
  E:\tesseract\Tesseract-OCR\tesseract.exe --list-langs [--tessdata-dir PATH]
  E:\tesseract\Tesseract-OCR\tesseract.exe --print-parameters [options...] [configfile...]
  E:\tesseract\Tesseract-OCR\tesseract.exe imagename|stdin outputbase|stdout [options...] [configfile...]

OCR options:
  --tessdata-dir PATH   Specify the location of tessdata path.
  --user-words PATH     Specify the location of user words file.
  --user-patterns PATH  Specify the location of user patterns file.
  -l LANG[+LANG]        Specify language(s) used for OCR.
  -c VAR=VALUE          Set value for config variables.
                        Multiple -c arguments are allowed.
  --psm NUM             Specify page segmentation mode.
  --oem NUM             Specify OCR Engine mode.
NOTE: These options must occur before any configfile.

Page segmentation modes:
  0    Orientation and script detection (OSD) only.
  1    Automatic page segmentation with OSD.
  2    Automatic page segmentation, but no OSD, or OCR.
  3    Fully automatic page segmentation, but no OSD. (Default)
  4    Assume a single column of text of variable sizes.
  5    Assume a single uniform block of vertically aligned text.
  6    Assume a single uniform block of text.
  7    Treat the image as a single text line.
  8    Treat the image as a single word.
  9    Treat the image as a single word in a circle.
 10    Treat the image as a single character.
 11    Sparse text. Find as much text as possible in no particular order.
 12    Sparse text with OSD.
 13    Raw line. Treat the image as a single text line,
                        bypassing hacks that are Tesseract-specific.
OCR Engine modes:
  0    Original Tesseract only.
  1    Cube only.
  2    Tesseract + cube.
  3    Default, based on what is available.

Single options:
  -h, --help            Show this help message.
  --help-psm            Show page segmentation modes.
  --help-oem            Show OCR Engine modes.
  -v, --version         Show version information.
  --list-langs          List available languages for tesseract engine.
  --print-parameters    Print tesseract parameters to stdout.

 

 2.進入cmd,進入到要識別的圖片的路徑下。

C:\Users\Administrator\Desktop\新建文件夾>tesseract ./1.jpg re
Error opening data file \tesseract\Tesseract-OCR\tessdata/eng.traineddata
Please make sure the TESSDATA_PREFIX environment variable is set to the parent directory of your "tessdata" directory.
Failed loading language 'eng'
Tesseract couldn't load any languages!
Could not initialize tesseract.

 

發現報錯沒有語言,解決辦法: 將  tesseract 安裝目錄下的  tessdata 文件夾配置到環境變量  TESSDATA_PREFIX  

C:\Users\Administrator>set TESSDATA_PREFIX
TESSDATA_PREFIX=E:\tesseract\Tesseract-OCR\tessdata

3.再次測試

C:\Users\Administrator\Desktop\新建文件夾>tesseract ./1.png re
Tesseract Open Source OCR Engine v3.05.01 with Leptonica

 

   會生成一個re.txt文件,內容如下:(發現中文亂碼)

 4.解決中文亂碼問題:加 -l 參數指定語言即可

(1)查看支持的語言

C:\Users\Administrator\Desktop\新建文件夾>tesseract --list-langs
List of available languages (107):
afr
amh
ara
。。。

 

(2)使用  chi_sim 識別圖片

C:\Users\Administrator\Desktop\新建文件夾>tesseract -l chi_sim ./1.png re
Tesseract Open Source OCR Engine v3.05.01 with Leptonica

 

 3.測試復雜的中文識別---詞庫訓練

 1.原來圖片如下

 

 

2. 識別之后的內容如下

 

3.解決上面的問題---利用jTessBoxEditor工具進行Tesseract3.02.02樣本訓練

  此工具基於java運行,所以需要安裝java環境。

1.下載   jTessBoxEditor :http://tenet.dl.sourceforge.net/project/vietocr/jTessBoxEditor/jTessBoxEditor-1.5.zip

2.解壓運行

$ java -jar jTessBoxEditor.jar

 

 

3. 將上面的圖片轉換成tif格式,用於后面生成box文件。可以通過畫圖,然后另存為tif即可

tif文面命名格式[lang].[fontname].exp[num].tif
lang是語言 fontname是字體 
比如我們要訓練自定義字庫 mylan 字體名normal
那么我們把圖片文件重命名 mylan.normal.exp0.jpg在轉tif。(畫圖工具中另存為就可以)

 

4.生成box文件。

tesseract mylan.normal.exp0.jpg mylan.normal.exp0 -l chi_sim batch.nochop makebox

 

box文件和對應的tif一定要在相同的目錄下,不然后面打不開。會生產一個box文件。

 

 

5.打開jTessBoxEditor矯正錯誤並訓練

 打開train.bat

 

 找到tif圖,打開,並校正。(校正完保存即可)

 

 6、訓練。

(1) 只要在命令行輸入命令即可。(執行第一條命令會生產.tr文件,也可以先執行一次然后刪掉tr測試是否可以訓練)

tesseract  mylan.normal.exp0.jpg mylan.normal.exp0  nobatch box.train


unicharset_extractor mylan.normal.exp0.box

或者輸入兩個合並執行的命令:

tesseract  mylan.normal.exp0.jpg mylan.normal.exp0  nobatch box.train && unicharset_extractor mylan.normal.exp0.box

 

 如下證明全部識別完畢:

 

(2)新建一個font_properties文件

里面內容寫入 normal 0 0 0 0 0 表示默認普通字體 (要求normal與上面的字體名稱必須一致),下面是命令直接重定向(注意重定向>和>>的區別是>是覆蓋模式,>>是追加模式):

echo normal 0 0 0 0 0 >> font_properties

 

(3)繼續敲命令:

shapeclustering -F font_properties -U unicharset mylan.normal.exp0.tr

mftraining -F font_properties -U unicharset -O unicharset mylan.normal.exp0.tr

cntraining mylan.normal.exp0.tr

或者一次性執行下面命令:

shapeclustering -F font_properties -U unicharset mylan.normal.exp0.tr && mftraining -F font_properties -U unicharset -O unicharset mylan.normal.exp0.tr && cntraining mylan.normal.exp0.tr

 

最后會生成五個文件,把目錄下的unicharset、inttemp、pffmtable、shapetable、normproto這五個文件前面都加上normal.

如圖:

或者執行如下命令進行重命名:

mv ./unicharset ./normal.unicharset && mv ./inttemp ./normal.inttemp && mv ./pffmtable ./normal.pffmtable && mv ./shapetable ./normal.shapetable && mv ./normproto ./normal.normproto

 

(4)命令行輸入,合並五個文件:

combine_tessdata normal.

得到訓練好的字庫。

 

(5)把 normal.traineddata 復制到Tesseract-OCR 安裝目錄下的tessdata文件夾中

或者執行以下命令即可:( TESSDATA_PREFIX 是配置的環境變量)

mv ./normal.traineddata $TESSDATA_PREFIX

或者執行復制命令:

cp ./normal.traineddata $TESSDATA_PREFIX

 

 7.測試:

識別命令:(可以使用兩種語言,也可以使用一種語言)

Administrator@MicroWin10-1535 MINGW64 ~/Desktop/新建文件夾
$ tesseract mylan.normal.exp0.jpg result -l normal
Tesseract Open Source OCR Engine v3.05.01 with Leptonica

Administrator@MicroWin10-1535 MINGW64 ~/Desktop/新建文件夾
$ tesseract mylan.normal.exp0.jpg result2 -l normal+chi_sim
Tesseract Open Source OCR Engine v3.05.01 with Leptonica

 

結果:(上面的   result   是指定生成的txt文件的前綴   )

 

補充:用notepad++打開之后會發現有換行:

 

  這個需要大量的訓練詞庫。不知道是否有更好的解決辦法。

 

補充:一個Java程序調用runtime執行本地命令,並讀取生成的文件內容:

package cn.xm.exam.test;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.FileUtils;
import org.apache.xmlbeans.impl.common.IOUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ibm.wsdl.util.IOUtils;

@SuppressWarnings("all")
public class PlainTest {
    private static final Logger logger = LoggerFactory.getLogger(Test.class);

    public static void main(String[] args) throws IOException {
        // 執行命令生成文件
        String cmd = "E:/tesseract/Tesseract-OCR/tesseract.exe G://test.jpg G://tmp -l normal+chi_sim";
        boolean exec = exec(cmd);
        if (exec) {
            String readFileToString = FileUtils.readFileToString(new File("G://tmp.txt"));
            System.out.println(readFileToString);
        }
    }

    public static boolean exec(String command) {
        Process process;// Process可以控制該子進程的執行或獲取該子進程的信息
        try {
            logger.debug("exec cmd : {}", command);
            process = Runtime.getRuntime().exec(command);// exec()方法指示Java虛擬機創建一個子進程執行指定的可執行程序,並返回與該子進程對應的Process對象實例。
            // 下面兩個可以獲取輸入輸出流
            InputStream errorStream = process.getErrorStream();
            InputStream inputStream = process.getInputStream();
        } catch (IOException e) {
            logger.error(" exec {} error", command, e);
            return false;
        }

        int exitStatus = 0;
        try {
            exitStatus = process.waitFor();// 等待子進程完成再往下執行,返回值是子線程執行完畢的返回值
            // 第二種接受返回值的方法
            int i = process.exitValue(); // 接收執行完畢的返回值
            logger.debug("i----" + i);
        } catch (InterruptedException e) {
            logger.error("InterruptedException  exec {}", command, e);
            return false;
        }

        if (exitStatus != 0) {
            logger.error("exec cmd exitStatus {}", exitStatus);
        } else {
            logger.debug("exec cmd exitStatus {}", exitStatus);
        }

        process.destroy(); // 銷毀子進程
        process = null;

        return true;
    }
}

結果:(會將換行也讀取出來)

1 23456
這是一告測試中文
不能告訴@154856.text
電話:1 8434391 711

 

=====下面研究 Tesseract  4.0版本的使用(推薦使用這個版本)=========

  官方對  Tesseract4.0 版本做了很多的改進,而且自帶的語言庫也增加了很多。下面研究在4.0版本的識別。經過研究,4.0版本是可以直接拿來就用的,都不用訓練詞。識別為pdf的准確率更加高,所以在實際中可以識別為pdf然后用apache-tika提取pdf的內容。這樣識別率更加的高效。

1. 下載安裝

2.修改環境變量為最新的4.0版本並測試

$ tesseract --version
tesseract v4.0.0.20181030
 leptonica-1.76.0
  libgif 5.1.4 : libjpeg 8d (libjpeg-turbo 1.5.3) : libpng 1.6.34 : libtiff 4.0.9 : zlib 1.2.11 : libwebp 0.6.1 : libopenjp2 2.2.0

 

3.接下來還是對上面的帶中文的進行識別

tesseract ./1.jpg result -l chi_sim

 

結果:(識別率已經非常准確了)

 

 4.測試將識別結果直接提取為字符串、存儲為pdf(雙層pdf)或者xml

(1)直接提取為文本

$ tesseract ./1.jpg stdout -l chi_sim
123456
這是一個測試中文

不能告訴@154856 .text
電話:18434391711

 

(2)提取為pdf

   在4.0之后可以自動將識別結果提取為pdf\txt\xml等格式的數據。

Administrator@MicroWin10-1535 MINGW64 ~/Desktop/新建文件夾
$ tesseract ./1.jpg result -l chi_sim pdf
Tesseract Open Source OCR Engine v4.0.0.20181030 with Leptonica

 結果:

(3)當然可以一次性提取為多個文件,只需要在后面空格分割就可以了

tesseract ./0101.jpg result -l chi_sim pdf txt

 

結果會生成三個文件

 

5.測試識別復雜的中文圖片

圖片內容如下:

(1)直接提取內容到輸出控制台

$ tesseract ./0101.jpg stdout -l chi_sim


一個車者對禪師說: “我放不下一-些事放不下一些人。”

禪師說沒有什么東西是真正放不下的。苦者說: 可我就信信放不下.

禪師遞給他一個水杯然后就入里面俠     -直例到水溢出來。貢者被通到馬_上松開了手,水杯掉在
地上摔壞了。

禪師說:其實,這個世界_上沒有什么事是放不下的,痛了,你自然就會放下

土者說到“我能換個水杯嗎?

禪師微微一笑道:“可以”他從包里拿出一一個水杯 ,說到再試試吧 , 禪師又往水杯里倒水,水溢出
來 , 這次他沒有放手

祥岳問道:“不湯嗎”?苦者說“和”

禪師又問“為何不放手?”葫者說道“這水杯是她送的。禪師回頭嘆“番狗是真的牛通

 

 

(2)查看提取tx和pdf的效率

$ tesseract ./0101.jpg result -l chi_sim pdf txt

 

txt和控制台的結果一樣:

 

pdf識別結果更加准確:(接近百分之百)

 

   經過上面的實驗發現啊,pdf的識別是識別的雙層pdf,我自己的一種思路就是:將識別結果存到pdf,然后用ApacheTika提取pdf的內容,這樣識別效率應該會更加准確。

 

6. java中調用runtime獲取識別結果和提取為pdf之后用ApacheTika提取pdf內容

(1)讀取內容到字符串中

package zd.dms.utils.ebuy;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.tika.exception.TikaException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

@SuppressWarnings("all")
public class PlainTest {
    private static final Logger logger = LoggerFactory.getLogger(PlainTest.class);

    public static void main(String[] args) throws IOException, SAXException, TikaException {
        // 執行命令生成文件
        String cmd = "E:/tesseract4/Tesseract-OCR/tesseract.exe G://0101.jpg stdout -l chi_sim";
        boolean exec = exec(cmd);
    }

    public static boolean exec(String command) {
        Process process;// Process可以控制該子進程的執行或獲取該子進程的信息
        String result = "";
        try {
            logger.debug("exec cmd : {}", command);
            process = Runtime.getRuntime().exec(command);// exec()方法指示Java虛擬機創建一個子進程執行指定的可執行程序,並返回與該子進程對應的Process對象實例。
            // 下面兩個可以獲取輸入輸出流
            InputStream errorStream = process.getErrorStream();

            // 獲取其正常的輸出流
            InputStream inputStream = process.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader br = new BufferedReader(inputStreamReader);
            String line = null;
            while ((line = br.readLine()) != null) {
                result += line;
            }

        } catch (IOException e) {
            logger.error(" exec {} error", command, e);
            return false;
        }

        int exitStatus = 0;
        try {
            exitStatus = process.waitFor();// 等待子進程完成再往下執行,返回值是子線程執行完畢的返回值
            // 第二種接受返回值的方法
            int i = process.exitValue(); // 接收執行完畢的返回值
            logger.debug("i----" + i);
        } catch (InterruptedException e) {
            logger.error("InterruptedException  exec {}", command, e);
            return false;
        }

        if (exitStatus != 0) {
            logger.error("exec cmd exitStatus {}", exitStatus);
        } else {
            logger.debug("exec cmd exitStatus {}", exitStatus);
        }

        process.destroy(); // 銷毀子進程
        process = null;

        // result就是獲取到的結果
        System.out.println(result);
        return true;
    }
}

結果:

  一個車者對禪師說: “我放不下一-些事放不下一些人。”禪師說沒有什么東西是真正放不下的。苦者說: 可我就信信放不下.禪師遞給他一個水杯然后就入里面俠     -直例到水溢出來。貢者被通到馬_上松開了手,水杯掉在地上摔壞了。禪師說:其實,這個世界_上沒有什么事是放不下的,痛了,你自然就會放下土者說到“我能換個水杯嗎?禪師微微一笑道:“可以”他從包里拿出一一個水杯 ,說到再試試吧 , 禪師又往水杯里倒水,水溢出來 , 這次他沒有放手祥岳問道:“不湯嗎”?苦者說“和”禪師又問“為何不放手?”葫者說道“這水杯是她送的。禪師回頭嘆“番狗是真的牛通     

 

(2)讀取內容到pdf中然后tika讀取pdf

package zd.dms.utils.ebuy;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.FileUtils;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.sax.BodyContentHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

@SuppressWarnings("all")
public class PlainTest {
    private static final Logger logger = LoggerFactory.getLogger(PlainTest.class);

    public static void main(String[] args) throws IOException, SAXException, TikaException {
        // 執行命令生成文件
        String cmd = "E:/tesseract4/Tesseract-OCR/tesseract.exe G://0101.jpg G://result -l chi_sim pdf";
        boolean exec = exec(cmd);
        if (exec) {
            BodyContentHandler handler = new BodyContentHandler();
            Metadata metadata = new Metadata();
            FileInputStream inputstream = new FileInputStream(new File("G://result.pdf"));
            ParseContext pcontext = new ParseContext();

            // parsing the document using PDF parser
            PDFParser pdfparser = new PDFParser();
            pdfparser.parse(inputstream, handler, metadata, pcontext);

            // getting the content of the document
            System.out.println("Contents of the PDF :" + handler.toString());
        }
    }

    public static boolean exec(String command) {
        Process process;// Process可以控制該子進程的執行或獲取該子進程的信息
        try {
            logger.debug("exec cmd : {}", command);
            process = Runtime.getRuntime().exec(command);// exec()方法指示Java虛擬機創建一個子進程執行指定的可執行程序,並返回與該子進程對應的Process對象實例。
            // 下面兩個可以獲取輸入輸出流
            InputStream errorStream = process.getErrorStream();
            InputStream inputStream = process.getInputStream();
        } catch (IOException e) {
            logger.error(" exec {} error", command, e);
            return false;
        }

        int exitStatus = 0;
        try {
            exitStatus = process.waitFor();// 等待子進程完成再往下執行,返回值是子線程執行完畢的返回值
            // 第二種接受返回值的方法
            int i = process.exitValue(); // 接收執行完畢的返回值
            logger.debug("i----" + i);
        } catch (InterruptedException e) {
            logger.error("InterruptedException  exec {}", command, e);
            return false;
        }

        if (exitStatus != 0) {
            logger.error("exec cmd exitStatus {}", exitStatus);
        } else {
            logger.debug("exec cmd exitStatus {}", exitStatus);
        }

        process.destroy(); // 銷毀子進程
        process = null;

        return true;
    }
}

結果:

個對禪師說 “我放 不 一-些事放不一 。”
禪師說沒有什么東西是真正不下的 者可我信不.
禪師遞給一水杯然后入里面俠 -直例到水溢出來 者通到馬上松了手,水掉
摔了。
禪師 :其,這個世界上沒有什么事是不下 , 痛了 , 你自然就放下
者到 “我能換個水杯?
禪師微微笑 :“可以”他里拿出一水,說到再試試吧 , 禪師又往水杯里倒水 ,水溢出

 

來 , 這次他沒有放手
祥岳 問 不湯”? 者 “和”
禪師又 何不放手?”者 “這水杯她送的 禪師回頭 “番真牛通

 

 

  git上面的文檔對4.0最新的每個命令都有介紹,參照git上的doc文件夾下面對每個文件的介紹:https://github.com/tesseract-ocr/tesseract/tree/master/doc

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM