使用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秒,即進行字體識別

 

最終結果截圖如下

 

 

 

 

 

完整代碼下載請點擊這里 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM