1. 程式人生 > >關於Tesseract OCR 中文訓練識別小試(java呼叫Tess4j)

關於Tesseract OCR 中文訓練識別小試(java呼叫Tess4j)

2017.9.20日小結
最近接到是關於消防系統協議解析儀器的專案,目的是從協議解析儀器獲取有效資料,並解析資料(目的是不希望消防主機的資料資訊再傳給主機廠商而是最後能給自己收集呼叫)。由於各個消防器材廠商的協議不同,如果從串列埠讀取資料並一個個協議進行解析工程量浩大並非一人之力可以完成,所以採取途徑是根據熱敏印表機口獲取有效資料(印表機報文格式統一),解析報文後可以判斷熱敏印表機資料集實際上是列印文字的點陣集並獲得有效資料。
這裡取一幀資料:1B 4B 50 00 00 00 00 10 F0 F0 10 00 00 10 10 F0 F0 10 10 00 00 00 00 60 60 00 00 00 C0 E0 30 10 30 E0 C0 00 C0 E0 30 10 30 E0 C0 00 00 00 00 00 00 00 00 00 00 01 09 12 22 E4 54 48 48 54 54 62 42 03 02 00 80 00 00 FE 04 04 04 E4 04 0C 74 84 04 04 04 00 0D
每幀資料16進位制 ,幀頭1B 4B,第三位是長度,50代表的長度80,結尾是00 0D。
16進位制轉換成2進位制,對應8位,8位縱向列印,也就是00列印結果是00000000。
第一個想法是將點陣集模擬出來成為圖片,呼叫文字識別。
第一步:將所有由01組成點陣集轉換為二維陣列
第二步:將二維陣列轉換成圖片,為了方便,0白色1黑色。(呼叫java的graphics)
第三部:使用google的Tesseract進行識別。這裡另發了一篇關於Tesseract識別過程的文章。
第二想法是將點陣集的每個字部分再分割成二維陣列,這裡二維陣列不能轉換成直接轉換成hashcode,即使相同的二維陣列轉換成hashcode,其結果也不同。人工新增key-value鍵值對的形式進行新增。(消防介面印表機輸出文字形式較少,使用這種方法可行度較高)
第一種方法測試多次後識別難度比較大,後採用第二種想法(比較簡單就不贅述了)。

關於Tesseract OCR文字識別:
1.下載:Tesseract可以識別多種語言,多種圖片格式。我使用的是3.0.2版本。網上有很多下載源,CSDN資源庫裡也有。下載完成後目錄:
這裡寫圖片描述

2、命令提示符進入你需要識別圖片的目錄下後,這是我需要識別圖片的目錄。
這裡寫圖片描述
3、給出一個例圖,這是我需要識別的印表機報文轉換成的圖片。
這裡寫圖片描述
4、對test.jpg圖片進行識別 輸入如下命令這裡寫圖片描述會將識別結果匯入一個result.txt的檔案。
這裡寫圖片描述
識別完成。
預設使用的是eng.traineddata字型檔進行識別。我現在需要的進行tesseract中文識別,所以可以下載chi_sim的中文字型檔,CSDN中也有相應資源。將下載的chi_sim.traineddata匯入下載目錄的tessdata下如圖:
這裡寫圖片描述


當中文庫匯入tessdata後,在輸入如下命令:
這裡寫圖片描述
谷歌的中chi_sim字型檔識別中文能力不是特別好,這裡需要自己訓練自己的中文庫滿足識別條件。
5、開始自己中文庫訓練
(1)完成以上部分後,需要下載一個第三方軟體jTessBoxEditor工具。這個工具是java寫的,執行時需要JRE。功能是用來修改產生的BOX檔案,用記事本開啟後可以發現這個box檔案是用來校驗文字的。
這裡寫圖片描述
(2)開啟這個軟體
這裡寫圖片描述
點選tools後再點選Merge TIFF,將所需要的圖片集轉換成tif格式,源圖片集格式支援jpg和tif兩種。合成的圖片集命名格式為[chi].[lzh].[exp4].tif 第一個空是字典格式,第二個空點陣圖片集的名字,第三個空位exp[num]。這裡寫圖片描述

