AndroidStudio使用百度SDK完成OCR文字识别

2 篇文章 0 订阅

前言

OCR 是 Optical Character Recognition 的缩写,翻译为光学字符识别,指的是针对印刷体字符,采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,通过识别软件将图像中的文字转换成文本格式,供文字处理软件进一步编辑加工的技术(当然,这是我抄别人的原话)。

先安利一下百度智能云,有大佬建好的轮子,咱们申请一下就可以用了,审核很快。当然也可以使用腾讯云和阿里云。

接入百度SDK

申请免费试用之后(当然要申请免费的,学习成本低),下载(下载地址)解压,会有这样的文件夹:
在这里插入图片描述
百度老哥已经给我们详细的提示了,这里可以了解下各个包的用法,简单过一下。如果不需要使用百度给的UI的话,只导入libs下的文件到项目中的lib中就可以了,其中libs中有四个文件夹和一个jar包,四个文件夹中是so文件,导入so文件看这里。

在build.gradle中的android下面添加

sourceSets {

    main {
        jniLibs.srcDirs= ['libs']
    }

}

加上这串代码,就可以实现将module下libs中的so一起打包到apk中。

在这里插入图片描述
如果你想导入UI包怎么办?百度的4已经告诉大家最好的方法是以模块方式导入,这里也介绍一下模块方式导入。
在这里插入图片描述
接下来选择对应的文件夹就行了,当然没那么简单,下面还需要在主工程下引入进去。
在bulid.gradle文件的dependencies里加入
implementation project(path: ‘:ocr_ui’)
在settings.gradle下加入
include ‘:app’, ':ocr_ui’
这样就导入模块成功了。

代码部分

我是采用了导入明文ak,sk的方式,UI我也导入了,但是相机那里出了问题,还不能使用。大家可以自己写个启动相机获取图片的方法,因为还需要用到provider的关系,我并没有使用,而是直接从图库选择图片这种方便的形式,有兴趣的童鞋可以自己补上拍照的方式。

package com.kxqin.ocrtest;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.widget.Toast;
import com.baidu.ocr.sdk.OCR;
import com.baidu.ocr.sdk.OnResultListener;
import com.baidu.ocr.sdk.exception.OCRError;
import com.baidu.ocr.sdk.model.AccessToken;

public class MainActivity extends AppCompatActivity {

    private boolean hasGotToken = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initAccessTokenWithAkSk();
        findViewById(R.id.btn_simple_text).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!checkTokenStatus()) {
                    return;
                }
                Intent intent = new Intent(MainActivity.this, SimpleTextActivity.class);
                startActivity(intent);
            }
        });
    }

    private boolean checkTokenStatus() {
        if (!hasGotToken) {
            Toast.makeText(getApplicationContext(), "token未获取到", Toast.LENGTH_SHORT).show();
        }
        return hasGotToken;
    }

    /**
     * 使用明文方式初始化token
     */
    private void initAccessTokenWithAkSk() {
        OCR.getInstance(this).initAccessTokenWithAkSk(new OnResultListener<AccessToken>() {
            @Override
            public void onResult(AccessToken accessToken) {
                String token = accessToken.getAccessToken();
                hasGotToken = true;
            }

            @Override
            public void onError(OCRError error) {
                error.printStackTrace();
                Looper.prepare();
                Toast.makeText(MainActivity.this, "token获取失败.........", Toast.LENGTH_SHORT).show();
            }
        }, this, "此处应该填你的AK", "你的SK");
    }
}

主页面现在只写了一个按钮,普通文本识别按钮,因为初步只完成了这个,后续有空我会把其他的识别都加上,毕竟百度送的免费的30天不用可就浪费了。initAccessTokenWithAkSk方法进行token通行证的确认ak和sk大家可以在百度控制台那里获取,和使用其他sdk一样都会创建应用,获取明文密钥的。

package com.kxqin.ocrtest;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import com.baidu.ocr.sdk.OCR;
import com.baidu.ocr.sdk.OnResultListener;
import com.baidu.ocr.sdk.exception.OCRError;
import com.baidu.ocr.sdk.model.GeneralBasicParams;
import com.baidu.ocr.sdk.model.GeneralResult;
import com.baidu.ocr.sdk.model.WordSimple;
import com.baidu.ocr.ui.camera.CameraActivity;
import com.baidu.ocr.ui.camera.CameraNativeHelper;
import com.baidu.ocr.ui.camera.CameraView;

import java.io.File;
import java.util.List;

