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 Guy 2035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li/** 2135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * An instance represents a sample if the label is available or a query if the 2235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * label is null. 2335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 2435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liclass Instance { 2535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final int SEQUENCE_SAMPLE_SIZE = 16; 2635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 27e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li private static final int PATCH_SAMPLE_SIZE = 16; 2835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 2935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private final static float[] ORIENTATIONS = { 30f40f074c43fcef627131d4b631251192761b4daaRomain Guy 0, (float) (Math.PI / 4), (float) (Math.PI / 2), (float) (Math.PI * 3 / 4), 31f40f074c43fcef627131d4b631251192761b4daaRomain Guy (float) Math.PI, -0, (float) (-Math.PI / 4), (float) (-Math.PI / 2), 32f40f074c43fcef627131d4b631251192761b4daaRomain Guy (float) (-Math.PI * 3 / 4), (float) -Math.PI 3335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li }; 3435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // the feature vector 3635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li final float[] vector; 3735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // the label can be null 3935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li final String label; 4035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 4135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // the id of the instance 42c534727972c3835ed997e84a349f259915ef2cddRomain Guy final long id; 43f40f074c43fcef627131d4b631251192761b4daaRomain Guy 4435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private Instance(long id, float[] sample, String sampleName) { 45c534727972c3835ed997e84a349f259915ef2cddRomain Guy this.id = id; 4635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li vector = sample; 4735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li label = sampleName; 48e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li } 49f40f074c43fcef627131d4b631251192761b4daaRomain Guy 50e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li private void normalize() { 51e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li float[] sample = vector; 5235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li float sum = 0; 53b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 5435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li int size = sample.length; 5535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li for (int i = 0; i < size; i++) { 5635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li sum += sample[i] * sample[i]; 5735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 58b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 59f40f074c43fcef627131d4b631251192761b4daaRomain Guy float magnitude = (float)Math.sqrt(sum); 60e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li for (int i = 0; i < size; i++) { 61e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li sample[i] /= magnitude; 62e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li } 6335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 6435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 6535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li /** 6635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * create a learning instance for a single stroke gesture 6735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 6835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param gesture 6935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @param label 7035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * @return the instance 7135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 72f40f074c43fcef627131d4b631251192761b4daaRomain Guy static Instance createInstance(int sequenceType, int orientationType, Gesture gesture, String label) { 7335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li float[] pts; 74e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li Instance instance; 750a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) { 76f40f074c43fcef627131d4b631251192761b4daaRomain Guy pts = temporalSampler(orientationType, gesture); 77e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li instance = new Instance(gesture.getID(), pts, label); 78e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li instance.normalize(); 7935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } else { 8035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li pts = spatialSampler(gesture); 81e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li instance = new Instance(gesture.getID(), pts, label); 8235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 83e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li return instance; 8435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 85f40f074c43fcef627131d4b631251192761b4daaRomain Guy 8635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static float[] spatialSampler(Gesture gesture) { 8746c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy return GestureUtils.spatialSampling(gesture, PATCH_SAMPLE_SIZE, false); 8835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 8935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 90f40f074c43fcef627131d4b631251192761b4daaRomain Guy private static float[] temporalSampler(int orientationType, Gesture gesture) { 9146c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy float[] pts = GestureUtils.temporalSampling(gesture.getStrokes().get(0), 9235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li SEQUENCE_SAMPLE_SIZE); 9346c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy float[] center = GestureUtils.computeCentroid(pts); 94f40f074c43fcef627131d4b631251192761b4daaRomain Guy float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]); 9535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 9635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li float adjustment = -orientation; 974758f1216bd16763c72500bc3c2f0fb43c08d613Yang Li if (orientationType != GestureStore.ORIENTATION_INVARIANT) { 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 10746c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy GestureUtils.translate(pts, -center[0], -center[1]); 10846c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy GestureUtils.rotate(pts, adjustment); 109b6d99b7d17fd1bb1326a70744bd01be5d1586487Romain Guy 11035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return pts; 11135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 11235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 11335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li} 114