Skip to content

Commit

Permalink
Merge pull request #5 from lafosca/debugMode
Browse files Browse the repository at this point in the history
Debug mode
  • Loading branch information
ignasi committed Jul 31, 2014
2 parents 9d10ad5 + e2501e2 commit bcfbe54
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 38 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ local.properties

# Signing
signing/
build/
12 changes: 7 additions & 5 deletions FaceCropper-library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@
* limitations under the License.
*/

apply plugin: 'android-library'
apply plugin: 'com.android.library'

android {
compileSdkVersion 19
buildToolsVersion "19.0.3"
buildToolsVersion "20.0.0"

defaultConfig {
minSdkVersion 8
targetSdkVersion 16
versionCode 1
versionName "1.0"
versionCode 2
versionName "1.1"
}
buildTypes {
release {
Expand All @@ -38,9 +38,11 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}

import com.android.builder.core.BuilderConstants

android.libraryVariants.all { variant ->
def name = variant.buildType.name
if (name.equals(com.android.builder.BuilderConstants.DEBUG)) {
if (name.equals(BuilderConstants.DEBUG)) {
return; // Skip debug builds.
}
def task = project.tasks.create "jar${name.capitalize()}", Jar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@
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;

Expand All @@ -41,15 +47,32 @@ public enum SizeMode { FaceMarginPx, EyeDistanceFactorMargin };
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() { }
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() {
Expand Down Expand Up @@ -90,48 +113,57 @@ public void setEyeDistanceFactorMargin(float eyeDistanceFactorMargin) {
mSizeMode = SizeMode.EyeDistanceFactorMargin;
}

public Bitmap cropFace(Context ctx, int resDrawable) {
// Set internal configuration to RGB_565
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
public boolean isDebug() {
return mDebug;
}

return cropFace(BitmapFactory.decodeResource(ctx.getResources(), resDrawable, bitmapOptions));
public void setDebug(boolean debug) {
mDebug = debug;
}

public Bitmap cropFace(Bitmap original) {
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(
fixedBitmap.getWidth(), fixedBitmap.getHeight(),
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(fixedBitmap, faces);
int faceCount = faceDetector.findFaces(mutableBitmap, faces);

if (BuildConfig.DEBUG) {
Log.d(LOG_TAG, faceCount + " faces found");
}

if (faceCount == 0) {
return fixedBitmap;
return new CropResult(mutableBitmap);
}

int initX = fixedBitmap.getWidth();
int initY = fixedBitmap.getHeight();
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
}
Expand All @@ -143,15 +175,20 @@ else if (SizeMode.EyeDistanceFactorMargin.equals(mSizeMode)) {

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, fixedBitmap.getWidth());
tEndY = Math.min(tEndY, fixedBitmap.getHeight());
tEndX = Math.min(tEndX, mutableBitmap.getWidth());
tEndY = Math.min(tEndY, mutableBitmap.getHeight());

initX = Math.min(initX, tInitX);
initY = Math.min(initY, tInitY);
Expand All @@ -162,18 +199,101 @@ else if (SizeMode.EyeDistanceFactorMargin.equals(mSizeMode)) {
int sizeX = endX - initX;
int sizeY = endY - initY;

if (sizeX + initX > fixedBitmap.getWidth()) {
sizeX = fixedBitmap.getWidth() - initX;
if (sizeX + initX > mutableBitmap.getWidth()) {
sizeX = mutableBitmap.getWidth() - initX;
}
if (sizeY + initY > fixedBitmap.getHeight()) {
sizeY = fixedBitmap.getHeight() - initY;
if (sizeY + initY > mutableBitmap.getHeight()) {
sizeY = mutableBitmap.getHeight() - initY;
}

Bitmap croppedBitmap = Bitmap.createBitmap(fixedBitmap, initX, initY, sizeX, sizeY);
if (fixedBitmap != croppedBitmap) {
fixedBitmap.recycle();
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;
}
}
}
8 changes: 4 additions & 4 deletions FaceCropper-sample/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
apply plugin: 'android'
apply plugin: 'com.android.application'

android {
compileSdkVersion 19
buildToolsVersion "19.0.3"
buildToolsVersion "20.0.0"

defaultConfig {
minSdkVersion 8
Expand All @@ -19,8 +19,8 @@ android {
}

dependencies {
compile 'com.android.support:appcompat-v7:+'
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.squareup.picasso:picasso:2.2.0'
compile project(':FaceCropper-library')
compile 'com.android.support:appcompat-v7:20.+'
compile 'com.squareup.picasso:picasso:2.2.0'
}
4 changes: 1 addition & 3 deletions FaceCropper-sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
package="cat.lafosca.facecropper.sample" >

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
Expand All @@ -18,7 +17,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ public class MainActivity extends ActionBarActivity {

@Override
public Bitmap transform(Bitmap source) {
return mFaceCropper.cropFace(source);
return mFaceCropper.getCroppedImage(source);
}

@Override
public String key() {
StringBuilder builder = new StringBuilder(48);
StringBuilder builder = new StringBuilder();

builder.append("faceCrop(");
builder.append("minSize=").append(mFaceCropper.getFaceMinSize());
Expand All @@ -47,13 +47,40 @@ public String key() {
}
};

private Transformation mDebugCropTransformation = new Transformation() {

@Override
public Bitmap transform(Bitmap source) {
return mFaceCropper.getFullDebugImage(source);
}

@Override
public String key() {
StringBuilder builder = new StringBuilder();

builder.append("faceDebugCrop(");
builder.append("minSize=").append(mFaceCropper.getFaceMinSize());
builder.append(",maxFaces=").append(mFaceCropper.getMaxFaces());

FaceCropper.SizeMode mode = mFaceCropper.getSizeMode();
if (FaceCropper.SizeMode.EyeDistanceFactorMargin.equals(mode)) {
builder.append(",distFactor=").append(mFaceCropper.getEyeDistanceFactorMargin());
} else if (FaceCropper.SizeMode.FaceMarginPx.equals(mode)) {
builder.append(",margin=").append(mFaceCropper.getFaceMarginPx());
}

return builder.append(")").toString();
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mFaceCropper = new FaceCropper(1f);
mFaceCropper.setFaceMinSize(0);
mFaceCropper.setDebug(true);
mPicasso = Picasso.with(this);

final ImageAdapter adapter = new ImageAdapter();
Expand Down Expand Up @@ -135,7 +162,7 @@ public void setupView(View v, int position) {
ImageView image = (ImageView) v.findViewById(R.id.imageView);
ImageView imageCropped = (ImageView) v.findViewById(R.id.imageViewCropped);

mPicasso.load(urls[position]).into(image);
mPicasso.load(urls[position]).transform(mDebugCropTransformation).into(image);

mPicasso.load(urls[position])
.config(Bitmap.Config.RGB_565)
Expand Down
Loading

0 comments on commit bcfbe54

Please sign in to comment.