Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Face detection only works with drawables not with images from SD card

Tags:

android

So I have code to detect up to 10 faces in any given image file and return to me info like the location of the eyes and other stuff like that. So when i tell it to use an image file that is stored in the drawable folder of resources for my project it works great. But when i have it try to find faces from a bitmap i import from the sd card it wont find any faces. But these are the same exact images. Any ideas? my code is bellow:

Edit: After further inspection I found that when i insert this line of code System.out.println("Row Bytes: " + sourceImage.getRowBytes()); I get the drawable is 352 and The SD card image is 704. Which I think means that the drawable is being compressed in the .apk file but the SD card image obviously is not. Not sure if this would effect anything.

 public class FaceView extends View {
           private static final int NUM_FACES = 10; // max is 64
           private static final boolean DEBUG = true;

           private FaceDetector arrayFaces;
           private FaceDetector.Face getAllFaces[] = new FaceDetector.Face[NUM_FACES];
           private FaceDetector.Face getFace = null;

           private PointF eyesMidPts[] = new PointF[NUM_FACES];
           private float  eyesDistance[] = new float[NUM_FACES];

           private Bitmap sourceImage;

           private Paint tmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
           private Paint pOuterBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);
           private Paint pInnerBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);

           private int picWidth, picHeight;
           private float xRatio, yRatio;

           public FaceView(Context context) {
                   super(context);

                   pInnerBullsEye.setStyle(Paint.Style.FILL);
                   pInnerBullsEye.setColor(Color.RED);

                   pOuterBullsEye.setStyle(Paint.Style.STROKE);
                   pOuterBullsEye.setColor(Color.RED);

                   tmpPaint.setStyle(Paint.Style.STROKE);
                   tmpPaint.setTextAlign(Paint.Align.CENTER);

                   BitmapFactory.Options bfo = new BitmapFactory.Options();
                   bfo.inPreferredConfig = Bitmap.Config.RGB_565;

                   //********This code imports the image from the SD card which does not work
                   String imageInSD = Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/testfolder/" + "face1" + ".png";

                   Bitmap sourceImage = BitmapFactory.decodeFile(imageInSD,bfo);

                   //**********This code uses an image in the projects drawable folder, this code works.
                   sourceImage = BitmapFactory.decodeResource( getResources() ,R.drawable.face1, bfo);

                   picWidth = sourceImage.getWidth();
                   picHeight = sourceImage.getHeight();

                   arrayFaces = new FaceDetector( picWidth, picHeight, NUM_FACES );
                   arrayFaces.findFaces(sourceImage, getAllFaces);

                   for (int i = 0; i < getAllFaces.length; i++)
                   {
                           getFace = getAllFaces[i];
                           try {
                                   PointF eyesMP = new PointF();
                                   getFace.getMidPoint(eyesMP);
                                   eyesDistance[i] = getFace.eyesDistance();
                                   eyesMidPts[i] = eyesMP;

                                   if (DEBUG)
                                   {
                                           Log.i("Face",
                                                   i +  " " + getFace.confidence() + " " + getFace.eyesDistance() + " "
                                                   + "Pose: ("+ getFace.pose(FaceDetector.Face.EULER_X) + ","
                                                   + getFace.pose(FaceDetector.Face.EULER_Y) + ","
                                                   + getFace.pose(FaceDetector.Face.EULER_Z) + ")"
                                                   + "Eyes Midpoint: ("+eyesMidPts[i].x + "," + eyesMidPts[i].y +")"
                                           );
                                   }
                           }
                           catch (Exception e)
                           {
                                   if (DEBUG) Log.e("Face", i + " is null");
                           }

                   }


           }

           @Override
           protected void onDraw(Canvas canvas)
           {
                   xRatio = getWidth()*1.0f / picWidth;
                   yRatio = getHeight()*1.0f / picHeight;
                   canvas.drawBitmap( sourceImage, null , new Rect(0,0,getWidth(),getHeight()),tmpPaint);
                   for (int i = 0; i < eyesMidPts.length; i++)
                   {
                           if (eyesMidPts[i] != null)
                           {
                                   pOuterBullsEye.setStrokeWidth(eyesDistance[i] /6);
                                   canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 2 , pOuterBullsEye);
                                   canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 6 , pInnerBullsEye);
                           }
                   }


           }  

}
like image 812
Peter Avatar asked Dec 27 '22 04:12

Peter


2 Answers

