Rotate a bitmap using render script android - android

When I use following code, it ends up with outofmemory exception. After doing researh Render script looks like a good candidate. Where can I find sample code for similar operation and how can integrate it to my project.
public Bitmap rotateBitmap(Bitmap image, int angle) {
if (image != null) {
Matrix matrix = new Matrix();
matrix.postRotate(angle, (image.getWidth()) / 2,
(image.getHeight()) / 2);
return Bitmap.createBitmap(image, 0, 0, image.getWidth(),
image.getHeight(), matrix, true);
}
return null;
}

Basically rotating bitmap is a task of rotating 2D array without using additional memory. And this is the correct implementation with RenderScript: Android: rotate image without loading it to memory .
But this is not necessary if all you want is just to display rotated Bitmap. You can simply extend ImageView and rotate the Canvas while drawing on it:
canvas.save();
canvas.rotate(angle, X + (imageW / 2), Y + (imageH / 2));
canvas.drawBitmap(imageBmp, X, Y, null);
canvas.restore();
What about ScriptIntrinsic, since it's just a built-in RenderScript kernels for common operations you cannot do nothing above the already implemented functions: ScriptIntrinsic3DLUT, ScriptIntrinsicBLAS, ScriptIntrinsicBlend, ScriptIntrinsicBlur, ScriptIntrinsicColorMatrix, ScriptIntrinsicConvolve3x3, ScriptIntrinsicConvolve5x5, ScriptIntrinsicHistogram, ScriptIntrinsicLUT, ScriptIntrinsicResize, ScriptIntrinsicYuvToRGB. They do not include functionality to rotate bitmap at the moment so you should create your own ScriptC script.

Try this code..
private Bitmap RotateImage(Bitmap _bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
_bitmap = Bitmap.createBitmap(_bitmap, 0, 0, _bitmap.getWidth(), _bitmap.getHeight(), matrix, true);
return _bitmap;
}
Use this code when select image from gallery.
like this..
File _file = new File(file_name);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap bitmap = BitmapFactory.decodeFile(file_name, options);
try {
ExifInterface exif = new ExifInterface(file_name);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
bitmap = RotateImage(bitmap, 90);
} else if (orientation ==ExifInterface.ORIENTATION_ROTATE_270) {
bitmap = RotateImage(bitmap, 270);
}
} catch (Exception e) {
e.printStackTrace();
}
image_holder.setImageBitmap(bitmap);

Related

Face Detection API- coordinates

