Improved angles variance and added the angles percentage evaluation

Change-Id: I312529ea89707d27a7ef1a5ffd6d94427eaf6e8f
This commit is contained in:
Blazej Magnowski
2015-09-25 16:41:27 -07:00
parent 91be2f88a5
commit a28de579c8
7 changed files with 147 additions and 23 deletions

View File

@@ -32,17 +32,26 @@ import java.util.List;
* previously calculated angle. Then it calculates the variance of the differences from a stroke.
* To the differences there is artificially added value 0.0 and the difference between the first
* angle and PI (angles are in radians). It helps with strokes which have few points and punishes
* more strokes which are not smooth. This classifier also tries to split the stroke into two parts
* int the place in which the biggest angle is. It calculates the angle variance of the two parts
* and sums them up. The reason the classifier is doing this, is because some human swipes at the
* beginning go for a moment in one direction and then they rapidly change direction for the rest
* of the stroke (like a tick). The final result is the minimum of angle variance of the whole
* stroke and the sum of angle variances of the two parts split up.
* more strokes which are not smooth.
*
* This classifier also tries to split the stroke into two parts in the place in which the biggest
* angle is. It calculates the angle variance of the two parts and sums them up. The reason the
* classifier is doing this, is because some human swipes at the beginning go for a moment in one
* direction and then they rapidly change direction for the rest of the stroke (like a tick). The
* final result is the minimum of angle variance of the whole stroke and the sum of angle variances
* of the two parts split up. The classifier tries the tick option only if the first part is
* shorter than the second part.
*
* Additionally, the classifier classifies the angles as left angles (those angles which value is
* in [0.0, PI - ANGLE_DEVIATION) interval), straight angles
* ([PI - ANGLE_DEVIATION, PI + ANGLE_DEVIATION] interval) and right angles
* ((PI + ANGLE_DEVIATION, 2 * PI) interval) and then calculates the percentage of angles which are
* in the same direction (straight angles can be left angels or right angles)
*/
public class AnglesVarianceClassifier extends StrokeClassifier {
public class AnglesClassifier extends StrokeClassifier {
private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
public AnglesVarianceClassifier(ClassifierData classifierData) {
public AnglesClassifier(ClassifierData classifierData) {
mClassifierData = classifierData;
}
@@ -66,10 +75,14 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
return AnglesVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance());
Data data = mStrokeMap.get(stroke);
return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance())
+ AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
}
private static class Data {
private final float ANGLE_DEVIATION = (float) Math.PI / 20.0f;
private List<Point> mLastThreePoints = new ArrayList<>();
private float mFirstAngleVariance;
private float mPreviousAngle;
@@ -80,6 +93,12 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
private float mSecondSum;
private float mCount;
private float mSecondCount;
private float mFirstLength;
private float mLength;
private float mAnglesCount;
private float mLeftAngles;
private float mRightAngles;
private float mStraightAngles;
public Data() {
mFirstAngleVariance = 0.0f;
@@ -88,6 +107,8 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
mSumSquares = mSecondSumSquares = 0.0f;
mSum = mSecondSum = 0.0f;
mCount = mSecondCount = 1.0f;
mLength = mFirstLength = 0.0f;
mAnglesCount = mLeftAngles = mRightAngles = mStraightAngles = 0.0f;
}
public void addPoint(Point point) {
@@ -95,6 +116,9 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
// Repetitions are being ignored so that proper angles are calculated.
if (mLastThreePoints.isEmpty()
|| !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) {
if (!mLastThreePoints.isEmpty()) {
mLength += mLastThreePoints.get(mLastThreePoints.size() - 1).dist(point);
}
mLastThreePoints.add(point);
if (mLastThreePoints.size() == 4) {
mLastThreePoints.remove(0);
@@ -102,6 +126,15 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
mLastThreePoints.get(2));
mAnglesCount++;
if (angle < Math.PI - ANGLE_DEVIATION) {
mLeftAngles++;
} else if (angle <= Math.PI + ANGLE_DEVIATION) {
mStraightAngles++;
} else {
mRightAngles++;
}
float difference = angle - mPreviousAngle;
// If this is the biggest angle of the stroke so then we save the value of
@@ -109,6 +142,7 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
// variance of the second part.
if (mBiggestAngle < angle) {
mBiggestAngle = angle;
mFirstLength = mLength;
mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount);
mSecondSumSquares = 0.0f;
mSecondSum = 0.0f;
@@ -132,9 +166,19 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
}
public float getAnglesVariance() {
return Math.min(getAnglesVariance(mSumSquares, mSum, mCount),
mFirstAngleVariance + getAnglesVariance(mSecondSumSquares, mSecondSum,
mSecondCount));
float anglesVariance = getAnglesVariance(mSumSquares, mSum, mCount);
if (mFirstLength < mLength / 2f) {
anglesVariance = Math.min(anglesVariance, mFirstAngleVariance
+ getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount));
}
return anglesVariance;
}
public float getAnglesPercentage() {
if (mAnglesCount == 0.0f) {
return 1.0f;
}
return (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount;
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.classifier;
public class AnglesPercentageEvaluator {
public static float evaluate(float value) {
float evaluation = 0.0f;
if (value < 1.00) evaluation++;
if (value < 0.95) evaluation++;
if (value < 0.90) evaluation++;
return evaluation;
}
}

View File

@@ -69,13 +69,13 @@ public class HumanInteractionClassifier extends Classifier {
mClassifierData = new ClassifierData(mDpi);
mHistoryEvaluator = new HistoryEvaluator();
mStrokeClassifiers.add(new AnglesVarianceClassifier(mClassifierData));
mStrokeClassifiers.add(new AnglesClassifier(mClassifierData));
mStrokeClassifiers.add(new SpeedClassifier(mClassifierData));
mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData));
mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData));
mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData));
mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData));
mStrokeClassifiers.add(new SpeedVarianceClassifier(mClassifierData));
mStrokeClassifiers.add(new SpeedAnglesClassifier(mClassifierData));
mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData));
mGestureClassifiers.add(new PointerCountClassifier(mClassifierData));

