Search code examples
androidbitmapcropface-detection

Bitmap is cropped wrong in onPictureTaken


I want to implement my own face detection/recognition android app. When camera finds some face, a rectangle is displayed on camera preview (in real time). App has method for taking photos too. However, I dont want to save whole picture, only the area within the rectangle - the human face. When I give the rectangle coordinates to Bitmap.createBitmap method to crop my picture, correctness of cropped photo depends on the place on display, where the rectangle was shown. When a detected face appears in the middle of preview, createBitmap crops it circa fine, but not if it shows on left or right side of the display. Seems like the coordinates I send to Bitmap.createBitmap are conversed but I cannot find the ratio. Any solutions?

  • Here is my onPictureTaken method:

     @Override
    public void onPictureTaken(byte[] data, Camera camera) {
    
        File pictureFile = getOutputMediaFile(); 
        if (pictureFile == null) {
            Log.d(TAG, "Error creating media file, check storage permissions: ");
            return;
        }
    
        Bitmap picture = BitmapFactory.decodeByteArray(data, 0, data.length);
        RectF faceRect = mPreview.getFaceRect();
    
    
        float x = faceRect.left;
        float y = faceRect.top;
        float w = faceRect.right - faceRect.left;
        float h = faceRect.bottom - faceRect.top;
    
        int intX = (int) x;
        int intY = (int) y;
        int intW = (int) w;
        int intH = (int) h;
    
        Bitmap croppedPicture = Bitmap.createBitmap(picture, intX, intY, intW, intH);       
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        croppedPicture.compress(Bitmap.CompressFormat.JPEG, 100, stream);
        byte[] byteArrayFromPicture = stream.toByteArray();
    
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile); 
            fos.write(byteArrayFromPicture);
            //fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
    

and here is some example of cropped picture, I do not have enough reputation to post more links:

(sorry about making picture of picture, I was lazy to implement saving the rectangle together with photo)


Solution

  • Resolved

    The solution was very simple - because of using frontal camera the captured image was always reflected, added two if-clauses:

    Bitmap picture = BitmapFactory.decodeByteArray(data, 0, data.length);
            RectF faceRect = mPreview.getFaceRect();
            Camera.Parameters parameters  = mCamera.getParameters();
            int picWidth = parameters.getPictureSize().width;
    
            int intX = 0;
            int intY = (int) faceRect.top;
            int intW = (int) (faceRect.right - faceRect.left);
            int intH = (int) (faceRect.bottom - faceRect.top);
    
            if(faceRect.left > picWidth / 2) {
                intX = (int) (faceRect.right - (faceRect.right - picWidth / 2) * 2);
            }
            else if(faceRect.left <= picWidth / 2) {
                intX = (int) (picWidth - faceRect.right);
            }
    
            Bitmap croppedPicture = Bitmap.createBitmap(picture, intX, intY, intW, intH);       
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            croppedPicture.compress(Bitmap.CompressFormat.JPEG, 100, stream);
            byte[] byteArrayFromPicture = stream.toByteArray();