1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright 2013 The Android Open Source Project
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License");
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License.
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *      http://www.apache.org/licenses/LICENSE-2.0
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS,
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License.
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Takes sharpness score, rates the image good if above 10, bad otherwise
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw.samples.simplecamera;
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Bitmap;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.os.AsyncTask;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.util.Log;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.widget.ImageView;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.Filter;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameImage2D;
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameType;
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameValue;
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.MffContext;
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.OutputPort;
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.Signature;
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class ImageGoodnessFilter extends Filter {
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final String TAG = "ImageGoodnessFilter";
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static String GREAT = "Great Picture!";
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static String GOOD = "Good Picture!";
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static String OK = "Ok Picture";
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static String BAD = "Bad Picture";
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static String AWFUL = "Awful Picture";
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static float SMALL_SCORE_INC = 0.25f;
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static float BIG_SCORE_INC = 0.5f;
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static float LOW_VARIANCE = 0.1f;
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static float MEDIUM_VARIANCE = 10;
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static float HIGH_VARIANCE = 100;
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float sharpnessMean = 0;
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float sharpnessVar = 0;
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float underExposureMean = 0;
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float underExposureVar = 0;
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float overExposureMean = 0;
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float overExposureVar = 0;
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float contrastMean = 0;
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float contrastVar = 0;
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float colorfulnessMean = 0;
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float colorfulnessVar = 0;
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float brightnessMean = 0;
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float brightnessVar = 0;
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float motionMean = 0;
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float scoreMean = 0;
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final float DECAY = 0.03f;
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param context
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param name
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public ImageGoodnessFilter(MffContext context, String name) {
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        super(context, name);
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Signature getSignature() {
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameType floatT = FrameType.single(float.class);
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameType imageIn = FrameType.image2D(FrameType.ELEMENT_RGBA8888, FrameType.READ_GPU);
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Signature()
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("sharpness", Signature.PORT_REQUIRED, floatT)
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("overExposure", Signature.PORT_REQUIRED, floatT)
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("underExposure", Signature.PORT_REQUIRED, floatT)
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("colorfulness", Signature.PORT_REQUIRED, floatT)
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("contrastRating", Signature.PORT_REQUIRED, floatT)
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("motionValues", Signature.PORT_REQUIRED, FrameType.array(float.class))
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("brightness", Signature.PORT_REQUIRED, floatT)
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("capturing", Signature.PORT_REQUIRED, FrameType.single(boolean.class))
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addInputPort("image", Signature.PORT_REQUIRED, imageIn)
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addOutputPort("goodOrBadPic", Signature.PORT_REQUIRED,
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        FrameType.single(String.class))
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .addOutputPort("score", Signature.PORT_OPTIONAL, floatT)
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .disallowOtherPorts();
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see androidx.media.filterfw.Filter#onProcess()
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onProcess() {
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue sharpnessFrameValue =
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getConnectedInputPort("sharpness").pullFrame().asFrameValue();
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float sharpness = ((Float)sharpnessFrameValue.getValue()).floatValue();
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue overExposureFrameValue =
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getConnectedInputPort("overExposure").pullFrame().asFrameValue();
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float overExposure = ((Float)overExposureFrameValue.getValue()).floatValue();
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue underExposureFrameValue =
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getConnectedInputPort("underExposure").pullFrame().asFrameValue();
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float underExposure = ((Float)underExposureFrameValue.getValue()).floatValue();
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue colorfulnessFrameValue =
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getConnectedInputPort("colorfulness").pullFrame().asFrameValue();
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float colorfulness = ((Float)colorfulnessFrameValue.getValue()).floatValue();
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue contrastRatingFrameValue =
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getConnectedInputPort("contrastRating").pullFrame().asFrameValue();
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float contrastRating = ((Float)contrastRatingFrameValue.getValue()).floatValue();
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue brightnessFrameValue =
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getConnectedInputPort("brightness").pullFrame().asFrameValue();
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float brightness = ((Float)brightnessFrameValue.getValue()).floatValue();
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue motionValuesFrameValue =
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getConnectedInputPort("motionValues").pullFrame().asFrameValue();
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float[] motionValues = (float[]) motionValuesFrameValue.getValue();
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float vectorAccel = (float) Math.sqrt(Math.pow(motionValues[0], 2) +
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Math.pow(motionValues[1], 2) + Math.pow(motionValues[2], 2));
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        String outStr;
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue capturingFrameValue =
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getConnectedInputPort("capturing").pullFrame().asFrameValue();
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        boolean capturing = (Boolean) capturingFrameValue.getValue();
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameImage2D inputImage = getConnectedInputPort("image").pullFrame().asFrameImage2D();
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // TODO: get rid of magic numbers
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float score = 0.0f;
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        score = computePictureScore(vectorAccel, sharpness, underExposure, overExposure,
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    contrastRating, colorfulness, brightness);
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (scoreMean == 0) scoreMean = score;
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        else scoreMean = scoreMean * (1 - DECAY) + score * DECAY;
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (motionMean == 0) motionMean = vectorAccel;
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        else motionMean = motionMean * (1 - DECAY) + vectorAccel * DECAY;
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float classifierScore = classifierComputeScore(vectorAccel, sharpness, underExposure,
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                colorfulness, contrastRating, score);
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//        Log.v(TAG, "ClassifierScore:: " + classifierScore);
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        final float GREAT_SCORE = 3.5f;
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        final float GOOD_SCORE = 2.5f;
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        final float OK_SCORE = 1.5f;
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        final float BAD_SCORE = 0.5f;
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (score >= GREAT_SCORE) {
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outStr = GREAT;
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (score >= GOOD_SCORE) {
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outStr = GOOD;
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (score >= OK_SCORE) {
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outStr = OK;
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (score >= BAD_SCORE) {
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outStr = BAD;
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outStr = AWFUL;
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if(capturing) {
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (outStr.equals(GREAT)) {
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                // take a picture
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Bitmap bitmap = inputImage.toBitmap();
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                new AsyncOperation().execute(bitmap);
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                final float RESET_FEATURES = 0.01f;
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                sharpnessMean = RESET_FEATURES;
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                underExposureMean = RESET_FEATURES;
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                overExposureMean = RESET_FEATURES;
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                contrastMean = RESET_FEATURES;
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                colorfulnessMean = RESET_FEATURES;
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                brightnessMean = RESET_FEATURES;
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        OutputPort outPort = getConnectedOutputPort("goodOrBadPic");
185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue stringFrame = outPort.fetchAvailableFrame(null).asFrameValue();
186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        stringFrame.setValue(outStr);
187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        outPort.pushFrame(stringFrame);
188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        OutputPort scoreOutPort = getConnectedOutputPort("score");
190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameValue scoreFrame = scoreOutPort.fetchAvailableFrame(null).asFrameValue();
191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        scoreFrame.setValue(score);
192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        scoreOutPort.pushFrame(scoreFrame);
193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private class AsyncOperation extends AsyncTask<Bitmap, Void, String> {
197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private Bitmap b;
198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        protected void onPostExecute(String result) {
199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            ImageView view = SmartCamera.getImageView();
200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            view.setImageBitmap(b);
201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        protected String doInBackground(Bitmap... params) {
205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // TODO Auto-generated method stub
206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            b = params[0];
207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return null;
208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // Returns a number between -1 and 1
212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float classifierComputeScore(float vectorAccel, float sharpness, float underExposure,
213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks           float colorfulness, float contrast, float score) {
214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float result = (-0.0223f * sharpness + -0.0563f * underExposure + 0.0137f * colorfulness
215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + 0.3102f * contrast + 0.0314f * vectorAccel + -0.0094f * score + 0.0227f *
216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                sharpnessMean + 0.0459f * underExposureMean + -0.3934f * contrastMean +
217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                -0.0697f * motionMean + 0.0091f * scoreMean + -0.0152f);
218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return result;
219227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
220227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
221227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // Returns a number between -1 and 4 representing the score for this picture
222227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float computePictureScore(float vector_accel, float sharpness,
223227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            float underExposure, float overExposure, float contrastRating, float colorfulness,
224227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            float brightness) {
225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        final float ACCELERATION_THRESHOLD_VERY_STEADY = 0.1f;
226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        final float ACCELERATION_THRESHOLD_STEADY = 0.3f;
227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        final float ACCELERATION_THRESHOLD_MOTION = 2f;
228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float score = 0.0f;
230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (vector_accel > ACCELERATION_THRESHOLD_MOTION) {
231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            score -= (BIG_SCORE_INC + BIG_SCORE_INC); // set score to -1, bad pic
232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (vector_accel > ACCELERATION_THRESHOLD_STEADY) {
233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            score -= BIG_SCORE_INC;
234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            score = subComputeScore(sharpness, underExposure, overExposure, contrastRating,
235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    colorfulness, brightness, score);
236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (vector_accel < ACCELERATION_THRESHOLD_VERY_STEADY) {
237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            score += BIG_SCORE_INC;
238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            score = subComputeScore(sharpness, underExposure, overExposure, contrastRating,
239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    colorfulness, brightness, score);
240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            score = subComputeScore(sharpness, underExposure, overExposure, contrastRating,
242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    colorfulness, brightness, score);
243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return score;
245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // Changes the score by at most +/- 3.5
248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float subComputeScore(float sharpness, float underExposure, float overExposure,
249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                float contrastRating, float colorfulness, float brightness, float score) {
250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // The score methods return values -0.5 to 0.5
251227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        final float SHARPNESS_WEIGHT = 2;
252227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        score += SHARPNESS_WEIGHT * sharpnessScore(sharpness);
253227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        score += underExposureScore(underExposure);
254227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        score += overExposureScore(overExposure);
255227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        score += contrastScore(contrastRating);
256227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        score += colorfulnessScore(colorfulness);
257227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        score += brightnessScore(brightness);
258227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return score;
259227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
260227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
261227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float sharpnessScore(float sharpness) {
262227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (sharpnessMean == 0) {
263227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            sharpnessMean = sharpness;
264227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            sharpnessVar = 0;
265227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return 0;
266227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
267227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            sharpnessMean = sharpnessMean * (1 - DECAY) + sharpness * DECAY;
268227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            sharpnessVar = sharpnessVar * (1 - DECAY) + (sharpness - sharpnessMean) *
269227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    (sharpness - sharpnessMean) * DECAY;
270227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (sharpnessVar < LOW_VARIANCE) {
271227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC;
272227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (sharpness < sharpnessMean && sharpnessVar > MEDIUM_VARIANCE) {
273227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -BIG_SCORE_INC;
274227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (sharpness < sharpnessMean) {
275227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -SMALL_SCORE_INC;
276227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (sharpness > sharpnessMean && sharpnessVar > HIGH_VARIANCE) {
277227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return 0;
278227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (sharpness > sharpnessMean && sharpnessVar > MEDIUM_VARIANCE) {
279227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return SMALL_SCORE_INC;
280227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else  {
281227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC; // low variance, sharpness above the mean
282227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
283227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
284227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
285227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
286227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float underExposureScore(float underExposure) {
287227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (underExposureMean == 0) {
288227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            underExposureMean = underExposure;
289227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            underExposureVar = 0;
290227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return 0;
291227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
292227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            underExposureMean = underExposureMean * (1 - DECAY) + underExposure * DECAY;
293227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            underExposureVar = underExposureVar * (1 - DECAY) + (underExposure - underExposureMean)
294227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    * (underExposure - underExposureMean) * DECAY;
295227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (underExposureVar < LOW_VARIANCE) {
296227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC;
297227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (underExposure > underExposureMean && underExposureVar > MEDIUM_VARIANCE) {
298227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -BIG_SCORE_INC;
299227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (underExposure > underExposureMean) {
300227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -SMALL_SCORE_INC;
301227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (underExposure < underExposureMean && underExposureVar > HIGH_VARIANCE) {
302227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return 0;
303227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (underExposure < underExposureMean && underExposureVar > MEDIUM_VARIANCE) {
304227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return SMALL_SCORE_INC;
305227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
306227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC; // low variance, underExposure below the mean
307227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
308227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
309227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
310227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
311227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float overExposureScore(float overExposure) {
312227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (overExposureMean == 0) {
313227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            overExposureMean = overExposure;
314227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            overExposureVar = 0;
315227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return 0;
316227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
317227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            overExposureMean = overExposureMean * (1 - DECAY) + overExposure * DECAY;
318227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            overExposureVar = overExposureVar * (1 - DECAY) + (overExposure - overExposureMean) *
319227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    (overExposure - overExposureMean) * DECAY;
320227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (overExposureVar < LOW_VARIANCE) {
321227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC;
322227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (overExposure > overExposureMean && overExposureVar > MEDIUM_VARIANCE) {
323227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -BIG_SCORE_INC;
324227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (overExposure > overExposureMean) {
325227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -SMALL_SCORE_INC;
326227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (overExposure < overExposureMean && overExposureVar > HIGH_VARIANCE) {
327227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return 0;
328227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (overExposure < overExposureMean && overExposureVar > MEDIUM_VARIANCE) {
329227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return SMALL_SCORE_INC;
330227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
331227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC; // low variance, overExposure below the mean
332227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
333227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
334227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
335227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
336227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float contrastScore(float contrast) {
337227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (contrastMean == 0) {
338227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            contrastMean = contrast;
339227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            contrastVar = 0;
340227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return 0;
341227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
342227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            contrastMean = contrastMean * (1 - DECAY) + contrast * DECAY;
343227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            contrastVar = contrastVar * (1 - DECAY) + (contrast - contrastMean) *
344227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    (contrast - contrastMean) * DECAY;
345227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (contrastVar < LOW_VARIANCE) {
346227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC;
347227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (contrast < contrastMean && contrastVar > MEDIUM_VARIANCE) {
348227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -BIG_SCORE_INC;
349227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (contrast < contrastMean) {
350227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -SMALL_SCORE_INC;
351227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (contrast > contrastMean && contrastVar > 100) {
352227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return 0;
353227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (contrast > contrastMean && contrastVar > MEDIUM_VARIANCE) {
354227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return SMALL_SCORE_INC;
355227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
356227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC; // low variance, contrast above the mean
357227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
358227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
359227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
360227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
361227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float colorfulnessScore(float colorfulness) {
362227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (colorfulnessMean == 0) {
363227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            colorfulnessMean = colorfulness;
364227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            colorfulnessVar = 0;
365227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return 0;
366227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
367227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            colorfulnessMean = colorfulnessMean * (1 - DECAY) + colorfulness * DECAY;
368227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            colorfulnessVar = colorfulnessVar * (1 - DECAY) + (colorfulness - colorfulnessMean) *
369227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    (colorfulness - colorfulnessMean) * DECAY;
370227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (colorfulnessVar < LOW_VARIANCE) {
371227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC;
372227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (colorfulness < colorfulnessMean && colorfulnessVar > MEDIUM_VARIANCE) {
373227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -BIG_SCORE_INC;
374227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (colorfulness < colorfulnessMean) {
375227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -SMALL_SCORE_INC;
376227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (colorfulness > colorfulnessMean && colorfulnessVar > 100) {
377227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return 0;
378227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (colorfulness > colorfulnessMean && colorfulnessVar > MEDIUM_VARIANCE) {
379227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return SMALL_SCORE_INC;
380227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
381227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC; // low variance, colorfulness above the mean
382227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
383227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
384227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
385227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
386227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float brightnessScore(float brightness) {
387227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (brightnessMean == 0) {
388227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            brightnessMean = brightness;
389227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            brightnessVar = 0;
390227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return 0;
391227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
392227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            brightnessMean = brightnessMean * (1 - DECAY) + brightness * DECAY;
393227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            brightnessVar = brightnessVar * (1 - DECAY) + (brightness - brightnessMean) *
394227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    (brightness - brightnessMean) * DECAY;
395227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (brightnessVar < LOW_VARIANCE) {
396227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC;
397227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (brightness < brightnessMean && brightnessVar > MEDIUM_VARIANCE) {
398227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -BIG_SCORE_INC;
399227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (brightness < brightnessMean) {
400227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return -SMALL_SCORE_INC;
401227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (brightness > brightnessMean && brightnessVar > 100) {
402227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return 0;
403227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (brightness > brightnessMean && brightnessVar > MEDIUM_VARIANCE) {
404227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return SMALL_SCORE_INC;
405227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
406227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return BIG_SCORE_INC; // low variance, brightness above the mean
407227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
408227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
409227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
410227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
411