Instance.java revision db567c390bd56c05614eaa83c02dbb99f97ad9cc
135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li/*
235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * Copyright (C) 2008-2009 The Android Open Source Project
335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li *
435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * Licensed under the Apache License, Version 2.0 (the "License");
535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * you may not use this file except in compliance with the License.
635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * You may obtain a copy of the License at
735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li *
835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li *      http://www.apache.org/licenses/LICENSE-2.0
935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li *
1035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * Unless required by applicable law or agreed to in writing, software
1135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * distributed under the License is distributed on an "AS IS" BASIS,
1235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * See the License for the specific language governing permissions and
1435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * limitations under the License.
1535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */
1635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
17db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guypackage android.gesture;
1835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
19b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guyimport android.graphics.Matrix;
20b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
2135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li/**
2235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * An instance represents a sample if the label is available or a query if the
2335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * label is null.
2435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */
2535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liclass Instance {
2635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static final int SEQUENCE_SAMPLE_SIZE = 16;
2735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
28e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    private static final int PATCH_SAMPLE_SIZE = 16;
2935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private final static float[] ORIENTATIONS = {
3135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            0, 45, 90, 135, 180, -0, -45, -90, -135, -180
3235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    };
3335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    // the feature vector
3535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    final float[] vector;
3635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    // the label can be null
3835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    final String label;
3935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
4035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    // the id of the instance
41c534727972c3835ed997e84a349f259915ef2cddRomain Guy    final long id;
42e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li
4335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private Instance(long id, float[] sample, String sampleName) {
44c534727972c3835ed997e84a349f259915ef2cddRomain Guy        this.id = id;
4535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        vector = sample;
4635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        label = sampleName;
47e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    }
48e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li
49e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    private void normalize() {
50e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        float[] sample = vector;
5135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        float sum = 0;
52b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
5335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        int size = sample.length;
5435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        for (int i = 0; i < size; i++) {
5535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            sum += sample[i] * sample[i];
5635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        }
57b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
58e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        float magnitude = (float) Math.sqrt(sum);
59e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        for (int i = 0; i < size; i++) {
60e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            sample[i] /= magnitude;
61e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        }
6235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    }
6335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
6435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    /**
6535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * create a learning instance for a single stroke gesture
6635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     *
6735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param gesture
6835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param label
6935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @return the instance
7035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     */
71e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    static Instance createInstance(int samplingType, Gesture gesture, String label) {
7235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        float[] pts;
73e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        Instance instance;
74e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        if (samplingType == GestureLibrary.SEQUENCE_SENSITIVE) {
75e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            pts = temporalSampler(samplingType, gesture);
76e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            instance = new Instance(gesture.getID(), pts, label);
77e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            instance.normalize();
7835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        } else {
7935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            pts = spatialSampler(gesture);
80e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            instance = new Instance(gesture.getID(), pts, label);
8135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        }
82e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        return instance;
8335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    }
84e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li
8535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static float[] spatialSampler(Gesture gesture) {
86c534727972c3835ed997e84a349f259915ef2cddRomain Guy        return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE);
8735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    }
8835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
89e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    private static float[] temporalSampler(int samplingType, Gesture gesture) {
90c534727972c3835ed997e84a349f259915ef2cddRomain Guy        float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0),
9135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                SEQUENCE_SAMPLE_SIZE);
92c534727972c3835ed997e84a349f259915ef2cddRomain Guy        float[] center = GestureUtilities.computeCentroid(pts);
9335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        float orientation = (float) Math.atan2(pts[1] - center[1], pts[0] - center[0]);
9435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        orientation *= 180 / Math.PI;
9535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
9635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        float adjustment = -orientation;
97e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) {
9835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            int count = ORIENTATIONS.length;
9935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            for (int i = 0; i < count; i++) {
10035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                float delta = ORIENTATIONS[i] - orientation;
10135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                if (Math.abs(delta) < Math.abs(adjustment)) {
10235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                    adjustment = delta;
10335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                }
10435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            }
10535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        }
10635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
107b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        Matrix m = new Matrix();
10835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        m.setTranslate(-center[0], -center[1]);
109b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy        m.postRotate(adjustment);
11035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        m.mapPoints(pts);
111b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy
11235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        return pts;
11335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    }
11435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
11535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li}
116