public class SimpleTextActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_CAMERA = 102;
    private int REQUEST_CODE_ALBUM = 2;
    private int REQUEST_ENHANCED_CODE_ALBUM = 3;

    private TextView infoTextView;
    private AlertDialog.Builder alertDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_simple_text);
        alertDialog = new AlertDialog.Builder(this);
        infoTextView = findViewById(R.id.info_text_view);
        CameraNativeHelper.init(this, OCR.getInstance(this).getLicense(),
                new CameraNativeHelper.CameraNativeInitCallback() {
                    @Override
                    public void onError(int errorCode, Throwable e) {
                        String msg;
                        switch (errorCode) {
                            case CameraView.NATIVE_SOLOAD_FAIL:
                                msg = "加载so失败,请确保apk中存在ui部分的so";
                                break;
                            case CameraView.NATIVE_AUTH_FAIL:
                                msg = "授权本地质量控制token获取失败";
                                break;
                            case CameraView.NATIVE_INIT_FAIL:
                                msg = "本地质量控制";
                                break;
                            default:
                                msg = String.valueOf(errorCode);
                        }
                        infoTextView.setText("本地质量控制初始化错误,错误原因: " + msg);
                    }
                });
        findViewById(R.id.take_a_photo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (checkGalleryPermission()) {
                    Intent intent = new Intent(SimpleTextActivity.this, CameraActivity.class);
                    intent.putExtra(CameraActivity.KEY_OUTPUT_FILE_PATH, FileUtil.getSaveFile(getApplication()).getAbsoluteFile());
                    intent.putExtra(CameraActivity.KEY_CONTENT_TYPE, CameraActivity.CONTENT_TYPE_GENERAL);
                    startActivityForResult(intent, REQUEST_CODE_CAMERA);
                }
            }
        });
        findViewById(R.id.select_a_photo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(Intent.ACTION_PICK, null);
                intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
                startActivityForResult(intent, REQUEST_CODE_ALBUM);
            }
        });
        findViewById(R.id.enhanced_photo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(Intent.ACTION_PICK, null);
                intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
                startActivityForResult(intent, REQUEST_ENHANCED_CODE_ALBUM);
            }
        });

    }

    /**
     * 文字普通识别
     * @param filePath
     */
    private void recSimpleText(String filePath) {
        // 通用文字识别参数设置
        GeneralBasicParams param = new GeneralBasicParams();
        param.setDetectDirection(true);
        param.setImageFile(new File(filePath));

        // 调用通用文字识别服务
        OCR.getInstance(this).recognizeGeneralBasic(param, new OnResultListener<GeneralResult>() {
            @Override
            public void onResult(GeneralResult generalResult) {
                if (generalResult != null) {
                    //alertText("", parseResultBean(generalResult));
                    setInfoTextView(parseResultBean(generalResult));
                }
            }

            @Override public void onError(OCRError error) {
                // 调用失败,返回OCRError对象
                alertText("调用失败", error.getMessage());
                } });
    }

    /**
     * 文字高精度识别
     * @param filePath
     */
    private void recEnhancedText(String filePath) {
        GeneralBasicParams params = new GeneralBasicParams();
        params.setDetectDirection(true);
        params.setImageFile(new File(filePath));

        OCR.getInstance(this).recognizeAccurateBasic(params, new OnResultListener<GeneralResult>() {
            @Override
            public void onResult(GeneralResult generalResult) {
                if (generalResult != null) {
                    //alertText("", parseResultBean(generalResult));
                    setInfoTextView(parseResultBean(generalResult));
                }
            }

            @Override
            public void onError(OCRError ocrError) {
                // 调用失败,返回OCRError对象
                alertText("调用失败", ocrError.getMessage());
            }
        });
    }

    /**
     * 解析返回结果
     * @param generalResult
     * @return
     */
    private String parseResultBean(GeneralResult generalResult) {
        StringBuilder stringBuilder = new StringBuilder();
        List<?> list = generalResult.getWordList();
        for (Object o : list) {
            if (o instanceof WordSimple) {
                stringBuilder.append(((WordSimple) o).getWords());
                stringBuilder.append("\n\n");
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 检查是否有权限
     * @return
     */
    private boolean checkGalleryPermission() {
        int ret = ActivityCompat.checkSelfPermission(SimpleTextActivity.this, Manifest.permission
                .READ_EXTERNAL_STORAGE);
        if (ret != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(SimpleTextActivity.this,
                    new String[] {Manifest.permission.READ_EXTERNAL_STORAGE},
                    1000);
            return false;
        }
        return true;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_CODE_CAMERA && resultCode == Activity.RESULT_OK) {
            if (data != null) {
                String contentType = data.getStringExtra(CameraActivity.KEY_CONTENT_TYPE);
                String filePath = FileUtil.getSaveFile(getApplicationContext()).getAbsolutePath();
                if (!TextUtils.isEmpty(contentType)) {
                    if (CameraActivity.CONTENT_TYPE_GENERAL.equals(contentType)) {
                        recSimpleText(filePath);
                    }
                }
            }
        }else if (requestCode == REQUEST_CODE_ALBUM) {
            // 从相册返回的数据
            if (data != null) {
                // 得到图片的全路径
                Uri uri = data.getData();
                recSimpleText(getRealPathFromURI(uri));
            }
        }
        else if (requestCode == REQUEST_ENHANCED_CODE_ALBUM) {
            // 从相册返回的数据
            if (data != null) {
                // 得到图片的全路径
                Uri uri = data.getData();
                recEnhancedText(getRealPathFromURI(uri));
            }
        }
    }

    /**
     * 错误弹窗
     * @param title
     * @param message
     */
    private void alertText(final String title, final String message) {
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                alertDialog.setTitle(title)
                        .setMessage(message)
                        .setPositiveButton("确定", null)
                        .show();
            }
        });
    }

    /**
     * 设置显示结果
     * @param text
     */
    private void setInfoTextView(final String text) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                infoTextView.setText(text);
            }
        });
    }

    /**
     * 将URI转化为string格式
     * @param contentURI
     * @return
     */
    private String getRealPathFromURI(Uri contentURI) {
        String result;
        Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
        if (cursor == null) {
            // Source is Dropbox or other similar local file path
            result = contentURI.getPath();
        } else {
            cursor.moveToFirst();
            int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            result = cursor.getString(idx);
            cursor.close();
        }
        return result;
    }

    @Override
    protected void onDestroy() {
        // 释放本地质量控制模型
        CameraNativeHelper.release();
        super.onDestroy();
    }
}

