Android ORC文字识别之识别×××号等(附源码)

项目地址
https://github.com/979451341/OrcTest

我们说说实现这个项目已实现的功能,能够截图手机界面的某一块,将这个某一块图片的Bitmap传给tess-two的代码来获取扫描结果

我这里在贴出tess-two这个专为Android而创建的文字识别框架的地址
https://github.com/rmtheis/tess-two

接下来我就说我如何一步一步的实现项目

1.实现基础界面,我这里贴出已完成的界面

这样是为了模仿扫描二维码的界面,因为扫描×××号码或者是手机号那样长条的数字,就将扫描区域也做成长条状,这个扫描区域是有意义的,因为到时候截图会只将扫描区域里的图片信息拿去扫描,这也是为了提高扫描速度和精度。

首先要实现这个界面,我们需要画出四个灰色长方体的位置大小,上下左右。

left是扫描区域左边离手机屏幕左边的距离是手机屏幕宽度的1/10,right就是扫描区域右边离手机屏幕左边的距离是手机屏幕宽度的9/10,top是扫描区域顶部离手机屏幕顶部的距离是手机屏幕宽度的1/3,bottom是扫描区域底部离手机屏幕顶部的距离是手机屏幕宽度的4/9

    WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = manager.getDefaultDisplay();

    PMwidth = display.getWidth();
    PMheight = display.getHeight();

    left = PMwidth/10;
    top = PMheight/3;
    right = PMwidth*9/10;
    bottom = PMheight*4/9;
    mFrameRect = new Rect(left,top,right,bottom);

画画

@Override
public void onDraw(Canvas canvas) {
    int width = PMwidth;
    int height = PMheight;
    Rect frame = mFrameRect;

    // 绘制焦点框外边的暗色背景
    mPaint.setColor(mMaskColor);
    canvas.drawRect(0, 0, width, frame.top, mPaint);
    canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, mPaint);
    canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, mPaint);
    canvas.drawRect(0, frame.bottom + 1, width, height, mPaint);

}

还没有完,还有布局文件放SurfaceView和按钮,还有刚才做的自定义View

2.显示Camera预览和Camera拍摄

这里SurfaceView如何显示Camera我不多说,只说如何把Camera预览变清晰,这里是通过循环自动对焦来完成。

设置自动对焦接口

mCamera.autoFocus(autoFocusCallback);

这个接口初始化传入了Handler

autoFocusCallback.setHandler(handler,MSG_AUTOFUCS);

然后这个接口实现类里,当完成自动对焦,会通过handler发送一个消息

@Override
public void onAutoFocus(boolean success, Camera camera) {
    Log.v("zzw", "autof focus "+success);
    if (mAutoFocusHandler != null) {
        mAutoFocusHandler.sendEmptyMessageDelayed(mAutoFocusMessage,AUTO_FOCUS_INTERVAL_MS);

// mAutoFocusHandler = null;
} else {
Log.v(TAG, "Got auto-focus callback, but no handler for it");
}
}

然后handler如何执行以下代码,再进行一次自动对焦,这样就完成了循环

                case MSG_AUTOFUCS:
                    cameraUtil.autoFocus();
                    break;

然后给按钮赋予拍摄功能,拍摄的还要停止聚焦

            handler.removeCallbacksAndMessages(null);
            cameraUtil.takePicture(TwoActivity.this,TwoActivity.this,TwoActivity.this);

这个函数会被调用,data就是图片数据

@Override
public void onPictureTaken(byte[] data, Camera camera) 

这里要注意一件事,拍摄后Camera预览界面就会停止,因为他停止聚焦了,我们需要重新设置自动对焦,并开启预览

