Face Detection Using Face API In Android App - Part Two

Read part one of this article from the following link.

Introduction

Android is one of the most popular operating systems for mobiles. In this article, I will show you how to detect a face with the help of Microsoft Face API.

Requirements

  • Android Studio
  • Little  knowledge of XML and Java
  • Android Emulator (or) Android mobile
  • Stable internet connection

Step 1

Go to activity_main.xml file and click the text botton. This XML file contains the designing code for Android app. In activity_main.xml, copy and paste the below code.

Activity_main.xml code

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"  
  3.     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"  
  4.     android:paddingRight="@dimen/activity_horizontal_margin"  
  5.     android:paddingTop="@dimen/activity_vertical_margin"  
  6.     android:paddingBottom="@dimen/activity_vertical_margin"  
  7.     android:orientation="vertical"  
  8.     tools:context=".ui.MainActivity">  
  9.     <LinearLayout  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="0dp"  
  12.         android:layout_weight="1"  
  13.         android:orientation="horizontal"  
  14.         android:layout_marginBottom="@dimen/view_margin" >  
  15.   
  16.         <ScrollView  
  17.             android:layout_width="0dp"  
  18.             android:layout_weight="1"  
  19.             android:layout_height="match_parent" >  
  20.   
  21.             <TextView  
  22.                 android:layout_width="match_parent"  
  23.                 android:layout_height="wrap_content"  
  24.                 android:layout_gravity="center_vertical"  
  25.                 android:gravity="center_vertical"  
  26.                 android:text="@string/detection_description" />  
  27.   
  28.         </ScrollView>  
  29.   
  30.         <Button  
  31.             android:layout_width="0dp"  
  32.             android:layout_height="wrap_content"  
  33.             android:layout_gravity="center"  
  34.             android:text="@string/detection"  
  35.             android:layout_weight="1"  
  36.             android:layout_marginLeft="@dimen/view_margin"  
  37.             android:layout_marginStart="@dimen/view_margin"  
  38.             android:onClick="detection"  
  39.             style="@style/ButtonStyle" />  
  40.   
  41.     </LinearLayout>  
  42.   
  43.   
  44. </LinearLayout>  

Android

Step 2

Create a new activity_detection.xml file (File ⇒ New ⇒Activity⇒Empty_activity).

Go to activity_detection.xml, and click the text botton. This XML file contains the designing code for Android app. In activity_detection.xml, copy and paste the below code.

activity_detection.xml code

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"  
  3.     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"  
  4.     android:paddingRight="@dimen/activity_horizontal_margin"  
  5.     android:paddingTop="@dimen/activity_vertical_margin"  
  6.     android:paddingBottom="@dimen/activity_vertical_margin"  
  7.     tools:context="ganeshannt.faceapi.ui.DetectionActivity">  
  8.   
  9.     <LinearLayout  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="match_parent"  
  12.         android:layout_alignParentTop="true"  
  13.   
  14.         android:layout_marginBottom="@dimen/view_margin"  
  15.         android:baselineAligned="false"  
  16.         android:orientation="vertical" >  
  17.   
  18.         <RelativeLayout  
  19.             android:layout_width="match_parent"  
  20.             android:layout_height="0dp"  
  21.             android:layout_weight="1"  
  22.             android:layout_marginBottom="@dimen/view_margin">  
  23.   
  24.             <RelativeLayout  
  25.                 android:id="@+id/image_control"  
  26.                 android:layout_width="100dp"  
  27.                 android:layout_height="match_parent"  
  28.                 android:layout_marginRight="@dimen/view_margin"  
  29.                 android:layout_marginEnd="@dimen/view_margin" >  
  30.   
  31.                 <TextView  
  32.                     android:layout_width="wrap_content"  
  33.                     android:layout_height="wrap_content"  
  34.                     android:layout_alignParentTop="true"  
  35.                     android:layout_alignParentLeft="true"  
  36.                     android:layout_alignParentStart="true"  
  37.                     android:text="@string/image" />  
  38.   
  39.                 <Button  
  40.                     android:id="@+id/select_image"  
  41.                     android:layout_width="match_parent"  
  42.                     android:layout_height="wrap_content"  
  43.                     android:layout_centerVertical="true"  
  44.                     android:layout_alignParentLeft="true"  
  45.                     android:layout_alignParentStart="true"  
  46.                     android:text="@string/select_image"  
  47.                     android:onClick="selectImage"  
  48.                     style="@style/ButtonStyle" />  
  49.   
  50.             </RelativeLayout>  
  51.   
  52.             <ImageView  
  53.                 android:id="@id/image"  
  54.                 android:layout_width="match_parent"  
  55.                 android:layout_height="match_parent"  
  56.                 android:layout_toRightOf="@id/image_control"  
  57.                 android:layout_toEndOf="@id/image_control"  
  58.                 android:background="#E0E0E0"  
  59.                 android:contentDescription="@string/detection" />  
  60.   
  61.         </RelativeLayout>  
  62.   
  63.         <TextView  
  64.             android:layout_width="wrap_content"  
  65.             android:layout_height="wrap_content"  
  66.             android:text="@string/result" />  
  67.   
  68.         <ListView  
  69.             android:id="@+id/list_detected_faces"  
  70.             android:layout_width="match_parent"  
  71.             android:layout_height="0dp"  
  72.             android:layout_weight="1"  
  73.             android:background="#E0E0E0"  
  74.             android:verticalSpacing="@dimen/view_margin" />  
  75.   
  76.     </LinearLayout>  
  77.   
  78.     <TextView  
  79.         android:id="@+id/info"  
  80.         android:layout_width="wrap_content"  
  81.         android:layout_height="wrap_content"  
  82.         android:layout_centerHorizontal="true"  
  83.         android:layout_above="@+id/button_bar"  
  84.         android:layout_gravity="center" />  
  85.   
  86.     <LinearLayout  
  87.         android:id="@+id/button_bar"  
  88.         android:layout_width="match_parent"  
  89.         android:layout_height="wrap_content"  
  90.         android:layout_alignParentBottom="true"  
  91.         android:orientation="horizontal" >  
  92.   
  93.         <Button  
  94.             android:id="@+id/detect"  
  95.             android:layout_width="0dp"  
  96.             android:layout_height="match_parent"  
  97.             android:layout_weight="1"  
  98.             android:layout_marginRight="@dimen/view_margin"  
  99.             android:layout_marginEnd="@dimen/view_margin"  
  100.             android:text="@string/detect"  
  101.             android:onClick="detect"  
  102.             style="@style/ButtonStyle" />  
  103.   
  104.         <Button  
  105.             android:id="@+id/view_log"  
  106.             android:layout_width="0dp"  
  107.             android:layout_height="match_parent"  
  108.             android:layout_weight="1"  
  109.             android:text="@string/view_log"  
  110.             android:background="@drawable/button_background"  
  111.             android:onClick="viewLog"  
  112.             style="@style/ButtonStyle" />  
  113.   
  114.     </LinearLayout>  
  115.   
  116. </RelativeLayout>  

Android

Step 3

Create new activity_select_image.xml file (File ⇒ New ⇒Activity⇒Empty_activity).

Go to activity_select_image.xml and click the text bottom. In activity_select_image.xml, copy and paste the below code.

