【本文編寫於2018年7月5日】
Tess4J是Tesseract的Java JNA wrapper。本文介紹了在CentOS 7 操作系統中使用Tess4J的步驟及注意事項。在正式開始之前,先花一點篇幅,對相關的技術作一簡要介紹。
一點點背景
Tesseract
Tesseract 是一個著名的開源OCR引擎,支持100多種語言,可以開箱即用。還可以通過訓練方式支持更多語言。Tesseract誕生於1984年,來自HP公司,2005年開源。自2006年起,由谷歌接手開發。截止目前,最新的穩定版本是2017年6月1日發布的3.05.01。還有一只比較活躍的基於LSTM(長短期記憶網絡,是一種時間遞歸神經網絡)的4.0版本,還在研發中,最新釋放的是2018年6月26日的4.0.0-beta.3。Tesseract由C++開發。
站點:
https://github.com/tesseract-ocr/tesseract
Leptonica
Tesseract作為OCR引擎,避免不了使用圖像處理。Tesseract使用的圖像處理主要由leptonica提供。Leptonica 包含眾多圖像處理和圖像分析相關的功能。
站點:
http://www.leptonica.com/
Java JNA Wrapper
JNA 是 Java Native Access的縮寫,顧名思義,是一個實現Java調用操作系統Native應用的庫。提起Java本地調用,大家自然聯想的JNI,但JNI使用過程十分復雜,會讓人望而生畏。JNA則采取更加自然的方式,為Java應用提供調用本地應用的支持。
站點:
https://github.com/java-native-access/jna
Tess4J
Tess4J通過Java JNA Wrapper,提供了Java的Tesseract API,同時還提供了Windows 32bit和64bit的Tesseract的DLL以及一些樣例圖像。通過Tess4J,可以在Windows下非常便利的通過Java使用Tesseract。對於Linux、MAC等其他操作系統,則需要自行構建Tesseract才可以使用Tess4J。
也就是說,原生的Tess4J並不是跨平台的,僅僅是對Windows開箱即用的。
這也是本文寫作的初衷,記錄在Linux環境中,使用Tess4J的步驟及淌過的坑。
本文使用的技術版本
為什么要單獨強調版本?長期混跡開源坑的同志們一定了解一個事實:大部分的開源項目其質量(功能可用性,文檔正確性、更新及時性)相對一般,在圈子里混,必須具備在眾多繁雜的信息中去偽存真的能力,在社區里大聲疾呼求關注的技巧,極強的動手能力以及百折不撓的精神。。。
對於某些技術問題,谷歌出來的結果中,很大一部分是無效的,會浪費大量的時間,甚至走入歧途。但同眾多作者交流后發現,絕大部分這類情況是有文章介紹方案不完整,或者不夠嚴謹導致的。
因此,我認為,作為分享的每一個實踐,需要具備可重復操作的基本要求。所以,我會盡量精確的重復我實踐過程使用的軟件及環境的版本,希望對大家有所幫助。
Tess4J:4.0.2
Tesseract:4.0.0-beta.1
Leptonica:1.76.0
JDK:1.8 Update 102 64bit
運行環境:CentOS 7 (內核:3.10.0-862.3.3.el7.x86_64)64bit
GCC:4.8.5
Clang:3.4
開發環境:Windows 10 64bit
為何這樣選?
這里的坑是,不能根據自己的喜好,使用新版本。我使用過Tesseract 4.0.0-beta.3,但運行JVM會報出Fatal Error最后自行退出,看報出的錯誤來判斷,大概是Tesseract中某些函數簽名變化,Tess4J中簽名與之不匹配所致。
還記得官方文檔(https://github.com/tesseract-ocr/tesseract/wiki)嗎?
官方Wiki提到,Linux的so庫,可以通過安裝預先編譯的包,如果按照Wiki操作,便會自動安裝最新版本。我也曾經嘗試通過yum列表舊版本安裝,發現即使所謂的舊版本,也會導致Tess4J運行時報錯。(通過yum下載並自動安裝的rpm包如下所示)
這里必須根據Tess4J適配的版本來選擇。
Tess4J的versionchanges.txt中描述了最近幾個版本的變化:
Version 4.0.0 (28 April 2018)
- Upgrade to Tesseract 4.0.0-beta.1 (45bb942)
- Update Lept4J to 1.9.3 (Leptonica 1.75.3)
Version 4.0.1 (2 May 2018)
- Fix a path issue when extracting resources from JAR to temp directory on Windows server
Version 4.0.2 (3 May 2018)
- Replace JNA string constant Platform.RESOURCE_PREFIX
- Update jai-imageio url
- Update Lept4J to 1.9.4
可見,最新版的Tess4J,僅對Tesseract 4.0.0-beta.1進行過適配,因此產生了上面描述的版本組合。鑒於無法確定預先構建的包哪個是從Tesseract 4.0.0-beta.1構建而來,因此只能通過源碼自行構建。
構建Tesseract
1 修改yum的Repo
可能是我所在的環境網絡非常差,yum默認會使用mirror,但絕大部分mirror連接不上,會導致下載過程在大量無效的mirror嘗試中進行,非常浪費時間。
因此,我關閉了yum的fast mirror插件(/etc/yum/pluginconf.d),另外修改了CentOS-Base.repo。
2 安裝必備包
yum -y update yum -y install libstdc++ autoconf automake libtool autoconf-archive pkg-config gcc gcc-c++ make libjpeg-devel libpng-devel libtiff-devel zlib-devel yum group install -y "Development Tools"
注意:autoconf-archive 是官方說明中都沒有提到的必備組件。
3 下載源碼
Leptonica
http://www.leptonica.com/source/leptonica-1.76.0.tar.gz
Tesseract
https://codeload.github.com/tesseract-ocr/tesseract/tar.gz/4.0.0-beta.1
下載完畢效果:
4 安裝Leptonica
tar -zxvf leptonica-1.76.0.tar.gz cd leptonica-1.76.0 ./autobuild ./configure make -j make install
5 安裝Tesseract
tar -zxvf 4.0.0-beta.1.tar.gz cd tesseract-4.0.0-beta.1/ ./autogen.sh PKG_CONFIG_PATH=/usr/local/lib/pkgconfig LIBLEPT_HEADERSDIR=/usr/local/include ./configure --with-extra-includes=/usr/local/include --with-extra-libraries=/usr/local/lib LDFLAGS="-L/usr/local/lib" CFLAGS="-I/usr/local/include" make -j make install ldconfig
6 確認安裝
經過漫長的編譯過程,Tesseract已經安裝完畢。
執行如下指令:
tesseract -v
顯示內容如下:
即為安裝完畢。
獲取so庫
在/usr/local/lib中,可以找到Tess4J需要的依賴庫libtesseract.so。可見libtesseract.so實際指向libtesseract.so.4.0.0。liblept.so是leptonica的庫,Tesseract也需要調用。
為Tess4J設置庫(so)文件位置
Tess4J的JAR包中,包含windows的DLL庫,其位置如下:
在Tess4J運行時,會將操作系統依賴的庫從JAR包中解壓出來使用,對於Linux系統的so文件,也是如此。Tess4J約定的Linux庫文件存儲路徑為classpath根路徑下的linux-x86-64。
既然已經拿到了so文件,顯而易見的有兩種方法:
1 修改tess4j-4.0.2.jar,將so文件按照約定路徑存儲,這樣Tess4J在運行時就會自動解壓使用。
但這種方式修改了Tess4J公開發布的JAR包,日后升級會有麻煩,因此,不建議這樣操作。
2 將linux-x86-64放到Java工程的classpath根目錄。這樣在運行時,Tess4J就可以找到庫了。我的Java工程采用的Gradle構建,因此將這些文件放到了src/main/resources下。
linux-x86-64目錄中包含的文件,是從Linux系統中/usr/local/lib拷貝而來,去掉了一些鏈接文件,具體如下:
至此,已經完成了Tess4J在庫文件方面的准備。
在Tess4J設置Tesseract數據目錄tessdata
Tesseract運行時是需要加載語言的訓練數據的,按照約定,這些訓練數據需要放在tessdata下。但Tess4J 4.0.2對Windows和Linux兩類操作系統目錄處理方式是不一致的。
初始化Tesseract的代碼,setDatapath就是用來設置tessdata目錄的。
ITesseract instance = new Tesseract(); //設置tessdata目錄 instance.setDatapath("/path/to/tessdata");
Tesseract的訓練數據以“語言名.traineddata”命名。
經過實測,在Windows中,需要直接指定到.traineddata所在目錄,在Linux中,則需要指定到一個目錄,其中包含一個叫做tessdata的文件夾,tessdata內部是.traineddata文件。
舉例說明:
在Windows中,instance.setDatapath("lngData/tessdata");
在Linux中,instance.setDatapath("lngData");
顯然這是一個BUG,不過開源項目有BUG已經是家常便飯了。
為此,我在實踐時根據操作系統做了一個小小的適配。
ITesseract instance = new Tesseract(); File tessTrainedDataLoc = null; if(SystemDetector.isWindows()) { //Windows Data目錄直接指定到*.traineddata所在目錄 tessTrainedDataLoc = new File(System.getProperty("user.dir"),"lngData\\tessdata"); } else { // 在Linux(如CentOS 7)中,Data目錄指定到tessdata上一級 tessTrainedDataLoc = new File(System.getProperty("user.dir"),"lngData"); } instance.setDatapath(tessTrainedDataLoc.getAbsolutePath());
以上用到的SystemDetector代碼:
import java.util.Properties; public class SystemDetector { private static boolean isWindows = false; private static boolean isLinux = false; static { Properties props = System.getProperties(); String systemName = props.getProperty("os.name"); if (systemName.toLowerCase().indexOf("windows") != -1) { isWindows = true; } if (systemName.toLowerCase().indexOf("linux") != -1) { isLinux = true; } } public static boolean isWindows() { return isWindows; } public static boolean isLinux() { return isLinux; } }
至此,全部完成。在Windows上開發的項目使用Tess4J,已經可以在Linux中正常運行。
關於Tesseract的訓練數據
Tesseract最大優勢就是可以開箱即用,擁有大量語言的訓練數據,實際使用時,可以根據需要進行OCR識別的內容類型添加。
但是不要貪多,識別范圍越廣,速度也就越慢,甚至還會影響精確度。建議在使用時盡量指定要識別內容的語言,類型,以便在准確度及效率之間取一個恰當的平衡。
Tesseract訓練數據可以從下面獲取:
https://github.com/tesseract-ocr/tessdata
Tesseract 4使用了LSTM,因此還有一個叫做tessdata_best的Repo,其內容是使用LSTM模型訓練的各種語言識別率最高的訓練數據。(推薦使用)
https://github.com/tesseract-ocr/tessdata_best
如果對Tesseract效果不滿意,還可以自行准備數據進行訓練。Tesseract所有項目均在Github上,鏈接地址為:
https://github.com/tesseract-ocr
【全文完】
歡迎轉載,請注明出處。