I have an image of women. I find her eye points using FaceDetector. Now I want to add hair image over her face using those eyes points.
I am loading that image from gallery using below code
btnLoad.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, RQS_LOADIMAGE);
}
});
In onActivityResult, i am checking the face cordinates
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
InputStream inputStream = getContentResolver().openInputStream(data.getData());
myBitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();
imgView.setImageBitmap(myBitmap);
if (myBitmap == null) {
Toast.makeText(MainActivity.this, "myBitmap == null", Toast.LENGTH_LONG).show();
} else {
detectFace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Face Detection method
private void detectFace() {
Paint myRectPaint = new Paint();
myRectPaint.setStrokeWidth(5);
myRectPaint.setColor(Color.RED);
myRectPaint.setStyle(Paint.Style.STROKE);
tempBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(myBitmap, 0, 0, null);
FaceDetector faceDetector = new FaceDetector.Builder(this)
.setTrackingEnabled(true)
.setLandmarkType(FaceDetector.ALL_LANDMARKS)
.setMode(FaceDetector.ACCURATE_MODE)
.setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
.build();
Frame frame = new Frame.Builder().setBitmap(myBitmap).build();
SparseArray<Face> faces = faceDetector.detect(frame);
imgView.setImageDrawable(new BitmapDrawable(getResources(), drawOnFace(faces)));
}
Getting Eye coordinates using below code :-
private Bitmap drawOnFace(SparseArray<Face> faceArray) {
tempBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(tempBitmap);
canvas.drawBitmap(myBitmap, 0, 0, null);
for (int i = 0; i < faceArray.size(); i++) {
Face face = faceArray.get(i);
for (Landmark landmark : face.getLandmarks()) {
switch (landmark.getType()) {
case Landmark.LEFT_EYE:
drawPoint(canvas, landmark.getPosition());
break;
case Landmark.RIGHT_EYE:
drawPoint(canvas, landmark.getPosition());
break;
}
}
}
return tempBitmap;
}
Draw circle over eyes using below code :-
private void drawPoint(Canvas canvas, PointF point) {
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(8);
paint.setStyle(Paint.Style.STROKE);
float x = point.x;
float y = point.y;
canvas.drawCircle(x, y, 10, paint);
}
Now inside DrawPoint method, I have eye coordinates. I want to use those points to put hair image over face.
I really don't know what to do next. Appreciate help guys.
Thank you in advance
To place image over camera preview use this code
float left=0,top=0;
Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.drawable.mustache);
//if you are in non activity then use context.getResources()
canvas.drawBitmap(bitmap,left,top,paint);
private static final int REQUET_LOADIMAGE = 111;
private Button btnDetect;
private ImageView image;
private Bitmap bitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photogallery);
image = (ImageView) findViewById(R.id.image);
btnDetect=(Button)findViewById(R.id.btnDetect);
btnDetect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
detectFacesInImage();
}
});
Intent intent = new Intent();
intent.setType("image/*"); // filter only image type files
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, REQUET_LOADIMAGE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUET_LOADIMAGE && resultCode == RESULT_OK) {
if (bitmap != null) {
bitmap.recycle();
}
try {
InputStream inputStream = getContentResolver().openInputStream(data.getData());
bitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();
image.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void detectFacesInImage() {
//Create a Paint object for drawing with
Paint myRectPaint = new Paint();
myRectPaint.setStrokeWidth(5);
myRectPaint.setColor(Color.RED);
myRectPaint.setStyle(Paint.Style.STROKE);
//Create a Canvas object for drawing on
Bitmap tempBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(bitmap, 0, 0, null);
//Detect the Faces
FaceDetector faceDetector = new FaceDetector.Builder(getApplicationContext())
.setTrackingEnabled(false)
.build();
Frame frame = new Frame.Builder().setBitmap(bitmap).build();
SparseArray<Face> faces = faceDetector.detect(frame);
if (faces.size() == 0) {
Toast.makeText(this, "None face detected!", Toast.LENGTH_SHORT).show();
} else {
//Draw Rectangles on the Faces
for (int i = 0; i < faces.size(); i++) {
Face thisFace = faces.valueAt(i);
float x1 = thisFace.getPosition().x;
float y1 = thisFace.getPosition().y;
float x2 = x1 + thisFace.getWidth();
float y2 = y1 + thisFace.getHeight();
tempCanvas.drawRoundRect(new RectF(x1, y1, x2, y2), 2, 2, myRectPaint);
faceDetector.release();
}
image.setImageDrawable(new BitmapDrawable(getResources(), tempBitmap));
}
}
}
I have successfully implemented face detection using google play-services-vision:9.4.0+' and also get the detected face by a simple program with the help of canvas.
I want to know the gender of the given photo on just onClicklistner.
Is there any way to do this?
Try to use this api: Gender Classification
https://algorithmia.com/algorithms/deeplearning/GenderClassification
import com.algorithmia.*;
import com.algorithmia.algo.*;
String input = "{\n"
+ " \"image\": \"data://deeplearning/example_data/m_ali.jpg\"\n"
+ "}";
AlgorithmiaClient client = Algorithmia.client("YOUR_API_KEY");
Algorithm algo = client.algo("algo://deeplearning/GenderClassification/1.0.1");
AlgoResponse result = algo.pipeJson(input);
System.out.println(result.asJsonString());
Json Result:
{
"results": [
[0.9948568344116211, "Male"],
[0.0051431627944111815, "Female"]
]
}
I have class allows you draw on an image from the filesystem. It has methods that I've shared below. The idea is that, as the image is touched, circles will be drawn on top of that image at each of the points that have been touched.
#Override
protected void onDraw(Canvas canvas) {
try{
if (mTextPaint == null)
{
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.CYAN);
}
if (cachedBitmap == null)
{
Bitmap immutableBitmap = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), Uri.fromFile(CameraActivity.getFile()));
cachedBitmap = immutableBitmap.copy(Bitmap.Config.ARGB_8888, true);
}
if (cachedCanvas == null)
{
cachedCanvas = canvas;
cachedCanvas.setBitmap(cachedBitmap);
}
if (! mPoints.isEmpty())
{
for (Point point : mPoints)
{
cachedCanvas.drawCircle(point.x, point.y, 25, mTextPaint);
}
Log.i(TAG, "Drawing points...");
}
}
catch (Exception e)
{
Log.e(TAG, "Error on draw: " + e.toString());
}
}
/**
* populates a list of points that have been touched
*
* #param event
* #return
*/
#Override
public boolean onTouchEvent(MotionEvent event)
{
Point point = new Point((int)event.getX(), (int)event.getY());
mPoints.add(point);
invalidate();
return true;
}
After this is done, I'd like to include a static method that returns the now drawn on bitmap, something like this:
public static Bitmap getCachedBitmap()
{
return cachedBitmap;
}
The problem is, the cachedBitmap variable is not being updated as it is being drawn on, so when I inspect the return value of cachedBitmap, I just get the Bitmap from the file URI specified in the initial immutableBitmap variable.
Any idea how I can return the altered bitmap?
You can take an image of outer layout which contains both the bitmap and the canvas on which circles are drawn:
View v = yourlayout.getRootView();
v.setDrawingCacheEnabled(true);
Bitmap bitmap = v.getDrawingCache();
BitmapDrawable drawable=new BitmapDrawable(bitmap);
By this way, you will get your initial image + edits.
Thanks for reading, have been trying to get this going for days and have searched as much code as I can. As you will see below I have tried a number of approaches.
I am using a 3rd party device that returns a Bitmap of size 152 x 500. There is a black strip vertically down the left side that is 24 wide. So in actual fact what I am needing is a 128 x 500 which would start 24 in from the left.
Whatever I try I just cannot seem to get rid of that black strip when the image is saved.
Here is the code, sorry it's so much but I thought I would just show it all. Look for
// Scan Button Clicked
and
Log.e("tag", "Wait For Scan Capture");
Much appreciate any help on this.
public class ImageCaptureActivity extends Activity implements OnClickListener {
private LinearLayout ll_root;
private Button btn_scan;
private Button btn_process;
private LinearLayout mLayout;
private Button mButton;
private FingerView mImageView;
private FPCDevKitInterface mFPCDevKit;
public View minutiaView;
public Bitmap tempBitmap;
public Bitmap scanBitmap;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_login_scan);
Log.e("tag", "0");
//ll_root = (LinearLayout)findViewById(R.id.ll_root);
btn_scan = (Button)findViewById(R.id.scan);
btn_process = (Button)findViewById(R.id.proceed_button);
Log.e("tag", "1");
// mFPCDevKit = new SSDDevice ((UsbManager) getSystemService(Context.USB_SERVICE));
// mImageView = new FingerView(this, mFPCDevKit.createCompatibleBitmap());
// mImageView.setLayoutParams(new LinearLayout.LayoutParams(200,200));
//add view here.
// ll_root.addView(mImageView);
// Just keep it commented, because we cannot find the id of ll_root. it is currently null.
Log.i("tag", "2");
Log.e("tag", "5");
/* ---------------------------------------------------------------------------------------------------------------*/
/* Following is the initial Screen Layout Section done as a Setup of the screen and Before the Capture is clicked */
// Manually set up the screen layout
mLayout = new LinearLayout(this);
mLayout.setOrientation(LinearLayout.VERTICAL);
// Manually create the Button
mButton = new Button(this);
mButton.setOnClickListener(this);
mButton.setText("Capture Image");
// Setup the FPC Service to get the finger scan from the device
Log.e("tag", "Setup FPC");
mFPCDevKit = new SSDDevice ((UsbManager) getSystemService(Context.USB_SERVICE));
// Call the FingerView function and then load the bitmap into mImageView
Log.e("tag", "Load into mImageView");
mImageView = new FingerView(this, mFPCDevKit.createCompatibleBitmap());
// Modify the viewing area for the scanned image size
mImageView.setLayoutParams(new LinearLayout.LayoutParams(24+128,500)); // Left area plus image width and crop of right area
// Add the Button and the mImageView to the Layout
Log.e("tag", "Add Views");
mLayout.addView(mButton);
mLayout.addView(mImageView);
// Display the screen
Log.e("tag", "Display Screen");
setContentView(mLayout);
// setContentView(R.layout.my_login_scan);
/* ----------- End Screen Layout Setup ------------------ */
}
public static AlertDialog createCapturePromtDialog(Context context,
DevKitType type) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (type == DevKitType.ASD)
builder.setTitle("Place finger on sensor");
else
builder.setTitle("Swipe finger over sensor");
return builder.create();
}
private class FingerView extends View {
public Bitmap mBitmap;
private Matrix mMatrix;
public FingerView(Context context, Bitmap bitmap) {
super(context);
mBitmap = bitmap;
mMatrix = new Matrix();
setBackgroundColor(Color.WHITE); // is the full screen area background colour as well as the template area colour
setDrawingCacheEnabled(true);
Log.e("tag", "FingerView");
}
public Bitmap getBitmap() {
return mBitmap;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.e("onSizeChanged", "w = " + w + " h = " + h + " oldw = " + oldw
+ " oldh = " + oldh);
// This use to Scale the current bitmap fill the screen.
// The last variable: Matrix.ScaleToFit.FILL for fill two dimensions
// Matrix.ScaleToFit.CENTER scale to center and keep the
// width/height ratio.
//mMatrix.setRectToRect(
// new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight()),
// new RectF(0, 0, w, h), Matrix.ScaleToFit.CENTER);
super.onSizeChanged(w, h, oldw, oldh);
// Lets try to resize to 150 x 500 - Harry July 14 2013
// mMatrix.setRectToRect(new RectF(0, 0, 128, 500),new RectF(-24, 0, 150, 500), Matrix.ScaleToFit.CENTER);
Log.e("tag", "Inside onsizechanged " + 0);
/* Scales image to fit into a new rectangle imageView
Matrix m = imageView.getImageMatrix();
RectF drawableRect = new RectF(0, 0, imageWidth, imageHeight);
RectF viewRect = new RectF(0, 0, imageView.getWidth(), imageView.getHeight());
m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);
imageView.setImageMatrix(m);
*/
}
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas) {
Log.e("onDraw Begin","");
canvas.drawBitmap(mBitmap, mMatrix, null);
super.onDraw(canvas);
}
}
// Scan Button Clicked
public void onClick(View v) {
Log.e("tag", "onClick happened");
// Erase the scan area to White
mImageView.getBitmap().eraseColor(Color.WHITE); // Doesn't seem to make a difference
// Bitmap tempBitmap = Bitmap.createBitmap(128+24+24,500,Bitmap.Config.ARGB_8888);
Log.e("onClick Enter second one= " + 0,
"w = " + 0 + " h =" + 0);
try {
// Wait for the scanner and then load the image into mImageView.mBitmap
mFPCDevKit.clearAbort();
Log.e("tag", "Wait For Scan Capture");
scanBitmap = mFPCDevKit.createCompatibleBitmap();
mFPCDevKit.waitAndCaptureImage(mImageView.getBitmap()); // Image displays in mImageView
//mFPCDevKit.waitAndCaptureImage(scanBitmap); // Tried to put image into a Bitmap
//Create a new image bitmap and attach a brand new canvas to it
// Bitmap minBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas tempCanvas = new Canvas(scanBitmap);
//Draw the image bitmap into the canvas
// tempCanvas.drawBitmap(scanBitmap, 0, 0, null);
//Draw everything else you want into the canvas, in this example a rectangle with rounded edges
// tempCanvas.drawRoundRect(new RectF(x1,y1,x2,y2), 2, 2, scanBitmap);
//Attach the canvas to the ImageView
// mImageView.setBackgroundDrawable(new BitmapDrawable(getResources(), scanBitmap));
// #Override protected void onDraw(Canvas canvas) { canvas.drawColor(0xFFAAAAAA); canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); if(item_id==3){ canvas.drawText(AppModel.contents, 100, 100, mPaint); } else{ canvas.drawPath(mPath, mPaint); } }
// Bitmap mmBitmap = Bitmap.createBitmap(mImageView.mBitmap, 22, 0, mImageView.mBitmap.getWidth()-100, mImageView.mBitmap.getHeight());
// Canvas canvas1 = new Canvas(mmBitmap);
// mImageView.setImageBitmap(tempBitmap);
// Crop the image here.
Log.e("before crop", "w = " + mImageView.getBitmap().getWidth()
+ " h = " + mImageView.getBitmap().getHeight());
// parameters show w = 176 h = 500
// Harry's mods to flow here --------
// Bitmap HarryBitmap = Bitmap.createBitmap(mImageView.getWidth(),mImageView.getHeight(),Bitmap.Config.ARGB_8888);
// Bitmap HarryBitmap = Bitmap.createBitmap(128,500,Bitmap.Config.ARGB_8888);
// Canvas canvas = new Canvas(HarryBitmap);
// mImageView.draw(canvas);
// Bitmap resizedbitmap1 = Bitmap.createBitmap(tempBitmap,24,0,150,500);
// Canvas canvas1 = new Canvas(resizedbitmap1);
// mImageView.draw(canvas1);
/* Try number 2 to approach
Paint paint = new Paint();
paint.setFilterBitmap(true);
int targetWidth = 128;
int targetHeight = 500;
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(scanBitmap);
canvas.drawBitmap( scanBitmap, new Rect(24, 0, 176, 500),
new RectF(0, 0, targetWidth, targetHeight), paint);
// Matrix matrix = new Matrix();
// matrix.postScale(1f, 1f);
// Bitmap resizedBitmap = Bitmap.createBitmap(targetBitmap, 0, 0, 128, 500, matrix, true);
//
// //convert Bitmap to resource
// //BitmapDrawable bd = new BitmapDrawable(resizedBitmap);
//
// canvas.drawBitmap( resizedBitmap, new Rect(24, 0, 128, 500),
// new Rect(0, 0, 128, 500), paint);
mImageView.draw(canvas);
*/
Log.e("after crop", "w = " + mImageView.getBitmap().getWidth()
+ " h = " + mImageView.getBitmap().getHeight());
// end Harry's mods to flow --------
// Save the image to the SD card for testing viewing
saveScreen(mImageView.getBitmap());
} catch (IOException e) {
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mImageView.postInvalidate();
}
// Not currently used - Harry July 14 2013
private Bitmap cropBitmap(Bitmap bitmap) {
Bitmap result = Bitmap.createBitmap(bitmap, 1, 1, 128, 500);
Log.e("croped",
"w = " + result.getWidth() + " h = " + result.getHeight());
return result;
}
public void saveScreen(Bitmap bitmap) {
Log.e("saveScreen Enter= " + bitmap.getByteCount(),
"w = " + bitmap.getWidth() + " h =" + bitmap.getHeight());
String root = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES).toString();
File myDir = new File(root + "/images");
myDir.mkdirs();
String fname = "FPCKit.jpg";
File file = new File(myDir, fname);
/*
* boolean done = false; int n = 1; do { String fname = "Image-" + n +
* ".jpg"; file = new File(myDir, fname); if (!file.exists()) { done =
* true; } n++; } while (!done);
*/
try {
FileOutputStream out = new FileOutputStream(file);
// bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
// Bitmap bmp = mImageView.getBitmap();
// bmp.compress(Bitmap.CompressFormat.JPEG, 100, out);
Log.e("onSave bytes= " + bitmap.getByteCount(),
"w = " + bitmap.getWidth() + " h =" + bitmap.getHeight());
//This will be as previous version. save entire image.
mImageView.getDrawingCache().compress(Bitmap.CompressFormat.JPEG, 100, out);
// bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
Toast toast = Toast.makeText(ImageCaptureActivity.this,
"Image saved to " + file.getAbsolutePath(),
Toast.LENGTH_SHORT);
toast.show();
} catch (Exception e) {
e.printStackTrace();
Toast toast = Toast.makeText(ImageCaptureActivity.this,
"Exception saving image: " + e.getLocalizedMessage(),
Toast.LENGTH_SHORT);
toast.show();
}
}
}
I'm using the code below. My app was able to draw on the canvas and save it.
But what I want to do is make an image as the background of the canvas so when I save it, it will look like an image with the user's drawing on top of it.
Thank you so much for any help! :)
#Override
public void run() {
Canvas canvas = null;
while (_run){
if(isDrawing == true){
try{
canvas = mSurfaceHolder.lockCanvas(null);
if(mBitmap == null){
mBitmap = Bitmap.createBitmap (1, 1, Bitmap.Config.ARGB_8888);
}
final Canvas c = new Canvas (mBitmap);
c.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawColor(0xffffffff);
commandManager.executeAll(c,previewDoneHandler);
previewPath.draw(c);
canvas.drawBitmap (mBitmap, 0, 0,null);
} finally {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
Try this stuff,
This will return a Bitmap that will be a Merged one of two Bitmap Images, also it will save in the SDCard.
public Bitmap combineImages(Bitmap c, Bitmap s) {
Bitmap cs = null;
int width, height = 0;
if (c.getWidth() > s.getWidth()) {
width = c.getWidth();
height = c.getHeight();
} else {
width = s.getWidth() + s.getWidth();
height = c.getHeight();
}
cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(c, 0, 0, null);
comboImage.drawBitmap(s, 100, 300, null);
/******
*
* Write file to SDCard
*
* ****/
String tmpImg = String.valueOf(System.currentTimeMillis()) + ".png";
OutputStream os = null;
try {
os = new FileOutputStream(Environment.getExternalStorageDirectory()
+ "/"+tmpImg);
cs.compress(CompressFormat.PNG, 100, os);
} catch (IOException e) {
Log.e("combineImages", "problem combining images", e);
}
return cs;
}
For any view that you are creating, you can create a bitmap of what it is currently displaying.
use:
view.setDrawingCacheEnabled(true);
Bitmap bitmap=view.getDrawingCache();
Does this help you in achieving what you want ?
*be sure to recycle these bitmaps when you are done.
bitmap.recycle();