activity_select_image.xml code

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  6.     android:paddingRight="@dimen/activity_horizontal_margin"  
  7.     android:paddingTop="@dimen/activity_vertical_margin"  
  8.     android:paddingBottom="@dimen/activity_vertical_margin"  
  9.     android:baselineAligned="false"  
  10.     android:orientation="vertical"  
  11.     tools:context="ganeshannt.faceapi.ui.SelectImageActivity">  
  12.   
  13.     <RelativeLayout android:layout_width="match_parent"  
  14.         android:layout_height="match_parent"  
  15.         android:layout_weight="2">  
  16.   
  17.         <Button  
  18.             android:id="@+id/button_take_a_photo"  
  19.             android:layout_width="match_parent"  
  20.             android:layout_height="wrap_content"  
  21.             android:text="@string/take_photo"  
  22.             android:layout_centerHorizontal="true"  
  23.             android:layout_alignParentBottom="true"  
  24.             android:onClick="takePhoto"  
  25.             style="@style/ButtonStyle" />  
  26.   
  27.         <TextView  
  28.             android:id="@id/info"  
  29.             android:layout_width="wrap_content"  
  30.             android:layout_height="wrap_content"  
  31.             android:layout_centerHorizontal="true"  
  32.             android:layout_above="@id/button_take_a_photo"  
  33.             android:layout_gravity="center" />  
  34.   
  35.     </RelativeLayout>  
  36.   
  37.     <RelativeLayout android:layout_width="match_parent"  
  38.         android:layout_height="match_parent"  
  39.         android:layout_weight="1">  
  40.   
  41.         <Button  
  42.             android:id="@+id/button_select_a_photo_in_album"  
  43.             android:layout_width="match_parent"  
  44.             android:layout_height="wrap_content"  
  45.             android:text="@string/select_image_in_album"  
  46.             android:layout_centerHorizontal="true"  
  47.             android:layout_centerVertical="true"  
  48.             android:onClick="selectImageInAlbum"  
  49.             style="@style/ButtonStyle" />  
  50.     </RelativeLayout>  
  51.   
  52. </LinearLayout>  

Android

Step 4

Create new item_face_with_description.xml file (File ⇒ New ⇒Activity⇒Empty_activity).

Go to item_face_with_description.xml, then click the text bottom. In item_face_with_description.xml, copy and paste the below code.

item_face_with_description.xml code

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:orientation="horizontal"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="wrap_content">  
  5.   
  6.     <ImageView  
  7.         android:id="@+id/face_thumbnail"  
  8.         android:layout_width="80dp"  
  9.         android:layout_height="80dp" />  
  10.   
  11.     <TextView  
  12.         android:layout_width="wrap_content"  
  13.         android:layout_height="wrap_content"  
  14.         android:layout_gravity="center_vertical"  
  15.         android:layout_marginLeft="@dimen/view_margin"  
  16.         android:layout_marginStart="@dimen/view_margin"  
  17.         android:id="@+id/text_detected_face" />  
  18.   
  19. </LinearLayout>  
Step 5

In MainActivity.java file, copy and paste the below code. Do not replace your package name otherwise the app will not run.

MainActivity.java code
  1. package ganeshannt.faceapi.ui;  
  2.   
  3. import android.app.AlertDialog;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.support.v7.app.AppCompatActivity;  
  7. import android.view.View;  
  8.   
  9. import ganeshannt.faceapi.R;  
  10.   
  11. public class MainActivity extends AppCompatActivity {  
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.   
  17.         if (getString(R.string.subscription_key).startsWith("Please")) {  
  18.             new AlertDialog.Builder(this)  
  19.                     .setTitle(getString(R.string.add_subscription_key_tip_title))  
  20.                     .setMessage(getString(R.string.add_subscription_key_tip))  
  21.                     .setCancelable(false)  
  22.                     .show();  
  23.         }  
  24.     }  
  25.   
  26.     public void detection(View view) {  
  27.         Intent intent = new Intent(this, DetectionActivity.class);  
  28.         startActivity(intent);  
  29.     }  
  30.   
  31. }  
Step 6

Create three (name : helper , log , ui) Android package folders (java->>new->>folder->>package folder).

Step 7

In helper folder, create file (class name: embeddedgridview,Imagehelper,storagehelper ) (File ⇒ New ⇒Java class).

In EmbeddedGridView.java, copy and paste the below code. Do not replace your package name otherwise app will not run.

EmbeddedGridView.java code

  1. package ganeshannt.faceapi.helper;  
  2.   
  3. import android.content.Context;  
  4. import android.util.AttributeSet;  
  5. import android.widget.GridView;  
  6.   
  7. public class EmbeddedGridView extends GridView {  
  8.     public EmbeddedGridView(Context context, AttributeSet attrs) {  
  9.         super(context, attrs);  
  10.     }  
  11.   
  12.     @Override  
  13.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  14.         int newHeightMeasureSpec =  
  15.                 MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST);  
  16.   
  17.         super.onMeasure(widthMeasureSpec, newHeightMeasureSpec);  
  18.         getLayoutParams().height = getMeasuredHeight();  
  19.     }  
  20. }  
ImageHelper.java code