View File

@@ -17,8 +17,11 @@
package com.android.systemui.classifier;
/**
* A classifier which looks at the ratio between the duration of the stroke and its number of
* points.
* A classifier which looks at the ratio between the length of the stroke and its number of
* points. The number of points is subtracted by 2 because the UP event comes in with some delay
* and it should not influence the ratio and also strokes which are long and have a small number
* of points are punished more (these kind of strokes are usually bad ones and they tend to score
* well in other classifiers).
*/
public class LengthCountClassifier extends StrokeClassifier {
public LengthCountClassifier(ClassifierData classifierData) {
@@ -26,6 +29,7 @@ public class LengthCountClassifier extends StrokeClassifier {
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
return LengthCountEvaluator.evaluate(stroke.getTotalLength() / stroke.getCount());
return LengthCountEvaluator.evaluate(stroke.getTotalLength()
/ Math.max(1.0f, stroke.getCount() - 2));
}
}

View File

@@ -23,10 +23,11 @@ package com.android.systemui.classifier;
public class LengthCountEvaluator {
public static float evaluate(float value) {
float evaluation = 0.0f;
if (value < 0.07) evaluation++;
if (value < 0.09) evaluation++;
if (value < 0.05) evaluation++;
if (value < 0.02) evaluation++;
if (value > 0.6) evaluation++;
if (value > 0.9) evaluation++;
if (value > 1.2) evaluation++;
return evaluation;
}

View File

@@ -28,14 +28,17 @@ import java.util.List;
* A classifier which for each point from a stroke, it creates a point on plane with coordinates
* (timeOffsetNano, distanceCoveredUpToThisPoint) (scaled by DURATION_SCALE and LENGTH_SCALE)
* and then it calculates the angle variance of these points like the class
* {@link AnglesVarianceClassifier} (without splitting it into two parts). The classifier ignores
* {@link AnglesClassifier} (without splitting it into two parts). The classifier ignores
* the last point of a stroke because the UP event comes in with some delay and this ruins the
* smoothness of this curve
* smoothness of this curve. Additionally, the classifier classifies calculates the percentage of
* angles which value is in [PI - ANGLE_DEVIATION, 2* PI) interval. The reason why the classifier
* does that is because the speed of a good stroke is most often increases, so most of these angels
* should be in this interval.
*/
public class SpeedVarianceClassifier extends StrokeClassifier {
public class SpeedAnglesClassifier extends StrokeClassifier {
private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
public SpeedVarianceClassifier(ClassifierData classifierData) {
public SpeedAnglesClassifier(ClassifierData classifierData) {
mClassifierData = classifierData;
}
@@ -64,12 +67,15 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
return SpeedVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance());
Data data = mStrokeMap.get(stroke);
return SpeedVarianceEvaluator.evaluate(data.getAnglesVariance())
+ SpeedAnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
}
private static class Data {
private final float DURATION_SCALE = 1e8f;
private final float LENGTH_SCALE = 1.0f;
private final float ANGLE_DEVIATION = (float) Math.PI / 10.0f;
private List<Point> mLastThreePoints = new ArrayList<>();
private Point mPreviousPoint;
@@ -78,6 +84,8 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
private float mSum;
private float mCount;
private float mDist;
private float mAnglesCount;
private float mAcceleratingAngles;
public Data() {
mPreviousPoint = null;
@@ -86,6 +94,7 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
mSum = 0.0f;
mCount = 1.0f;
mDist = 0.0f;
mAnglesCount = mAcceleratingAngles = 0.0f;
}
public void addPoint(Point point) {
@@ -108,6 +117,11 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
mLastThreePoints.get(2));
mAnglesCount++;
if (angle >= (float) Math.PI - ANGLE_DEVIATION) {
mAcceleratingAngles++;
}
float difference = angle - mPreviousAngle;
mSum += difference;
mSumSquares += difference * difference;
@@ -120,5 +134,12 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
public float getAnglesVariance() {
return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
}
public float getAnglesPercentage() {
if (mAnglesCount == 0.0f) {
return 1.0f;
}
return (mAcceleratingAngles) / mAnglesCount;
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.classifier;
public class SpeedAnglesPercentageEvaluator {
public static float evaluate(float value) {
float evaluation = 0.0f;
if (value < 1.00) evaluation++;
if (value < 0.95) evaluation++;
if (value < 0.90) evaluation++;
return evaluation;
}
}