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

来源:互联网 发布:查开放房记录软件 编辑:程序博客网 时间:2024/06/04 19:58

本篇博客是有了实时扫描识别的需求,然后看到了一篇博客,在其基础上按项目需求改进而成。感谢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 previewmCamera.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中都有,有什么问题欢迎在评论留言讨论。




原创粉丝点击