Differences between Bitmaps and BufferedImages - android

I am trying to port some code from a regular Java program into the Android platform. Unfortunately, a significant part of the program involves manipulating images, and Java's AWT was taken away from me. I am trying to replace awt.BufferedImage with Bitmap, and was hoping that the only differences between the two classes would be their interfaces. I read some of the documentation, and it looked like that is true, but after wrapping all of the image stuff into a nice little class and testing almost-the-same code on both my development machine and an actual phone, one program works and the other does not. So:
The encoding for color does not change - right? It is still 0xAARRGGBB - right?
The images themselves are not changed - right? When I put an image into res/drawable, it is exactly the same image. Most notably, they don't alter the resolution in any way - right?
Accessing the pixels is essentially the same - right? I essentially replaced all of my get/setRGB(x,y,RGB) with get/setPixel(x,y,color). There are no changes to the method of indexing into the grid - is there?

Solved: when opening the image, I failed to create a BitmapFactory.Options() with inDither set to false. The BitmapFactory then failed to produce an exact copy, putting some alterations in the resulting Bitmap in order to make it more pleasing for display.

Related

Opencv4Android,stitching two images

I have to stitch two images and I use openCV4Android.I read docs and some threads in about stitching images,for example: Panorama – Image Stitching in OpenCV , Homography between images using OpenCV for Android , Stitch multiple images , Error matching with ORB in Android and others.At first,it seems easy.But the result is strange!Below,you can see two images that I used for test and result:
Here is "image1":
This is "image2":
You can see drawed features:
And this is result of warping image1:
What I did wrong?Or it may be I did not understand good?
Quick answer:
I would say that you don't have enough overlap between your images. If you look at your matches (what you call "drawed features"), most of them are wrong. As a first test, try to stitch two images that have, say, 80% overlap.
More details:
Big picture:
When you stitch two images, you assume that there exists an affine transform (your "homography") that will project features from one image onto the other one. When you know this transform, then you know the relative position of your images and you can "put them together". If the homography transform that you find is bad, then the stitching will be bad as well.
How do we find the homography transform, then?
First of all, you detect features (with your FeatureDetector) on both images.
Then, you describe them (with your DescriptorExtractor). Basically this creates a representation of your features, so that you can compare two features and see how similar they are.
You match (using your DescriptorMatcher) features from the first image to the features from the second image. It means that for each feature in the first image, you try to find the most similar one in the second image. Those are your "drawed features".
From those matches, you use an algorithm called "RANSAC" to find the homography transform corresponding to your data. The idea is that you try to find a set of matches from all your "drawed features" that makes sense geometrically.
But why doesn't it work here?
If you look at your "drawed features", you will see that only a few ones on the "Go" part of "Google" and some in the boorkmarks correspond, when the others are wrong. It means that most of your matches are bad, and then it makes it possible to find a homography that works for this data, but that is wrong.
In order to have a better homography, you would need much more "good" matches. Consequently, you probably need to have more overlap between your images.
NOTE: try your code with the images used in "Panorama – Image Stitching in OpenCV"

Memory management when changing src for ImageView

I am still new to Android, and never had to deal with memory management in my previous experience.
In my android application, I have an activity with a TextView, a ListView, and ImageView. I have listeners for the textview and listview, and the code that changes the contents in all three of those views. The contents is stored in the arraylist. The source for the ImageView is stored in form of a String (filenames), and the code that makes the changes looks like this:
tv1.setText(myText);
imgView.setImageResource(myImage);
This worked perfectly well while I only had a few images to test the logic, but once I added more images, I started to get the OutOfMemory error. If I make the images smaller, I get that error a little later in the process, but I still get it.
At first, I thought that Android does not release the previous source, so I thought using recycle() before the reassignment will help. Instead, I've got another error when I try to change the source:
Cannot draw recycled bitmaps
It looks like I am missing some vital understanding about how the ImageView handles the source images. Does it assign the bitmap reference and then keeps the same reference, but somehow changes content?
Then, after reading this article, I realized I have a different kind of problem altogether, the one that might be solved by using the inBitmap. Yet, the documentation says the bitmaps have to be the same size for that, and mine are not.
I am thinking of converting my drawable to bitmap, then scaling it to some hard-coded dimensions, then using inBitmap. I guess my second question is - does this approach make sense? Are there any downfalls in scaling the images? And any examples would be appreciated, of course.
Thank you!

