Back to project page AndroidFaceCropper.
The source code is released under:
Apache License
If you think the Android project AndroidFaceCropper listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright (C) 2014 lafosca Studio, SL *// w w w . ja v a 2 s . c o m * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cat.lafosca.facecropper; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.media.FaceDetector; import android.util.Log; /** * An utility that crops faces from bitmaps. * It support multiple faces (max 8 by default) and crop them all, fitted in the same image. */ public class FaceCropper { private static final String LOG_TAG = FaceCropper.class.getSimpleName(); public enum SizeMode { FaceMarginPx, EyeDistanceFactorMargin }; private static final int MAX_FACES = 8; private static final int MIN_FACE_SIZE = 200; private int mFaceMinSize = MIN_FACE_SIZE; private int mFaceMarginPx = 100; private float mEyeDistanceFactorMargin = 2f; private int mMaxFaces = MAX_FACES; private SizeMode mSizeMode = SizeMode.EyeDistanceFactorMargin; private boolean mDebug; private Paint mDebugPainter; private Paint mDebugAreaPainter; public FaceCropper() { initPaints(); } public FaceCropper(int faceMarginPx) { setFaceMarginPx(faceMarginPx); initPaints(); } public FaceCropper(float eyesDistanceFactorMargin) { setEyeDistanceFactorMargin(eyesDistanceFactorMargin); initPaints(); } private void initPaints() { mDebugPainter = new Paint(); mDebugPainter.setColor(Color.RED); mDebugPainter.setAlpha(80); mDebugAreaPainter = new Paint(); mDebugAreaPainter.setColor(Color.GREEN); mDebugAreaPainter.setAlpha(80); } public int getMaxFaces() { return mMaxFaces; } public void setMaxFaces(int maxFaces) { this.mMaxFaces = maxFaces; } public int getFaceMinSize() { return mFaceMinSize; } public void setFaceMinSize(int faceMinSize) { mFaceMinSize = faceMinSize; } public int getFaceMarginPx() { return mFaceMarginPx; } public void setFaceMarginPx(int faceMarginPx) { mFaceMarginPx = faceMarginPx; mSizeMode = SizeMode.FaceMarginPx; } public SizeMode getSizeMode() { return mSizeMode; } public float getEyeDistanceFactorMargin() { return mEyeDistanceFactorMargin; } public void setEyeDistanceFactorMargin(float eyeDistanceFactorMargin) { mEyeDistanceFactorMargin = eyeDistanceFactorMargin; mSizeMode = SizeMode.EyeDistanceFactorMargin; } public boolean isDebug() { return mDebug; } public void setDebug(boolean debug) { mDebug = debug; } protected CropResult cropFace(Bitmap original, boolean debug) { Bitmap fixedBitmap = BitmapUtils.forceEvenBitmapSize(original); fixedBitmap = BitmapUtils.forceConfig565(fixedBitmap); Bitmap mutableBitmap = fixedBitmap.copy(Bitmap.Config.RGB_565, true); if (fixedBitmap != mutableBitmap) { fixedBitmap.recycle(); } FaceDetector faceDetector = new FaceDetector( mutableBitmap.getWidth(), mutableBitmap.getHeight(), mMaxFaces); FaceDetector.Face[] faces = new FaceDetector.Face[mMaxFaces]; // The bitmap must be in 565 format (for now). int faceCount = faceDetector.findFaces(mutableBitmap, faces); if (BuildConfig.DEBUG) { Log.d(LOG_TAG, faceCount + " faces found"); } if (faceCount == 0) { return new CropResult(mutableBitmap); } int initX = mutableBitmap.getWidth(); int initY = mutableBitmap.getHeight(); int endX = 0; int endY = 0; PointF centerFace = new PointF(); Canvas canvas = new Canvas(mutableBitmap); canvas.drawBitmap(mutableBitmap, new Matrix(), null); // Calculates minimum box to fit all detected faces for (int i = 0; i < faceCount; i++) { FaceDetector.Face face = faces[i]; // Eyes distance * 3 usually fits an entire face int faceSize = (int) (face.eyesDistance() * 3); if (SizeMode.FaceMarginPx.equals(mSizeMode)) { faceSize += mFaceMarginPx * 2; // *2 for top and down/right and left effect } else if (SizeMode.EyeDistanceFactorMargin.equals(mSizeMode)) { faceSize += face.eyesDistance() * mEyeDistanceFactorMargin; } faceSize = Math.max(faceSize, mFaceMinSize); face.getMidPoint(centerFace); if (debug) { canvas.drawPoint(centerFace.x, centerFace.y, mDebugPainter); canvas.drawCircle(centerFace.x, centerFace.y, face.eyesDistance() * 1.5f, mDebugPainter); } int tInitX = (int) (centerFace.x - faceSize / 2); int tInitY = (int) (centerFace.y - faceSize / 2); tInitX = Math.max(0, tInitX); tInitY = Math.max(0, tInitY); int tEndX = tInitX + faceSize; int tEndY = tInitY + faceSize; tEndX = Math.min(tEndX, mutableBitmap.getWidth()); tEndY = Math.min(tEndY, mutableBitmap.getHeight()); initX = Math.min(initX, tInitX); initY = Math.min(initY, tInitY); endX = Math.max(endX, tEndX); endY = Math.max(endY, tEndY); } int sizeX = endX - initX; int sizeY = endY - initY; if (sizeX + initX > mutableBitmap.getWidth()) { sizeX = mutableBitmap.getWidth() - initX; } if (sizeY + initY > mutableBitmap.getHeight()) { sizeY = mutableBitmap.getHeight() - initY; } Point init = new Point(initX, initY); Point end = new Point(initX + sizeX, initY + sizeY); return new CropResult(mutableBitmap, init, end); } @Deprecated public Bitmap cropFace(Context ctx, int resDrawable) { return getCroppedImage(ctx, resDrawable); } @Deprecated public Bitmap cropFace(Bitmap bitmap) { return getCroppedImage(bitmap); } public Bitmap getFullDebugImage(Context ctx, int resDrawable) { // Set internal configuration to RGB_565 BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565; return getFullDebugImage(BitmapFactory.decodeResource(ctx.getResources(), resDrawable, bitmapOptions)); } public Bitmap getFullDebugImage(Bitmap bitmap) { CropResult result = cropFace(bitmap, true); Canvas canvas = new Canvas(result.getBitmap()); canvas.drawBitmap(result.getBitmap(), new Matrix(), null); canvas.drawRect(result.getInit().x, result.getInit().y, result.getEnd().x, result.getEnd().y, mDebugAreaPainter); return result.getBitmap(); } public Bitmap getCroppedImage(Context ctx, int resDrawable) { // Set internal configuration to RGB_565 BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565; return getCroppedImage(BitmapFactory.decodeResource(ctx.getResources(), resDrawable, bitmapOptions)); } public Bitmap getCroppedImage(Bitmap bitmap) { CropResult result = cropFace(bitmap, mDebug); Bitmap croppedBitmap = Bitmap.createBitmap(result.getBitmap(), result.getInit().x, result.getInit().y, result.getEnd().x - result.getInit().x, result.getEnd().y - result.getInit().y); if (result.getBitmap() != croppedBitmap) { result.getBitmap().recycle(); } return croppedBitmap; } protected class CropResult { Bitmap mBitmap; Point mInit; Point mEnd; public CropResult(Bitmap bitmap, Point init, Point end) { mBitmap = bitmap; mInit = init; mEnd = end; } public CropResult(Bitmap bitmap) { mBitmap = bitmap; mInit = new Point(0, 0); mEnd = new Point(bitmap.getWidth(), bitmap.getHeight()); } public Bitmap getBitmap() { return mBitmap; } public Point getInit() { return mInit; } public Point getEnd() { return mEnd; } } }