// 刷新相机
public void refreshCamera(){
    if (surfaceHolder.getSurface() == null){
        // preview surface does not exist
        return;
    }

    // stop preview before making changes
    try {
        mCamera.stopPreview();
    } catch(Exception e){
        // ignore: tried to stop a non-existent preview
    }

    // set preview size and make any resize, rotate or
    // reformatting changes here
    // start preview with new settings

    try {
        mCamera.setPreviewDisplay(surfaceHolder);
        mCamera.startPreview();
        mCamera.autoFocus(autoFocusCallback);
    } catch (Exception e) {

    }
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

3.处理图片数据,完成局部截图

继续在onPictureTaken函数的data数据处理

因为处理图片是耗时任务,所以开启子线程完成

这里先开启一个等待对话框

    if(!mypDialog.isShowing())
    mypDialog.show();

然后开启子线程

    if(data != null){
        new Thread(new BitmapThread(bitmap,data,handler,TwoActivity.this)).start();

    }

将data转换为Bitmap数据

    bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

将图片旋转90度

    bitmap = rotateBitmap(bitmap,90);

这是旋转Bitmap的函数

public static Bitmap rotateBitmap(Bitmap source, float angle) {
    Matrix matrix = new Matrix();
    matrix.postRotate(angle);
    return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}

切割Bitmap,将扫描区域的图片切割出来

    int PMwidth = bitmap.getWidth(); // 得到图片的宽,高
    int PMheight = bitmap.getHeight();

    int left = PMwidth/10;
    int top = PMheight/3;
    int right = PMwidth*9/10;
    int bottom = PMheight*4/9;
    int width = right - left;
    int height = bottom - top;

    Log.v("zzw",PMheight+" "+PMwidth);

    bitmap = Bitmap.createBitmap(bitmap, left, top, width, height, null,
            false);

4.扫描出结果

其实tess-two框架的使用很简单,但是使用这个框架需要依靠训练文件来完成扫描,我在res目录下放了raw文件夹,里面的eng_traineddata文件就是这个用途,但是我们不能直接使用它们,我们需要将他们复制到手机存储里

下面的代码意思是在应用私有路径里创建tesseract/tessdata/eng.traineddata相关路径的文件并使用输入流将文件的数据读出来,然后使用输出流将数据传入eng.traineddata文件

public static void initTessTrainedData(Context context){

    if(initiated){
        return;
    }

    File appFolder = context.getFilesDir();
    File folder = new File(appFolder, tessdir);
    if(!folder.exists()){
        folder.mkdir();
    }

    tesseractFolder = folder.getAbsolutePath();

    File subfolder = new File(folder, subdir);
    if(!subfolder.exists()){
        subfolder.mkdir();
    }

    File file = new File(subfolder, filename);
    trainedDataPath = file.getAbsolutePath();
    Log.d(TAG, "Trained data filepath: " + trainedDataPath);

    if(!file.exists()) {

        try {
            FileOutputStream fileOutputStream;
            byte[] bytes = readRawTrainingData(context);
            if (bytes == null){
                return;
            }

            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);
            fileOutputStream.close();
            initiated = true;
            Log.d(TAG, "Prepared training data file");
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Error opening training data file\n" + e.getMessage());
        } catch (IOException e) {
            Log.e(TAG, "Error opening training data file\n" + e.getMessage());
        }
    }
    else{
        initiated = true;
    }
}

好了再说说tess-two框架的使用

创建TessBaseAPI

    TessBaseAPI tessBaseAPI = new TessBaseAPI();

关闭测试

    tessBaseAPI.setDebug(true);

设置训练数据路径和识别文字是英文

    tessBaseAPI.init(path, "eng");