So I am using the API to detect faces in images, and it is working well for me so far. I have not been able to figure out how to crop the image to the face however. I know how to crop the Bitmap, but it requires getting the top left position of the face in the Bitmap and width and height. When I query for the top left position using
points = face.getPosition();
Bitmap bmp = Bitmap.createBitmap(bit,(int)points.x,(int)(-1.0*points.y),(int)face.getWidth(),(int)face.getHeight());
But when I look at points, I notice that y is -63.5555 and x is 235.6666; I dont understand why there is a negative y coordinate. I did some Debugging and looked inside the face object; I found that it contained a PointF object already that had positive x and y coordinates. So why is a negative y coordinate being returned in this case?
The bounding box estimates the dimensions of the head, even though it may not be entirely visible within the photo. The coordinates may be negative if the face is cropped by the top or left of the image (e.g., the top of the head is cropped off the top of the picture, resulting in a y coordinate above 0).
The difference that you see in debugging is due to that fact that the implementation internally uses the head center position to represent the position (approximately at the mid-point between the eyes), but the API translates this to the top-left position when you call getPosition, for your convenience.
Also note that the bounding box is not necessarily a tight bounds on the face. If you want a tighter fit, you should enable landmark detection and compute your desired level of cropping relative to the returned landmarks.
I have used the same API before and was able to successfully crop the face.
Try
//Crop face option
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
//Bitmap bitmap = BitmapFactory.decodeFile(pictureFile.getAbsolutePath(), options);
Bitmap bitmap = getRotatedImageToUpload(pictureFile.getAbsolutePath());
Bitmap faceBitmap = Bitmap.createBitmap(bitmap, (int) faceCentre.x, (int) faceCentre.y, (int) faceWidth, (int) faceHeight);
FileOutputStream out = null;
try {
out = new FileOutputStream(getOutputMediaFile());
faceBitmap.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
// PNG is a lossless format, the compression factor (100) is ignored
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//End of Crop face option
And the code for getRotateImageToUpload is
public Bitmap getRotatedImageToUpload(String filePath) {
try {
String file = filePath;
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, bounds);
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm = BitmapFactory.decodeFile(file, opts);
ExifInterface exif = null;
exif = new ExifInterface(file);
String orientString = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
int orientation = orientString != null ? Integer.parseInt(orientString) : ExifInterface.ORIENTATION_NORMAL;
int rotationAngle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) rotationAngle = 90;
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) rotationAngle = 180;
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) rotationAngle = 270;
Matrix matrix = new Matrix();
matrix.setRotate(rotationAngle, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
Bitmap rotatedBitmap = Bitmap.createBitmap(bm, 0, 0, bounds.outWidth, bounds.outHeight, matrix, true);
return rotatedBitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

Rotate bitmap without outofMemoery exception on android

This is my code to rotate a image. Image is already down sampled and decoded. But this throws an exception because it creates an additional copy of the image. How can I generate the image safely?
public Bitmap rotateBitmap(Bitmap image, int angle) {
if (image != null) {
Matrix matrix = new Matrix();
matrix.postRotate(angle, (image.getWidth()) / 2,
(image.getHeight()) / 2);
return Bitmap.createBitmap(image, 0, 0, image.getWidth(),
image.getHeight(), matrix, true);
}
return null;
}

Rotating image decentres image using janmuller library

I am using janmuller android library to perform rotation of an image . On rotating it 90 degrees to the left or right the image is rotated , however it gets de centred on the screen . This is the code I have used from janmuller library
public void onRotateRight(View v) {
mBitmap = Util.rotateImage(mBitmap, 90);
RotateBitmap rotateBitmap = new RotateBitmap(mBitmap);
mImageView.setImageRotateBitmapResetBase(rotateBitmap, true);
mRunFaceDetection.run();
}
This is the rotateImage function
public static Bitmap rotateImage(Bitmap src, float degree) {
// create new matrix
Matrix matrix = new Matrix();
// setup rotation degree
matrix.postRotate(degree);
Bitmap bmp = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
return bmp;
}
public void onRotateRight(View v) {
mBitmap = Util.rotateImage(mBitmap, 90);
RotateBitmap rotateBitmap = new RotateBitmap(mBitmap);
mImageView.setImageRotateBitmapResetBase(rotateBitmap, true);
mRunFaceDetection.run();
}
I wonder why you have so much code. Especially i wonder that after having used rotateImage() on the bitmap you dont put it back in the imageview. There is so much code with rotate (why is that needed?) and reset base (what does that?) that it is difficult to say who is to blame when things go wrong. Better try with a normal ImageView first before you blame janmuller. More like this:
public void onRotateRight(View v) {
mBitmap = Util.rotateImage(mBitmap, 90);
mImageView.setImageBitMap(mBitmap);
}
That should be enough to test;
The function rotateImage() looks ok.

Getting OME while rotating Bitmap

I am trying to rotate Img(Bitmap), by the fallowing code. its working fine up to 5-6 rotations, after that am getting OME?
private void rotateImg() {
Matrix matrix = new Matrix();
matrix.postScale(curScale, curScale);
matrix.postRotate(curRotate);
try {
temp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(),
temp.getHeight(), matrix, true);
setImage.setImageBitmap(temp);
} catch (OutOfMemoryError e) {
curRotate = curRotate - 45.0f;
Toast.makeText( this,"Out Of Memory",Toast.LENGTH_LONG).show();
}
}
here "test" is an static bitmap file loaded from SDCard.
Why are you creating the bitmap every time? Is there any specific reason?
If not use the following code:
private void rotateImg() {
int cx = temp.getWidth() / 2;
int cy = temp.getHeight() / 2;
matrix.preTranslate(-cx, -cy);
matrix.postRotate(curRotate);
matrix.postTranslate(cx, cy);
setImage.setImageMatrix(matrix);
}
The first answer is probably one potential solution. The issue here is that you're creating a lot of Bitmap objects, which are fairly big, and they're not getting gc'd for whatever reason.
A better solution might be to use a single bitmap, and apply the rotation / scaling when you draw it. For example, if you were drawing on a Canvas that's part of a View, rotateImg could simply rotate the matrix and call invalidate on the view, and then in the view's onDraw method you'd use the void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint) on the canvas to render the bitmap. Docs are here.
Maybe you have to use bitmap.recycle() method each time you call this method. Try something like this,
private void rotateImg() {
Matrix matrix = new Matrix();
matrix.postScale(curScale, curScale);
matrix.postRotate(curRotate);
try {
temp.recycle(); //removes the memory occupied by this bitmap object
temp=null;
temp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(),
temp.getHeight(), matrix, true);
setImage.setImageBitmap(temp);
} catch (OutOfMemoryError e) {
curRotate = curRotate - 45.0f;
Toast.makeText( this,"Out Of Memory",Toast.LENGTH_LONG).show();
}
}

