1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Calculates the mean and standard deviation of the values in the input image.
18// It takes in an RGBA image, but assumes that r, g, b, a are all the same values.
19
20package androidx.media.filterpacks.numeric;
21
22import android.util.Log;
23
24import androidx.media.filterfw.Filter;
25import androidx.media.filterfw.Frame;
26import androidx.media.filterfw.FrameBuffer2D;
27import androidx.media.filterfw.FrameType;
28import androidx.media.filterfw.FrameValue;
29import androidx.media.filterfw.InputPort;
30import androidx.media.filterfw.MffContext;
31import androidx.media.filterfw.OutputPort;
32import androidx.media.filterfw.Signature;
33import androidx.media.filterfw.geometry.Quad;
34
35import java.nio.ByteBuffer;
36
37/**
38 * Get the sample mean and variance of a 2-D buffer of bytes over a given rectangle.
39 * TODO: Add more statistics as needed.
40 * TODO: Check if crop rectangle is necessary to be included in this filter.
41 */
42public class StatsFilter extends Filter {
43
44    private static final int MEAN_INDEX = 0;
45    private static final int STDEV_INDEX = 1;
46
47    private final float[] mStats = new float[2];
48
49    private Quad mCropRect = Quad.fromRect(0f, 0f, 1f, 1f);
50    private static final String TAG = "StatsFilter";
51    private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
52
53    /**
54     * @param context
55     * @param name
56     */
57    public StatsFilter(MffContext context, String name) {
58        super(context, name);
59    }
60
61    @Override
62    public Signature getSignature() {
63        FrameType inputFrame = FrameType.buffer2D(FrameType.ELEMENT_INT8);
64        FrameType floatT = FrameType.single(float.class);
65        return new Signature()
66                .addInputPort("buffer", Signature.PORT_REQUIRED, inputFrame)
67                .addInputPort("cropRect", Signature.PORT_OPTIONAL, FrameType.single(Quad.class))
68                .addOutputPort("mean", Signature.PORT_REQUIRED, floatT)
69                .addOutputPort("stdev", Signature.PORT_REQUIRED, floatT)
70                .disallowOtherPorts();
71    }
72
73    @Override
74    public void onInputPortOpen(InputPort port) {
75        if (port.getName().equals("cropRect")) {
76            port.bindToFieldNamed("mCropRect");
77            port.setAutoPullEnabled(true);
78        }
79    }
80
81    private void calcMeanAndStd(ByteBuffer pixelBuffer, int width, int height, Quad quad) {
82        // Native
83        pixelBuffer.rewind();
84        regionscore(pixelBuffer, width, height, quad.topLeft().x, quad.topLeft().y,
85                quad.bottomRight().x, quad.bottomRight().y, mStats);
86        if (mLogVerbose) {
87            Log.v(TAG, "Native calc stats: Mean = " + mStats[MEAN_INDEX] + ", Stdev = "
88                    + mStats[STDEV_INDEX]);
89        }
90    }
91
92    /**
93     * @see androidx.media.filterfw.Filter#onProcess()
94     */
95    @Override
96    protected void onProcess() {
97        FrameBuffer2D inputFrame = getConnectedInputPort("buffer").pullFrame().asFrameImage2D();
98        ByteBuffer pixelBuffer = inputFrame.lockBytes(Frame.MODE_READ);
99
100        calcMeanAndStd(pixelBuffer, inputFrame.getWidth(), inputFrame.getHeight(), mCropRect);
101        inputFrame.unlock();
102
103        OutputPort outPort = getConnectedOutputPort("mean");
104        FrameValue outFrame = outPort.fetchAvailableFrame(null).asFrameValue();
105        outFrame.setValue(mStats[MEAN_INDEX]);
106        outPort.pushFrame(outFrame);
107
108        OutputPort outPortStdev = getConnectedOutputPort("stdev");
109        FrameValue outFrameStdev = outPortStdev.fetchAvailableFrame(null).asFrameValue();
110        outFrameStdev.setValue(mStats[STDEV_INDEX]);
111        outPortStdev.pushFrame(outFrameStdev);
112    }
113
114    private native void regionscore(ByteBuffer imageBuffer, int width, int height, float left,
115            float top, float right, float bottom, float[] statsArray);
116
117    static {
118        System.loadLibrary("smartcamera_jni");
119    }
120}
121