Android中使用orc實現(xiàn)文字識別

一荚孵、什么是orc?

引用百度百科的介紹妹窖,指利用光學字符識別(ORC全稱:Optical Character Recognition)技術,將圖片收叶、照片上的文字內(nèi)容骄呼,直接轉換為可編輯文本,支持JPG、PNG蜓萄、GIF隅茎、BMP、DOC等圖片格式嫉沽。簡單一句話辟犀,就是可以把圖片上的文字識別出來。應用的場景有很多绸硕,比如說:身份證號碼識別堂竟,銀行卡號識別等等。

二臣咖、效果展示

身份證號識別

三跃捣、開始集成

Github上面已經(jīng)提供了android端的工具api,Github地址:https://github.com/rmtheis/tess-two<br />

集成流程<br />
1.下載中文簡體語言包
2.導入依賴
3.API的使用夺蛇,獲取TessBaseAPI mBaseAPI = new TessBaseAPI();實例
4.API的使用疚漆,初始化TessBaseAPI設置,設置識別的語言和語言包所在文件路徑 mBaseAPI.init(path + File.separator, "chi_sim");
5.API的使用刁赦,設置Bitmap娶聘,mBaseAPI.setImage(bitmap);
6.API的使用,從Bitmap獲取文字信息甚脉,mBaseAPI.getUTF8Text();

1.下載中文簡體語言包

語言包下載地址
找到tessdata——>chi_sim.traineddata<br />
下載好了之后丸升,需要放到sd卡中,目錄不限牺氨,但是必須要放在tessdata目錄里面狡耻,如果沒有tessdata目錄需要手動創(chuàng)建,例如我是Demo中是放在sd卡根目錄中猴凹,就直接在sd卡根目錄創(chuàng)建tessdata目錄夷狰,然后把下載好的chi_sim.traineddata語言包丟進去,實際項目中,在識別時候最好坐下語言包是否復制到位的檢查郊霎,以免出現(xiàn)異常沼头。Demo中僅僅是檢查了是否創(chuàng)建tessdata目錄,這里實際上仍然存在風險的书劝。

2.導入依賴

Gradle方式添加:

https://github.com/rmtheis/tess-two

3.MainActivity代碼

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private TextView mTvInfo;
private TessBaseAPI mBaseAPI;
private ProgressBar mProbar;
private String path;
private RadioGroup mRadioGroup;
private RadioButton mRbtnIdCard;
private RadioButton mRbtnBankNumber;
private RadioButton mRbtnTxt;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.btn_start).setOnClickListener(this);
    mProbar = (ProgressBar) findViewById(R.id.pb);
    mTvInfo = (TextView) findViewById(R.id.tv_info);
    mRadioGroup = (RadioGroup) findViewById(R.id.rg);
    mRbtnIdCard = (RadioButton) findViewById(R.id.rb_idCard);
    mRbtnBankNumber = (RadioButton) findViewById(R.id.rb_bankNumber);
    mRbtnTxt = (RadioButton) findViewById(R.id.rb_txt);
    mRadioGroup.check(0);

    path = Environment.getExternalStorageDirectory().getAbsoluteFile().getAbsolutePath();
}

@Override
public void onClick(View v) {
    mTvInfo.setText("");
    switch (v.getId()) {
        case R.id.btn_start:
            if (Build.VERSION.SDK_INT >= 23) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    // 沒有權限
                    if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)){
                        //如果沒勾選“不再詢問”进倍,向用戶發(fā)起權限請求
                        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 0);
                    }else{
                        Toast.makeText(this,"請前往設置——>存儲卡權限——>允許",Toast.LENGTH_SHORT).show();
                    }
                } else {
                    // 有權限,接著你要干的活
                    startReadText();
                }
            }else{
                startReadText();
            }
            break;
    }
}


private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 0:
                String s = (String) msg.obj;
                if (!TextUtils.isEmpty(s)) {
                    mProbar.setVisibility(View.GONE);
                    mTvInfo.setText(s);
                    //釋放bitmap
                    mBaseAPI.clear();
                } else {
                    mProbar.setVisibility(View.GONE);
                    Toast.makeText(MainActivity.this, "識別圖片內(nèi)容失敗", Toast.LENGTH_SHORT).show();
                }

                break;
            case 1:
                Toast.makeText(MainActivity.this, "讀取圖片失敗", Toast.LENGTH_SHORT).show();
                break;
        }
    }
};

private Bitmap getBitmap(int id) {
    Bitmap bitmap = null;
    try {
        bitmap = BitmapFactory.decodeResource(getResources(), id);
    } catch (Exception e) {
        return null;
    }
    return bitmap;
}

/**
 * 開始識別文字
 */
private void startReadText() {

    File f = new File(path+"/tessdata") ;
    if(!f.exists()){
        Toast.makeText(this,"請先下載好語言包置于sd/tessdata目錄",Toast.LENGTH_SHORT).show();
        return;
    }

    final int btnId = mRadioGroup.getCheckedRadioButtonId();
    final int resId ;
    if(R.id.rb_idCard==btnId){
        resId = R.drawable.idcard;
    }else if(R.id.rb_bankNumber==btnId){
        resId = R.drawable.bank_number;
    }else{
        resId = R.drawable.tet_info;
    }

    mProbar.setVisibility(View.VISIBLE);
    new Thread() {
        @Override
        public void run() {
            mBaseAPI = new TessBaseAPI();//初始化需要耗時,可以啟動時程序時购对,預初始化
            mBaseAPI.init(path + File.separator, "chi_sim");
            Bitmap bitmap = getBitmap(resId);
            if (bitmap == null) {
                mHandler.sendEmptyMessage(1);
            } else {
                mBaseAPI.setImage(bitmap);
                //根據(jù)Init的語言猾昆,獲得ocr后的字符串
                String t = mBaseAPI.getUTF8Text();//耗時操作
                Message obtain = Message.obtain();
                obtain.what = 0;
                obtain.obj = t;
                mHandler.sendMessage(obtain);
            }
        }
    }.start();
}
}

4.activity_main.xml代碼

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.demo.orc.MainActivity">

<RadioGroup
    android:id="@+id/rg"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <RadioButton
        android:checked="true"
        android:id="@+id/rb_idCard"
        android:text="身份證"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <RadioButton
        android:id="@+id/rb_bankNumber"
        android:text="銀行卡"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <RadioButton
        android:id="@+id/rb_txt"
        android:text="文字"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RadioGroup>


<Button
    android:id="@+id/btn_start"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="開始識別"/>

<TextView
    android:text="識別結果展示區(qū):"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        android:id="@+id/pb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="gone"/>

    <TextView
        android:id="@+id/tv_info"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text=""/>

</FrameLayout>
</LinearLayout>

四、提高識別率

Demo識別率其實不是很理想骡苞,比如把數(shù)字0識別成了字母O等垂蜗,這是因為我們的根本沒有進行樣本訓練坑赡。關于樣本的訓練,我目前還沒實際操作過么抗,因為公司的識別需求更為復雜,這個框架難以達到效果亚铁,公司買了第三方的一個識別框架蝇刀。不過僅僅是實現(xiàn)身份證號,銀行卡號徘溢,和一些簡單的文字信息吞琐,用這個框架足以實現(xiàn)。需要樣本訓練的童鞋可以參考這篇博客:樣本訓練博客 然爆。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末站粟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子曾雕,更是在濱河造成了極大的恐慌奴烙,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剖张,死亡現(xiàn)場離奇詭異切诀,居然都是意外死亡,警方通過查閱死者的電腦和手機搔弄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門幅虑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人顾犹,你說我怎么就攤上這事倒庵。” “怎么了炫刷?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵擎宝,是天一觀的道長。 經(jīng)常有香客問我柬唯,道長认臊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任锄奢,我火速辦了婚禮失晴,結果婚禮上,老公的妹妹穿的比我還像新娘拘央。我一直安慰自己涂屁,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布灰伟。 她就那樣靜靜地躺著拆又,像睡著了一般儒旬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上帖族,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天栈源,我揣著相機與錄音,去河邊找鬼竖般。 笑死甚垦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的涣雕。 我是一名探鬼主播艰亮,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼挣郭!你這毒婦竟也來了迄埃?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤兑障,失蹤者是張志新(化名)和其女友劉穎侄非,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體流译,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡彩库,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了先蒋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骇钦。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖竞漾,靈堂內(nèi)的尸體忽然破棺而出眯搭,到底是詐尸還是另有隱情,我是刑警寧澤业岁,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布鳞仙,位于F島的核電站,受9級特大地震影響笔时,放射性物質(zhì)發(fā)生泄漏棍好。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一允耿、第九天 我趴在偏房一處隱蔽的房頂上張望借笙。 院中可真熱鬧,春花似錦较锡、人聲如沸业稼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽低散。三九已至俯邓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間熔号,已是汗流浹背稽鞭。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留引镊,地道東北人川慌。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像祠乃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子兑燥,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

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