Lossless image rotation - java

I'm currently trying to implement a rotate feature in my app wich is playing with images.
The feature would allow the user to rotate an image -90 and +90 degree (switching landscape/portrait mode)
Here is my code :
public Bitmap rotateRight(Bitmap bm) {
Matrix matrix = new Matrix();
matrix.postRotate((float)90);
Bitmap nbm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
nbm.setDensity(bm.getDensity());
return nbm;
}
After that, i save the image to the filesystem.
This work perfectly but the problem appears if i try to rotate 5 or 6 times the same image. The image quality will decrease and I will finally have a very ugly image to show...
Could you help me ?
Thank you in advance !

First: the last parameter in createBitmap() is whether to filter the resulting bitmap. As it is set to true, every time you perform this action your bitmap will become slightly more "blurred". As you do not change the size of the Bitmap, you might want to turn this off.
Secondly: make sure you save the image as a lossless format, such as PNG. If you save as JPG or another lossy format you will always reduce quality with each save, even if you set quality parameters to highest.

Related

Applying Effects to HD Images

I am developing an app that deals with images and applying filters, borders etc to the image..(like photo editing app).
I am facing issue when applying filters or borders to HD images (as images will be of different size and resolution).
My Question is how do I apply filters without changing the size or dimension of the Image.
Please help regarding this, Thanks in advance.
As I mentioned in the comment section of the Code, for smaller size images getDrawingCache is returning a value, but for the bigger size images it is returning null.
public Bitmap getBorderAppliedBitmap(PorterShapeImageView imgView , GPUImage gpuImage)
{
Bitmap bmp = gpuImage.getBitmapWithFilterApplied();
imgView.setImageBitmap(bmp);
imgView.setDrawingCacheEnabled(true);
imgView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
imgView.layout(0, 0,
imgView.getMeasuredWidth(), imgView.getMeasuredHeight());
imgView.buildDrawingCache(true);
Bitmap bmap = Bitmap.createBitmap(imgView.getDrawingCache());
<!-- getting null from the method imgView.getDraingCache() only for the bigger size Images -->
imgView.setDrawingCacheEnabled(false);
return bmap;
}
What you must be facing is limited Android resources issue for Image Processing techniques. The best advice for you would be to shift towards NDK and write image filters in JNI using OpenCV .
It is the best option for faster results in HD images. Any how there must be a boundary to the resolution to which an image can be processed because all professional apps create their own boundary parameters.

How to convert an indexed image to a RGB image in Java?

I have a color indexed TIFF image (8-bits) and I want to convert it to a RGB 24-bits image (not indexed). What would be the way to do that?
I'm using JMagick. In a weird way, it works fine for indexed 8-bits images that are grayscale when i use:
image.transformRgbImage(info.getColorspace());
even if the image, though not indexed any more, is still 8-bits after that, which is lucky as it is grayscale and should actually be 8-bits. The weird stuff is that the transformRgbImage() performs that although I'd rather expect it to convert the image to a 24-bits one. Anyway...
The same way doesn't work for a color indexed 8-bits image. I just don't know how to use the JMagick API to achieve that goal. I tried setting:
image.setDepth(24);
or:
info.setDepth(24);
but both result in an EXCEPTION_ACCESS_VIOLATION. When I set:
info.setDepth(32);
no exception is raised, 1) but the image is 32-bits, which shouldn't be, and 2) it is all black (1 unique color). Why does the setDepth(24) raises such an exception?? How should I do?
Thanks in advance for your help.
I dont know about jmagick, but generally once you created an image object its properties are fixed (size and color model).
You don't change an images properties, you create a new image with the desired target properties and paint your original image into the new image. In plain core java you would simply do it like this:
public BufferedImage toRGB(Image i) {
BufferedImage rgb = new BufferedImage(i.getWidth(null), i.getHeight(null), BufferedImage.TYPE_INT_RGB);
rgb.createGraphics().drawImage(i, 0, 0, null);
return rgb;
}

Image Resize UpScale lost Quality

I want to try up scale image up to 3 times.
For example,
Up Scaled Image
I am using this library for Image Resizing.
The following code snipped does the trick,
public static BufferedImage getScaledSampledImage(BufferedImage img,
int targetWidth, int targetHeight, boolean higherQuality) {
ResampleOp resampleOp = new ResampleOp(targetWidth, targetHeight);
resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Normal);
BufferedImage rescaledImage = resampleOp.filter(img, null);
return rescaledImage;
}
You can see there a resized images are lower quality. I want that I can up scale images at least 3 times than the original image without quality lost.
Is it Pposible? Should I need to change existing library ?
Thanks
The fact is that when you scale an image up, it has to create data where there was none. (Roughly speaking). To do this, you have to interpolate between the existing pixels to fill in the new ones. You may be able to get better results by trying different kinds of interpolation - but the best method will be different for different kinds of images.
Since your sample image is just squares, nearest-neighbour interpolation will likely give you the best results. If you are scaling up an image of scenery or maybe a portrait you'll need a more clever algorithm.
The result will rarely look perfect, and it's best to start with a larger image if possible!
Take a look here to get an understanding of the problem. http://en.wikipedia.org/wiki/Image_scaling#Scaling_methods

