/*
* Copyright 2013 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.
*/
// Takes in an array, returns the size of the array
package androidx.media.filterfw.samples.simplecamera;
import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.Camera.Face;
import android.util.Log;
import androidx.media.filterfw.Filter;
import androidx.media.filterfw.Frame;
import androidx.media.filterfw.FrameImage2D;
import androidx.media.filterfw.FrameType;
import androidx.media.filterfw.FrameValues;
import androidx.media.filterfw.MffContext;
import androidx.media.filterfw.OutputPort;
import androidx.media.filterfw.Signature;
import java.nio.ByteBuffer;
public class FaceSquareFilter extends Filter {
private static final String TAG = "FaceSquareFilter";
private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
private static int FACE_X_RANGE = 2000;
private static int WIDTH_OFFSET = 1000;
private static int HEIGHT_OFFSET = 1000;
public FaceSquareFilter(MffContext context, String name) {
super(context, name);
}
@Override
public Signature getSignature() {
FrameType imageType = FrameType.buffer2D(FrameType.ELEMENT_RGBA8888);
FrameType facesType = FrameType.array(Camera.Face.class);
return new Signature()
.addInputPort("image", Signature.PORT_REQUIRED, imageType)
.addInputPort("faces", Signature.PORT_REQUIRED, facesType)
.addOutputPort("image", Signature.PORT_REQUIRED, imageType)
.disallowOtherPorts();
}
/**
* @see androidx.media.filterfw.Filter#onProcess()
*/
@Override
protected void onProcess() {
// Get inputs
FrameImage2D imageFrame = getConnectedInputPort("image").pullFrame().asFrameImage2D();
FrameValues facesFrame = getConnectedInputPort("faces").pullFrame().asFrameValues();
Face[] faces = (Face[]) facesFrame.getValues();
int[] dims = imageFrame.getDimensions();
ByteBuffer buffer = imageFrame.lockBytes(Frame.MODE_WRITE);
byte[] pixels = buffer.array();
// For every face in faces, draw a white rect around the
// face following the rect member of the Face
drawBoxes(pixels, faces, dims);
imageFrame.unlock();
OutputPort outPort = getConnectedOutputPort("image");
outPort.pushFrame(imageFrame);
}
public void drawBoxes(byte[] pixels, Face[] faces, int[] dims) {
for(int i = 0; i < faces.length; i++) {
Rect tempRect = faces[i].rect;
int top = (tempRect.top+HEIGHT_OFFSET)*dims[1]/FACE_X_RANGE;
int bottom = (tempRect.bottom+HEIGHT_OFFSET)*dims[1]/FACE_X_RANGE;
int left = (tempRect.left+WIDTH_OFFSET)*dims[0]/FACE_X_RANGE;
int right = (tempRect.right+WIDTH_OFFSET)*dims[0]/FACE_X_RANGE;
if (top < 0) {
top = 0;
} else if (top > dims[1]) {
top = dims[1];
}
if (left < 0) {
left = 0;
} else if (left > dims[0]) {
left = dims[0];
}
if (bottom > dims[1]) {
bottom = dims[1];
} else if (bottom < 0) {
bottom = 0;
}
if (right > dims[0]) {
right = dims[0];
} else if (right < 0) {
right = 0;
}
for (int j = 0; j < (bottom - top); j++) {
// Left edge
if (left > 0 && top > 0) {
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) +
ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE;
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) +
ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE;
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) +
ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE;
}
// Right edge
if (right > 0 && top > 0) {
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) +
ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE;
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) +
ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE;
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) +
ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE;
}
}
for (int k = 0; k < (right - left); k++) {
// Top edge
if (top < dims[1]) {
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) +
ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE;
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) +
ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE;
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) +
ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE;
}
// Bottom edge
if (bottom < dims[1]) {
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) +
ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE;
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) +
ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE;
pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) +
ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE;
}
}
}
}
}