Improved angles variance and added the angles percentage evaluation
Change-Id: I312529ea89707d27a7ef1a5ffd6d94427eaf6e8f
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user