Android rotate bitmap 90 degrees results in squashed image. Need a true rotate between portrait and landscape

I am trying to rotate a bitmap image 90 degrees to change it from a landscape format to a portrait format. Example:
[a, b, c, d]
[e, f, g, h]
[i, j, k, l]
rotated 90 degree clockwise becomes
[i,e,a]
[j,f,b]
[k,g,c]
[l,h,d]
Using the code below (from an online example) the image is rotated 90 degrees but retains the landscape aspect ratio so you end up with a vertically squashed image. Am I doing something wrong? Is there another method I need to use? I am also willing to rotate the jpeg file that I'm using to create the bitmap if that is easier.
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
matrix.postRotate(90);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOriginal, 0, 0, widthOriginal, heightOriginal, matrix, true);
This is all you need to rotate the image:
Matrix matrix = new Matrix();
matrix.postRotate(90);
rotated = Bitmap.createBitmap(original, 0, 0,
original.getWidth(), original.getHeight(),
matrix, true);
In your code sample, you included a call to postScale. Could that be the reason your image is being stretched? Perhaps take that one out and do some more testing.
Here's how you would rotate it properly (this insures proper rotation of the image)
public static Bitmap rotate(Bitmap b, int degrees) {
if (degrees != 0 && b != null) {
Matrix m = new Matrix();
m.setRotate(degrees, (float) b.getWidth() / 2, (float) b.getHeight() / 2);
try {
Bitmap b2 = Bitmap.createBitmap(
b, 0, 0, b.getWidth(), b.getHeight(), m, true);
if (b != b2) {
b.recycle();
b = b2;
}
} catch (OutOfMemoryError ex) {
throw ex;
}
}
return b;
}
This code worked great for me:
Matrix matrix = new Matrix();
matrix.setRotate(90, 0, 0);
matrix.postTranslate(original.getHeight(), 0);
rotatedBitmap = Bitmap.createBitmap(newWidth, newHeight, original.getConfig());
Canvas tmpCanvas = new Canvas(rotatedBitmap);
tmpCanvas.drawBitmap(original, matrix, null);
tmpCanvas.setBitmap(null);
check the canvas size where you draw the bitmap, maybe your canvas is still landscape, so only the square part of the rotated bitmap could be seen.

Categories

Resources