It is used to pick the image from photos album.
  1. package ganeshannt.faceapi.helper;  
  2.   
  3. import android.content.ContentResolver;  
  4. import android.database.Cursor;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.BitmapFactory;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.Color;  
  9. import android.graphics.Matrix;  
  10. import android.graphics.Paint;  
  11. import android.graphics.Rect;  
  12. import android.media.ExifInterface;  
  13. import android.net.Uri;  
  14. import android.provider.MediaStore;  
  15.   
  16. import com.microsoft.projectoxford.face.contract.Face;  
  17.   
  18.   
  19.   
  20. import com.microsoft.projectoxford.face.contract.FaceRectangle;  
  21.   
  22. import java.io.IOException;  
  23. import java.io.InputStream;  
  24.   
  25. /** 
  26.  * Defined several functions to load, draw, save, resize, and rotate images. 
  27.  */  
  28. public class ImageHelper {  
  29.   
  30.     // The maximum side length of the image to detect, to keep the size of image less than 4MB.  
  31.     // Resize the image if its side length is larger than the maximum.  
  32.     private static final int IMAGE_MAX_SIDE_LENGTH = 1280;  
  33.   
  34.     // Ratio to scale a detected face rectangle, the face rectangle scaled up looks more natural.  
  35.     private static final double FACE_RECT_SCALE_RATIO = 1.3;  
  36.   
  37.     // Decode image from imageUri, and resize according to the expectedMaxImageSideLength  
  38.     // If expectedMaxImageSideLength is  
  39.     //     (1) less than or equal to 0,  
  40.     //     (2) more than the actual max size length of the bitmap  
  41.     //     then return the original bitmap  
  42.     // Else, return the scaled bitmap  
  43.     public static Bitmap loadSizeLimitedBitmapFromUri(  
  44.             Uri imageUri,  
  45.             ContentResolver contentResolver) {  
  46.         try {  
  47.             // Load the image into InputStream.  
  48.             InputStream imageInputStream = contentResolver.openInputStream(imageUri);  
  49.   
  50.             // For saving memory, only decode the image meta and get the side length.  
  51.             BitmapFactory.Options options = new BitmapFactory.Options();  
  52.             options.inJustDecodeBounds = true;  
  53.             Rect outPadding = new Rect();  
  54.             BitmapFactory.decodeStream(imageInputStream, outPadding, options);  
  55.   
  56.             // Calculate shrink rate when loading the image into memory.  
  57.             int maxSideLength =  
  58.                     options.outWidth > options.outHeight ? options.outWidth: options.outHeight;  
  59.             options.inSampleSize = 1;  
  60.             options.inSampleSize = calculateSampleSize(maxSideLength, IMAGE_MAX_SIDE_LENGTH);  
  61.             options.inJustDecodeBounds = false;  
  62.             if (imageInputStream != null) {  
  63.                 imageInputStream.close();  
  64.             }  
  65.   
  66.             // Load the bitmap and resize it to the expected size length  
  67.             imageInputStream = contentResolver.openInputStream(imageUri);  
  68.             Bitmap bitmap = BitmapFactory.decodeStream(imageInputStream, outPadding, options);  
  69.             maxSideLength = bitmap.getWidth() > bitmap.getHeight()  
  70.                     ? bitmap.getWidth(): bitmap.getHeight();  
  71.             double ratio = IMAGE_MAX_SIDE_LENGTH / (double) maxSideLength;  
  72.             if (ratio < 1) {  
  73.                 bitmap = Bitmap.createScaledBitmap(  
  74.                         bitmap,  
  75.                         (int)(bitmap.getWidth() * ratio),  
  76.                         (int)(bitmap.getHeight() * ratio),  
  77.                         false);  
  78.             }  
  79.   
  80.             return rotateBitmap(bitmap, getImageRotationAngle(imageUri, contentResolver));  
  81.         } catch (Exception e) {  
  82.             return null;  
  83.         }  
  84.     }  
  85.   
  86.     // Draw detected face rectangles in the original image. And return the image drawn.  
  87.     // If drawLandmarks is set to be true, draw the five main landmarks of each face.  
  88.     public static Bitmap drawFaceRectanglesOnBitmap(  
  89.             Bitmap originalBitmap, Face[] faces, boolean drawLandmarks) {  
  90.         Bitmap bitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);  
  91.         Canvas canvas = new Canvas(bitmap);  
  92.   
  93.         Paint paint = new Paint();  
  94.         paint.setAntiAlias(true);  
  95.         paint.setStyle(Paint.Style.STROKE);  
  96.         paint.setColor(Color.GREEN);  
  97.         int stokeWidth = Math.max(originalBitmap.getWidth(), originalBitmap.getHeight()) / 100;  
  98.         if (stokeWidth == 0) {  
  99.             stokeWidth = 1;  
  100.         }  
  101.         paint.setStrokeWidth(stokeWidth);  
  102.   
  103.         if (faces != null) {  
  104.             for (Face face : faces) {  
  105.                 FaceRectangle faceRectangle =  
  106.                         calculateFaceRectangle(bitmap, face.faceRectangle, FACE_RECT_SCALE_RATIO);  
  107.   
  108.                 canvas.drawRect(  
  109.                         faceRectangle.left,  
  110.                         faceRectangle.top,  
  111.                         faceRectangle.left + faceRectangle.width,  
  112.                         faceRectangle.top + faceRectangle.height,  
  113.                         paint);  
  114.   
  115.                 if (drawLandmarks) {  
  116.                     int radius = face.faceRectangle.width / 30;  
  117.                     if (radius == 0) {  
  118.                         radius = 1;  
  119.                     }  
  120.                     paint.setStyle(Paint.Style.FILL);  
  121.                     paint.setStrokeWidth(radius);  
  122.   
  123.                     canvas.drawCircle(  
  124.                             (float) face.faceLandmarks.pupilLeft.x,  
  125.                             (float) face.faceLandmarks.pupilLeft.y,  
  126.                             radius,  
  127.                             paint);  
  128.   
  129.                     canvas.drawCircle(  
  130.                             (float) face.faceLandmarks.pupilRight.x,  
  131.                             (float) face.faceLandmarks.pupilRight.y,  
  132.                             radius,  
  133.                             paint);  
  134.   
  135.                     canvas.drawCircle(  
  136.                             (float) face.faceLandmarks.noseTip.x,  
  137.                             (float) face.faceLandmarks.noseTip.y,  
  138.                             radius,  
  139.                             paint);  
  140.   
  141.                     canvas.drawCircle(  
  142.                             (float) face.faceLandmarks.mouthLeft.x,  
  143.                             (float) face.faceLandmarks.mouthLeft.y,  
  144.                             radius,  
  145.                             paint);  
  146.   
  147.                     canvas.drawCircle(  
  148.                             (float) face.faceLandmarks.mouthRight.x,  
  149.                             (float) face.faceLandmarks.mouthRight.y,  
  150.                             radius,  
  151.                             paint);  
  152.   
  153.                     paint.setStyle(Paint.Style.STROKE);  
  154.                     paint.setStrokeWidth(stokeWidth);  
  155.                 }  
  156.             }  
  157.         }  
  158.   
  159.         return bitmap;  
  160.     }  
  161.   
  162.     // Highlight the selected face thumbnail in face list.  
  163.     public static Bitmap highlightSelectedFaceThumbnail(Bitmap originalBitmap) {  
  164.         Bitmap bitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);  
  165.         Canvas canvas = new Canvas(bitmap);  
  166.         Paint paint = new Paint();  
  167.         paint.setAntiAlias(true);  
  168.         paint.setStyle(Paint.Style.STROKE);  
  169.         paint.setColor(Color.parseColor("#3399FF"));  
  170.         int stokeWidth = Math.max(originalBitmap.getWidth(), originalBitmap.getHeight()) / 10;  
  171.         if (stokeWidth == 0) {  
  172.             stokeWidth = 1;  
  173.         }  
  174.         bitmap.getWidth();  
  175.         paint.setStrokeWidth(stokeWidth);  
  176.         canvas.drawRect(  
  177.                 0,  
  178.                 0,  
  179.                 bitmap.getWidth(),  
  180.                 bitmap.getHeight(),  
  181.                 paint);  
  182.   
  183.         return bitmap;  
  184.     }  
  185.   
  186.     // Crop the face thumbnail out from the original image.  
  187.     // For better view for human, face rectangles are resized to the rate faceRectEnlargeRatio.  
  188.     public static Bitmap generateFaceThumbnail(  
  189.             Bitmap originalBitmap,  
  190.             FaceRectangle faceRectangle) throws IOException {  
  191.         FaceRectangle faceRect =  
  192.                 calculateFaceRectangle(originalBitmap, faceRectangle, FACE_RECT_SCALE_RATIO);  
  193.   
  194.         return Bitmap.createBitmap(  
  195.                 originalBitmap, faceRect.left, faceRect.top, faceRect.width, faceRect.height);  
  196.     }  
  197.   
  198.     // Return the number of times for the image to shrink when loading it into memory.  
  199.     // The SampleSize can only be a final value based on powers of 2.  
  200.     private static int calculateSampleSize(int maxSideLength, int expectedMaxImageSideLength) {  
  201.         int inSampleSize = 1;  
  202.   
  203.         while (maxSideLength > 2 * expectedMaxImageSideLength) {  
  204.             maxSideLength /= 2;  
  205.             inSampleSize *= 2;  
  206.         }  
  207.   
  208.         return inSampleSize;  
  209.     }  
  210.   
  211.     // Get the rotation angle of the image taken.  
  212.     private static int getImageRotationAngle(  
  213.             Uri imageUri, ContentResolver contentResolver) throws IOException {  
  214.         int angle = 0;  
  215.         Cursor cursor = contentResolver.query(imageUri,  
  216.                 new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, nullnullnull);  
  217.         if (cursor != null) {  
  218.             if (cursor.getCount() == 1) {  
  219.                 cursor.moveToFirst();  
  220.                 angle = cursor.getInt(0);  
  221.             }  
  222.             cursor.close();  
  223.         } else {  
  224.             ExifInterface exif = new ExifInterface(imageUri.getPath());  
  225.             int orientation = exif.getAttributeInt(  
  226.                     ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);  
  227.   
  228.             switch (orientation) {  
  229.                 case ExifInterface.ORIENTATION_ROTATE_270:  
  230.                     angle = 270;  
  231.                     break;  
  232.                 case ExifInterface.ORIENTATION_ROTATE_180:  
  233.                     angle = 180;  
  234.                     break;  
  235.                 case ExifInterface.ORIENTATION_ROTATE_90:  
  236.                     angle = 90;  
  237.                     break;  
  238.                 default:  
  239.                     break;  
  240.             }  
  241.         }  
  242.         return angle;  
  243.     }  
  244.   
  245.     // Rotate the original bitmap according to the given orientation angle  
  246.     private static Bitmap rotateBitmap(Bitmap bitmap, int angle) {  
  247.         // If the rotate angle is 0, then return the original image, else return the rotated image  
  248.         if (angle != 0) {  
  249.             Matrix matrix = new Matrix();  
  250.             matrix.postRotate(angle);  
  251.             return Bitmap.createBitmap(  
  252.                     bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);  
  253.         } else {  
  254.             return bitmap;  
  255.         }  
  256.     }  
  257.   
  258.     // Resize face rectangle, for better view for human  
  259.     // To make the rectangle larger, faceRectEnlargeRatio should be larger than 1, recommend 1.3  
  260.     private static FaceRectangle calculateFaceRectangle(  
  261.             Bitmap bitmap, FaceRectangle faceRectangle, double faceRectEnlargeRatio) {  
  262.         // Get the resized side length of the face rectangle  
  263.         double sideLength = faceRectangle.width * faceRectEnlargeRatio;  
  264.         sideLength = Math.min(sideLength, bitmap.getWidth());  
  265.         sideLength = Math.min(sideLength, bitmap.getHeight());  
  266.   
  267.         // Make the left edge to left more.  
  268.         double left = faceRectangle.left  
  269.                 - faceRectangle.width * (faceRectEnlargeRatio - 1.0) * 0.5;  
  270.         left = Math.max(left, 0.0);  
  271.         left = Math.min(left, bitmap.getWidth() - sideLength);  
  272.   
  273.         // Make the top edge to top more.  
  274.         double top = faceRectangle.top  
  275.                 - faceRectangle.height * (faceRectEnlargeRatio - 1.0) * 0.5;  
  276.         top = Math.max(top, 0.0);  
  277.         top = Math.min(top, bitmap.getHeight() - sideLength);  
  278.   
  279.         // Shift the top edge to top more, for better view for human  
  280.         double shiftTop = faceRectEnlargeRatio - 1.0;  
  281.         shiftTop = Math.max(shiftTop, 0.0);  
  282.         shiftTop = Math.min(shiftTop, 1.0);  
  283.         top -= 0.15 * shiftTop * faceRectangle.height;  
  284.         top = Math.max(top, 0.0);  
  285.   
  286.         // Set the result.  
  287.         FaceRectangle result = new FaceRectangle();  
  288.         result.left = (int)left;  
  289.         result.top = (int)top;  
  290.         result.width = (int)sideLength;  
  291.         result.height = (int)sideLength;  
  292.         return result;  
  293.     }  
  294. }  