设置白名单

    tessBaseAPI.setVariable(TessBaseAPI.VAR_CHAR_WHITELIST, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");

设置黑名单

    tessBaseAPI.setVariable(TessBaseAPI.VAR_CHAR_BLACKLIST, "[email protected]#$%^&*()_+=-[]}{;:‘\"\\|~`,./<>?"); 

设置识别模式

    tessBaseAPI.setPageSegMode(TessBaseAPI.PageSegMode.PSM_AUTO_OSD);

传入bitmap数据

    tessBaseAPI.setImage(bitmap);

获取扫描结果

    String inspection = tessBaseAPI.getHOCRText(0);

结束TestBaseAPI的使用

    tessBaseAPI.end();

实现扫描×××号码,这里是通过正则表达式来判断扫描出的结果是否有×××号码,也就是说tess-two其实是只是扫描出Bitmap文件里面有哪些文字,然后使用正则表达式来筛选出我们需要的数据。也就是说我们通过换取正则表达式就能做到扫描手机号等,带有某种规律的数字或者字母

这是正则表达式的线上工具地址,大家可以自己试试 http://tool.oschina.net/regex/#

private static Pattern pattern = Pattern.compile("\\d{17}[\\d|x]|\\d{15}");
public static String getTelNum(String sParam){
    if(TextUtils.isEmpty(sParam)){
        return "";
    }

    Matcher matcher = pattern.matcher(sParam);
    StringBuilder bf = new StringBuilder();
    while (matcher.find()) {
        bf.append(matcher.group()).append(",");
    }
    int len = bf.length();
    if (len > 0) {
        bf.deleteCharAt(len - 1);
    }
    return bf.toString();
}

然后通过handler返回结果

    Message message = Message.obtain();
    message.what = 1;
    Bundle bundle = new Bundle();
    bundle.putString("decode",strDecode);
    message.setData(bundle);
    message.what = TwoActivity.MSG_BITMAP;
    handler.sendMessage(message);

取消加载框,并将局部截图的图像和扫描的结果通过DialogFragment显示出来

                    mypDialog.dismiss();
                    String strDecode = msg.getData().getString("decode","扫描失败");

                    if(strDecode == null ||strDecode.equals(""))
                        strDecode = "扫描失败";

                    imageDialogFragment.setImage(bitmap);
                    imageDialogFragment.setText(strDecode);
                    imageDialogFragment.show(getFragmentManager(), "ImageDialogFragment");

5.结论

其实还没有结束因为我本想做出一个能够扫描整张×××的项目,我看一下网上有很多API都能实现这个功能,但都要钱,如果要是能够实现这个功能,并发到github,我岂不是成为大神了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

原文地址:http://blog.51cto.com/13591594/2083466

时间: 2024-10-16 22:54:28

Android ORC文字识别之识别×××号等(附源码)的相关文章

Android仿微信底部菜单栏+顶部菜单栏(附源码)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文要实现仿微信微信底部菜单栏+顶部菜单栏,采用ViewPage来做,每一个page对应一个XML,当手指在ViewPage左右滑动时,就相应显示不同的page(其实就是xml)并且同时改变底部菜单按钮的图片变暗或变亮,同时如果点击底部菜单按钮,左右滑动page(其实就是xml)并且改变相应按钮的亮度. 最终效果:源码免费下载 一.布局 1.顶部菜单布局,命名为top_layout.xml

android 打造ListView和Gridview万能adapter适配器(附源码)

android开发中,我们离不开adapter,每个项目都有很多地方需要adapter,那么我们如何让自己少写adapter代码呢?那就是封装adapter,让我们的adapter成为万能的adapter.下面我列出我实现的思路,供给大家学习与参考,当然有更好的方式也可以提供建议哦. 一.针对Listview或GridView的万能适配器(源码) 1.第一步实现公用的viewholder/** * 优化adapter用的ViewHolder * Created by admin on 17/8/

Android仿UC浏览器左右上下滚动功能(附源码)

本文要解决在侧滑菜单右边加个文本框,并能实现文本的上下滑动和菜单的左右滚动.这里推荐可以好好看看android的触摸事件的分发机制,这里我就不详细讲了,我只讲讲这个应用.要实现的功能就像UC浏览器(或其它手机浏览器)的左右滚动,切换网页,上下滚动,拖动内容. 目录:一.功能要求与实现       二.布局与代码       三.原理与说明 本文的效果:(源码下载) 一.功能要求与实现 1.功能要求: (1)手指一开始按着屏幕左右移动时,只能左右滚动菜单,如果这时手指一直按着,而且上下移动了,那么

Android中Loader及LoaderManager的使用(附源码下载)

managedQuery方法的缺陷 Loader是用来更好地加载数据的,在我们谈论Loader之前,我们先研究一下Activity的managedQuery方法,该方法也是用于在Activity中加载数据的.在Android 3.0之前的版本中,我们如果想在Activity中通过ContentResolver对ContentProvider进行查询,我们可以方便的调用Activity的managedQuery方法,该方法的源码如下: @Deprecated public final Cursor

Android使用xml自定义软键盘效果(附源码)

Android使用xml自定义软键盘效果原理: 1,软键盘其实是个控件,使用android.inputmethodserver.KeyboardView类定义. 2,主布局中使用帧布局,当我们需要显示软键盘时设置为可见,不需要时设置为不可见. 3,编写xml文件,定义键盘内容.使用xml文件填充KeyBoardView布局 4,设置EditText的监听事件. 完成键盘开发. 上效果图: 1,源码研究android.inputmethodserver.KeyboardView: /* * Cop

Android Studio 一个完整的APP实例(附源码和数据库)

前言: 这是我独立做的第一个APP,是一个记账本APP. This is the first APP, I've ever done on my own. It's a accountbook APP. 源码: https://github.com/AnneHan/accountBook 欢迎satr or fork 备注: APP中所涉及到的图标请勿商用 效果图 (备注:在把图片制作成gif时,图片的质量受损,所以最终呈现出来的gif图片,背景变得有些模糊) 开发环境 IDE:Android

Android Paint的使用以及方法介绍(附源码下载)

要绘图,首先得调整画笔,待画笔调整好之后,再将图像绘制到画布上,这样才可以显示在手机屏幕上.Android 中的画笔是 Paint类,Paint 中包含了很多方法对其属性进行设置,主要方法如下: setAntiAlias: 设置画笔的锯齿效果.    setColor: 设置画笔颜色    setARGB:  设置画笔的a,r,p,g值.    setAlpha:  设置Alpha值    setTextSize: 设置字体尺寸.    setStyle:  设置画笔风格,空心或者实心.    

Android中Canvas绘图基础详解(附源码下载)

Android中,如果我们想绘制复杂的自定义View或游戏,我们就需要熟悉绘图API.Android通过Canvas类暴露了很多drawXXX方法,我们可以通过这些方法绘制各种各样的图形.Canvas绘图有三个基本要素:Canvas.绘图坐标系以及Paint.Canvas是画布,我们通过Canvas的各种drawXXX方法将图形绘制到Canvas上面,在drawXXX方法中我们需要传入要绘制的图形的坐标形状,还要传入一个画笔Paint.drawXXX方法以及传入其中的坐标决定了要绘制的图形的形状

Android中的多线程编程(一)附源码

Android中多线程编程:Handler类.Runnable类.Thread类之概念分析 1.Handler类: Handler是谷歌封装的一种机制:可以用来更新UI以及消息的发送和处理.Handler是运行在主线程(UI线程). (2).使用Handler机制的原因: 这是谷歌封装的一种更新UI机制和消息机制,如果不使用这个来更新UI和发送处理消息的时候就会抛出异常. (3).Handler的使用: Handler发送消息其实是发送给自己.也就是说由自己来进行发送和处理.是因为Handler

android 实现检测版本,下载apk更新(附源码)

其实这不是什么难事了,都有热更新的技术了,只是记录一下,大神勿嘲笑. 先说下思路,首先要有更新的接口,只要进入app,就监测一下接口,是否更新,更新的话,检测本地版本是否低于接口返回的版本,低的话,就根据返回的路径下载apk更新.接口返回的字段起码有 更新标志.更新版本,更新描述,apk下载地址. 更新标志应该有三种状态,更新,询问更新,强制更新,可以启动一个Service(不要忘记在清单文件中注册)来进行检查更新以及下载的工作: 这下面就是 Service里的全部代码,也不是很难理解,重要的地