专栏首页微卡智享Android使用Tesseract-ocr进行文字识别

Android使用Tesseract-ocr进行文字识别

前言

Tessseract是一款由HP实验室开发由 Google 维护的开源 OCR(Optical Character Recognition , 光学字符识别)引擎。能够支持中文十分难得。虽然其识别效果不是很理想,但是对于要求不高的中小型项目来说,已经足够用了。

Tesseract-OCR下载地址

文字识别一般都用的tesseract-ocr。 GitHub:https://github.com/tesseract-ocr/tesseract

我们今天在Android上应用推荐的有个tess-two

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

还有一个字体识别库Tessdata(chi_sim.traineddata中文简体,chi_tra.traineddata中文繁体,eng.traineddata 英文库)

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

演示效果

上图中,整张图进行识别,我感觉效果还可以,如果前置用OPENCV做图像的预处理后,可能效果会更好。

代码实现

首先下载tess-two和字体库

下载完成到我们的目录中

新建一个TesserartDemo的项目,导入tess-two

建好项目后,我们通过Import Module导入tess-two,由于tess-two是个ndk的项目,所以我们必须要在SDK Tools里面加入CMake和NDK,如下图,具体NDK可以看看以前的文章《Android NDK编程(一)---NDK介绍及环境搭建

导入完tess-two后,我们进行编译,结果发现编译不过去,提示android-maven的错误。网上找了找资料,发现了解决办法。在tess-two的build.gradle的文件中配置

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
        classpath 'org.codehaus.groovy:groovy-backports-compat23:2.3.5'
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'
        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
    }
}

apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'

如下图:

重新编译,这次时间较长,我自己的电话大概花了十几分钟才编译完成。

拷贝字库文件进Android设备

我们利用Device File Explorer打开我们的虚拟机,将chi_sim.traineddata的字库文件拷贝到mnt/sdcard/tesserart/tessdata下,没有这个目录可以自己创建一下,后面会说到为什么拷贝到这里

AndroidManifest.xml

在这里面加入读取内存卡和写入内存卡的权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

在res/drawable里面把我们的图片文件复制进来

activity_main.xml布局文件

在布局文件中加入一个imageview,一个button和一个TextView

<?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:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <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>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private ImageView imgv;
    private TextView tvshow;
    private Button btnocr;
    private Bitmap bmp;

    //如果Android的版本大于23,路径取根目录下的tesserart,小于的话是
    //在mnt/sdcard下面
    private String DATAPATH=Environment.getExternalStorageDirectory().getAbsolutePath() +
            File.separator + "tesserart";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        requestPermission();


        imgv=findViewById(R.id.imgv);
        //获取自己的图片,这里是自己放在项目里面的。
        bmp=BitmapFactory.decodeResource(this.getResources(), R.drawable.tiddmg);
        imgv.setImageBitmap(bmp);
        imgv.setScaleType(ImageView.ScaleType.FIT_XY);

        tvshow=findViewById(R.id.tvshow);
        btnocr=findViewById(R.id.btnOcr);

        btnocr.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                try {
                    TessBaseAPI mTess=new TessBaseAPI();
                    //存放tessdata的文件路径 就是chi_sim.traineddata文件的位置chi_sim.traineddata
                    //选择语言 chi_sim 简体中文  eng 英文
                    String language="chi_sim";

                    File dirdatapath=new File(DATAPATH);
                    if (!dirdatapath.exists()) {
                        dirdatapath.mkdirs();
                    }
                    File dir=new File(DATAPATH,"tessdata");
                    if (!dir.exists())
                        dir.mkdirs();
                    tvshow.append(DATAPATH+"\r\n");
                    mTess.init(DATAPATH, language);
                    //将图片设置到mTess进行识别
                    mTess.setImage(bmp);
                    //获取识别的文字(这里会等一段时间,这里的代码是在主线程的,建议将这部分代码放到子线程)
                    String result=mTess.getUTF8Text();
                    tvshow.append("结果为:" + result);
                } catch (Exception e) {
                    e.printStackTrace();
                    tvshow.append(e.getMessage());
                }
            }
        });

    }

    void requestPermission() {
        final int REQUEST_CODE=1;
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{
                            Manifest.permission.WRITE_EXTERNAL_STORAGE,
                            Manifest.permission.READ_EXTERNAL_STORAGE},
                    REQUEST_CODE);
        }
    }

}