StorageHelper.java code

It is used to allocate the storage space for face detecting images.
  1. package ganeshannt.faceapi.helper;  
  2.   
  3. import android.content.Context;  
  4. import android.content.SharedPreferences;  
  5.   
  6. import java.util.HashSet;  
  7. import java.util.List;  
  8. import java.util.Set;  
  9.   
  10. /** 
  11.  * Defined several functions to manage local storage. 
  12.  */  
  13. public class StorageHelper {  
  14.     public static Set<String> getAllPersonGroupIds(Context context) {  
  15.         SharedPreferences personGroupIdSet =  
  16.                 context.getSharedPreferences("PersonGroupIdSet", Context.MODE_PRIVATE);  
  17.         return personGroupIdSet.getStringSet("PersonGroupIdSet"new HashSet<String>());  
  18.     }  
  19.   
  20.     public static String getPersonGroupName(String personGroupId, Context context) {  
  21.         SharedPreferences personGroupIdNameMap =  
  22.                 context.getSharedPreferences("PersonGroupIdNameMap", Context.MODE_PRIVATE);  
  23.         return personGroupIdNameMap.getString(personGroupId, "");  
  24.     }  
  25.   
  26.     public static void setPersonGroupName(String personGroupIdToAdd, String personGroupName, Context context) {  
  27.         SharedPreferences personGroupIdNameMap =  
  28.                 context.getSharedPreferences("PersonGroupIdNameMap", Context.MODE_PRIVATE);  
  29.   
  30.         SharedPreferences.Editor personGroupIdNameMapEditor = personGroupIdNameMap.edit();  
  31.         personGroupIdNameMapEditor.putString(personGroupIdToAdd, personGroupName);  
  32.         personGroupIdNameMapEditor.commit();  
  33.   
  34.         Set<String> personGroupIds = getAllPersonGroupIds(context);  
  35.         Set<String> newPersonGroupIds = new HashSet<>();  
  36.         for (String personGroupId: personGroupIds) {  
  37.             newPersonGroupIds.add(personGroupId);  
  38.         }  
  39.         newPersonGroupIds.add(personGroupIdToAdd);  
  40.         SharedPreferences personGroupIdSet =  
  41.                 context.getSharedPreferences("PersonGroupIdSet", Context.MODE_PRIVATE);  
  42.         SharedPreferences.Editor personGroupIdSetEditor = personGroupIdSet.edit();  
  43.         personGroupIdSetEditor.putStringSet("PersonGroupIdSet", newPersonGroupIds);  
  44.         personGroupIdSetEditor.commit();  
  45.     }  
  46.   
  47.     public static void deletePersonGroups(List<String> personGroupIdsToDelete, Context context) {  
  48.         SharedPreferences personGroupIdNameMap =  
  49.                 context.getSharedPreferences("PersonGroupIdNameMap", Context.MODE_PRIVATE);  
  50.         SharedPreferences.Editor personGroupIdNameMapEditor = personGroupIdNameMap.edit();  
  51.         for (String personGroupId: personGroupIdsToDelete) {  
  52.             personGroupIdNameMapEditor.remove(personGroupId);  
  53.         }  
  54.         personGroupIdNameMapEditor.commit();  
  55.   
  56.         Set<String> personGroupIds = getAllPersonGroupIds(context);  
  57.         Set<String> newPersonGroupIds = new HashSet<>();  
  58.         for (String personGroupId: personGroupIds) {  
  59.             if (!personGroupIdsToDelete.contains(personGroupId)) {  
  60.                 newPersonGroupIds.add(personGroupId);  
  61.             }  
  62.         }  
  63.         SharedPreferences personGroupIdSet =  
  64.                 context.getSharedPreferences("PersonGroupIdSet", Context.MODE_PRIVATE);  
  65.         SharedPreferences.Editor personGroupIdSetEditor = personGroupIdSet.edit();  
  66.         personGroupIdSetEditor.putStringSet("PersonGroupIdSet", newPersonGroupIds);  
  67.         personGroupIdSetEditor.commit();  
  68.     }  
  69.   
  70.     public static Set<String> getAllPersonIds(String personGroupId, Context context) {  
  71.         SharedPreferences personIdSet =  
  72.                 context.getSharedPreferences(personGroupId + "PersonIdSet", Context.MODE_PRIVATE);  
  73.         return personIdSet.getStringSet("PersonIdSet"new HashSet<String>());  
  74.     }  
  75.   
  76.     public static String getPersonName(String personId, String personGroupId, Context context) {  
  77.         SharedPreferences personIdNameMap =  
  78.                 context.getSharedPreferences(personGroupId + "PersonIdNameMap", Context.MODE_PRIVATE);  
  79.         return personIdNameMap.getString(personId, "");  
  80.     }  
  81.   
  82.     public static void setPersonName(String personIdToAdd, String personName, String personGroupId, Context context) {  
  83.         SharedPreferences personIdNameMap =  
  84.                 context.getSharedPreferences(personGroupId + "PersonIdNameMap", Context.MODE_PRIVATE);  
  85.   
  86.         SharedPreferences.Editor personIdNameMapEditor = personIdNameMap.edit();  
  87.         personIdNameMapEditor.putString(personIdToAdd, personName);  
  88.         personIdNameMapEditor.commit();  
  89.   
  90.         Set<String> personIds = getAllPersonIds(personGroupId, context);  
  91.         Set<String> newPersonIds = new HashSet<>();  
  92.         for (String personId: personIds) {  
  93.             newPersonIds.add(personId);  
  94.         }  
  95.         newPersonIds.add(personIdToAdd);  
  96.         SharedPreferences personIdSet =  
  97.                 context.getSharedPreferences(personGroupId + "PersonIdSet", Context.MODE_PRIVATE);  
  98.         SharedPreferences.Editor personIdSetEditor = personIdSet.edit();  
  99.         personIdSetEditor.putStringSet("PersonIdSet", newPersonIds);  
  100.         personIdSetEditor.commit();  
  101.     }  
  102.   
  103.     public static void deletePersons(List<String> personIdsToDelete, String personGroupId, Context context) {  
  104.         SharedPreferences personIdNameMap =  
  105.                 context.getSharedPreferences(personGroupId + "PersonIdNameMap", Context.MODE_PRIVATE);  
  106.         SharedPreferences.Editor personIdNameMapEditor = personIdNameMap.edit();  
  107.         for (String personId: personIdsToDelete) {  
  108.             personIdNameMapEditor.remove(personId);  
  109.         }  
  110.         personIdNameMapEditor.commit();  
  111.   
  112.         Set<String> personIds = getAllPersonIds(personGroupId, context);  
  113.         Set<String> newPersonIds = new HashSet<>();  
  114.         for (String personId: personIds) {  
  115.             if (!personIdsToDelete.contains(personId)) {  
  116.                 newPersonIds.add(personId);  
  117.             }  
  118.         }  
  119.         SharedPreferences personIdSet =  
  120.                 context.getSharedPreferences(personGroupId + "PersonIdSet", Context.MODE_PRIVATE);  
  121.         SharedPreferences.Editor personIdSetEditor = personIdSet.edit();  
  122.         personIdSetEditor.putStringSet("PersonIdSet", newPersonIds);  
  123.         personIdSetEditor.commit();  
  124.     }  
  125.   
  126.     public static Set<String> getAllFaceIds(String personId, Context context) {  
  127.         SharedPreferences faceIdSet =  
  128.                 context.getSharedPreferences(personId + "FaceIdSet", Context.MODE_PRIVATE);  
  129.         return faceIdSet.getStringSet("FaceIdSet"new HashSet<String>());  
  130.     }  
  131.   
  132.     public static String getFaceUri(String faceId, Context context) {  
  133.         SharedPreferences faceIdUriMap =  
  134.                 context.getSharedPreferences("FaceIdUriMap", Context.MODE_PRIVATE);  
  135.         return faceIdUriMap.getString(faceId, "");  
  136.     }  
  137.   
  138.     public static void setFaceUri(String faceIdToAdd, String faceUri, String personId, Context context) {  
  139.         SharedPreferences faceIdUriMap =  
  140.                 context.getSharedPreferences("FaceIdUriMap", Context.MODE_PRIVATE);  
  141.   
  142.         SharedPreferences.Editor faceIdUriMapEditor = faceIdUriMap.edit();  
  143.         faceIdUriMapEditor.putString(faceIdToAdd, faceUri);  
  144.         faceIdUriMapEditor.commit();  
  145.   
  146.         Set<String> faceIds = getAllFaceIds(personId, context);  
  147.         Set<String> newFaceIds = new HashSet<>();  
  148.         for (String faceId: faceIds) {  
  149.             newFaceIds.add(faceId);  
  150.         }  
  151.         newFaceIds.add(faceIdToAdd);  
  152.         SharedPreferences faceIdSet =  
  153.                 context.getSharedPreferences(personId + "FaceIdSet", Context.MODE_PRIVATE);  
  154.         SharedPreferences.Editor faceIdSetEditor = faceIdSet.edit();  
  155.         faceIdSetEditor.putStringSet("FaceIdSet", newFaceIds);  
  156.         faceIdSetEditor.commit();  
  157.     }  
  158.   
  159.     public static void deleteFaces(List<String> faceIdsToDelete, String personId, Context context) {  
  160.         Set<String> faceIds = getAllFaceIds(personId, context);  
  161.         Set<String> newFaceIds = new HashSet<>();  
  162.         for (String faceId: faceIds) {  
  163.             if (!faceIdsToDelete.contains(faceId)) {  
  164.                 newFaceIds.add(faceId);  
  165.             }  
  166.         }  
  167.         SharedPreferences faceIdSet =  
  168.                 context.getSharedPreferences(personId + "FaceIdSet", Context.MODE_PRIVATE);  
  169.         SharedPreferences.Editor faceIdSetEditor = faceIdSet.edit();  
  170.         faceIdSetEditor.putStringSet("FaceIdSet", newFaceIds);  
  171.         faceIdSetEditor.commit();  
  172.     }  
  173. }  
