Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aeed1816 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 2219 into donut

* changes:
  Updated LetterRecognizer & related gesture recognition code - added personalization for letter recognizer
parents 0dc9a4bb e6ea003a
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -49,11 +49,11 @@ public class GestureLibrary {
    private static final String NAMESPACE = "";

    public static final int SEQUENCE_INVARIANT = 1;
    // when SEQUENCE_SENSITIVE is used, only single stroke gestures are allowed
    // when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed
    public static final int SEQUENCE_SENSITIVE = 2;

    // ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures
    public static final int ORIENTATION_INVARIANT = 1;
    // ORIENTATION_SENSITIVE is only available for single stroke gestures
    public static final int ORIENTATION_SENSITIVE = 2;

    private int mSequenceType = SEQUENCE_SENSITIVE;
@@ -77,8 +77,8 @@ public class GestureLibrary {
    }

    /**
     * Specify whether the gesture library will handle orientation sensitive
     * gestures. Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE
     * Specify how the gesture library will handle orientation. 
     * Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE
     * 
     * @param style
     */
@@ -114,8 +114,8 @@ public class GestureLibrary {
     * @return a list of predictions of possible entries for a given gesture
     */
    public ArrayList<Prediction> recognize(Gesture gesture) {
        Instance instance = Instance.createInstance(this, gesture, null);
        return mClassifier.classify(this, instance);
        Instance instance = Instance.createInstance(mSequenceType, gesture, null);
        return mClassifier.classify(mSequenceType, instance.vector);
    }

    /**
@@ -134,7 +134,7 @@ public class GestureLibrary {
            mEntryName2gestures.put(entryName, gestures);
        }
        gestures.add(gesture);
        mClassifier.addInstance(Instance.createInstance(this, gesture, entryName));
        mClassifier.addInstance(Instance.createInstance(mSequenceType, gesture, entryName));
        mChanged = true;
    }

@@ -300,7 +300,7 @@ public class GestureLibrary {
                mGestures = null;
            } else if (localName.equals(GestureConstants.XML_TAG_GESTURE)) {
                mGestures.add(mCurrentGesture);
                mClassifier.addInstance(Instance.createInstance(GestureLibrary.this,
                mClassifier.addInstance(Instance.createInstance(mSequenceType,
                        mCurrentGesture, mEntryName));
                mCurrentGesture = null;
            } else if (localName.equals(GestureConstants.XML_TAG_STROKE)) {
+8 −0
Original line number Diff line number Diff line
@@ -244,4 +244,12 @@ public class GestureStroke {
    public void invalidate() {
        mCachedPath = null;
    }
    
    /**
     * Compute an oriented bounding box of the stroke
     * @return OrientedBoundingBox
     */
    public OrientedBoundingBox computeOrientedBoundingBox() {
        return GestureUtilities.computeOrientedBoundingBox(points);
    }
}
+8 −10
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import java.io.IOException;

import static com.android.gesture.GestureConstants.*;

public final class GestureUtilities {
final class GestureUtilities {
    private static final int TEMPORAL_SAMPLING_RATE = 16;

    private GestureUtilities() {
@@ -348,33 +348,31 @@ public final class GestureUtilities {
    /**
     * Calculate the cosine distance between two instances
     * 
     * @param in1
     * @param in2
     * @param vector1
     * @param vector2
     * @return the distance between 0 and Math.PI
     */
    static double cosineDistance(Instance in1, Instance in2) {
    static double cosineDistance(float[] vector1, float[] vector2) {
        float sum = 0;
        float[] vector1 = in1.vector;
        float[] vector2 = in2.vector;
        int len = vector1.length;
        for (int i = 0; i < len; i++) {
            sum += vector1[i] * vector2[i];
        }
        return Math.acos(sum / (in1.magnitude * in2.magnitude));
        return Math.acos(sum);
    }

    public static OrientedBoundingBox computeOrientedBoundingBox(ArrayList<GesturePoint> pts) {
    static OrientedBoundingBox computeOrientedBoundingBox(ArrayList<GesturePoint> pts) {
        GestureStroke stroke = new GestureStroke(pts);
        float[] points = temporalSampling(stroke, TEMPORAL_SAMPLING_RATE);
        return computeOrientedBoundingBox(points);
    }

    public static OrientedBoundingBox computeOrientedBoundingBox(float[] points) {
    static OrientedBoundingBox computeOrientedBoundingBox(float[] points) {
        float[] meanVector = computeCentroid(points);
        return computeOrientedBoundingBox(points, meanVector);
    }

    public static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) {
    static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) {
        Matrix tr = new Matrix();
        tr.setTranslate(-centroid[0], -centroid[1]);
        tr.mapPoints(points);
+21 −13
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ package com.android.gesture;
class Instance {
    private static final int SEQUENCE_SAMPLE_SIZE = 16;

    private static final int PATCH_SAMPLE_SIZE = 8;
    private static final int PATCH_SAMPLE_SIZE = 16;

    private final static float[] ORIENTATIONS = {
            0, 45, 90, 135, 180, -0, -45, -90, -135, -180
@@ -35,9 +35,6 @@ class Instance {
    // the label can be null
    final String label;

    // the length of the vector
    final float magnitude;

    // the id of the instance
    final long id;
    
@@ -45,12 +42,19 @@ class Instance {
        this.id = id;
        vector = sample;
        label = sampleName;
    }
    
    private void normalize() {
        float[] sample = vector;
        float sum = 0;
        int size = sample.length;
        for (int i = 0; i < size; i++) {
            sum += sample[i] * sample[i];
        }
        magnitude = (float) Math.sqrt(sum);
        float magnitude = (float) Math.sqrt(sum);
        for (int i = 0; i < size; i++) {
            sample[i] /= magnitude;
        }
    }

    /**
@@ -60,21 +64,25 @@ class Instance {
     * @param label
     * @return the instance
     */
    static Instance createInstance(GestureLibrary gesturelib, Gesture gesture, String label) {
    static Instance createInstance(int samplingType, Gesture gesture, String label) {
        float[] pts;
        if (gesturelib.getGestureType() == GestureLibrary.SEQUENCE_SENSITIVE) {
            pts = temporalSampler(gesturelib, gesture);
        Instance instance;
        if (samplingType == GestureLibrary.SEQUENCE_SENSITIVE) {
            pts = temporalSampler(samplingType, gesture);
            instance = new Instance(gesture.getID(), pts, label);
            instance.normalize();
        } else {
            pts = spatialSampler(gesture);
            instance = new Instance(gesture.getID(), pts, label);
        }
        return new Instance(gesture.getID(), pts, label);
        return instance;
    }
    
    private static float[] spatialSampler(Gesture gesture) {
        return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE);
    }

    private static float[] temporalSampler(GestureLibrary gesturelib, Gesture gesture) {
    private static float[] temporalSampler(int samplingType, Gesture gesture) {
        float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0),
                SEQUENCE_SAMPLE_SIZE);
        float[] center = GestureUtilities.computeCentroid(pts);
@@ -82,7 +90,7 @@ class Instance {
        orientation *= 180 / Math.PI;

        float adjustment = -orientation;
        if (gesturelib.getOrientationStyle() == GestureLibrary.ORIENTATION_SENSITIVE) {
        if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) {
            int count = ORIENTATIONS.length;
            for (int i = 0; i < count; i++) {
                float delta = ORIENTATIONS[i] - orientation;
+5 −5
Original line number Diff line number Diff line
@@ -34,21 +34,21 @@ class InstanceLearner extends Learner {
    private static final String LOGTAG = "InstanceLearner";

    @Override
    ArrayList<Prediction> classify(GestureLibrary lib, Instance instance) {
    ArrayList<Prediction> classify(int gestureType, float[] vector) {
        ArrayList<Prediction> predictions = new ArrayList<Prediction>();
        ArrayList<Instance> instances = getInstances();
        int count = instances.size();
        TreeMap<String, Double> label2score = new TreeMap<String, Double>();
        for (int i = 0; i < count; i++) {
            Instance sample = instances.get(i);
            if (sample.vector.length != instance.vector.length) {
            if (sample.vector.length != vector.length) {
                continue;
            }
            double distance;
            if (lib.getGestureType() == GestureLibrary.SEQUENCE_SENSITIVE) {
                distance = GestureUtilities.cosineDistance(sample, instance);
            if (gestureType == GestureLibrary.SEQUENCE_SENSITIVE) {
                distance = GestureUtilities.cosineDistance(sample.vector, vector);
            } else {
                distance = GestureUtilities.squaredEuclideanDistance(sample.vector, instance.vector);
                distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector);
            }
            double weight;
            if (distance == 0) {
Loading