利用tess-two和cv4j實現(xiàn)簡單的ocr功能

ocr

光學(xué)字符識別(英語:Optical Character Recognition, OCR)是指對文本資料的圖像文件進(jìn)行分析識別處理又憨,獲取文字及版面信息的過程翠霍。

Tesseract

Tesseract是Ray Smith于1985到1995年間在惠普布里斯托實驗室開發(fā)的一個OCR引擎蠢莺,曾經(jīng)在1995 UNLV精確度測試中名列前茅寒匙。但1996年后基本停止了開發(fā)。2006年躏将,Google邀請Smith加盟锄弱,重啟該項目考蕾。目前項目的許可證是Apache 2.0。該項目目前支持Windows会宪、Linux和Mac OS等主流平臺肖卧。但作為一個引擎,它只提供命令行工具掸鹅。 現(xiàn)階段的Tesseract由Google負(fù)責(zé)維護(hù)塞帐,是最好的開源OCR Engine之一,并且支持中文河劝。

tess-two是Tesseract在Android平臺上的移植壁榕。

下載tess-two:

compile 'com.rmtheis:tess-two:8.0.0'

然后將訓(xùn)練好的eng.traineddata放入android項目的assets文件夾中,就可以識別英文了赎瞎。

1. 簡單地識別英文

初始化tess-two牌里,加載訓(xùn)練好的tessdata

    private void prepareTesseract() {
        try {
            prepareDirectory(DATA_PATH + TESSDATA);
        } catch (Exception e) {
            e.printStackTrace();
        }

        copyTessDataFiles(TESSDATA);
    }

    /**
     * Prepare directory on external storage
     *
     * @param path
     * @throws Exception
     */
    private void prepareDirectory(String path) {

        File dir = new File(path);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                Log.e(TAG, "ERROR: Creation of directory " + path + " failed, check does Android Manifest have permission to write to external storage.");
            }
        } else {
            Log.i(TAG, "Created directory " + path);
        }
    }

    /**
     * Copy tessdata files (located on assets/tessdata) to destination directory
     *
     * @param path - name of directory with .traineddata files
     */
    private void copyTessDataFiles(String path) {
        try {
            String fileList[] = getAssets().list(path);

            for (String fileName : fileList) {

                // open file within the assets folder
                // if it is not already there copy it to the sdcard
                String pathToDataFile = DATA_PATH + path + "/" + fileName;
                if (!(new File(pathToDataFile)).exists()) {

                    InputStream in = getAssets().open(path + "/" + fileName);

                    OutputStream out = new FileOutputStream(pathToDataFile);

                    // Transfer bytes from in to out
                    byte[] buf = new byte[1024];
                    int len;

                    while ((len = in.read(buf)) > 0) {
                        out.write(buf, 0, len);
                    }
                    in.close();
                    out.close();

                    Log.d(TAG, "Copied " + fileName + "to tessdata");
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "Unable to copy files to tessdata " + e.toString());
        }
    }
取景框.JPG

拍完照后,調(diào)用startOCR方法务甥。

    private void startOCR(Uri imgUri) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 4; // 1 - means max size. 4 - means maxsize/4 size. Don't use value <4, because you need more memory in the heap to store your data.
            Bitmap bitmap = BitmapFactory.decodeFile(imgUri.getPath(), options);

            String result = extractText(bitmap);
            resultView.setText(result);

        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }
    }

extractText()會調(diào)用tess-two的api來實現(xiàn)ocr文字識別牡辽。

    private String extractText(Bitmap bitmap) {
        try {
            tessBaseApi = new TessBaseAPI();
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            if (tessBaseApi == null) {
                Log.e(TAG, "TessBaseAPI is null. TessFactory not returning tess object.");
            }
        }

        tessBaseApi.init(DATA_PATH, lang);

        tessBaseApi.setImage(bitmap);
        String extractedText = "empty result";
        try {
            extractedText = tessBaseApi.getUTF8Text();
        } catch (Exception e) {
            Log.e(TAG, "Error in recognizing text.");
        }
        tessBaseApi.end();
        return extractedText;
    }

最后,顯示識別的效果敞临,此時的效果還算可以态辛。


簡單地識別英文.JPG

2. 識別代碼

接下來,嘗試用上面的程序識別一段代碼挺尿。


識別代碼.JPG

此時奏黑,效果一塌糊涂。我們重構(gòu)一下startOCR()编矾,增加局部的二值化處理熟史。

    private void startOCR(Uri imgUri) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 4; // 1 - means max size. 4 - means maxsize/4 size. Don't use value <4, because you need more memory in the heap to store your data.
            Bitmap bitmap = BitmapFactory.decodeFile(imgUri.getPath(), options);

            CV4JImage cv4JImage = new CV4JImage(bitmap);
            Threshold threshold = new Threshold();
            threshold.adaptiveThresh((ByteProcessor)(cv4JImage.convert2Gray().getProcessor()), Threshold.ADAPTIVE_C_MEANS_THRESH, 12, 30, Threshold.METHOD_THRESH_BINARY);
            Bitmap newBitmap = cv4JImage.getProcessor().getImage().toBitmap(Bitmap.Config.ARGB_8888);

            ivImage2.setImageBitmap(newBitmap);

            String result = extractText(newBitmap);
            resultView.setText(result);

        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }
    }