Step 8
 
In log folder, create file(class name:DetectionLogActivity ) (File ⇒ New ⇒Java class).

In DetectionLogActivity.java, copy and paste the below code. Do not replace your package name otherwise the app will not run.

DetectionLogActivity.java code

  1. package ganeshannt.faceapi.log;  
  2.   
  3. import android.content.Context;  
  4. import android.os.Bundle;  
  5. import android.support.v7.app.AppCompatActivity;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9. import android.widget.BaseAdapter;  
  10. import android.widget.ListView;  
  11. import android.widget.TextView;  
  12.   
  13. import ganeshannt.faceapi.R;  
  14. import ganeshannt.faceapi.helper.LogHelper;  
  15.   
  16. import java.util.List;  
  17.   
  18. public class DetectionLogActivity extends AppCompatActivity {  
  19.   
  20.     @Override  
  21.     protected void onCreate(Bundle savedInstanceState) {  
  22.         super.onCreate(savedInstanceState);  
  23.         setContentView(R.layout.activity_detection_log);  
  24.   
  25.         LogAdapter logAdapter = new LogAdapter();  
  26.         ListView listView = (ListView) findViewById(R.id.log);  
  27.         listView.setAdapter(logAdapter);  
  28.     }  
  29.   
  30.     // The adapter of the ListView which contains the detection log.  
  31.     private class LogAdapter extends BaseAdapter {  
  32.         // The detection log.  
  33.         List<String> log;  
  34.   
  35.         LogAdapter() {  
  36.             log = LogHelper.getDetectionLog();  
  37.         }  
  38.   
  39.         @Override  
  40.         public boolean isEnabled(int position) {  
  41.             return false;  
  42.         }  
  43.   
  44.         @Override  
  45.         public int getCount() {  
  46.             return log.size();  
  47.         }  
  48.   
  49.         @Override  
  50.         public Object getItem(int position) {  
  51.             return log.get(position);  
  52.         }  
  53.   
  54.         @Override  
  55.         public long getItemId(int position) {  
  56.             return position;  
  57.         }  
  58.   
  59.         @Override  
  60.         public View getView(final int position, View convertView, ViewGroup parent) {  
  61.             if (convertView == null) {  
  62.                 LayoutInflater layoutInflater =  
  63.                         (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  64.                 convertView = layoutInflater.inflate(R.layout.item_log, parent, false);  
  65.             }  
  66.             convertView.setId(position);  
  67.   
  68.             ((TextView)convertView.findViewById(R.id.log)).setText(log.get(position));  
  69.   
  70.             return convertView;  
  71.         }  
  72.     }  
  73. }  
Step 9

In ui folder, create file (class name:DetectionActivity,Select-Image_Activity,MainActivity ) (File ⇒ New ⇒Java class).

In DetectionActivity.java, copy and paste the below code. Do not replace your package name otherwise the app will not run.

DetectionActivity.java code

  1. package ganeshannt.faceapi.ui;  
  2.   
  3. import android.app.ProgressDialog;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.graphics.Bitmap;  
  7. import android.net.Uri;  
  8. import android.os.AsyncTask;  
  9. import android.os.Bundle;  
  10. import android.support.annotation.NonNull;  
  11. import android.support.v7.app.AppCompatActivity;  
  12. import android.text.TextUtils;  
  13. import android.view.LayoutInflater;  
  14. import android.view.View;  
  15. import android.view.ViewGroup;  
  16. import android.widget.BaseAdapter;  
  17. import android.widget.Button;  
  18. import android.widget.ImageView;  
  19. import android.widget.ListView;  
  20. import android.widget.TextView;  
  21.   
  22. import com.microsoft.projectoxford.face.FaceServiceClient;  
  23. import com.microsoft.projectoxford.face.contract.Accessory;  
  24. import com.microsoft.projectoxford.face.contract.Blur;  
  25. import com.microsoft.projectoxford.face.contract.Emotion;  
  26. import com.microsoft.projectoxford.face.contract.Exposure;  
  27. import com.microsoft.projectoxford.face.contract.Face;  
  28. import com.microsoft.projectoxford.face.contract.FacialHair;  
  29. import com.microsoft.projectoxford.face.contract.Hair;  
  30. import com.microsoft.projectoxford.face.contract.HeadPose;  
  31. import com.microsoft.projectoxford.face.contract.Makeup;  
  32. import com.microsoft.projectoxford.face.contract.Noise;  
  33. import com.microsoft.projectoxford.face.contract.Occlusion;  
  34. import ganeshannt.faceapi.R;  
  35. import ganeshannt.faceapi.helper.ImageHelper;  
  36. import ganeshannt.faceapi.helper.LogHelper;  
  37. import ganeshannt.faceapi.helper.SampleApp;  
  38. import ganeshannt.faceapi.log.DetectionLogActivity;  
  39.   
  40. import java.io.ByteArrayInputStream;  
  41. import java.io.ByteArrayOutputStream;  
  42. import java.io.IOException;  
  43. import java.io.InputStream;  
  44. import java.text.DecimalFormat;  
  45. import java.util.ArrayList;  
  46. import java.util.Arrays;  
  47. import java.util.List;  
  48.   
  49. public class DetectionActivity extends AppCompatActivity {  
  50.     // Background task of face detection.  
  51.     private class DetectionTask extends AsyncTask<InputStream, String, Face[]> {  
  52.         private boolean mSucceed = true;  
  53.   
  54.         @Override  
  55.         protected Face[] doInBackground(InputStream... params) {  
  56.             // Get an instance of face service client to detect faces in image.  
  57.             FaceServiceClient faceServiceClient = SampleApp.getFaceServiceClient();  
  58.             try {  
  59.                 publishProgress("Detecting...");  
  60.   
  61.                 // Start detection.  
  62.                 return faceServiceClient.detect(  
  63.                         params[0],  /* Input stream of image to detect */  
  64.                         true,       /* Whether to return face ID */  
  65.                         true,       /* Whether to return face landmarks */  
  66.                         /* Which face attributes to analyze, currently we support: 
  67.                            age,gender,headPose,smile,facialHair */  
  68.                         new FaceServiceClient.FaceAttributeType[] {  
  69.                                 FaceServiceClient.FaceAttributeType.Age,  
  70.                                 FaceServiceClient.FaceAttributeType.Gender,  
  71.                                 FaceServiceClient.FaceAttributeType.Smile,  
  72.                                 FaceServiceClient.FaceAttributeType.Glasses,  
  73.                                 FaceServiceClient.FaceAttributeType.FacialHair,  
  74.                                 FaceServiceClient.FaceAttributeType.Emotion,  
  75.                                 FaceServiceClient.FaceAttributeType.HeadPose,  
  76.                                 FaceServiceClient.FaceAttributeType.Accessories,  
  77.                                 FaceServiceClient.FaceAttributeType.Blur,  
  78.                                 FaceServiceClient.FaceAttributeType.Exposure,  
  79.                                 FaceServiceClient.FaceAttributeType.Hair,  
  80.                                 FaceServiceClient.FaceAttributeType.Makeup,  
  81.                                 FaceServiceClient.FaceAttributeType.Noise,  
  82.                                 FaceServiceClient.FaceAttributeType.Occlusion  
  83.                         });  
  84.             } catch (Exception e) {  
  85.                 mSucceed = false;  
  86.                 publishProgress(e.getMessage());  
  87.                 addLog(e.getMessage());  
  88.                 return null;  
  89.             }  
  90.         }  
  91.   
  92.         @Override  
  93.         protected void onPreExecute() {  
  94.             mProgressDialog.show();  
  95.             addLog("Request: Detecting in image " + mImageUri);  
  96.         }  
  97.   
  98.         @Override  
  99.         protected void onProgressUpdate(String... progress) {  
  100.             mProgressDialog.setMessage(progress[0]);  
  101.             setInfo(progress[0]);  
  102.         }  
  103.   
  104.         @Override  
  105.         protected void onPostExecute(Face[] result) {  
  106.             if (mSucceed) {  
  107.                 addLog("Response: Success. Detected " + (result == null ? 0 : result.length)  
  108.                         + " face(s) in " + mImageUri);  
  109.             }  
  110.   
  111.             // Show the result on screen when detection is done.  
  112.             setUiAfterDetection(result, mSucceed);  
  113.         }  
  114.     }  
  115.   
  116.     // Flag to indicate which task is to be performed.  
  117.     private static final int REQUEST_SELECT_IMAGE = 0;  
  118.   
  119.     // The URI of the image selected to detect.  
  120.     private Uri mImageUri;  
  121.   
  122.     // The image selected to detect.  
  123.     private Bitmap mBitmap;  
  124.   
  125.     // Progress dialog popped up when communicating with server.  
  126.     ProgressDialog mProgressDialog;  
  127.   
  128.     // When the activity is created, set all the member variables to initial state.  
  129.     @Override  
  130.     protected void onCreate(Bundle savedInstanceState) {  
  131.         super.onCreate(savedInstanceState);  
  132.         setContentView(R.layout.activity_detection);  
  133.   
  134.         mProgressDialog = new ProgressDialog(this);  
  135.         mProgressDialog.setTitle(getString(R.string.progress_dialog_title));  
  136.   
  137.         // Disable button "detect" as the image to detect is not selected.  
  138.         setDetectButtonEnabledStatus(false);  
  139.   
  140.         LogHelper.clearDetectionLog();  
  141.     }  
  142.   
  143.     // Save the activity state when it's going to stop.  
  144.     @Override  
  145.     protected void onSaveInstanceState(Bundle outState) {  
  146.         super.onSaveInstanceState(outState);  
  147.   
  148.         outState.putParcelable("ImageUri", mImageUri);  
  149.     }  
  150.   
  151.     // Recover the saved state when the activity is recreated.  
  152.     @Override  
  153.     protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {  
  154.         super.onRestoreInstanceState(savedInstanceState);  
  155.   
  156.         mImageUri = savedInstanceState.getParcelable("ImageUri");  
  157.         if (mImageUri != null) {  
  158.             mBitmap = ImageHelper.loadSizeLimitedBitmapFromUri(  
  159.                     mImageUri, getContentResolver());  
  160.         }  
  161.     }  
  162.   
  163.     // Called when image selection is done.  
  164.     @Override  
  165.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  166.         switch (requestCode) {  
  167.             case REQUEST_SELECT_IMAGE:  
  168.                 if (resultCode == RESULT_OK) {  
  169.                     // If image is selected successfully, set the image URI and bitmap.  
  170.                     mImageUri = data.getData();  
  171.                     mBitmap = ImageHelper.loadSizeLimitedBitmapFromUri(  
  172.                             mImageUri, getContentResolver());  
  173.                     if (mBitmap != null) {  
  174.                         // Show the image on screen.  
  175.                         ImageView imageView = (ImageView) findViewById(R.id.image);  
  176.                         imageView.setImageBitmap(mBitmap);  
  177.   
  178.                         // Add detection log.  
  179.                         addLog("Image: " + mImageUri + " resized to " + mBitmap.getWidth()  
  180.                                 + "x" + mBitmap.getHeight());  
  181.                     }  
  182.   
  183.                     // Clear the detection result.  
  184.                     FaceListAdapter faceListAdapter = new FaceListAdapter(null);  
  185.                     ListView listView = (ListView) findViewById(R.id.list_detected_faces);  
  186.                     listView.setAdapter(faceListAdapter);  
  187.   
  188.                     // Clear the information panel.  
  189.                     setInfo("");  
  190.   
  191.                     // Enable button "detect" as the image is selected and not detected.  
  192.                     setDetectButtonEnabledStatus(true);  
  193.                 }  
  194.                 break;  
  195.             default:  
  196.                 break;  
  197.         }  
  198.     }  
  199.   
  200.     // Called when the "Select Image" button is clicked.  
  201.     public void selectImage(View view) {  
  202.         Intent intent = new Intent(this, SelectImageActivity.class);  
  203.         startActivityForResult(intent, REQUEST_SELECT_IMAGE);  
  204.     }  
  205.   
  206.     // Called when the "Detect" button is clicked.  
  207.     public void detect(View view) {  
  208.         // Put the image into an input stream for detection.  
  209.         ByteArrayOutputStream output = new ByteArrayOutputStream();  
  210.         mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);  
  211.         ByteArrayInputStream inputStream = new ByteArrayInputStream(output.toByteArray());  
  212.   
  213.         // Start a background task to detect faces in the image.  
  214.         new DetectionTask().execute(inputStream);  
  215.   
  216.         // Prevent button click during detecting.  
  217.         setAllButtonsEnabledStatus(false);  
  218.     }  
  219.   
  220.     // View the log of service calls.  
  221.     public void viewLog(View view) {  
  222.         Intent intent = new Intent(this, DetectionLogActivity.class);  
  223.         startActivity(intent);  
  224.     }  
  225.   
  226.     // Show the result on screen when detection is done.  
  227.     private void setUiAfterDetection(Face[] result, boolean succeed) {  
  228.         // Detection is done, hide the progress dialog.  
  229.         mProgressDialog.dismiss();  
  230.   
  231.         // Enable all the buttons.  
  232.         setAllButtonsEnabledStatus(true);  
  233.   
  234.         // Disable button "detect" as the image has already been detected.  
  235.         setDetectButtonEnabledStatus(false);  
  236.   
  237.         if (succeed) {  
  238.             // The information about the detection result.  
  239.             String detectionResult;  
  240.             if (result != null) {  
  241.                 detectionResult = result.length + " face"  
  242.                         + (result.length != 1 ? "s" : "") + " detected";  
  243.   
  244.                 // Show the detected faces on original image.  
  245.                 ImageView imageView = (ImageView) findViewById(R.id.image);  
  246.                 imageView.setImageBitmap(ImageHelper.drawFaceRectanglesOnBitmap(  
  247.                         mBitmap, result, true));  
  248.   
  249.                 // Set the adapter of the ListView which contains the details of the detected faces.  
  250.                 FaceListAdapter faceListAdapter = new FaceListAdapter(result);  
  251.   
  252.                 // Show the detailed list of detected faces.  
  253.                 ListView listView = (ListView) findViewById(R.id.list_detected_faces);  
  254.                 listView.setAdapter(faceListAdapter);  
  255.             } else {  
  256.                 detectionResult = "0 face detected";  
  257.             }  
  258.             setInfo(detectionResult);  
  259.         }  
  260.   
  261.         mImageUri = null;  
  262.         mBitmap = null;  
  263.     }  
  264.   
  265.     // Set whether the buttons are enabled.  
  266.     private void setDetectButtonEnabledStatus(boolean isEnabled) {  
  267.         Button detectButton = (Button) findViewById(R.id.detect);  
  268.         detectButton.setEnabled(isEnabled);  
  269.     }  
  270.   
  271.     // Set whether the buttons are enabled.  
  272.     private void setAllButtonsEnabledStatus(boolean isEnabled) {  
  273.         Button selectImageButton = (Button) findViewById(R.id.select_image);  
  274.         selectImageButton.setEnabled(isEnabled);  
  275.   
  276.         Button detectButton = (Button) findViewById(R.id.detect);  
  277.         detectButton.setEnabled(isEnabled);  
  278.   
  279.         Button ViewLogButton = (Button) findViewById(R.id.view_log);  
  280.         ViewLogButton.setEnabled(isEnabled);  
  281.     }  
  282.   
  283.     // Set the information panel on screen.  
  284.     private void setInfo(String info) {  
  285.         TextView textView = (TextView) findViewById(R.id.info);  
  286.         textView.setText(info);  
  287.     }  
  288.   
  289.     // Add a log item.  
  290.     private void addLog(String log) {  
  291.         LogHelper.addDetectionLog(log);  
  292.     }  
  293.   
  294.     // The adapter of the GridView which contains the details of the detected faces.  
  295.     private class FaceListAdapter extends BaseAdapter {  
  296.         // The detected faces.  
  297.         List<Face> faces;  
  298.   
  299.         // The thumbnails of detected faces.  
  300.         List<Bitmap> faceThumbnails;  
  301.   
  302.         // Initialize with detection result.  
  303.         FaceListAdapter(Face[] detectionResult) {  
  304.             faces = new ArrayList<>();  
  305.             faceThumbnails = new ArrayList<>();  
  306.   
  307.             if (detectionResult != null) {  
  308.                 faces = Arrays.asList(detectionResult);  
  309.                 for (Face face : faces) {  
  310.                     try {  
  311.                         // Crop face thumbnail with five main landmarks drawn from original image.  
  312.                         faceThumbnails.add(ImageHelper.generateFaceThumbnail(  
  313.                                 mBitmap, face.faceRectangle));  
  314.                     } catch (IOException e) {  
  315.                         // Show the exception when generating face thumbnail fails.  
  316.                         setInfo(e.getMessage());  
  317.                     }  
  318.                 }  
  319.             }  
  320.         }  
  321.   
  322.         @Override  
  323.         public boolean isEnabled(int position) {  
  324.             return false;  
  325.         }  
  326.   
  327.         @Override  
  328.         public int getCount() {  
  329.             return faces.size();  
  330.         }  
  331.   
  332.         @Override  
  333.         public Object getItem(int position) {  
  334.             return faces.get(position);  
  335.         }  
  336.   
  337.         @Override  
  338.         public long getItemId(int position) {  
  339.             return position;  
  340.         }  
  341.   
  342.         @Override  
  343.         public View getView(final int position, View convertView, ViewGroup parent) {  
  344.             if (convertView == null) {  
  345.                 LayoutInflater layoutInflater =  
  346.                         (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  347.                 convertView = layoutInflater.inflate(R.layout.item_face_with_description, parent, false);  
  348.             }  
  349.             convertView.setId(position);  
  350.   
  351.             // Show the face thumbnail.  
  352.             ((ImageView) convertView.findViewById(R.id.face_thumbnail)).setImageBitmap(  
  353.                     faceThumbnails.get(position));  
  354.   
  355.             // Show the face details.  
  356.             DecimalFormat formatter = new DecimalFormat("#0.0");  
  357.             String face_description = String.format("Age: %s  Gender: %s\nHair: %s  FacialHair: %s\nMakeup: %s  %s\nForeheadOccluded: %s  Blur: %s\nEyeOccluded: %s  %s\n" +  
  358.                             "MouthOccluded: %s  Noise: %s\nGlassesType: %s\nHeadPose: %s\nAccessories: %s",  
  359.                     faces.get(position).faceAttributes.age,  
  360.                     faces.get(position).faceAttributes.gender,  
  361.                     getHair(faces.get(position).faceAttributes.hair),  
  362.                     getFacialHair(faces.get(position).faceAttributes.facialHair),  
  363.                     getMakeup((faces.get(position)).faceAttributes.makeup),  
  364.                     getEmotion(faces.get(position).faceAttributes.emotion),  
  365.                     faces.get(position).faceAttributes.occlusion.foreheadOccluded,  
  366.                     faces.get(position).faceAttributes.blur.blurLevel,  
  367.                     faces.get(position).faceAttributes.occlusion.eyeOccluded,  
  368.                     faces.get(position).faceAttributes.exposure.exposureLevel,  
  369.                     faces.get(position).faceAttributes.occlusion.mouthOccluded,  
  370.                     faces.get(position).faceAttributes.noise.noiseLevel,  
  371.                     faces.get(position).faceAttributes.glasses,  
  372.                     getHeadPose(faces.get(position).faceAttributes.headPose),  
  373.                     getAccessories(faces.get(position).faceAttributes.accessories)  
  374.                     );  
  375.             ((TextView) convertView.findViewById(R.id.text_detected_face)).setText(face_description);  
  376.   
  377.             return convertView;  
  378.         }  
  379.   
  380.         private String getHair(Hair hair) {  
  381.             if (hair.hairColor.length == 0)  
  382.             {  
  383.                 if (hair.invisible)  
  384.                     return "Invisible";  
  385.                 else  
  386.                     return "Bald";  
  387.             }  
  388.             else  
  389.             {  
  390.                 int maxConfidenceIndex = 0;  
  391.                 double maxConfidence = 0.0;  
  392.   
  393.                 for (int i = 0; i < hair.hairColor.length; ++i)  
  394.                 {  
  395.                     if (hair.hairColor[i].confidence > maxConfidence)  
  396.                     {  
  397.                         maxConfidence = hair.hairColor[i].confidence;  
  398.                         maxConfidenceIndex = i;  
  399.                     }  
  400.                 }  
  401.   
  402.                 return hair.hairColor[maxConfidenceIndex].color.toString();  
  403.             }  
  404.         }  
  405.   
  406.         private String getMakeup(Makeup makeup) {  
  407.             return  (makeup.eyeMakeup || makeup.lipMakeup) ? "Yes" : "No" ;  
  408.         }  
  409.   
  410.         private String getAccessories(Accessory[] accessories) {  
  411.             if (accessories.length == 0)  
  412.             {  
  413.                 return "NoAccessories";  
  414.             }  
  415.             else  
  416.             {  
  417.                 String[] accessoriesList = new String[accessories.length];  
  418.                 for (int i = 0; i < accessories.length; ++i)  
  419.                 {  
  420.                     accessoriesList[i] = accessories[i].type.toString();  
  421.                 }  
  422.   
  423.                 return TextUtils.join(",", accessoriesList);  
  424.             }  
  425.         }  
  426.   
  427.         private String getFacialHair(FacialHair facialHair) {  
  428.             return (facialHair.moustache + facialHair.beard + facialHair.sideburns > 0) ? "Yes" : "No";  
  429.         }  
  430.   
  431.         private String getEmotion(Emotion emotion)  
  432.         {  
  433.             String emotionType = "";  
  434.             double emotionValue = 0.0;  
  435.             if (emotion.anger > emotionValue)  
  436.             {  
  437.                 emotionValue = emotion.anger;  
  438.                 emotionType = "Anger";  
  439.             }  
  440.             if (emotion.contempt > emotionValue)  
  441.             {  
  442.                 emotionValue = emotion.contempt;  
  443.                 emotionType = "Contempt";  
  444.             }  
  445.             if (emotion.disgust > emotionValue)  
  446.             {  
  447.                 emotionValue = emotion.disgust;  
  448.                 emotionType = "Disgust";  
  449.             }  
  450.             if (emotion.fear > emotionValue)  
  451.             {  
  452.                 emotionValue = emotion.fear;  
  453.                 emotionType = "Fear";  
  454.             }  
  455.             if (emotion.happiness > emotionValue)  
  456.             {  
  457.                 emotionValue = emotion.happiness;  
  458.                 emotionType = "Happiness";  
  459.             }  
  460.             if (emotion.neutral > emotionValue)  
  461.             {  
  462.                 emotionValue = emotion.neutral;  
  463.                 emotionType = "Neutral";  
  464.             }  
  465.             if (emotion.sadness > emotionValue)  
  466.             {  
  467.                 emotionValue = emotion.sadness;  
  468.                 emotionType = "Sadness";  
  469.             }  
  470.             if (emotion.surprise > emotionValue)  
  471.             {  
  472.                 emotionValue = emotion.surprise;  
  473.                 emotionType = "Surprise";  
  474.             }  
  475.             return String.format("%s: %f", emotionType, emotionValue);  
  476.         }  
  477.   
  478.         private String getHeadPose(HeadPose headPose)  
  479.         {  
  480.             return String.format("Pitch: %s, Roll: %s, Yaw: %s", headPose.pitch, headPose.roll, headPose.yaw);  
  481.         }  
  482.     }  
  483. }  
