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 
20 package androidx.media.filterpacks.numeric;
21 
22 import android.util.Log;
23 
24 import androidx.media.filterfw.Filter;
25 import androidx.media.filterfw.Frame;
26 import androidx.media.filterfw.FrameBuffer2D;
27 import androidx.media.filterfw.FrameType;
28 import androidx.media.filterfw.FrameValue;
29 import androidx.media.filterfw.InputPort;
30 import androidx.media.filterfw.MffContext;
31 import androidx.media.filterfw.OutputPort;
32 import androidx.media.filterfw.Signature;
33 import androidx.media.filterfw.geometry.Quad;
34 
35 import 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  */
42 public 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      */
StatsFilter(MffContext context, String name)57     public StatsFilter(MffContext context, String name) {
58         super(context, name);
59     }
60 
61     @Override
getSignature()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
onInputPortOpen(InputPort port)74     public void onInputPortOpen(InputPort port) {
75         if (port.getName().equals("cropRect")) {
76             port.bindToFieldNamed("mCropRect");
77             port.setAutoPullEnabled(true);
78         }
79     }
80 
calcMeanAndStd(ByteBuffer pixelBuffer, int width, int height, Quad quad)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
onProcess()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 
regionscore(ByteBuffer imageBuffer, int width, int height, float left, float top, float right, float bottom, float[] statsArray)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