Home | History | Annotate | Download | only in media
      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 
     17 package android.media;
     18 
     19 import android.graphics.Bitmap;
     20 import android.graphics.PointF;
     21 import android.util.Log;
     22 
     23 import java.lang.IllegalArgumentException;
     24 
     25 /**
     26  * Identifies the faces of people in a
     27  * {@link android.graphics.Bitmap} graphic object.
     28  */
     29 public 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      * Note that the width of the image must be even.
    106      *
    107      * @param width  the width of the image
    108      * @param height the height of the image
    109      * @param maxFaces the maximum number of faces to identify
    110      *
    111      */
    112     public FaceDetector(int width, int height, int maxFaces)
    113     {
    114         if (!sInitialized) {
    115             return;
    116         }
    117         fft_initialize(width, height, maxFaces);
    118         mWidth = width;
    119         mHeight = height;
    120         mMaxFaces = maxFaces;
    121         mBWBuffer = new byte[width * height];
    122     }
    123 
    124     /**
    125      * Finds all the faces found in a given {@link android.graphics.Bitmap}.
    126      * The supplied array is populated with {@link FaceDetector.Face}s for each
    127      * face found. The bitmap must be in 565 format (for now).
    128      *
    129      * @param bitmap the {@link android.graphics.Bitmap} graphic to be analyzed
    130      * @param faces  an array in which to place all found
    131      *               {@link FaceDetector.Face}s. The array must be sized equal
    132      *               to the <var>maxFaces</var> value set at initialization
    133      * @return the number of faces found
    134      * @throws IllegalArgumentException if the Bitmap dimensions don't match
    135      *               the dimensions defined at initialization or the given array
    136      *               is not sized equal to the <var>maxFaces</var> value defined
    137      *               at initialization
    138      */
    139     public int findFaces(Bitmap bitmap, Face[] faces)
    140     {
    141         if (!sInitialized) {
    142             return 0;
    143         }
    144         if (bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) {
    145             throw new IllegalArgumentException(
    146                     "bitmap size doesn't match initialization");
    147         }
    148         if (faces.length < mMaxFaces) {
    149             throw new IllegalArgumentException(
    150                     "faces[] smaller than maxFaces");
    151         }
    152 
    153         int numFaces = fft_detect(bitmap);
    154         if (numFaces >= mMaxFaces)
    155             numFaces = mMaxFaces;
    156         for (int i=0 ; i<numFaces ; i++) {
    157             if (faces[i] == null)
    158                 faces[i] = new Face();
    159             fft_get_face(faces[i], i);
    160         }
    161         return numFaces;
    162     }
    163 
    164 
    165     /* no user serviceable parts here ... */
    166     @Override
    167     protected void finalize() throws Throwable {
    168         fft_destroy();
    169     }
    170 
    171     /*
    172      * We use a class initializer to allow the native code to cache some
    173      * field offsets.
    174      */
    175     private static boolean sInitialized;
    176     native private static void nativeClassInit();
    177 
    178     static {
    179         sInitialized = false;
    180         try {
    181             System.loadLibrary("FFTEm");
    182             nativeClassInit();
    183             sInitialized = true;
    184         } catch (UnsatisfiedLinkError e) {
    185             Log.d("FFTEm", "face detection library not found!");
    186         }
    187     }
    188 
    189     native private int  fft_initialize(int width, int height, int maxFaces);
    190     native private int  fft_detect(Bitmap bitmap);
    191     native private void fft_get_face(Face face, int i);
    192     native private void fft_destroy();
    193 
    194     private long    mFD;
    195     private long    mSDK;
    196     private long    mDCR;
    197     private int     mWidth;
    198     private int     mHeight;
    199     private int     mMaxFaces;
    200     private byte    mBWBuffer[];
    201 }
    202 
    203