Android OCR tesseract: using data from Pixa objects to display bounding boxes

I am currently playing around with OCR on android. Therefore I wrote a small app with a Camera preview and now I am feeding tessearact tools (tess-two) images from my onPreviewFrame method. Now I want to display the bounding rectacles from the OCR on my Camera Preview. The TessBaseAPI provides methods that return character/word bouding boxes. The type of the returned object is Pixa, as in the leptonica library provided with tess-two.
So my Question is: How do i get usable coordinates which I can use to draw the bounding boxes on my camera preview from the Pixa objects returned by getCharacters() or getWords() from the TessBaseAPI?
GetCharacters() and getWords() in the BaseAPI
leptonicas Pixa class
Important:
Because the previews only supported image-format is YUV N21 and as far from what I have read the tess-API requires ARGB_8888 Bitmaps I have the following workaround in my onPreviewFrame method right before i feed the bitmap to the TessAPI: (I am also rotating by 90 degrees clockwise because I am using the camera in portrait orientation, but the cameras preview frames come in landscape)
//byte[] bmpdata <- the image in a byte array (NV21 Imageformat) in onPreviewFrame
YuvImage yuvimage = new YuvImage(bmpdata,ImageFormat.NV21,width,height,null);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Rect rect = new Rect(0, 0, width, height);
yuvimage.compressToJpeg(rect, 100, outStream);
Bitmap bmp = BitmapFactory.decodeByteArray(outStream.toByteArray(),0,outStream.size());
Matrix mtx = new Matrix();
mtx.preRotate(90);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mtx, false);
bmp = bmp.copy(Bitmap.Config.ARGB_8888, true);
TessTBaseApi.setImage(bmp);
So basically, I compress the NV21 byte[] I got from the camera into a YuvImage, then into a jpeg, and from there into a bitmap. I searched the web alot for the solution on how to get bitmap/jpeg from the NV21 array and this was the easiest i found. This bitmap will be fed to tesseract tools OCR. This brings me to my second question:
How, after these compressions and 90 degree rotation, do I locate where I have to draw the boxes on screen? (relative to before the compressions and the rotation)
This might not be the best or even a good way to supply the OCR with live frames, I appreciate very much comments, other solutions or suggestions of ways of optimzation.
I started this Project two days ago and am a very beginner in programming for android and ocr. During these two days this page helped me alot and answered questions I had so far very well, so thanks for that and thank you in advance for helping me with my current problem. If you would like to see more code or have questions, I will supply and be glad to answer anything I can.
Greetings
You can browse trough the whole API sourcecode on github trough the Pixa class and GetCharacters() links, cant insert more hyperlinks.
TessTBaseApi.getWords().getBoxRects() will return an ArrayList of bounding box Rects with coordinates relative to your bmp bitmap.

Multitouch gestures and Images in Android

I need to display a very big image (8000x8000 for example) in a view allowing the user to zoom in and out.
I have checked several options for detecting the user touches and transform the image according to that. For example:
How to use Multi-touch in Android
And others using gesture/touch detectors, etc.
The problem is that none of them takes care of the Bitmap size and the posible crashes because the Bitmap doesn't fit in the memory.
So what I'm looking for is how to implement that like the Android's Gallery does. Without lose quality when the image is zoomed in and of course without crashes
Any ideas? Complete, working answers will be bountried with up to 300 points depending on the complexity and quality of the answer
Try showing only a scaled subset of the bitmap and decode as few as possible. I managed something similar to this. These are the code snippets which helped me a lot:
To calculate all values you need (e.g. scale factor, number of pixels etc.) you can use inJustDecodeBounds to get the size of the bitmap without allocating any memory.:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, opt);
int width = opt.outWidth;
int height = opt.outHeight;
To decode only a subset of a bitmap use this:
Bitmap.createBitmap(
source,
xCoordinateOfFirstPixel,
yCoordinateOfFirstPixel,
xNumberOfPixels,
yNumberOfPixels
);
To create a scaled bitmap:
Bitmap.createScaledBitmap(
source,
dstWidth,
dstHeight,
filter
);
To draw a subset of a bitmap:
Canvas.drawBitmap(
source,
new Rect(
subsetLeft,
subsetTop,
subsetRight,
subsetBottom
),
new Rect(0,0,dstWidth, dstHeight),
paint
);
Edit:
I forget to mentioned this snipplet for creating scaled images. To save memory this is what you want:
BitmapFactory.Options opt = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap scaledBitmap = BitmapFactory.decodeFile(path, opt);
Since inSampleSize must be an integer I used createScaledBitmap to adjust the bitmap a bit more.
http://www.anddev.org/large_image_scrolling_using_low_level_touch_events-t11182.html
Possibly?
the sites down at the moment, so it may not even be relevant to you in the end, but i thought i should post it.
also
" ZOOM CONTROL (Widget) listen to the OnTouch event to handle the panning "
finally:
https://github.com/MikeOrtiz/TouchImageView
^^ might be EXACTLY what your looking for as far as i know 2.0+
failing that, a webview and load the file like that.

Categories

Resources