• 使用zinnia制作android手写输入功能(下)在项目中使用zinnia


    新建项目,名为TOMHW,把编译得到的包含.so文件的armeabi文件夹复制到项目中的libs文件夹下

    打开模拟器,在ddms中把handwriting-zh_CN.model文件push到/data/data目录下

    整个项目视图如下

    AndroidManifest.xml代码如下

    View Code
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.tomhw"
        android:versionCode="1"
        android:versionName="1.0">
    
        <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="15" />
    
        <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
        
        <application android:label="@string/app_name"
            android:icon="@drawable/ic_launcher"
            android:theme="@style/AppTheme">
            
            <activity android:name=".MainActivity"
                          android:label="@string/app_name">
                          
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
                
            </activity>
    
        </application>
    
    </manifest>

    mainactivity.xml代码如下

    View Code
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        
    </LinearLayout>

    zinnia官网的usage代码可以看出,zinnia的使用流程如下:

    1.读取model文件

    2.把笔画用zinnia_character_add添加到character中

    3.用recognizer_classify把character拿到model中识别并返回结果给result

    4.从result中取出结果显示出来

    所以MainActivity.java的代码如下

    View Code
    package com.tomhw;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.os.Bundle;
    import android.view.KeyEvent;
    import android.view.MotionEvent;
    import android.view.SurfaceHolder;
    import android.view.SurfaceHolder.Callback;
    import android.view.SurfaceView;
    
    
    public class MainActivity extends Activity {
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(new MyView(this));
            
        }
    
        
        //能显示出手写轨迹的view
        public class MyView extends SurfaceView implements Callback, Runnable{
    
            //按下返回键即退出程序
            @Override
            public boolean onKeyDown(int keyCode, KeyEvent event) {
                
                if (keyCode == KeyEvent.KEYCODE_BACK) {
                    finish();
                }
    
                return true;
            }
    
            //建立手写输入对象
            long recognizer = 0;
            long character = 0;
            long result = 0;
            int modelState = 0;  //显示model文件载入状态
            int strokes = 0; //总笔画数
            
            boolean resultDisplay = false; //是否显示结果
            
            int handwriteCount = 0; //笔画数
            
            private Thread mThread;
            SurfaceHolder mSurfaceHolder = null;
            Canvas mCanvas = null;
            Paint mPaint = null;
            Path mPath = null;
            Paint mTextPaint = null; //文字画笔
            public static final int FRAME = 60;//画布更新帧数
            boolean mIsRunning = false; //控制是否更新
            float posX, posY; //触摸点当前座标
            //触发定时识别任务
            Timer tExit;
            TimerTask task;
            
            public MyView(Context context) {
                super(context);
    
                //设置拥有焦点
                this.setFocusable(true);
                //设置触摸时拥有焦点
                this.setFocusableInTouchMode(true);
                //获取holder
                mSurfaceHolder = this.getHolder();
                //添加holder到callback函数之中
                mSurfaceHolder.addCallback(this);
                
                //创建画布
                mCanvas = new Canvas();
                
                //创建画笔
                mPaint = new Paint();
                mPaint.setColor(Color.BLUE);//颜色
                mPaint.setAntiAlias(true);//抗锯齿
                //Paint.Style.STROKE 、Paint.Style.FILL、Paint.Style.FILL_AND_STROKE 
                //意思分别为 空心 、实心、实心与空心 
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setStrokeCap(Paint.Cap.ROUND);//设置画笔为圆滑状
                mPaint.setStrokeWidth(5);//设置线的宽度
                
                //创建路径轨迹
                mPath = new Path();
                
                //创建文字画笔
                mTextPaint = new Paint();
                mTextPaint.setColor(Color.BLACK);
                mTextPaint.setTextSize(15);
                
                //创建手写识别
                if (character == 0) {
                    character = characterNew();
                    characterClear(character);
                    characterSetWidth(character, 300);
                    characterSetHeight(character, 300);
                }
                if (recognizer == 0) {
                    recognizer = recognizerNew();
                }
                
                //打开成功返回1
                modelState = recognizerOpen(recognizer, "/data/data/handwriting-zh_CN.model");
                if (modelState != 1) {
                    System.out.println("model文件打开失败");
                    return;
                }
            }
            
            @Override
            public boolean onTouchEvent(MotionEvent event) {
    
                //获取触摸动作以及座标
                int action = event.getAction();
                float x = event.getX();
                float y = event.getY();
                
                //按触摸动作分发执行内容
                switch (action) {
                case MotionEvent.ACTION_DOWN:
                    if (tExit != null) {
                        tExit.cancel();
                        tExit = null;
                        task = null;
                    }
                    resultDisplay = false;
                    mPath.moveTo(x, y);//设定轨迹的起始点
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    mPath.quadTo(posX, posY, x, y); //随触摸移动设置轨迹
                    characterAdd(character, handwriteCount, (int)x, (int)y);
                    break;
                    
                case MotionEvent.ACTION_UP:
                    handwriteCount++;
                    tExit = new Timer();
                    task = new TimerTask() {
                        
                        @Override
                        public void run() {
                            resultDisplay = true;
                        }
                    };
                    tExit.schedule(task, 1000);
                    break;
                }
                
                //记录当前座标
                posX = x;
                posY = y;
                
                return true;
            }
    
    
            private void Draw(){
                //防止canvas为null导致出现null pointer问题
                if (mCanvas != null) {
                    mCanvas.drawColor(Color.WHITE);  //清空画布
                    mCanvas.drawPath(mPath, mPaint);    //画出轨迹
                    //数据记录
                    mCanvas.drawText("model打开状态 : " + modelState, 5, 20, mTextPaint);
                    mCanvas.drawText("触点X的座标 : " + posX, 5, 40, mTextPaint);
                    mCanvas.drawText("触点Y的座标 : " + posY, 5, 60, mTextPaint);
                    
                    strokes = (int)characterStrokesSize(character);
                    mCanvas.drawText("总笔画数 : " + strokes, 5, 80, mTextPaint);
                }
                
                //进行文字检索
                if (strokes > 0 && resultDisplay) {
                    result = recognizerClassify(recognizer, character, 10); 
                    if (tExit != null) {
                        tExit.cancel();
                        tExit = null;
                        task = null;
                    }
                    characterClear(character);
                    strokes = 0;
                    mPath.reset();//触摸结束即清除轨迹
                    resultDisplay = false;
                    handwriteCount = 0;
                }
                
                //显示识别出的文字
                if (result != 0) {
                    for (int i = 0; i < resultSize(result); i++) {
                        mCanvas.drawText(resultValue(result, i) + " : " + resultScore(result, i), 5, 100 + i * 20, mTextPaint);
                    }    
                }
    
            }
            
    
            
            @Override
            public void run() {
    
                while(mIsRunning){
                    //更新前的时间
                    long startTime = System.currentTimeMillis();
                    
                    //线程安全锁
                    synchronized(mSurfaceHolder){
                        mCanvas = mSurfaceHolder.lockCanvas();
                        Draw();
                        mSurfaceHolder.unlockCanvasAndPost(mCanvas);
                    }
                    //获取更新后的时间
                    long endTime = System.currentTimeMillis();
                    //获取更新时间差
                    int diffTime = (int)(endTime - startTime);
                    //确保每次更新都为FRAME
                    while(diffTime <= FRAME){
                        diffTime = (int)(System.currentTimeMillis() - startTime);
                        //Thread.yield(): 与Thread.sleep(long millis):的区别,
                        //Thread.yield(): 是暂停当前正在执行的线程对象 ,并去执行其他线程。
                        //Thread.sleep(long millis):则是使当前线程暂停参数中所指定的毫秒数然后在继续执行线程
                        Thread.yield();
                    }
                }
                
            }
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                mIsRunning = true;
                mThread = new Thread(this);
                mThread.start();
            }
    
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width,
                    int height) {
                // TODO Auto-generated method stub
                
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                resultDestroy(result);
                characterDestroy(character);
                recognizerDestroy(recognizer);
                mThread = null;
            }
            
        }
        
        
        
        
        
        
        
        //jni封装方法的声明
        //charater
        public native long characterNew();
        public native void characterDestroy(long c);
        public native void characterClear(long stroke);
        public native int characterAdd(long character, long id, int x, int y);
        public native void characterSetWidth(long character, long width);
        public native void characterSetHeight(long character, long height);
        
        public native long characterStrokesSize(long character);
        
        //recognizer
        public native long recognizerNew();
        public native void recognizerDestroy(long recognizer);
        public native int recognizerOpen(long recognizer, String filename);
        public native String recognizerStrerror(long recognizer);
        public native long recognizerClassify(long recognizer, long character, long nbest);
        
        //result
        public native String resultValue(long result, long index);
        public native float resultScore(long result, long index);
        public native long resultSize(long result);
        public native void resultDestroy(long result);
        
        //载入.so文件
        static{
            System.loadLibrary("zinniajni");
        }
        
    }

    代码流程:用surfaceview定时刷新画面,用path来描绘手写轨迹,用canvas显示出来

    当用户碰触屏幕时,即取消字体识别任务,用户移动时用path记录轨迹,用户手指离开屏幕时就马上约定识别任务,

    若用户下一次碰触屏幕与上一次离开屏幕的时间差大于1秒,即进行字体识别

    最终结果截图如下

    完整代码下载请点击这里 

  • 相关阅读:
    一个关于css3背景透明的例子
    原生js写的一个当前年份日期星期和时间的显示
    一个原生js写的加减乘除运算
    风行一时瀑布流网页布局,实现无限加载(jquery)
    bootstrap你让前端小狮子们又喜又恨
    潭州课堂25班:Ph201805201 django 项目 第二十一课 文章主页 新闻列表页面功能 (课堂笔记)
    潭州课堂25班:Ph201805201 django 项目 第二十课 数据库分析设计图 (课堂笔记)
    潭州课堂25班:Ph201805201 django 项目 第十九课 文章主页数据库模型,前后台功能实现 (课堂笔记)
    潭州课堂25班:Ph201805201 django 项目 第十八课 前台 注解 (课堂笔记)
    潭州课堂25班:Ph201805201 django 项目 第十七课 用户登录,登出实现 (课堂笔记)
  • 原文地址:https://www.cnblogs.com/tomboy/p/2698968.html
Copyright © 2020-2023  润新知