19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.media; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.PointF; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.IllegalArgumentException; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Identifies the faces of people in a 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.graphics.Bitmap} graphic object. 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class FaceDetector { 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A Face contains all the information identifying the location 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of a face in a bitmap. 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class Face { 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The minimum confidence factor of good face recognition */ 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final float CONFIDENCE_THRESHOLD = 0.4f; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The x-axis Euler angle of a face. */ 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int EULER_X = 0; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The y-axis Euler angle of a face. */ 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int EULER_Y = 1; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The z-axis Euler angle of a face. */ 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int EULER_Z = 2; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns a confidence factor between 0 and 1. This indicates how 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * certain what has been found is actually a face. A confidence 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * factor above 0.3 is usually good enough. 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float confidence() { 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mConfidence; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the position of the mid-point between the eyes. 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param point the PointF coordinates (float values) of the 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * face's mid-point 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void getMidPoint(PointF point) { 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // don't return a PointF to avoid allocations 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project point.set(mMidPointX, mMidPointY); 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the distance between the eyes. 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float eyesDistance() { 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mEyesDist; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the face's pose. That is, the rotations around either 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the X, Y or Z axis (the positions in 3-dimensional Euclidean space). 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param euler the Euler axis to retrieve an angle from 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (<var>EULER_X</var>, <var>EULER_Y</var> or 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <var>EULER_Z</var>) 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the Euler angle of the of the face, for the given axis 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float pose(int euler) { 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // don't use an array to avoid allocations 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (euler == EULER_X) 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPoseEulerX; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (euler == EULER_Y) 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPoseEulerY; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (euler == EULER_Z) 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPoseEulerZ; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException(); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // private ctor, user not supposed to build this object 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Face() { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mConfidence; 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mMidPointX; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mMidPointY; 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mEyesDist; 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mPoseEulerX; 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mPoseEulerY; 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mPoseEulerZ; 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a FaceDetector, configured with the size of the images to 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be analysed and the maximum number of faces that can be detected. 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * These parameters cannot be changed once the object is constructed. 105d6ccc9bcf0bdbca315d0c57c69f26df975eb5264Gloria Wang * Note that the width of the image must be even. 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param width the width of the image 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param height the height of the image 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param maxFaces the maximum number of faces to identify 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public FaceDetector(int width, int height, int maxFaces) 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!sInitialized) { 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fft_initialize(width, height, maxFaces); 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidth = width; 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHeight = height; 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMaxFaces = maxFaces; 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBWBuffer = new byte[width * height]; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Finds all the faces found in a given {@link android.graphics.Bitmap}. 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The supplied array is populated with {@link FaceDetector.Face}s for each 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * face found. The bitmap must be in 565 format (for now). 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param bitmap the {@link android.graphics.Bitmap} graphic to be analyzed 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param faces an array in which to place all found 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link FaceDetector.Face}s. The array must be sized equal 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to the <var>maxFaces</var> value set at initialization 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of faces found 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws IllegalArgumentException if the Bitmap dimensions don't match 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the dimensions defined at initialization or the given array 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is not sized equal to the <var>maxFaces</var> value defined 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * at initialization 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int findFaces(Bitmap bitmap, Face[] faces) 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!sInitialized) { 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) { 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException( 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "bitmap size doesn't match initialization"); 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (faces.length < mMaxFaces) { 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException( 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "faces[] smaller than maxFaces"); 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numFaces = fft_detect(bitmap); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (numFaces >= mMaxFaces) 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFaces = mMaxFaces; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i=0 ; i<numFaces ; i++) { 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (faces[i] == null) 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project faces[i] = new Face(); 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fft_get_face(faces[i], i); 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return numFaces; 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* no user serviceable parts here ... */ 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() throws Throwable { 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fft_destroy(); 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * We use a class initializer to allow the native code to cache some 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * field offsets. 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean sInitialized; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native private static void nativeClassInit(); 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sInitialized = false; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.loadLibrary("FFTEm"); 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nativeClassInit(); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sInitialized = true; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsatisfiedLinkError e) { 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d("FFTEm", "face detection library not found!"); 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native private int fft_initialize(int width, int height, int maxFaces); 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native private int fft_detect(Bitmap bitmap); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native private void fft_get_face(Face face, int i); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native private void fft_destroy(); 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 194075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat private long mFD; 195075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat private long mSDK; 196075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat private long mDCR; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mWidth; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mHeight; 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMaxFaces; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private byte mBWBuffer[]; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 203