I'm trying to develop face detection using google-mlkit. After setup camera, analyzer, detector etc following docs from google-mlkit https://developers.google.com/ml-kit/vision/face-detection/android, I'm able to detect face. After detect face I'm trying to extract detected face image.
Get detected face boundingBox, extract full bitmap into detected face bitmap using boundingBox. Code below.
Bitmap bmp = Bitmap.createBitmap(mediaImage.getWidth(), mediaImage.getHeight(), Bitmap.Config.ARGB_8888);
YuvToRgbConverter converter = new YuvToRgbConverter(context);
converter.yuvToRgb(mediaImage, bmp);
Bitmap extractedBmp = extractFace(
bmp,
(int) (face.getBoundingBox().exactCenterX() / 2),
(int) (face.getBoundingBox().exactCenterY() / 2),
face.getBoundingBox().width(),
face.getBoundingBox().height()
);
private Bitmap extractFace(Bitmap bmp, int x, int y, int width, int height) {
return Bitmap.createBitmap(bmp, x, y, width, height);
}
Sometimes It's success and sometimes also failed. After debugging I found it's error because of x + width must be <= bitmap.width().
What I'm doing wrong?
Exception is correct.
It happens because face boundingBox can go outside of the image (bitmap).
Also it possible for x and y as well. Try this simple recalculation.
private fun extractFace(bmp: Bitmap, x: Int, y: Int, width: Int, height: Int): Bitmap? {
val originX = if (x + width > bmp.width) (bmp.width - width) else x
val originY = if (y + height > bmp.height) (bmp.height - height) else y
return Bitmap.createBitmap(bmp, originX, originY, width, height)
}
PS: Please check this calculation someone, it should work, thank you
Could you try util methods provided in the mlkit sample here to create a bimap from YUV image?
Related
I have a big bitmap - sometimes with height 2000 sometimes 4000 etc. This is possible to split this big bitmap dividing by 1500 and save into array?
For example if I have bitmap with height 2300 I want to have array with two bitmaps: one 1500 height and second 800.
You can use the createBitmap() to create bitmap chunks from the original Bitmap.
The below function takes in a bitmap and the desired chunk size (1500 in your case).
And split the bitmap vertically if the width is greater than height, and horizontally otherwise.
fun getBitmaps(bitmap: Bitmap, maxSize: Int): List<Bitmap> {
val width = bitmap.width
val height = bitmap.height
val nChunks = ceil(max(width, height) / maxSize.toDouble())
val bitmaps: MutableList<Bitmap> = ArrayList()
var start = 0
for (i in 1..nChunks.toInt()) {
bitmaps.add(
if (width >= height)
Bitmap.createBitmap(bitmap, start, 0, width / maxSize, height)
else
Bitmap.createBitmap(bitmap, 0, start, width, height / maxSize)
)
start += maxSize
}
return bitmaps
}
Usage:
getBitmaps(myBitmap, 1500)
Yes, you can use Bitmap.createBitmap(bmp, offsetX, offsetY, width, height);
to create a "slice" of the bitmap starting at a particular x and y offset, and having a particular width and height.
I'll leave the math up to you.
I'm developing an Android project using canvas and I have a scaling problem. to make it more simple I'm going to use an example.
Let's supposed my view is : width 1300px and height 800px , I'm putting a canvas inside that goes a static width 1300px but the height is a variable. If my canvas is > 800px so the canvas will goes out of the view so I was trying to use canvas.scale() but I don't know how to calculate the exact value to put inside the scale !
Any ideas ?
My personally, I think you should create a new Canvas. To do that you should resize your bitmap first. Using the below method to compute the scale between size of view and size of bitmap.
public static float computeScale(float w1, float h1, float w2, float h2) {
if (w1 > 0 && h1 > 0 && w2 > 0 && h2 > 0) {
return Math.max(w1 / w2, h1 / h2);
}
return 1;
}
So the scale and the new bitmap width, height will be calculated by the below code:
float scale = computeScale(viewWidth, viewHeight, bitmapWith, bitmapHeight);
if(scale > 1){
int newWidth = Math.round(bitmapWidth / scale);
int newHeight = Math.round(bitmapHeight / scale);
}
// The code for resizing the source bitmap with the newWidth and newHeight.
// Bitmap newBitmap = ...;
Finally, you use the new bitmap to create a new Canvas.
Canvas canvas = new Canvas(newBitmap);
Hey I've got this problem in an app I'm making. I need to create a pre translated bitmap which means create a new bitmap from the old one where the pixels are shifted by a specified amount. I thought I could achieve that with a matrix with set post or pre translate but none of those move the pixels or do anything visible for that matter.
Functions such as rotate or scale do work on the bitmap and do what is expected. The translate also works on the canvas but it doesn't move the bitmap pixels which is what I want. Is it even possible to do it?
Am I doing something wrong why the translate functions don't work on the bitmap?
Here is a piece of code that shows what I'm doing.
private void move(float dx, float dy) {
moveX = (float) (dx*complexScale);
moveY = (float) (dy*complexScale);
//canvasMatrix.setTranslate(dx,dy);
if(!render.isAlive()) {
focusX = focusX0 - dx*complexScale;
focusY = focusY0 - dy*complexScale;
bitmapMatrix.setTranslate(dx, dy);
needRefresh = true;
}
}
private void generate() {
if (!render.isAlive()) {
render = new Thread(generator);
fractal = Bitmap.createBitmap(fractal,0,0,mapWidth,mapHeight,bitmapMatrix,true);
setComplexAxis();
render.start();
}
}
There are two ways to do translation. Below dx is the translation in the X axis, and dy is the translation in the Y axis. The other variables should be self explanatory.
1 - Translation within the image (without rotation)
val newBitmap = Bitmap.createBitmap(originalBitmap, dx, dy, newWidth, newHeight, matrix, false)
2 - Complex matrix
matrix.postTranslate(dx, dy)
val newBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(newBitmap)
canvas.drawBitmap(originalBitmap, matrix, null)
This is an old question but figured I would still answer to help those who stumble upon it like I did.
Translation is done on the canvas. I am not entirely sure if you can just manipulate the pixel. I would recommend creating a view for the bitmap image and apply the translation on the canvas of the view
I searched through this site to find out how to rotate a image back and forth and came up with my own with the help of other post on this site, it works great, the only problem is now I got it working so it rotates back and forth the way I like it, how the heck do I now position it on the screen?
heres the code so far:
private Bitmap ray;
private int mRot = -33;
private boolean goRight = true;
void onRotDraw(Canvas canvas)
{
int width = ray.getWidth();
int height = ray.getHeight();
if (mRot > 30){
goRight = false;
}
if (mRot < -30){
goRight = true;
}
if (goRight){
mRot += 1;
}else
{
mRot -= 1;
}
canvas.rotate(mRot,width / 2,height / 2);
this.Draw_Sprite(canvas, 0, mRot );
}
public void Draw_Sprite(Canvas c, int whatever, int rot) {
//rotating image back and forth
int width = ray.getWidth();
int height = ray.getHeight();
Rect src = new Rect(width - width, height - height, width, height);
Rect dst = new Rect(width - width, height - height, width, height);
c.drawBitmap(this.ray, src, dst, null);
}
Usually with drawBitmap I use it to position my images but this one uses the src and dst instead for the size of the rectangle, so now it works great but how would I change the position on the screen from 0,0 to where I want it to go?
this was taken partially or mostly from this post:
Sprite Rotation in Android using Canvas.DrawBitmap. I am close, what am I doing wrong?
Which gave me all I needed to get this going except how to set the x and y position on the screen, any help with this would be greatly appreciated, I've been wrecking my brains out trying to find a way to get this set the x and y positions with no luck and its probably something simple.
Thanks in advance.
This is a piece of code from that other post you referenced:
Rect src = new Rect(0, 0, width, height);
Rect dst = new Rect(x, y, x + width, y + height);
It's the x and y in the dst Rect that determine the location of the bitmap.
Your code:
Rect src = new Rect(width - width, height - height, width, height);
Rect dst = new Rect(width - width, height - height, width, height);
Is going to always draw it at 0, 0 because width - width will be 0 and height - height will be 0.
I'm making a game for Android and I need to rotate an image. When I rotate it obviously it's dimensions change. For example when it's rotated 45 degrees (it's square but I'd like this to work for any rectangle so it's a more general solution) it's width and height become the length of the diagonal, which is longer than the original. After some algebra you can work out that the scale factor is sqrt(2). But the only way I know of to rotate a bitmap is with a matrix. Ex:
matrix.postRotate(degrees);
rotated = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, true);
Using this method the size of the bitmap remains constant so to fit the rotated image in the content of the image must shrink. Which causes my problem.
What I have now should work but when run doesn't. Probably because it's overly complex, never the less, here it is:
float totalRotated = 0;
public void rotate(float degrees){
if(mBitmap != null){
float increment = (float)((mBitmap.getWidth()/45.0)*(Math.sqrt(2)-1));
totalRotated += degrees;
totalRotated -= (float)((int)totalRotated/360)*360;
matrix.reset();
matrix.setRotate(totalRotated);
rotated = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, true);
rotated = Bitmap.createScaledBitmap(rotated, (int)(mBitmap.getWidth()+(((Math.abs(Math.abs(((int)totalRotated%90)-45)-45)))*increment)), (int)(mBitmap.getHeight()+(((Math.abs(Math.abs(((int)totalRotated%90)-45)-45)))*increment)), true);
}
}
Using the Log.d function I was able to determine that the dimensions set in the last statement are what I expect them to be but the image doesn't change size. Since this doesn't even work, I need a better way to do this or a way to fix my method. Also my method only works for squares. So, how can I do this?
EDIT:
My method does work, I just didn't call setBounds() This can't be the only way to do it though, this is so inefficient.
It's not clear what you're looking for, so here's a function based on yours that attempts to compute the proper width and height of the new bitmap and do the rotation by creating just a single bitmap.
float totalRotated = 0;
public void rotate(float degrees){
if(mBitmap != null){
// compute the absolute rotation
totalRotated = (totalRotated + degrees) % 360;
// precompute some trig functions
double radians = Math.toRadians(totalRotated);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
// figure out total width and height of new bitmap
int newWidth = mBitmap.getWidth() * cos + mBitmap.getHeight() * sin;
int newHeight = mBitmap.getWidth() * sin + mBitmap.getHeight() * cos;
// set up matrix
matrix.reset();
matrix.setRotate(totalRotated);
// create new bitmap by rotating mBitmap
rotated = Bitmap.createBitmap(mBitmap, 0, 0,
newWidth, newHeight, matrix, true);
}
}
I tried Gabe's solution and got the same errors that Ramesh and Regis got. This worked for me:
double radians = Math.toRadians(totalRotated);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
// figure out total width and height of new bitmap
final int width = mBitmap.getWidth();
final int height = mBitmap.getHeight();
final int newWidth = (int) (width * cos + height * sin);
final int newHeight = (int) (width * sin + height * cos);
// set up matrix
final Matrix tf = new Matrix();
tf.postRotate((float) Math.toDegrees(radians), width / 2, height / 2);
tf.postTranslate(
(newWidth - width) / 2,
(newHeight - height) / 2);
// create new bitmap by rotating mBitmap with canvas
final Bitmap rotatedBmp = Bitmap.createBitmap(
newWidth, newHeight, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(rotatedBmp);
canvas.drawBitmap(mBitmap, tf, null);