Android + Face Detection + Cropping faces to List View

Hi Friends,

Face detection with Android may not be such a huge task after all. You can take the help of below link for detecting faces from any given image.



The above site provides a very good way of identifying faces for any given image. 

However, having detected the faces, how can you crop and extract the faces to a Array/ArrayList which could aid selecting a particular face for processing further. 

Kindly download the apk from the following link
Kindly download the source code for this project from the following link.

Pre-Requirements

1.  Eclipse with android SDK (As for the technical requirements)
2. Good understanding and knowledge of basics of Android and Java.

Running through the link will bring forward the below application flow:

Camera View -> Display captured image with detected faces -> List View of Detected Faces

Details of the application
Starting the app launches the camera activity, which has been built using CameraActivity.java and Preview.Java classes. 

Camera Activity
I would not be diving deep into the camera part concerning the application. You can get more details on camera class from my other blog concerning various types of camera in android. 


However, whats important to take over from the CameraActivity.java are the below lines of code. Having received the image byte array, compress the same (by converting it to bitmap) and transfer the byte array to next activity where the actual face detection magic happens. 


      @Override  
      public void onPictureTaken(byte[] data, Camera camera) {  
           // TODO Auto-generated method stub  
          
           //Convert image from byte[] to bitmap  
           Bitmap imageBitmap = BitmapFactory  
                     .decodeByteArray(data, 0, data.length);  
           
           //Downscale and compress the image bitmap  
           imageBitmap = scaleDownBitmap(imageBitmap, 240, this);  
           ByteArrayOutputStream stream = new ByteArrayOutputStream();  
           imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);  
           
           //Convert back the image from bitmap to byte[]  
           byte[] byteArray = stream.toByteArray();  
           mCamera.startPreview();  
           m_Progress.EndDialog();  
           
           //Send the image byte[] to next activity  
           Intent resultsActivity = new Intent(CameraActivity.this,  
                     DetectFaces.class);  
           resultsActivity.putExtra("ImageByteArray", byteArray);  
           startActivity(resultsActivity);  
      }  

Detect Faces
And this is the activity where all the magic happens. Having received the image, the image is converted back to bitmap and sent to detectFaces() function. I request you to kindly run through the detectFaces function. The comments provided should be self explanatory. 

detectFaces() function holds two important responsibilities:
1. Draw rectangles around the detected faces
2. Crop the detected faces and stack them into a ArrayList<Bitmap>

 private void detectFaces() {  
           if (null != imageBitmap) {  
                int width = imageBitmap.getWidth();  
                int height = imageBitmap.getHeight();  

                // Call face detector object  
                FaceDetector detector = new FaceDetector(width, height,  
                          DetectFaces.MAX_FACES);  
                Face[] faces = new Face[DetectFaces.MAX_FACES];  
                Bitmap bitmap565 = Bitmap.createBitmap(width, height,  
                          Config.RGB_565);  
                Paint ditherPaint = new Paint();  
                Paint drawPaint = new Paint();  

                // Set properties of the rectangle that should appear for a detected  
                // face  
                ditherPaint.setDither(true);  
                drawPaint.setColor(Color.GREEN);  
                drawPaint.setStyle(Paint.Style.STROKE);  
                drawPaint.setStrokeWidth(3);  

                // Create a canvas and draw the imagebitmap over the canvas  
                Canvas canvas = new Canvas();  
                canvas.setBitmap(bitmap565);  
                canvas.drawBitmap(imageBitmap, 0, 0, ditherPaint);  

                // trigger the face detector function and store the number of faces  
                // detected as int paramter faceFound  
                facesFound = detector.findFaces(bitmap565, faces); 
 
                // This parameters find the midpoint, eyeDistance and confidence in  
                // a face  
                PointF midPoint = new PointF();  
                float eyeDistance = 0.0f;  
                float confidence = 0.0f;  
                Log.i("FaceDetector", "Number of faces found: " + facesFound);  
                if (facesFound > 0) {  

                     // Select detected faces, one after one  
                     for (int index = 0; index < facesFound; ++index) {  
                          // Get mid point, eye distance and confidence of the face  
                          faces[index].getMidPoint(midPoint);  
                          eyeDistance = faces[index].eyesDistance();  
                          confidence = faces[index].confidence();  
                          Log.i("FaceDetector", "Confidence: " + confidence  
                                    + ", Eye distance: " + eyeDistance  
                                    + ", Mid Point: (" + midPoint.x + ", " + midPoint.y  
                                    + ")");  
                          try {  

                               // Draw a rectange depending upon face parameters.  
                               // Kindly note that this is just for displaying the  
                               // rectangle  
                               canvas.drawRect((float) midPoint.x - (eyeDistance * 2),  
                                         (float) midPoint.y - (eyeDistance * 2),  
                                         (int) midPoint.x + (eyeDistance * 2),  
                                         (int) midPoint.y + (eyeDistance * 2), drawPaint);  

                               // And this is for cropping the detected face from the  
                               // image  
                               Bitmap croppedBitmap = Bitmap.createBitmap(imageBitmap,  
                                         (int) (midPoint.x - (eyeDistance * 2)),  
                                         (int) (midPoint.y - (eyeDistance * 2)),  
                                         (int) (eyeDistance * 4),  
                                         (int) (eyeDistance * 4));  
                               extractedFaces.add(croppedBitmap);  
                               imageDimensions.add(midPoint.x + "," + midPoint.y + ","  
                                         + (eyeDistance * 2) + "," + (eyeDistance * 3)  
                                         + "," + "IMGPNG");  
                          } catch (Exception e) {  
                               /*  
                                * Toast.makeText( getApplicationContext(),  
                                * "Too many faces/face size is too small, kindly go back and try again..."  
                                * , Toast.LENGTH_SHORT).show();  
                                */  
                          }  
                     }  
                }  
                Log.i("Number of Faces detected", extractedFaces.size() + "");  
                String filepath = Environment.getExternalStorageDirectory()  
                          + "/facedetect" + System.currentTimeMillis() + ".jpg";  
                try {  
                     FileOutputStream fos = new FileOutputStream(filepath);  
                     bitmap565.compress(CompressFormat.JPEG, 90, fos);  
                     fos.flush();  
                     fos.close();  
                } catch (FileNotFoundException e) {  
                     e.printStackTrace();  
                } catch (IOException e) {  
                     e.printStackTrace();  
                }  
                ImageView imageView = (ImageView) findViewById(R.id.ivCapturedImage);  

                // Set the image view in this activity with the detected faces  
                // bitmap  
                imageView.setImageBitmap(bitmap565);  
           }  
      }  

Display Detected Faces

The sent ArrayList<Bitmap> is received in the DisplayDetectedFaces.java activity and displayed. 

Now what you intend to do with the received face bitmap is completely left you. One of the most appropriate use of the same would be to use the face for processing a face recognition algorithm and hence recognize the face. 

Comments