blob: 94030c321e3bd3dca339961afefefaff00314fad [file] [log] [blame]
/*
* Copyright (C) 2012 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.
*/
// Calculates the mean and standard deviation of the values in the input image.
// It takes in an RGBA image, but assumes that r, g, b, a are all the same values.
package androidx.media.filterpacks.numeric;
import android.util.Log;
import androidx.media.filterfw.Filter;
import androidx.media.filterfw.Frame;
import androidx.media.filterfw.FrameBuffer2D;
import androidx.media.filterfw.FrameType;
import androidx.media.filterfw.FrameValue;
import androidx.media.filterfw.InputPort;
import androidx.media.filterfw.MffContext;
import androidx.media.filterfw.OutputPort;
import androidx.media.filterfw.Signature;
import androidx.media.filterfw.geometry.Quad;
import java.nio.ByteBuffer;
/**
* Get the sample mean and variance of a 2-D buffer of bytes over a given rectangle.
* TODO: Add more statistics as needed.
* TODO: Check if crop rectangle is necessary to be included in this filter.
*/
public class StatsFilter extends Filter {
private static final int MEAN_INDEX = 0;
private static final int STDEV_INDEX = 1;
private final float[] mStats = new float[2];
private Quad mCropRect = Quad.fromRect(0f, 0f, 1f, 1f);
private static final String TAG = "StatsFilter";
private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
/**
* @param context
* @param name
*/
public StatsFilter(MffContext context, String name) {
super(context, name);
}
@Override
public Signature getSignature() {
FrameType inputFrame = FrameType.buffer2D(FrameType.ELEMENT_INT8);
FrameType floatT = FrameType.single(float.class);
return new Signature()
.addInputPort("buffer", Signature.PORT_REQUIRED, inputFrame)
.addInputPort("cropRect", Signature.PORT_OPTIONAL, FrameType.single(Quad.class))
.addOutputPort("mean", Signature.PORT_REQUIRED, floatT)
.addOutputPort("stdev", Signature.PORT_REQUIRED, floatT)
.disallowOtherPorts();
}
@Override
public void onInputPortOpen(InputPort port) {
if (port.getName().equals("cropRect")) {
port.bindToFieldNamed("mCropRect");
port.setAutoPullEnabled(true);
}
}
private void calcMeanAndStd(ByteBuffer pixelBuffer, int width, int height, Quad quad) {
// Native
pixelBuffer.rewind();
regionscore(pixelBuffer, width, height, quad.topLeft().x, quad.topLeft().y,
quad.bottomRight().x, quad.bottomRight().y, mStats);
if (mLogVerbose) {
Log.v(TAG, "Native calc stats: Mean = " + mStats[MEAN_INDEX] + ", Stdev = "
+ mStats[STDEV_INDEX]);
}
}
/**
* @see androidx.media.filterfw.Filter#onProcess()
*/
@Override
protected void onProcess() {
FrameBuffer2D inputFrame = getConnectedInputPort("buffer").pullFrame().asFrameImage2D();
ByteBuffer pixelBuffer = inputFrame.lockBytes(Frame.MODE_READ);
calcMeanAndStd(pixelBuffer, inputFrame.getWidth(), inputFrame.getHeight(), mCropRect);
inputFrame.unlock();
OutputPort outPort = getConnectedOutputPort("mean");
FrameValue outFrame = outPort.fetchAvailableFrame(null).asFrameValue();
outFrame.setValue(mStats[MEAN_INDEX]);
outPort.pushFrame(outFrame);
OutputPort outPortStdev = getConnectedOutputPort("stdev");
FrameValue outFrameStdev = outPortStdev.fetchAvailableFrame(null).asFrameValue();
outFrameStdev.setValue(mStats[STDEV_INDEX]);
outPortStdev.pushFrame(outFrameStdev);
}
private native void regionscore(ByteBuffer imageBuffer, int width, int height, float left,
float top, float right, float bottom, float[] statsArray);
static {
System.loadLibrary("smartcamera_jni");
}
}