Android OutOfMemory exception - Is there another approach for my needs?

My app is loading a large image (a house floorplan), then drawing touch-reactive objects (furniture, lamps etc.) on the image. I have a base image file included with my app but the objects come from coords in my database.
I've successfully deployed the app in multiple iterations, but now I need to use larger base images and BitmapFactory is causing an OutOfMemory exception on many devices (both old and new devices; anything with < 32MB heap seems to crash). I've read the 157 OOM questions on SO, but I'm afraid the link they all seem to point to won't help me since resolution / zooming is critical to the app's function.
I've tried to test the device's available memory before loading, but the results are spotty at best (some devices like the galaxy S3 report plenty of heap but still crash). I've also tried decreasing resolution but the image became unusable when reduced to a safe size based on the above test.
Is there another way to implement this design without ever using bitmaps?
I need to:
Load large base image
Create clickable shapes on top of the base image, maintaining their position / scale relative to the base image
BONUS: in the iOS version of my app, I can do SVG-style text scaling so a long label on a small object will stay inside the object
instead of running across the map(and will be invisible until the
image is zoomed). Replicating this in android would make me a happy
code monkey.
I can post code if needed, but you've all seen it before (almost all of it came from SO).
Thanks in advance for reading, and for any help you can give.
you have a few options:
break your large image into tiles, load these tiles into an array, and move a camera object around and only load tiles that need to be drawn, as the comments suggest.
make your image small and scale it up using 'android:scaletype`
Draw lines and curves on a Canvas object at runtime.
Use OpenGL
The appropriate solution really depends on how you want it to look. Tiling will take more dev effort but will look better, just be careful that you are properly cleaning up any tiles that aren't being drawn...
dynamically scaling will be easier, but you cannot guarantee the image won't be blurry.
Drawing on a Canvas object at runtime could work well-- just use Lines of different width and circles and Rects etc.
Using OpenGL will have the steepest learning curve, and might be overkill. This depends on your purpose.
You might like to look into using a "largeHeap"
http://developer.android.com/reference/android/R.styleable.html#AndroidManifestApplication_largeHeap
Here are some options:
1) Use tiles. Use tiles and dynamically load your data. Honestly, this is the best solution. With this solution you can load arbitrarily large images.
I've successfully used this approach for an endless paint canvas and it works quite well. You really only need to draw what is directly visible to the user. Tiles is a way to cast away pieces you don't need. A pyramid of tiles (where you pre-downsample your images and create more tiles), allows you to do this in a clean and fast way.
2) Use native code. The memory restrictions on native code are not the same as Java code. You can get away with allocating more memory.
3) Use OpenGL. Once again, the memory restriction for OpenGL are not the same as Java code.
4) Convert your original plan to an SVG and use an SVG library like this one.
5) Use "largeHeap". I strongly discourage this, as I think a largeHeap is rarely the solution, there are generally cleaner ways to approach the problem.
if the image is static , you might wish to use this nice library:
https://github.com/ManuelPeinado/ImageLayout
if the library doesn't support auto-downsampling of the image, you should do it by yourself, in order to use the best image for the current device (so that you won't get OOM).
for auto-sizing text , you might have some luch with the next post:
Auto-fit TextView for Android

Text and Fonts with Canvas in Android using OpenGL

