FaceDetector.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* 2 * Copyright (C) 2006 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 17package android.media; 18 19import android.graphics.Bitmap; 20import android.graphics.PointF; 21import android.util.Log; 22 23import java.lang.IllegalArgumentException; 24 25/** 26 * Identifies the faces of people in a 27 * {@link android.graphics.Bitmap} graphic object. 28 */ 29public class FaceDetector { 30 31 /** 32 * A Face contains all the information identifying the location 33 * of a face in a bitmap. 34 */ 35 public class Face { 36 /** The minimum confidence factor of good face recognition */ 37 public static final float CONFIDENCE_THRESHOLD = 0.4f; 38 /** The x-axis Euler angle of a face. */ 39 public static final int EULER_X = 0; 40 /** The y-axis Euler angle of a face. */ 41 public static final int EULER_Y = 1; 42 /** The z-axis Euler angle of a face. */ 43 public static final int EULER_Z = 2; 44 45 /** 46 * Returns a confidence factor between 0 and 1. This indicates how 47 * certain what has been found is actually a face. A confidence 48 * factor above 0.3 is usually good enough. 49 */ 50 public float confidence() { 51 return mConfidence; 52 } 53 /** 54 * Sets the position of the mid-point between the eyes. 55 * @param point the PointF coordinates (float values) of the 56 * face's mid-point 57 */ 58 public void getMidPoint(PointF point) { 59 // don't return a PointF to avoid allocations 60 point.set(mMidPointX, mMidPointY); 61 } 62 /** 63 * Returns the distance between the eyes. 64 */ 65 public float eyesDistance() { 66 return mEyesDist; 67 } 68 /** 69 * Returns the face's pose. That is, the rotations around either 70 * the X, Y or Z axis (the positions in 3-dimensional Euclidean space). 71 * 72 * @param euler the Euler axis to retrieve an angle from 73 * (<var>EULER_X</var>, <var>EULER_Y</var> or 74 * <var>EULER_Z</var>) 75 * @return the Euler angle of the of the face, for the given axis 76 */ 77 public float pose(int euler) { 78 // don't use an array to avoid allocations 79 if (euler == EULER_X) 80 return mPoseEulerX; 81 else if (euler == EULER_Y) 82 return mPoseEulerY; 83 else if (euler == EULER_Z) 84 return mPoseEulerZ; 85 throw new IllegalArgumentException(); 86 } 87 88 // private ctor, user not supposed to build this object 89 private Face() { 90 } 91 private float mConfidence; 92 private float mMidPointX; 93 private float mMidPointY; 94 private float mEyesDist; 95 private float mPoseEulerX; 96 private float mPoseEulerY; 97 private float mPoseEulerZ; 98 } 99 100 101 /** 102 * Creates a FaceDetector, configured with the size of the images to 103 * be analysed and the maximum number of faces that can be detected. 104 * These parameters cannot be changed once the object is constructed. 105 * 106 * @param width the width of the image 107 * @param height the height of the image 108 * @param maxFaces the maximum number of faces to identify 109 * 110 */ 111 public FaceDetector(int width, int height, int maxFaces) 112 { 113 if (!sInitialized) { 114 return; 115 } 116 fft_initialize(width, height, maxFaces); 117 mWidth = width; 118 mHeight = height; 119 mMaxFaces = maxFaces; 120 mBWBuffer = new byte[width * height]; 121 } 122 123 /** 124 * Finds all the faces found in a given {@link android.graphics.Bitmap}. 125 * The supplied array is populated with {@link FaceDetector.Face}s for each 126 * face found. The bitmap must be in 565 format (for now). 127 * 128 * @param bitmap the {@link android.graphics.Bitmap} graphic to be analyzed 129 * @param faces an array in which to place all found 130 * {@link FaceDetector.Face}s. The array must be sized equal 131 * to the <var>maxFaces</var> value set at initialization 132 * @return the number of faces found 133 * @throws IllegalArgumentException if the Bitmap dimensions don't match 134 * the dimensions defined at initialization or the given array 135 * is not sized equal to the <var>maxFaces</var> value defined 136 * at initialization 137 */ 138 public int findFaces(Bitmap bitmap, Face[] faces) 139 { 140 if (!sInitialized) { 141 return 0; 142 } 143 if (bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) { 144 throw new IllegalArgumentException( 145 "bitmap size doesn't match initialization"); 146 } 147 if (faces.length < mMaxFaces) { 148 throw new IllegalArgumentException( 149 "faces[] smaller than maxFaces"); 150 } 151 152 int numFaces = fft_detect(bitmap); 153 if (numFaces >= mMaxFaces) 154 numFaces = mMaxFaces; 155 for (int i=0 ; i<numFaces ; i++) { 156 if (faces[i] == null) 157 faces[i] = new Face(); 158 fft_get_face(faces[i], i); 159 } 160 return numFaces; 161 } 162 163 164 /* no user serviceable parts here ... */ 165 @Override 166 protected void finalize() throws Throwable { 167 fft_destroy(); 168 } 169 170 /* 171 * We use a class initializer to allow the native code to cache some 172 * field offsets. 173 */ 174 private static boolean sInitialized; 175 native private static void nativeClassInit(); 176 177 static { 178 sInitialized = false; 179 try { 180 System.loadLibrary("FFTEm"); 181 nativeClassInit(); 182 sInitialized = true; 183 } catch (UnsatisfiedLinkError e) { 184 Log.d("FFTEm", "face detection library not found!"); 185 } 186 } 187 188 native private int fft_initialize(int width, int height, int maxFaces); 189 native private int fft_detect(Bitmap bitmap); 190 native private void fft_get_face(Face face, int i); 191 native private void fft_destroy(); 192 193 private int mFD; 194 private int mSDK; 195 private int mDCR; 196 private int mWidth; 197 private int mHeight; 198 private int mMaxFaces; 199 private byte mBWBuffer[]; 200} 201 202