OCR实时扫描识别中英文--tess_two在Android的使用

本篇博客是有了实时扫描识别的需求,然后看到了一篇博客,在其基础上按项目需求改进而成。感谢Si-Kang的贡献,基于交流进步的想法这里把我处理的一些问题写出来

转载地址:http://blog.csdn.net/mr_sk/article/details/72877492#comments


本篇博客Demo地址http://download.csdn.net/detail/g_ying_jie/9883095


第一步集成:

compile 'com.rmtheis:tess-two:7.0.0'

第二步:下载tess-two的中文包,Demo中已经包含了。

第三步:声明权限,记得安卓6.0动态权限申请:

<uses-permission android:name="android.permission.CAMERA" />
    <!-- 声明使用Camera意图 -->
    <uses-feature android:name="android.hardware.camera" />
    <!-- 声明调用Camera自动对焦功能 -->
    <uses-feature android:name="android.hardware.camera.autofocus" />

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

第四步:获取读写权限后把字库从项目的assets目录复制到手机存储中,注意存储的路径一定要包含tessdata目录,因为在TessBaseAPI初始化的时候回去查找该目录

/**
* datapath是你传入的文字库路径,可以看到这里在传入的datapath后加了一个"tessdata"目录
* 然后验证了这个目录是否存在,如果不在,就会报错"数据目录必须包含tessdata目录"
*/
 File tessdata = new File(datapath + "tessdata");
         //tessdata是否存在且是个目录
        if (!tessdata.exists() || !tessdata.isDirectory())
            throw new IllegalArgumentException("Data path must contain subfolder tessdata!");

/**
     * 将assets中的识别库复制到SD卡中
     *
     * @param path 要存放在SD卡中的 完整的文件名。这里是"/storage/emulated/0//tessdata/chi_sim.traineddata"
     * @param name assets中的文件名 这里是 "chi_sim.traineddata"
     */
    public void copyToSD(String path, String name) {

        //如果存在就删掉
        File f = new File(path);
        if (f.exists()) {
            f.delete();
        }
        if (!f.exists()) {
            File p = new File(f.getParent());
            if (!p.exists()) {
                p.mkdirs();
            }
            try {
                f.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        InputStream is = null;
        OutputStream os = null;
        try {
            is = this.getAssets().open(name);
            File file = new File(path);
            os = new FileOutputStream(file);
            byte[] bytes = new byte[2048];
            int len = 0;
            while ((len = is.read(bytes)) != -1) {
                os.write(bytes, 0, len);
            }
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null)
                    is.close();
                if (os != null)
                    os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

第五步:利用surfaceview和camera实时预览画面,通过onPreviewFrame回调预览的帧画面,然后转化成bitmap传到TessBaseAPI进行异步识别。详细的流程请看Demo中的CameraView类。这里讲下我碰到的一些问题。

①测试需要,我想把实时预览的图片和解析后的内容通过Imageview和TextView展示出来,那么我的在CameraView中拿到CameraActivity的两个子控件,这里采用了CameraView的setTag方法,很多人可能都知道怎么去传一个,那怎么传递多个呢?

首先在strings文件加入两个key

<resources>
    <string name="app_name">TestTessTwo</string>
    <item name="tag_img" type="id"></item>
    <item name="tag_text" type="id"></item>
</resources>
然后通过下面的方式setTag

cameraView.setTag(R.id.tag_text, tv_content);
cameraView.setTag(R.id.tag_img, img);
最后通过key获取对应的控件

imageView = (ImageView) getTag(R.id.tag_img);
textView = (TextView) getTag(R.id.tag_text);


②扫描动画TranslateAnimation的执行非常卡顿,主要是由于setPreviewCallback实时回调onPreviewFrame消耗了大量资源,并且onPreviewFrame的裁剪图片和解析内容过于耗时导致。

首先对于onPreviewFrame的图片及识别处理应该全部放到子线程中执行,可通过handler的方式回调子线程结果然后在主线程作相应处理。

然后setPreviewCallback以setPreviewCallbackWithBuffer替代,避免camera预览不断地开辟和回收内存。注意该方法要结合addCallbackBuffer使用,不然会出现只回调一次onPreviewFrame的情况,具体使用如下

开始预览前的处理,screenWidth和screenHeight是你确定的预览尺寸。可通过camera.getParameters().getPreviewSize();获取

mCamera.addCallbackBuffer(new byte[((screenWidth * screenHeight) * ImageFormat.getBitsPerPixel(ImageFormat.NV21)) / 8]);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.setPreviewDisplay(mHolder);//set the surface to be used for live preview
mCamera.startPreview();

然后在onPreviewFrame中添加camera.addCallbackBuffer(data);

/**
     * Camera帧数据回调用
     */
    @Override
    public void onPreviewFrame(final byte[] data, final Camera camera) {
        camera.addCallbackBuffer(data);
        new Thread(new Runnable() {
            @Override
            public void run() {


好了就谈这么多吧,具体的运用在Demo中都有,有什么问题欢迎在评论留言讨论。




猜你喜欢

转载自blog.csdn.net/g_ying_jie/article/details/73849492
今日推荐