Alright I believe I know what your issue is here. The device can not render the image to a bitmap image as it sits in external memory. The face recognition is working its just not making it to the canvas. All devices have a rendering limit on my xoom its (2048x2048) I found that here. The reason that it works when you add the image as a resource is because your file is downsized as it builds the .apk (to be honest I'm not sure why it does this, but I left a little println for testing, someone else could answer that better). Anyway I just scaled the bitmap by dividing by 2 after your code looked for faces and before it tries to render the bitmap to the canvas. Now everything seems to work fine. You may want to adjust your face indicators but its functional. I hope this helps.

public class FaceView extends View {
private static final int NUM_FACES = 1; // max is 64
private static final boolean DEBUG = true;

private FaceDetector arrayFaces;
private FaceDetector.Face getAllFaces[] = new FaceDetector.Face[NUM_FACES];
private FaceDetector.Face getFace = null;

private PointF eyesMidPts[] = new PointF[NUM_FACES];
private float  eyesDistance[] = new float[NUM_FACES];

private Bitmap sourceImage;

private Paint tmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pOuterBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pInnerBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);

private int picWidth, picHeight;
private float xRatio, yRatio;

public FaceView(Context context) {
        super(context);

        pInnerBullsEye.setStyle(Paint.Style.FILL);
        pInnerBullsEye.setColor(Color.RED);

        pOuterBullsEye.setStyle(Paint.Style.STROKE);
        pOuterBullsEye.setColor(Color.RED);

        tmpPaint.setStyle(Paint.Style.STROKE);
        tmpPaint.setTextAlign(Paint.Align.CENTER);

        BitmapFactory.Options bfo = new BitmapFactory.Options();
        bfo.inPreferredConfig = Bitmap.Config.RGB_565;

        //********This code imports the image from the SD card which does not work
        String imageInSD = Environment.getExternalStorageDirectory().getAbsolutePath() + "/face1" + ".jpg";

        System.out.println(imageInSD);

        sourceImage = BitmapFactory.decodeFile(imageInSD, bfo);

        //Bitmap sourceImage;// = BitmapFactory.decodeFile(imageInSD,bfo);


        //**********This code uses an image in the projects drawable folder, this code works.
        //sourceImage = BitmapFactory.decodeResource( getResources() ,R.drawable.face1, bfo);

        picWidth = sourceImage.getWidth();
        picHeight = sourceImage.getHeight(); 

        System.out.println(picWidth + "x" + picHeight);

        arrayFaces = new FaceDetector( picWidth, picHeight, NUM_FACES );
        arrayFaces.findFaces(sourceImage, getAllFaces);

        sourceImage = Bitmap.createScaledBitmap (sourceImage, picWidth/2, picHeight/2, false);

        for (int i = 0; i < getAllFaces.length; i++)
        {
                getFace = getAllFaces[i];
                try {
                        PointF eyesMP = new PointF();
                        getFace.getMidPoint(eyesMP);
                        eyesDistance[i] = getFace.eyesDistance();
                        eyesMidPts[i] = eyesMP;

                        if (DEBUG)
                        {
                                Log.i("Face",
                                        i +  " " + getFace.confidence() + " " + getFace.eyesDistance() + " "
                                        + "Pose: ("+ getFace.pose(FaceDetector.Face.EULER_X) + ","
                                        + getFace.pose(FaceDetector.Face.EULER_Y) + ","
                                        + getFace.pose(FaceDetector.Face.EULER_Z) + ")"
                                        + "Eyes Midpoint: ("+eyesMidPts[i].x + "," + eyesMidPts[i].y +")"
                                );
                        }
                }
                catch (Exception e)
                {
                        if (DEBUG) Log.e("Face", i + " is null");
                }

        }


}

@Override
protected void onDraw(Canvas canvas)
{
        xRatio = getWidth()*1.0f / picWidth; 
        yRatio = getHeight()*1.0f / picHeight;
        canvas.drawBitmap( sourceImage, null , new Rect(0,0,getWidth(),getHeight()),tmpPaint);
        for (int i = 0; i < eyesMidPts.length; i++)
        {
                if (eyesMidPts[i] != null)
                {
                        pOuterBullsEye.setStrokeWidth(eyesDistance[i] /6);
                        canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 2 , pOuterBullsEye);
                        canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 6 , pInnerBullsEye);
                }
        }


}

}

like image 195
shibbybird Avatar answered Dec 29 '22 19:12

shibbybird


Turns out the issue is that the pictures taken by the Camera are saved as PNG files and the face detection can only successfully work from the SD card if it is using JPG files. Simply convert the files to JPG and it works fine.

like image 40
Peter Avatar answered Dec 29 '22 19:12

Peter