Merge change 2593 into donut
* changes: Bug fixes and performance improvements
This commit is contained in:
@@ -136,7 +136,7 @@ public class GestureLibrary {
|
|||||||
* @return a list of predictions of possible entries for a given gesture
|
* @return a list of predictions of possible entries for a given gesture
|
||||||
*/
|
*/
|
||||||
public ArrayList<Prediction> recognize(Gesture gesture) {
|
public ArrayList<Prediction> recognize(Gesture gesture) {
|
||||||
Instance instance = Instance.createInstance(mSequenceType, gesture, null);
|
Instance instance = Instance.createInstance(mSequenceType, mOrientationStyle, gesture, null);
|
||||||
return mClassifier.classify(mSequenceType, instance.vector);
|
return mClassifier.classify(mSequenceType, instance.vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ public class GestureLibrary {
|
|||||||
mNamedGestures.put(entryName, gestures);
|
mNamedGestures.put(entryName, gestures);
|
||||||
}
|
}
|
||||||
gestures.add(gesture);
|
gestures.add(gesture);
|
||||||
mClassifier.addInstance(Instance.createInstance(mSequenceType, gesture, entryName));
|
mClassifier.addInstance(Instance.createInstance(mSequenceType, mOrientationStyle, gesture, entryName));
|
||||||
mChanged = true;
|
mChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,10 +337,14 @@ public class GestureLibrary {
|
|||||||
for (int j = 0; j < gestureCount; j++) {
|
for (int j = 0; j < gestureCount; j++) {
|
||||||
final Gesture gesture = Gesture.deserialize(in);
|
final Gesture gesture = Gesture.deserialize(in);
|
||||||
gestures.add(gesture);
|
gestures.add(gesture);
|
||||||
classifier.addInstance(Instance.createInstance(mSequenceType, gesture, name));
|
classifier.addInstance(Instance.createInstance(mSequenceType, mOrientationStyle, gesture, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
namedGestures.put(name, gestures);
|
namedGestures.put(name, gestures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Learner getLearner() {
|
||||||
|
return mClassifier;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Matrix;
|
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
@@ -147,10 +146,12 @@ public class GestureStroke {
|
|||||||
final float[] pts = GestureUtilities.temporalSampling(this, numSample);
|
final float[] pts = GestureUtilities.temporalSampling(this, numSample);
|
||||||
final RectF rect = boundingBox;
|
final RectF rect = boundingBox;
|
||||||
|
|
||||||
final Matrix matrix = new Matrix();
|
GestureUtilities.translate(pts, -rect.left, -rect.top);
|
||||||
matrix.setTranslate(-rect.left, -rect.top);
|
|
||||||
matrix.postScale(width / rect.width(), height / rect.height());
|
float sx = width / rect.width();
|
||||||
matrix.mapPoints(pts);
|
float sy = height / rect.height();
|
||||||
|
float scale = sx > sy ? sy : sx;
|
||||||
|
GestureUtilities.scale(pts, scale, scale);
|
||||||
|
|
||||||
float mX = 0;
|
float mX = 0;
|
||||||
float mY = 0;
|
float mY = 0;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.graphics.Matrix;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -380,22 +379,17 @@ final class GestureUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) {
|
static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) {
|
||||||
Matrix tr = new Matrix();
|
translate(points, -centroid[0], -centroid[1]);
|
||||||
tr.setTranslate(-centroid[0], -centroid[1]);
|
|
||||||
tr.mapPoints(points);
|
|
||||||
|
|
||||||
double[][] array = computeCoVariance(points);
|
double[][] array = computeCoVariance(points);
|
||||||
double[] targetVector = computeOrientation(array);
|
double[] targetVector = computeOrientation(array);
|
||||||
|
|
||||||
float angle;
|
float angle;
|
||||||
if (targetVector[0] == 0 && targetVector[1] == 0) {
|
if (targetVector[0] == 0 && targetVector[1] == 0) {
|
||||||
angle = -90;
|
angle = (float) -Math.PI/2;
|
||||||
} else { // -PI<alpha<PI
|
} else { // -PI<alpha<PI
|
||||||
angle = (float) Math.atan2(targetVector[1], targetVector[0]);
|
angle = (float) Math.atan2(targetVector[1], targetVector[0]);
|
||||||
angle = (float) (180 * angle / Math.PI);
|
rotate(points, -angle);
|
||||||
Matrix trans = new Matrix();
|
|
||||||
trans.setRotate(-angle);
|
|
||||||
trans.mapPoints(points);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float minx = Float.MAX_VALUE;
|
float minx = Float.MAX_VALUE;
|
||||||
@@ -446,4 +440,36 @@ final class GestureUtilities {
|
|||||||
}
|
}
|
||||||
return targetVector;
|
return targetVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float[] rotate(float[] points, double angle) {
|
||||||
|
double cos = Math.cos(angle);
|
||||||
|
double sin = Math.sin(angle);
|
||||||
|
int size = points.length;
|
||||||
|
for (int i = 0; i < size; i += 2) {
|
||||||
|
float x = (float) (points[i] * cos - points[i + 1] * sin);
|
||||||
|
float y = (float) (points[i] * sin + points[i + 1] * cos);
|
||||||
|
points[i] = x;
|
||||||
|
points[i + 1] = y;
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float[] translate(float[] points, float dx, float dy) {
|
||||||
|
int size = points.length;
|
||||||
|
for (int i = 0; i < size; i += 2) {
|
||||||
|
points[i] += dx;
|
||||||
|
points[i + 1] += dy;
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float[] scale(float[] points, float sx, float sy) {
|
||||||
|
int size = points.length;
|
||||||
|
for (int i = 0; i < size; i += 2) {
|
||||||
|
points[i] *= sx;
|
||||||
|
points[i + 1] *= sy;
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.Matrix;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance represents a sample if the label is available or a query if the
|
* An instance represents a sample if the label is available or a query if the
|
||||||
@@ -28,7 +27,9 @@ class Instance {
|
|||||||
private static final int PATCH_SAMPLE_SIZE = 16;
|
private static final int PATCH_SAMPLE_SIZE = 16;
|
||||||
|
|
||||||
private final static float[] ORIENTATIONS = {
|
private final static float[] ORIENTATIONS = {
|
||||||
0, 45, 90, 135, 180, -0, -45, -90, -135, -180
|
0, (float) (Math.PI / 4), (float) (Math.PI / 2), (float) (Math.PI * 3 / 4),
|
||||||
|
(float) Math.PI, -0, (float) (-Math.PI / 4), (float) (-Math.PI / 2),
|
||||||
|
(float) (-Math.PI * 3 / 4), (float) -Math.PI
|
||||||
};
|
};
|
||||||
|
|
||||||
// the feature vector
|
// the feature vector
|
||||||
@@ -68,11 +69,11 @@ class Instance {
|
|||||||
* @param label
|
* @param label
|
||||||
* @return the instance
|
* @return the instance
|
||||||
*/
|
*/
|
||||||
static Instance createInstance(int samplingType, Gesture gesture, String label) {
|
static Instance createInstance(int sequenceType, int orientationType, Gesture gesture, String label) {
|
||||||
float[] pts;
|
float[] pts;
|
||||||
Instance instance;
|
Instance instance;
|
||||||
if (samplingType == GestureLibrary.SEQUENCE_SENSITIVE) {
|
if (sequenceType == GestureLibrary.SEQUENCE_SENSITIVE) {
|
||||||
pts = temporalSampler(samplingType, gesture);
|
pts = temporalSampler(orientationType, gesture);
|
||||||
instance = new Instance(gesture.getID(), pts, label);
|
instance = new Instance(gesture.getID(), pts, label);
|
||||||
instance.normalize();
|
instance.normalize();
|
||||||
} else {
|
} else {
|
||||||
@@ -86,15 +87,14 @@ class Instance {
|
|||||||
return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE);
|
return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] temporalSampler(int samplingType, Gesture gesture) {
|
private static float[] temporalSampler(int orientationType, Gesture gesture) {
|
||||||
float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0),
|
float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0),
|
||||||
SEQUENCE_SAMPLE_SIZE);
|
SEQUENCE_SAMPLE_SIZE);
|
||||||
float[] center = GestureUtilities.computeCentroid(pts);
|
float[] center = GestureUtilities.computeCentroid(pts);
|
||||||
float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]);
|
float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]);
|
||||||
orientation *= 180 / Math.PI;
|
|
||||||
|
|
||||||
float adjustment = -orientation;
|
float adjustment = -orientation;
|
||||||
if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) {
|
if (orientationType == GestureLibrary.ORIENTATION_SENSITIVE) {
|
||||||
int count = ORIENTATIONS.length;
|
int count = ORIENTATIONS.length;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
float delta = ORIENTATIONS[i] - orientation;
|
float delta = ORIENTATIONS[i] - orientation;
|
||||||
@@ -104,10 +104,8 @@ class Instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix m = new Matrix();
|
GestureUtilities.translate(pts, -center[0], -center[1]);
|
||||||
m.setTranslate(-center[0], -center[1]);
|
GestureUtilities.rotate(pts, adjustment);
|
||||||
m.postRotate(adjustment);
|
|
||||||
m.mapPoints(pts);
|
|
||||||
|
|
||||||
return pts;
|
return pts;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,9 @@
|
|||||||
|
|
||||||
package android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.util.Config;
|
|
||||||
import android.util.Log;
|
|
||||||
import static android.gesture.GestureConstants.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,7 +27,7 @@ import java.util.TreeMap;
|
|||||||
|
|
||||||
class InstanceLearner extends Learner {
|
class InstanceLearner extends Learner {
|
||||||
@Override
|
@Override
|
||||||
ArrayList<Prediction> classify(int gestureType, float[] vector) {
|
ArrayList<Prediction> classify(int sequenceType, float[] vector) {
|
||||||
ArrayList<Prediction> predictions = new ArrayList<Prediction>();
|
ArrayList<Prediction> predictions = new ArrayList<Prediction>();
|
||||||
ArrayList<Instance> instances = getInstances();
|
ArrayList<Instance> instances = getInstances();
|
||||||
int count = instances.size();
|
int count = instances.size();
|
||||||
@@ -43,7 +38,7 @@ class InstanceLearner extends Learner {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double distance;
|
double distance;
|
||||||
if (gestureType == GestureLibrary.SEQUENCE_SENSITIVE) {
|
if (sequenceType == GestureLibrary.SEQUENCE_SENSITIVE) {
|
||||||
distance = GestureUtilities.cosineDistance(sample.vector, vector);
|
distance = GestureUtilities.cosineDistance(sample.vector, vector);
|
||||||
} else {
|
} else {
|
||||||
distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector);
|
distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector);
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Reference in New Issue
Block a user