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