這裡寫圖片描述按要求命名後。
這裡需要注意生成tif時候單個漢子識別通常會出現問題,比如對“一”這個字進行識別會出現emptypage的提示,編譯器認為這個是一張空圖片。所以採用一張圖上有好幾個字的方式進行一起識別。這樣也方便後面使用jTessBoxEditor對其進行修改,如果是emptypage的話後面使用Tesseract 3.0.2識別會不顯示文字特徵,也就無法進行修改了。合成圖片集時儘量多張圖片,哪怕一樣的,我用的是10張一樣的圖片進行合成tif的這樣識別得出來,5張的時候識別還是有一定問題。
(3)生成BOX檔案,還是剛才的圖片集的目錄
輸入命令tesseract.exe chi.lzh.exp4.tif chi.lzh.exp4 batch.nochop makebox
這裡寫圖片描述
Box檔案生成完畢。
(4)校驗文字,用剛才jTessBoxEditor開啟剛才生成的tif檔案。
這裡寫圖片描述 這裡寫圖片描述
我們會發現文字資訊不對,這時候需要手動校驗,表示非常的麻煩。
這裡注意圖片集問題參考第二步注意事項。開啟如何沒有任何特徵矩形框則說明jTessBoxEditor沒有識別到任何特徵,參考第二步對圖片集進行調整。
開啟box介面如下
這裡寫圖片描述
(5)生成tr檔案,命令為tesseract.exe chi.lzh.exp4.tif chi.lzh.exp4 nobatch box.train,生成成功。
這裡寫圖片描述
(6)生成unicharset檔案 unicharset_extractor chi.lzh..exp4.box,生成成功。
這裡寫圖片描述
(7)新建font_properties檔案 用記事本新建一個明文font_properties
內容格式為lzh 0 0 0 0 0,lzh是新建tif中間的內容
這裡寫圖片描述
(8)在分別執行三個命令對tr特徵集合進行操作
1.shapeclustering.exe -F font-properties.txt -U unicharset chi.lzh.exp4.tr
2.Mftraining.exe -F font_properties.txt -U unicharset - O unicharset chi.lzh.exp4.tr
3.Cntraining.exe chi.lzh.exp4.tr
注意:這個版本的命令必須加上properties.txt 結尾的txt必須加上
(9)給下列重新命名找出下列五個檔案unicharset,inttemp,pffmtable,shapetable,normproto在前面加上lzh.(就是你的tif中間的名字)
這裡寫圖片描述這裡寫圖片描述
(10)最後執行combine_tessdata lzh.(後面是有點的)
如果最後生成traineddata則說明可以用了,將lzh.traineddata加入安裝的tesseract的tessdata檔案中就可以進行使用。再用tesseract.exe test.jpg test -l lzh就可以了,開啟test
結果:這裡寫圖片描述

這裡寫圖片描述
6.如果要進行字典合併,必須要生成字典過程中tif和box,tr,unicharset存在,同時font_properties也必須修改。最後將所有的tr,unicharset,inttemp,normproto,pfftable全部改成lzh。使用combine_tessdata lzh.合併成一個大的字型檔檔案。

後面貼一段eclipse工程中呼叫Tess4j的程式碼片段,匯入Tess4j JAR包後即可以使用lzh新生成的字型檔完成呼叫,注意工程下拷入的tessdata中必須也新增lzh.traineddata;
下載地址:http://sourceforge.net/projects/tess4j/
粗暴的方法是將lib中所有的JAR包中檔案全部匯入,然後將com.recognition.software.jdeskew和net.開頭的package全部轉入工程下 即可以實現呼叫
匯入完成後目錄如圖
這裡寫圖片描述

public class Test {//test
    public static void main(String [] args)
    {
        try{
            //圖片位置
            File imageFile = new File("J:\\develop\\jee_workspace2\\protocol_analysis\\picture\\test1.jpg");
            //JNA 介面對映
            ITesseract instance = new Tesseract();
            //設定tessdata位置
            instance.setDatapath("J:\\develop\\jee_workspace2\\protocol_analysis");
            //選擇字型檔檔案  只需要檔名 不需要字尾名
            instance.setLanguage("lzh");
            //開始識別
            String result = instance.doOCR(imageFile);
            System.out.println(result);
            }catch (TesseractException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
    }


}