这里面我也是仿照Demo写的,但是不一样的是我只是做了简单的文字识别,而且相机拍照emmm还是坏的。原因也是我了解了一下才知道拍照所需要的东西并不止这些,需要另外准备,为了先简单实现识别,这个拍照之后再做吧。方法的注释大概解释了每个方法的作用,其实并没有什么好说的,因为这都是根据百度API介绍写的最简单的,简单来说就是打开相册-获取图片地址-传到百度服务器-返回结果类,然后自己解析结果类里面的list即可。如果没有使用到UI的话,那也用不到CameraActivity之类的。目前我也没有使用。

结果

先来一个不是很清楚的渣手机拍照
在这里插入图片描述
在这里插入图片描述

昨晚的五杀拍照!你看文字还是识别的很准确的,但是带了符号之类的会影响识别。
百度sdk也说了 最好控制图片大小,因为就算太大的图片上传也会被压缩,影响质量。同时一个页面中的字数建议小于70个字,字数过多过密也会影响识别结果,当然这是高精度下的识别结果,你问我普通识别呢?这。。。普通识别下建议只用于截屏或者文档识别吧,要不然识别的内容惨不忍睹。

再来看看一个截屏下的识别结果:
在这里插入图片描述
在这里插入图片描述

我这算不算受到骚扰呢?报警可以吗?退订还没用呢0_0

自己完成了之后也不知道该怎么向别人讲述,如果代码片段中有不清楚的地方可以单独问我吼。

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 19
    评论
Android OCR文字识别可以通过使用Tesseract OCR库来实现。以下是实现OCR文字识别的步骤: 1. 在build.gradle文件中添加以下依赖项: ```gradle implementation 'com.rmtheis:tess-two:9.0.0' ``` 2. 将训练数据文件夹(tessdata)复制到项目的assets文件夹中。 3. 在MainActivity.java文件中添加以下代码: ```java // 导入Tesseract OCR库 import com.googlecode.tesseract.android.TessBaseAPI; public class MainActivity extends AppCompatActivity { // 声明OCR引擎 private TessBaseAPI mTess; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化OCR引擎 mTess = new TessBaseAPI(); String datapath = getFilesDir() + "/tesseract/"; String language = "eng"; mTess.init(datapath, language); // 获取ImageView、Button和TextView控件 ImageView imageView = findViewById(R.id.imgv); Button button = findViewById(R.id.btnOcr); TextView textView = findViewById(R.id.tvshow); // 设置Button的点击事件 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 获取ImageView中的Bitmap对象 Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap(); // 将Bitmap对象传递给OCR引擎进行文字识别 mTess.setImage(bitmap); String result = mTess.getUTF8Text().replace(" ", "").toLowerCase(); // 将识别结果显示在TextView中 textView.setText(result); } }); } @Override protected void onDestroy() { super.onDestroy(); // 释放OCR引擎 mTess.end(); } } ``` 4. 在布局文件中添加一个ImageView、一个Button和一个TextView控件。 ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="match_parent" android:layout_height="300dp" android:id="@+id/imgv"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnOcr" android:text="识别"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:id="@+id/tvshow" /> </LinearLayout> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KIDD-4869

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值