在這里,使用cv4j來實現(xiàn)圖像的二值化處理窄俏。

            CV4JImage cv4JImage = new CV4JImage(bitmap);
            Threshold threshold = new Threshold();
            threshold.adaptiveThresh((ByteProcessor)(cv4JImage.convert2Gray().getProcessor()), Threshold.ADAPTIVE_C_MEANS_THRESH, 12, 30, Threshold.METHOD_THRESH_BINARY);
            Bitmap newBitmap = cv4JImage.getProcessor().getImage().toBitmap(Bitmap.Config.ARGB_8888);

圖像二值化就是將圖像上的像素點的灰度值設(shè)置為0或255蹂匹,也就是將整個圖像呈現(xiàn)出明顯的黑白效果。圖像的二值化有利于圖像的進(jìn)一步處理凹蜈,使圖像變得簡單限寞,而且數(shù)據(jù)量減小,能凸顯出感興趣的目標(biāo)的輪廓仰坦。

cv4j的github地址:https://github.com/imageprocessor/cv4j

cv4jgloomyfish和我一起開發(fā)的圖像處理庫履植,純java實現(xiàn)。

再來試試效果悄晃,圖片中間部分是二值化后的效果静尼,此時基本能識別出代碼的內(nèi)容。


先做二值化再識別代碼.JPG

3. 識別中文

如果要識別中文字體传泊,需要使用中文的數(shù)據(jù)包鼠渺。可以去下面的網(wǎng)站上下載眷细。

https://github.com/tesseract-ocr/tessdata

跟中文相關(guān)的數(shù)據(jù)包有chi_sim.traineddata拦盹、chi_tra.traineddata,它們分別表示是簡體中文和繁體中文溪椎。

tessBaseApi.init(DATA_PATH, lang);

前面的例子都是識別英文的普舆,所以原先的lang值為"eng",現(xiàn)在要識別簡體中文的話需要將其值改為"chi_sim"校读。

識別中文.JPG

最后

本項目只是demo級別的演示沼侣,離生產(chǎn)環(huán)境的使用還差的很遠(yuǎn)。
本項目的github地址:https://github.com/fengzhizi715/Tess-TwoDemo

為何說只是demo級別呢歉秫?

  • 數(shù)據(jù)包很大蛾洛,特別是中文的大概有50多M,放在移動端的肯定不合適雁芙。一般正確的做法轧膘,都是放在云端。
  • 識別文字很慢兔甘,特別是中文谎碍,工程上還有很多優(yōu)化的空間。
  • 做ocr之前需要做很多預(yù)處理的工作洞焙,在本例子中只用了二值化蟆淀,其實還有很多預(yù)處理的步驟比如傾斜校正、字符切割等等澡匪。
  • 為了提高tess-two的識別率熔任,可以自己訓(xùn)練數(shù)據(jù)集。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末仙蛉,一起剝皮案震驚了整個濱河市笋敞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌荠瘪,老刑警劉巖夯巷,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異哀墓,居然都是意外死亡趁餐,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門篮绰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來后雷,“玉大人,你說我怎么就攤上這事⊥瓮唬” “怎么了勉抓?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長候学。 經(jīng)常有香客問我藕筋,道長,這世上最難降的妖魔是什么梳码? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任隐圾,我火速辦了婚禮,結(jié)果婚禮上掰茶,老公的妹妹穿的比我還像新娘暇藏。我一直安慰自己,他們只是感情好濒蒋,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布盐碱。 她就那樣靜靜地躺著,像睡著了一般啊胶。 火紅的嫁衣襯著肌膚如雪甸各。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天焰坪,我揣著相機(jī)與錄音趣倾,去河邊找鬼。 笑死某饰,一個胖子當(dāng)著我的面吹牛儒恋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播黔漂,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼诫尽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了炬守?” 一聲冷哼從身側(cè)響起牧嫉,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎减途,沒想到半個月后酣藻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡鳍置,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年辽剧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片税产。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡怕轿,死狀恐怖偷崩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撞羽,我是刑警寧澤阐斜,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站放吩,受9級特大地震影響智听,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渡紫,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望考赛。 院中可真熱鬧惕澎,春花似錦、人聲如沸颜骤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忍抽。三九已至八孝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鸠项,已是汗流浹背干跛。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留祟绊,地道東北人楼入。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像牧抽,于是被迫代替她去往敵國和親嘉熊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 不好意思,這個名字忒俗了讲坎,忒不文雅了孕惜,不過,這句話道出了我的心思衣赶。 工作中诊赊,你有沒有發(fā)現(xiàn)這樣一種人?...
    大錢小胖閱讀 301評論 2 1
  • 馬上就要這個學(xué)期的學(xué)習(xí)啦府瞄,馬上就有兩門超級無敵難的考試過了之后就是短暫的休息時間碧磅,之后就可以繼續(xù)認(rèn)真學(xué)習(xí)WSET然...
    LuryYang閱讀 434評論 0 0
  • 洛克菲勒自傳 約翰·D·洛克菲勒 美國石油大王碘箍,洛克菲勒財團(tuán)的創(chuàng)始人,美...
    哇魯魯220閱讀 464評論 0 0
  • 今天早上送女兒到幼兒園鲸郊,老師帶領(lǐng)別的孩子在跳繩丰榴。看著別的小朋友都會跳了秆撮,我女兒還不會跳四濒,于是留下來看看老師會不會教...
    多多少少7閱讀 724評論 1 0