重点说明:

上图中DATAPATH的文件路径,用Environment.getExternalStorageDirectory().getAbsolutePath(),在API23以下的时候,路径就是我们拷贝的mnt\sdcard\,如果在API23或以上直接就是我们的根目录,我自己的模拟器是Android 4.1的也就是API18,所以这里直接拷文件拷到mnt\sdcard下了。刚才测试时用了自己手机(Android9.0),发现在mnt的sdcard下也有,可能我自己研究错了这里,先划掉吧。



上图中mTess.init这个要重点说一下,我们开始的DATAPATH的路径是mnt/sdcard/tesserart,在拷贝字库文件时我们下面还创建了一个tessdata的文件夹才拷进去了,如果你这里设置为mnt/sdcard/tesserart/tessdata的路径,就会报错了。

点开init这个函数我们看一下里面的写法

上图中标红色的就是它自己会根据输入的路径查找tessdata的文件夹,所以这里我们格外注意一下。

这样整个DEMO程序就可以运行起来如文章开始的效果了,如果是android6.0开始,要记得自己申请动态的权限读取内存。

-END-

本文分享自微信公众号 - 微卡智享(VaccaeShare),作者:Vaccae

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android里用AsyncTask后的接口回调

    AsyncTask,即异步任务,是Android给我们提供的一个处理异步任务的类.通过此类,可以实现UI线程和后台线程进行通讯,后台线程执行异步任务,并把结果返...

    Vaccae
  • 学习|Android侧滑框架SmartSwipe使用

    前两天看到一篇文章介绍了一些开源框架,其中无意间看到了这个SmartSwipe的侧滑框架,根据上面的介绍及演示的动态效果,使用起来确实很不错,于是自己做了个De...

    Vaccae
  • Android JetPack组件CameraX使用及修改显示图像

    好久没用Kotlin写Android的代码了,刚开始写起来还有点生,不过适应了一阵也算是恢复过来了。今天这篇主要是说说Android JepPack组件中Cam...

    Vaccae
  • Android EditText使用详解-包含很多教程上看不到的功能演示

    标题有点大,说是详解,其实就是对EditText的一些常用功能的介绍,包括密码框,电话框,空白提示文字等等的讲解,尽量的介绍详细一点,也就是所谓的详解了。。呵呵

    飞雪无情
  • 使用Android studio3.6的java api方式调用opencv

    (2)File- New- Import Module,然后选择自己的java-opencv的相对应路径,比如,D:\Android\OpenCV-androi...

    砸漏
  • Android实现简单的城市列表功能

    砸漏
  • Android 滑动渐变背景Toolbar、点击置顶ScrollView

    这个置顶是滑动的置顶,不包括外层布局。 好了,效果图看到了,你有没有动力开始写代码呢? 创建一个SlideLayoutDemo的项目 然后在res下新建一...

    晨曦_LLW
  • View 源码分析——setContentView

    分析一下 android 中布局的加载流程,每次新建 activity 时都要在 onCreate 中调用 setContentView(R.layout.ac...

    CatEatFish
  • kotlin构建MVVM应用之双向数据绑定

    我们在构建MVVM应用的时候数据时双向流动的,比如:用户输入了数据,那么我们的model层的数据也要自动跟着更新或者我们校验了数据,是图层也要给用户反馈;网络请...

    大话swift
  • Service的跨进程开发Android开发高级进阶

    Service的跨进程通信主要由两种Android提供的方法进行,一个是AIDL,通过创建一个AIDL文件来完成,另一个是利用Messenger,发送Messa...

    爱因斯坦福

扫码关注云+社区

领取腾讯云代金券