hyoromoのブログ

iOS/AndroidもしくはCocos2dxネタを書いています

Gesture APIを利用

AndroidOS1.6以上から使えるようになった android.gesture APIを試してみました。
Googleが提供しているSampleがあります。

ジェスチャーライブラリ作成

事前に使用するジェスチャーを登録しておく必要があります。
ジェスチャーを登録する方法は以下の二種類となります。

  • ADVでSDカードありで作成し、アプリ内にあるGestures Builderにてジェスチャー登録。
  • android-sdk/samples/android-5(以上)/GestureBuilder/ をビルドしてSDカードのある端末にインストール、端末上にてジェスチャー登録。

ジェスチャー登録後にデバイスのsdcard直下gesturesが作成されているのでPC側にコピーする。
なお、どちらの方法でも構いませんが、端末上でジェスチャー登録する方が描きやすいのでオススメです。

アプリに取り込む

プロジェクトを作成し、/res/raw/ 以下gesturesを配置する。

ジェスチャーを読み込む

Googleが提供しているSampleとほぼ変わりませんが、以下のように読み込めます。

public class MainActivity extends Activity implements OnGesturePerformedListener {
    private GestureLibrary mLibrary;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mLibrary = GestureLibraries.fromRawResource(this, R.raw.gestures);
        if (!mLibrary.load()) {
            finish();
        }

        GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures);
        gestures.addOnGesturePerformedListener(this);
    }

    // 描かれた後に呼ばれる
    public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
        ArrayList<Prediction> predictions = mLibrary.recognize(gesture);
        if (predictions.size() > 0) {
            Prediction prediction = predictions.get(0);
            // 描かれた絵と登録した絵の一致度(スコア)が一番高い
            if (prediction.score > 1.0) {
                if (gestureName.equals("登録したジェスチャー名")) {
                    // 絵が一致した際に処理させたい内容を書く
                }
            }
        }
    }
}

最初にライブラリを読み込み、ジェスチャー後にコールバックされるよう addOnGesturePerformedListener を設定しておきます。
次に読み込む xml layout を見ていきます。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
>
    <android.gesture.GestureOverlayView
        android:id="@+id/gestures"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
    >
    <!-- ジェスチャー領域に表示させるWidgetを追加 -->
    </android.gesture.GestureOverlayView>
</FrameLayout>

android.gesture.GestureOverlayView がジェスチャー独自Viewとなります。

登録されたジェスチャー情報読込

登録された情報を表示させたい場合は以下のようにします。

String[] entries = mLibrary.getGestureEntries().toArray(new String[0]);
Arrays.sort(entries);
for (String name : entries) {
	for (Gesture gesture : mLibrary.getGestures(name)) {
		gesture.toBitmap(72, 72, 8, 0xFFFFFF00);
	}
}

nameがジェスチャー登録時に設定したName。
Gesture#toBitmapが登録した絵。引数には画像サイズとストローク色を指定できる。
途中nameでソートしてますが、これはジェスチャー登録された順に取得されるので、nameに重み付けをしてソートさせた方が良いからです。
ソートしないと以下の画像みたいな無規則な並びとなります。

ジェスチャーアプリを開発する上での注意点

一致率を高める

ジェスチャーの評価には最小二乗法らしい...と、以前twitterで教えて貰いましたが、これについてはサッパリ分からないで感覚で説明します。
ジェスチャー開始地点とジェスチャー終了地点が重要となります。横線を書くだけのジェスチャーでも、左から右へ書くのと、右から左へ書くのとでは、完成図としては同じでも別物として扱われます。
これが円の場合、左から時計回り、上から時計回り、右から時計回り、下から時計回り、左から反時計回り、上から反時計回り、右から反時計回り、下から反時計回り。。。等の種類があり、一致させるのが困難です。
そこで楽に一致させる方法ですが、以下の事を行うと良いです。

  • 始点と終点を明確とする。
  • 始点と終点、終点から始点の2種類用意する。

始点と終点を明確とするため、単なる円でも始点と終点を重ねず、少し歯抜けにさせて描く。それを時計回りと反時計回りの2種類用意。

似た絵は描かない

登録されたジェスチャー情報を元に、描かれたジェスチャーに登録されたジェスチャーを付き合わせて一番共通点の多いジェスチャーが候補として選ばれます。
と言うことは、似た図形が多ければ多いほど誤認識が多くなります。

禁止ジェスチャー

縦の一本線は登録できません。