Android中使用orc實(shí)現(xiàn)文字識(shí)別實(shí)例
一、什么是orc?
引用百度百科的介紹,指利用光學(xué)字符識(shí)別(ORC全稱:Optical Character Recognition)技術(shù),將圖片、照片上的文字內(nèi)容,直接轉(zhuǎn)換為可編輯文本,支持JPG、PNG、GIF、BMP、DOC等圖片格式。簡(jiǎn)單一句話,就是可以把圖片上的文字識(shí)別出來(lái)。應(yīng)用的場(chǎng)景有很多,比如說(shuō):身份證號(hào)碼識(shí)別,銀行卡號(hào)識(shí)別等等。
二、效果展示
這里筆者實(shí)現(xiàn)的僅僅是一個(gè)效果,實(shí)際使用可能需要對(duì)它進(jìn)行訓(xùn)練以提高識(shí)別率,第一次做gif圖片,效果不是很好



三、開始集成
Github上面已經(jīng)提供了android端的工具api,Github地址:https://github.com/rmtheis/tess-two
集成流2
1.下載中文簡(jiǎn)體語(yǔ)言包
2.導(dǎo)入依賴
3.API的使用,獲取TessBaseAPI mBaseAPI = new TessBaseAPI();實(shí)例
4.API的使用,初始化TessBaseAPI設(shè)置,設(shè)置識(shí)別的語(yǔ)言和語(yǔ)言包所在文件路徑 mBaseAPI.init(path + File.separator, "chi_sim");
5.API的使用,設(shè)置Bitmap,mBaseAPI.setImage(bitmap);
6.API的使用,從Bitmap獲取文字信息,mBaseAPI.getUTF8Text();
1.下載中文簡(jiǎn)體語(yǔ)言包
找到tessdata——>chi_sim.traineddata
下載好了之后,需要放到sd卡中,目錄不限,但是必須要放在tessdata目錄里面,如果沒有tessdata目錄需要手動(dòng)創(chuàng)建,例如我是Demo中是放在sd卡根目錄中,就直接在sd卡根目錄創(chuàng)建tessdata目錄,然后把下載好的chi_sim.traineddata語(yǔ)言包丟進(jìn)去,實(shí)際項(xiàng)目中,在識(shí)別時(shí)候最好坐下語(yǔ)言包是否復(fù)制到位的檢查,以免出現(xiàn)異常。Demo中僅僅是檢查了是否創(chuàng)建tessdata目錄,這里實(shí)際上仍然存在風(fēng)險(xiǎn)的。
2.導(dǎo)入依賴
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) {
// 沒有權(quán)限
if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)){
//如果沒勾選“不再詢問(wèn)”,向用戶發(fā)起權(quán)限請(qǐng)求
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 0);
}else{
Toast.makeText(this,"請(qǐng)前往設(shè)置——>存儲(chǔ)卡權(quán)限——>允許",Toast.LENGTH_SHORT).show();
}
} else {
// 有權(quán)限,接著你要干的活
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, "識(shí)別圖片內(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;
}
/**
* 開始識(shí)別文字
*/
private void startReadText() {
File f = new File(path+"/tessdata") ;
if(!f.exists()){
Toast.makeText(this,"請(qǐng)先下載好語(yǔ)言包置于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();//初始化需要耗時(shí),可以啟動(dòng)時(shí)程序時(shí),預(yù)初始化
mBaseAPI.init(path + File.separator, "chi_sim");
Bitmap bitmap = getBitmap(resId);
if (bitmap == null) {
mHandler.sendEmptyMessage(1);
} else {
mBaseAPI.setImage(bitmap);
//根據(jù)Init的語(yǔ)言,獲得ocr后的字符串
String t = mBaseAPI.getUTF8Text();//耗時(shí)操作
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="開始識(shí)別"/>
<TextView
android:text="識(shí)別結(jié)果展示區(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>
四、提高識(shí)別率
Demo識(shí)別率其實(shí)不是很理想,比如把數(shù)字0識(shí)別成了字母O等,這是因?yàn)槲覀兊母緵]有進(jìn)行樣本訓(xùn)練。關(guān)于樣本的訓(xùn)練,我目前還沒實(shí)際操作過(guò),因?yàn)楣镜淖R(shí)別需求更為復(fù)雜,這個(gè)框架難以達(dá)到效果,公司買了第三方的一個(gè)識(shí)別框架。不過(guò)僅僅是實(shí)現(xiàn)身份證號(hào),銀行卡號(hào),和一些簡(jiǎn)單的文字信息,用這個(gè)框架足以實(shí)現(xiàn)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android?Flutter實(shí)現(xiàn)自由落體彈跳動(dòng)畫效果
粒子運(yùn)動(dòng)是將對(duì)象按照一定物理公式進(jìn)行的自定義軌跡運(yùn)動(dòng),與普通動(dòng)畫不同的是,它沒有強(qiáng)制性的動(dòng)畫開始到結(jié)束的時(shí)間概念。本文將利用Flutter實(shí)現(xiàn)自由落體彈跳動(dòng)畫效果,感興趣的小伙伴可以學(xué)習(xí)一下2022-10-10
Kotlin 封裝萬(wàn)能SharedPreferences存取任何類型詳解
這篇文章主要介紹了Kotlin 封裝萬(wàn)能SharedPreferences存取任何類型詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05
Android統(tǒng)一處理登錄后攜帶數(shù)據(jù)跳轉(zhuǎn)到目標(biāo)頁(yè)面的方式
我們?cè)陂_發(fā)的時(shí)候,一定會(huì)遇到頁(yè)面跳轉(zhuǎn),下面這篇文章主要給大家介紹了關(guān)于Android統(tǒng)一處理登錄后攜帶數(shù)據(jù)跳轉(zhuǎn)到目標(biāo)頁(yè)面的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06
Android通過(guò)訪問(wèn)網(wǎng)頁(yè)查看網(wǎng)頁(yè)源碼實(shí)例詳解
這篇文章主要介紹了Android通過(guò)訪問(wèn)網(wǎng)頁(yè)查看網(wǎng)頁(yè)源碼的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android編程實(shí)現(xiàn)webview將網(wǎng)頁(yè)打包成apk的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)webview將網(wǎng)頁(yè)打包成apk的方法,以打包HTML5為例分析了webview打包apk的相關(guān)方法、屬性與事件操作技巧,需要的朋友可以參考下2017-08-08
Android RecyclerView網(wǎng)格布局(支持多種分割線)詳解(2)
這篇文章主要為大家詳細(xì)介紹了Android RecyclerView網(wǎng)格布局,支持多種分割線,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
基于Android平臺(tái)實(shí)現(xiàn)拼圖小游戲
這篇文章主要為大家詳細(xì)介紹了基于Android平臺(tái)實(shí)現(xiàn)拼圖小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Android 中TeaPickerView數(shù)據(jù)級(jí)聯(lián)選擇器功能的實(shí)例代碼
這篇文章主要介紹了Android TeaPickerView數(shù)據(jù)級(jí)聯(lián)選擇器 ,需要的朋友可以參考下2019-06-06

