1 /* 2 * Copyright 2013 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 // Takes in an array, returns the size of the array 17 18 package androidx.media.filterfw.samples.simplecamera; 19 20 import android.graphics.Rect; 21 import android.hardware.Camera; 22 import android.hardware.Camera.Face; 23 import android.util.Log; 24 import androidx.media.filterfw.Filter; 25 import androidx.media.filterfw.Frame; 26 import androidx.media.filterfw.FrameImage2D; 27 import androidx.media.filterfw.FrameType; 28 import androidx.media.filterfw.FrameValues; 29 import androidx.media.filterfw.MffContext; 30 import androidx.media.filterfw.OutputPort; 31 import androidx.media.filterfw.Signature; 32 33 import java.nio.ByteBuffer; 34 35 public class FaceSquareFilter extends Filter { 36 37 private static final String TAG = "FaceSquareFilter"; 38 private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 39 40 private static int FACE_X_RANGE = 2000; 41 private static int WIDTH_OFFSET = 1000; 42 private static int HEIGHT_OFFSET = 1000; 43 44 public FaceSquareFilter(MffContext context, String name) { 45 super(context, name); 46 } 47 48 @Override 49 public Signature getSignature() { 50 FrameType imageType = FrameType.buffer2D(FrameType.ELEMENT_RGBA8888); 51 FrameType facesType = FrameType.array(Camera.Face.class); 52 return new Signature() 53 .addInputPort("image", Signature.PORT_REQUIRED, imageType) 54 .addInputPort("faces", Signature.PORT_REQUIRED, facesType) 55 .addOutputPort("image", Signature.PORT_REQUIRED, imageType) 56 .disallowOtherPorts(); 57 } 58 59 /** 60 * @see androidx.media.filterfw.Filter#onProcess() 61 */ 62 @Override 63 protected void onProcess() { 64 // Get inputs 65 FrameImage2D imageFrame = getConnectedInputPort("image").pullFrame().asFrameImage2D(); 66 FrameValues facesFrame = getConnectedInputPort("faces").pullFrame().asFrameValues(); 67 Face[] faces = (Face[]) facesFrame.getValues(); 68 int[] dims = imageFrame.getDimensions(); 69 ByteBuffer buffer = imageFrame.lockBytes(Frame.MODE_WRITE); 70 byte[] pixels = buffer.array(); 71 72 // For every face in faces, draw a white rect around the 73 // face following the rect member of the Face 74 drawBoxes(pixels, faces, dims); 75 76 imageFrame.unlock(); 77 78 OutputPort outPort = getConnectedOutputPort("image"); 79 outPort.pushFrame(imageFrame); 80 } 81 82 public void drawBoxes(byte[] pixels, Face[] faces, int[] dims) { 83 for(int i = 0; i < faces.length; i++) { 84 Rect tempRect = faces[i].rect; 85 int top = (tempRect.top+HEIGHT_OFFSET)*dims[1]/FACE_X_RANGE; 86 int bottom = (tempRect.bottom+HEIGHT_OFFSET)*dims[1]/FACE_X_RANGE; 87 int left = (tempRect.left+WIDTH_OFFSET)*dims[0]/FACE_X_RANGE; 88 int right = (tempRect.right+WIDTH_OFFSET)*dims[0]/FACE_X_RANGE; 89 90 if (top < 0) { 91 top = 0; 92 } else if (top > dims[1]) { 93 top = dims[1]; 94 } 95 if (left < 0) { 96 left = 0; 97 } else if (left > dims[0]) { 98 left = dims[0]; 99 } 100 if (bottom > dims[1]) { 101 bottom = dims[1]; 102 } else if (bottom < 0) { 103 bottom = 0; 104 } 105 if (right > dims[0]) { 106 right = dims[0]; 107 } else if (right < 0) { 108 right = 0; 109 } 110 111 for (int j = 0; j < (bottom - top); j++) { 112 // Left edge 113 if (left > 0 && top > 0) { 114 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) + 115 ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE; 116 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) + 117 ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE; 118 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) + 119 ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE; 120 } 121 122 // Right edge 123 if (right > 0 && top > 0) { 124 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) + 125 ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE; 126 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) + 127 ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE; 128 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) + 129 ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE; 130 } 131 132 } 133 for (int k = 0; k < (right - left); k++) { 134 // Top edge 135 if (top < dims[1]) { 136 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) + 137 ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE; 138 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) + 139 ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE; 140 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) + 141 ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE; 142 143 } 144 // Bottom edge 145 if (bottom < dims[1]) { 146 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) + 147 ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE; 148 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) + 149 ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE; 150 pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) + 151 ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE; 152 } 153 154 155 } 156 157 } 158 } 159 } 160