I'm using the code outlined in the following post:
Draw text in OpenGL ES
I thought I could use this technique in order to dynamically display text (say an FPS counter). I realised that calls to resources to get the drawable slows down this process quite a lot, and I didn't need a bitmap background, so I removed it.
The technique works, but after a while (~2000 frames) the whole phone locks up. I suspect there's some memory which is not being freed in this code but I don't know where. I tried offloading the Canvas, Paint and Bitmap object creations which worked (so they aren't created every single frame) but the same problem still occurs.
I suspect therefore, that the generated GL texture is to blame, but I'm unsure how to remove it, or if this is even the case.
Any help would be appreciated.
EDIT: As an alternative, can someone please point out an easy way to render text to the screen dynamically (e.g. should be able to render the # of frames since starting for example, continually being updated and increasing). All the ways I can think of are either extremely tedious (make individual quads for each digit, store the textures for 0-9 in memory, parse the number and render each digit onto each quad), cannot be updated in good time (overlay Views) or can't get the required positioning in the glSurfaceView.
CBFG - http://www.codehead.co.uk/cbfg
This really is exactly what I've been wanting. You build a bitmap file from a font file using CBFG which can then be loaded and displayed with only a few lines of code (after importing his packages). It's literally as easy as fnt.PrintAt(gl,"Hello world!", 50, 160); in onDraw and more importantly, it handles dynamic text really well. I strongly advise anyone who is the same situation to try this.
two things I can guess you'll want to try:
1) dont' recreate the number of your frs every frame, generate number 1 to 60 and always reuse those.
2) there is an issue I found when generating text for my textures is that the font loader code of android never frees the memory space so avoid loading the font all the time, do it once and store a reference to it
I just wrote an entire tutorial on creating exactly what you are looking for.
The idea is basically to use font files and then generate a font bitmap (or atlas) at run-time instead of using a tool like CBFG to generate it offline. The benefit of this is that you can ship a small font file instead of multiple large bitmaps with your app, and never have to sacrifice font quality by using scaling.
The tutorial includes full working source (that can be dropped into any project). If you are interested go have a look here.

Split GIF into frames

Trying to play animated GIFs on Android here (see Android: How do a display a large animated gif given a url?). It's anything but smooth. On Android 1.5, the Movie.decodeStream()/decodeFile() returns a null. On Android 1.6, with the GIF files I've got, it returns a zero-sized movie with zero duration - clearly not adequate.
The referenced question suggests splitting the GIF into frames (and then rendering these). How exactly do i accomplish that, please?
EDIT: tried opening one of my GIFs with GNU giflib in Windows. It choked on the very first frame. The GIF itself is all right, all browsers (save Android's) display and animate it fine.
EDIT2: worked with giflib 4.1.4. Not sure what was broken in 4.1.6, but there you go. Next step: build giflib for Android via NDK, somehow integrate with the Bitmap class.
EDIT3: giflib it is. In conjuction with Bitmap.copyPixelsFromBuffer. The colors are all askew right now, but the basic design seems workable.
EDIT: I've migrated my project to Google GifFileDecoder, slightly patched. The MovieView class from the legacy solution remained mostly intact, but the GIF parsing logic is in Java.
Couple points of interest:
GifFileDecoder does its own looping. If the animation is looped and you do readFrame() until there are no more frames, this loop will be infinite; the decoder has its own wrap-around logic. Also, the buffer that readFrame() returns is being reused over and over, so don't store the result of readFrame as it is, next time you call readFrame it will be overwritten. Make a deep copy instead. Also, the decoder assumes reading from a file, but can be trivially modified to read from any other stream, sacrificing the looping logic.
Here's the 10 year old answer, for old times' sake:
giflib 4.1.4 and NDK. You have to manually resolve the palette colors in the GIF to match one of Android's ARGBxxxx formats, then pass the pixel array to a Bitmap object via copyPixelsFromBuffer(). If you want transparency and/or animation, you have to go through extension blocks and look for the one with code 0xf9.
Shared my code, along with guidance, here: http://rathertech.blogspot.com/2014/04/splitting-gif-into-frames-on-android.html

Categories

Resources