下面是整个详解步骤过程
效果图
- 流程:获取assets中的图片显示到页面,提取照片内的文字
一、OCR的含义
ocr是Optical Character Recognition(光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程
二、什么是Tesseract
简单地说,Tesseract 就是OCR所说的"识别软件"的具体实现
- 其实看官网已经是5、6年前就开始不维护了
- 这里也指明了,不在维护,可前往 Tesseract Tools 的一个分支Tesseract4Android官网,这里还是写一下Tesseract 的demo吧,做参考
当然你也可以直接去Tesseract4Android的参考文章
Tesseract4Android参考文章
三、前提准备
1、添加依赖
注意:
1、Android 2.3 或更高版本
2、数据文件必须是 复制到 Android 设备的子目录中tessdata(上一级文件夹的名称必须是tessdata,后缀必须是.traineddata)
javascript
dependencies {
implementation 'com.rmtheis:tess-two:9.1.0'
}
2、数据文件下载路径
- 数据包下载下来放到assets文件夹下
四、实际代码案例Demo如下:
Main.xml
javascript
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ImageView
android:id="@+id/main_iv_image"
android:layout_width="match_parent"
android:layout_height="500dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"/>
<Button
android:id="@+id/main_bt_recognize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_gravity="center_horizontal"
android:text="读取一张图片并识别" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_gravity="center_horizontal"
android:text="识别结果:" />
<TextView
android:id="@+id/main_tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_gravity="center_horizontal" />
</LinearLayout>
Main.java
javascript
package com.example.ocrapplication.ui;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.ocrapplication.R;
import com.googlecode.tesseract.android.TessBaseAPI;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class TesseractActivity extends AppCompatActivity {
public static final String TESS_DATA = "/tessdata";
private static final String TARGET_FILENAME = "cs.png";
// private static final String DATA_FILENAME = "eng.traineddata";
private static final String DATA_FILENAME = "chi_sim.traineddata";
private static final String TAG = TesseractActivity.class.getSimpleName();
private Button main_bt_recognize;
private TextView main_tv_result;
private ImageView main_iv_image;
private Bitmap bitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tesseract);
// 检查并请求应用所需权限
checkPermission();
// 获取控件对象
initView();
// 设置控件的监听器
setListener();
}
@SuppressLint("HandlerLeak")
private Handler handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
Bundle data = msg.getData();
main_tv_result.setText(data.getString("data"));
break;
}
}
};
private void setListener() {
// 设置识别按钮的监听器
main_bt_recognize.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 点击后的主程序
mainProgram();
}
});
}
// 获得界面需要交互的控件
private void initView() {
main_bt_recognize = findViewById(R.id.main_bt_recognize);
main_tv_result = findViewById(R.id.main_tv_result);
main_iv_image = findViewById(R.id.main_iv_image);
// 从assets中获取一张Bitmap图片
bitmap = getBitmapFromAssets(TesseractActivity.this, TARGET_FILENAME);
// 同时显示在界面
main_iv_image.setImageBitmap(bitmap);
}
// OCR识别的主程序
private void mainProgram() {
if (bitmap != null) {
// 准备工作:创建路径和Tesserect的数据
prepareTess();
// 初始化Tesserect
TessBaseAPI tessBaseAPI = new TessBaseAPI();
String dataPath = getExternalFilesDir("/").getPath() + "/";
tessBaseAPI.init(dataPath, "chi_sim");
//因为识别比较耗时,建议开启开启子线程识别
new Thread(new Runnable() {
@Override
public void run() {
// 识别并显示结果
String result = getOCRResult(tessBaseAPI, bitmap);
//把数据返回到主线程上面显示
Message message=new Message();
message.what=1;
Bundle bundle = new Bundle();
bundle.putString("data",result);
message.setData(bundle);
handler.sendMessage(message);
}
}).start();
}
}
// 进行OCR并返回识别结果
private String getOCRResult(TessBaseAPI tessBaseAPI, Bitmap bitmap) {
tessBaseAPI.setImage(bitmap);
String result = "-";
try{
result = tessBaseAPI.getUTF8Text();
}catch (Exception e){
}
tessBaseAPI.end();
return result;
}
// 为Tesserect复制(从assets中复制过去)所需的数据
private void prepareTess() {
try{
// 先创建必须的目录
File dir = getExternalFilesDir(TESS_DATA);
if(!dir.exists()){
if (!dir.mkdir()) {
Toast.makeText(getApplicationContext(), "目录" + dir.getPath() + "没有创建成功", Toast.LENGTH_SHORT).show();
}
}
// 从assets中复制必须的数据
String pathToDataFile = dir + "/" + DATA_FILENAME;
if (!(new File(pathToDataFile)).exists()) {
InputStream in = getAssets().open(DATA_FILENAME);
OutputStream out = new FileOutputStream(pathToDataFile);
byte[] buff = new byte[1024];
int len;
while ((len = in.read(buff)) > 0) {
out.write(buff, 0, len);
}
in.close();
out.close();
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
// 从assets中读取一张Bitmap类型的图片
private Bitmap getBitmapFromAssets(Context context, String filename) {
Bitmap bitmap = null;
AssetManager assetManager = context.getAssets();
try {
InputStream is = assetManager.open(filename);
bitmap = BitmapFactory.decodeStream(is);
is.close();
Log.i("TAG", "图片读取成功。");
// Toast.makeText(getApplicationContext(), "图片读取成功。", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Log.i("TAG", "图片读取失败。");
// Toast.makeText(getApplicationContext(), "图片读取失败。", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
return bitmap;
}
// 检查应用所需的权限,如不满足则发出权限请求
private void checkPermission() {
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(TesseractActivity.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 120);
}
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(TesseractActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 121);
}
}
}