Select_image_Activity.java code
  1. package ganeshannt.faceapi.ui;  
  2. import android.content.Intent;  
  3. import android.net.Uri;  
  4. import android.os.Bundle;  
  5. import android.os.Environment;  
  6. import android.provider.MediaStore;  
  7. import android.support.annotation.NonNull;  
  8. import android.support.v7.app.AppCompatActivity;  
  9. import android.view.View;  
  10. import android.widget.TextView;  
  11.   
  12. import java.io.File;  
  13. import java.io.IOException;  
  14.   
  15. import ganeshannt.faceapi.R;  
  16.   
  17. // The activity for the user to select a image and to detect faces in the image.  
  18. public class SelectImageActivity extends AppCompatActivity {  
  19.     // Flag to indicate the request of the next task to be performed  
  20.     private static final int REQUEST_TAKE_PHOTO = 0;  
  21.     private static final int REQUEST_SELECT_IMAGE_IN_ALBUM = 1;  
  22.   
  23.     // The URI of photo taken with camera  
  24.     private Uri mUriPhotoTaken;  
  25.   
  26.     // When the activity is created, set all the member variables to initial state.  
  27.     @Override  
  28.     protected void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.activity_select_image);  
  31.     }  
  32.   
  33.     // Save the activity state when it's going to stop.  
  34.     @Override  
  35.     protected void onSaveInstanceState(Bundle outState) {  
  36.         super.onSaveInstanceState(outState);  
  37.         outState.putParcelable("ImageUri", mUriPhotoTaken);  
  38.     }  
  39.   
  40.     // Recover the saved state when the activity is recreated.  
  41.     @Override  
  42.     protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {  
  43.         super.onRestoreInstanceState(savedInstanceState);  
  44.         mUriPhotoTaken = savedInstanceState.getParcelable("ImageUri");  
  45.     }  
  46.   
  47.     // Deal with the result of selection of the photos and faces.  
  48.     @Override  
  49.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  50.         switch (requestCode)  
  51.         {  
  52.             case REQUEST_TAKE_PHOTO:  
  53.             case REQUEST_SELECT_IMAGE_IN_ALBUM:  
  54.                 if (resultCode == RESULT_OK) {  
  55.                     Uri imageUri;  
  56.                     if (data == null || data.getData() == null) {  
  57.                         imageUri = mUriPhotoTaken;  
  58.                     } else {  
  59.                         imageUri = data.getData();  
  60.                     }  
  61.                     Intent intent = new Intent();  
  62.                     intent.setData(imageUri);  
  63.                     setResult(RESULT_OK, intent);  
  64.                     finish();  
  65.                 }  
  66.                 break;  
  67.             default:  
  68.                 break;  
  69.         }  
  70.     }  
  71.   
  72.     // When the button of "Take a Photo with Camera" is pressed.  
  73.     public void takePhoto(View view) {  
  74.         Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  
  75.         if(intent.resolveActivity(getPackageManager()) != null) {  
  76.             // Save the photo taken to a temporary file.  
  77.             File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);  
  78.             try {  
  79.                 File file = File.createTempFile("IMG_"".jpg", storageDir);  
  80.                 mUriPhotoTaken = Uri.fromFile(file);  
  81.                 intent.putExtra(MediaStore.EXTRA_OUTPUT, mUriPhotoTaken);  
  82.                 startActivityForResult(intent, REQUEST_TAKE_PHOTO);  
  83.             } catch (IOException e) {  
  84.                 setInfo(e.getMessage());  
  85.             }  
  86.         }  
  87.     }  
  88.   
  89.     // When the button of "Select a Photo in Album" is pressed.  
  90.     public void selectImageInAlbum(View view) {  
  91.         Intent intent = new Intent(Intent.ACTION_GET_CONTENT);  
  92.         intent.setType("image/*");  
  93.         if (intent.resolveActivity(getPackageManager()) != null) {  
  94.             startActivityForResult(intent, REQUEST_SELECT_IMAGE_IN_ALBUM);  
  95.         }  
  96.     }  
  97.   
  98.     // Set the information panel on screen.  
  99.     private void setInfo(String info) {  
  100.         TextView textView = (TextView) findViewById(R.id.info);  
  101.         textView.setText(info);  
  102.     }  
  103. }  
MainActivity.java code
  1. package ganeshannt.faceapi.ui;  
  2.   
  3. import android.app.AlertDialog;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.support.v7.app.AppCompatActivity;  
  7. import android.view.View;  
  8.   
  9. import ganeshannt.faceapi.R;  
  10.   
  11. public class MainActivity extends AppCompatActivity {  
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.   
  17.         if (getString(R.string.subscription_key).startsWith("Please")) {  
  18.             new AlertDialog.Builder(this)  
  19.                     .setTitle(getString(R.string.add_subscription_key_tip_title))  
  20.                     .setMessage(getString(R.string.add_subscription_key_tip))  
  21.                     .setCancelable(false)  
  22.                     .show();  
  23.         }  
  24.     }  
  25.   
  26.     public void detection(View view) {  
  27.         Intent intent = new Intent(this, DetectionActivity.class);  
  28.         startActivity(intent);  
  29.     }  
  30.   
  31. }  
Step 10

Click the "Make Project" option and run.

Deliverables

Here, we have successfully detected the face using Face API in Android app.

Android
Android

Android

Android

Android

Don’t forgot to like and follow me. If you have any doubts, just comment below.

Up Next
    Ebook Download
    View all
    Learn
    View all