今天想着把之前作過的一個Android的文字檢測識別應用好好的回顧一下,由於之前寫java程序,目的就是能用就行,不會仔細看每個部分代碼,也不會記他們的用法,不回會去查API,借鑑別人的例程,用過就忘了,如今想着要改變,因而就回顧了一番。html
以前檢測用到的是Tesseract_OCR,之因此能在Android的上運行,是由於黑暗伯爵大神已經把tess-two(爲android寫的tesseract-tools)編譯好了,而後我直接用的。我仍是小白,徹底不懂編譯那些,若是讓我本身搞.... 反正最後編譯成so文件(這個是linux平臺下的動態連接庫,能夠類比dll),而後我用編譯好的so文件,以及jar包導入到工程,照葫蘆畫瓢把文字識別部分和本身以前看論文寫的文字檢測部分合到一塊兒,而後百度了怎麼調用攝像頭,而後寫了一個攝像頭拍照,而後檢測文字所在區域,處理,而後識別的應用。之後有時間會詳細的從新把應用梳理一遍,而後記錄,固然這不是今天的重點。若是對Android上如何作OCR感興趣,能夠參考 這裏 。java
回到正題,前幾天同窗問我之前作的文字識別是咋搞得,他想用用,我因而就想把程序移回來到java上,結果我百度才發現原來還有另一種思路,那就是執行exe進程。先在pc上安裝好tesseract_orc,而後jvm運行命令行跑識別程序,完成識別後結果寫入txt,最後讀取txt把內容返回到java程序中。這麼想一想也行,因而便試了試。(PS:我是後來才發現也有Java的API tess4j,參考 這裏)linux
而後就是講本身具體怎麼實現:android
工程也就兩部分,一部分是GUI,反正我如今對於Java的基礎知識薄弱,而後經常使用類也用的很少,因此藉此機會正好熟悉。數組
GUI主要用到javax.swing包和java.awt包,swing主要寫組件,awt是事件(其實awt也能夠寫組件),可是說swing是對awt中組建的優化,因此如今經常使用swing。GUI裏面比較重要的概念仍是容器,組件必須放到容器裏面才能顯示,經常使用frame和dialog。我此次寫GUI用到jframe,jbutton,filedialog,JLabel,imageicon這幾個類app
界面以下jvm
FileDialog
類顯示一個對話框窗口,用戶能夠從中選擇文件。JLabel
對象能夠顯示文本、圖像或同時顯示兩者。能夠經過設置垂直和水平對齊方式,指定標籤顯示區中標籤內容在何處對齊。默認狀況下,標籤在其顯示區內垂直居中對齊。默認狀況下,只顯示文本的標籤是開始邊對齊;而只顯示圖像的標籤則水平居中對齊。界面的具體代碼我就不貼上來了,值得注意的是圖片壓縮顯示有一個小trick。優化
imagePath = new String(dirPath+fileName); imageico = new ImageIcon(imagePath); int w = imageico.getIconWidth(); int h = imageico.getIconHeight(); double ratio = (double)w/(double)h; if(ratio>4/3){ h = (int)(640*h/w); w = 640; }else{ w = (int)(480*w/h); h = 480; } imageico.setImage(imageico.getImage().getScaledInstance(w,h,imageico.getImage().SCALE_DEFAULT));
另外,就是文字識別的部分,主要仍是一個執行進程的過程,那麼首先得下載安裝Tesseract_OCR:ui
安裝下載的工做參考 這裏this
那麼這邊主要的挑戰就是使用java執行進程和作文件io,主要分一下幾點:
1.java操做命令行主要用到processbuilder & process 類,出自java.lang
通常都是ProcessBuilder.start() 和 Runtime.exec(ArrayList<String>) 方法建立一個本機進程,並返回 Process 子類的一個實例,該實例可用來控制進程並得到相關信息。Process 類提供了執行從進程輸入、執行輸出到進程、等待進程完成、檢查進程的退出狀態以及銷燬(殺掉)進程的方法。
Runtime.getRuntime.exec(ArrayList<String> cmd)
processbuilder pb; pb.command(ArrayList<String> cmd);
這裏就是用的processbuilder pb,新建一個實例,而且把運行參數保存到字符串表單cmd裏,而後pb.command(ArrayList<String> cmd)執行,結果保存到指定txt中;
2.表示文件的類file類 出自java.io
它是文件和目錄路徑名的抽象表示形式。
主要方法getName(),getPath(),getParentPath();
在執行命令行時,表示輸入的圖片,表示輸出txt均可以用到file類。
3.讀取字節流過程 出自java.io
FileInputStream 從文件系統中的某個文件中得到輸入字節。哪些文件可用取決於主機環境,這裏能夠讀取圖片。
new FileInputStream(outputFile.getAbsolutePath()) 新建一個文件輸入字節流
new InputStreamReader(new FileInputStream(outputFile.getAbsolutePath()),"UTF-8")。文件輸入字節流變成文件輸入字符流
BufferedReader從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。
主要是兩種用法還能夠這麼使用
BufferedReader in = new BufferedReader(new FileReader("foo.in"));
或者
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("foo.in"),"UTF-8"));
前者不能指定編碼,然後者能夠。
在最後把txt中文本讀取到java程序,進而顯示在GUI中用到
識別的代碼以下
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; public class textRecognizer{ private String textResult; /** * 輸出的結果 */ private final String EOL = System.getProperty("line.separator"); //回車 private String tessPath = "D:\\Tesseract-OCR"; //tessocr程序所在目錄 public textRecognizer(String path) { try { File imagefile = new File(path); textResult = this.recognizeText(imagefile); } catch (Exception e) { e.printStackTrace(); } } public String getResult(){ return textResult; } private String recognizeText(File imageFile) throws Exception { /** * 設置輸出文件的保存的文件目錄 */ File outputFile = new File(imageFile.getParentFile(),"output"); StringBuffer strB = new StringBuffer(); //設置cmd命令行字符串形式 List<String> cmd = new ArrayList<String>(); cmd.add(tessPath + "\\tesseract"); cmd.add(imageFile.getName()); cmd.add(outputFile.getName()); cmd.add("-l"); cmd.add("eng"); //啓動exe進程 ProcessBuilder pb = new ProcessBuilder(); pb.directory(imageFile.getParentFile()); pb.command(cmd); pb.redirectErrorStream(true); Process process = pb.start(); //等待此進程完成 int w = process.waitFor(); if (w == 0){// 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 recognize the image or its selected region."; break; case 31: msg = "Unsupported image format."; break; default: msg = "Errors occurred."; } throw new RuntimeException(msg); } new File(outputFile.getAbsolutePath()+ ".txt").delete(); /** * 若是作驗證碼 * return strB.toString().replaceAll("\\s*", ""); */ return strB.toString(); } }
惋惜的是最後檢測的結果通常。
今天寫程序期間還有其餘的有意思的地方我也有記錄。