Java tutorial
/* * Copyright (C) 2006 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. */ package android.media; import android.graphics.Bitmap; import android.graphics.PointF; import android.util.Log; import java.lang.IllegalArgumentException; /** * Identifies the faces of people in a * {@link android.graphics.Bitmap} graphic object. */ public class FaceDetector { /** * A Face contains all the information identifying the location * of a face in a bitmap. */ public class Face { /** The minimum confidence factor of good face recognition */ public static final float CONFIDENCE_THRESHOLD = 0.4f; /** The x-axis Euler angle of a face. */ public static final int EULER_X = 0; /** The y-axis Euler angle of a face. */ public static final int EULER_Y = 1; /** The z-axis Euler angle of a face. */ public static final int EULER_Z = 2; /** * Returns a confidence factor between 0 and 1. This indicates how * certain what has been found is actually a face. A confidence * factor above 0.3 is usually good enough. */ public float confidence() { return mConfidence; } /** * Sets the position of the mid-point between the eyes. * @param point the PointF coordinates (float values) of the * face's mid-point */ public void getMidPoint(PointF point) { // don't return a PointF to avoid allocations point.set(mMidPointX, mMidPointY); } /** * Returns the distance between the eyes. */ public float eyesDistance() { return mEyesDist; } /** * Returns the face's pose. That is, the rotations around either * the X, Y or Z axis (the positions in 3-dimensional Euclidean space). * * @param euler the Euler axis to retrieve an angle from * (<var>EULER_X</var>, <var>EULER_Y</var> or * <var>EULER_Z</var>) * @return the Euler angle of the of the face, for the given axis */ public float pose(int euler) { // don't use an array to avoid allocations if (euler == EULER_X) return mPoseEulerX; else if (euler == EULER_Y) return mPoseEulerY; else if (euler == EULER_Z) return mPoseEulerZ; throw new IllegalArgumentException(); } // private ctor, user not supposed to build this object private Face() { } private float mConfidence; private float mMidPointX; private float mMidPointY; private float mEyesDist; private float mPoseEulerX; private float mPoseEulerY; private float mPoseEulerZ; } /** * Creates a FaceDetector, configured with the size of the images to * be analysed and the maximum number of faces that can be detected. * These parameters cannot be changed once the object is constructed. * Note that the width of the image must be even. * * @param width the width of the image * @param height the height of the image * @param maxFaces the maximum number of faces to identify * */ public FaceDetector(int width, int height, int maxFaces) { if (!sInitialized) { return; } fft_initialize(width, height, maxFaces); mWidth = width; mHeight = height; mMaxFaces = maxFaces; mBWBuffer = new byte[width * height]; } /** * Finds all the faces found in a given {@link android.graphics.Bitmap}. * The supplied array is populated with {@link FaceDetector.Face}s for each * face found. The bitmap must be in 565 format (for now). * * @param bitmap the {@link android.graphics.Bitmap} graphic to be analyzed * @param faces an array in which to place all found * {@link FaceDetector.Face}s. The array must be sized equal * to the <var>maxFaces</var> value set at initialization * @return the number of faces found * @throws IllegalArgumentException if the Bitmap dimensions don't match * the dimensions defined at initialization or the given array * is not sized equal to the <var>maxFaces</var> value defined * at initialization */ public int findFaces(Bitmap bitmap, Face[] faces) { if (!sInitialized) { return 0; } if (bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) { throw new IllegalArgumentException("bitmap size doesn't match initialization"); } if (faces.length < mMaxFaces) { throw new IllegalArgumentException("faces[] smaller than maxFaces"); } int numFaces = fft_detect(bitmap); if (numFaces >= mMaxFaces) numFaces = mMaxFaces; for (int i = 0; i < numFaces; i++) { if (faces[i] == null) faces[i] = new Face(); fft_get_face(faces[i], i); } return numFaces; } /* no user serviceable parts here ... */ @Override protected void finalize() throws Throwable { fft_destroy(); } /* * We use a class initializer to allow the native code to cache some * field offsets. */ private static boolean sInitialized; native private static void nativeClassInit(); static { sInitialized = false; try { System.loadLibrary("FFTEm"); nativeClassInit(); sInitialized = true; } catch (UnsatisfiedLinkError e) { Log.d("FFTEm", "face detection library not found!"); } } native private int fft_initialize(int width, int height, int maxFaces); native private int fft_detect(Bitmap bitmap); native private void fft_get_face(Face face, int i); native private void fft_destroy(); private long mFD; private long mSDK; private long mDCR; private int mWidth; private int mHeight; private int mMaxFaces; private byte mBWBuffer[]; }