I'm making an Android live wallpaper using OpenGL.
I would like to let the user pick an image to use for the background. Can someone give me any advice on an easy way to do this?
I know that I need to down sample bitmaps before loading them to avoid using huge amounts of memory for large bitmaps.
I also know OpenGL only supports texture sizes that are powers of two. It looks like messy work having to calculate the down scale factor then calculate the closest good texture size and then scale a quad with that texture appropriately to the screen.
It would also be nice to have the wallpaper panning feature when homescreens change.
Is there any easier way than doing all of the above myself? If not, is there sample code available for what appears to be a very common task?
Related
I am new to computer vision but I am trying to code an android app which does the following:
Get the live camera preview and try to detect one logo in that (i have the logo in my resources). In real-time. Draw a rect around the logo if found. If there is no match, dont draw the rectangle.
I already tried a couple of things including template-matching and feature detection using ORB.
Why that didnt work:
Template-matching:
Issues with scaling and rotation. I tried a multi scale variant of it but a) the performance was really bad and b) the rectangle was of course always shown trying to search for the image. There was no way to actually confirm in the code if the logo was found or not.
ORB feature detection:
Also pretty slow (5-6 fps) but it worked ok-ish. The other problem was that also i never could be sure if the logo was in the picture or not. ORB found random matches even if the logo was not in the picture.
Like I said, I am very new to this. I would appreciate the help on what would be the best way to achieve:
Confirm if a picture A (around 200x200 pixels) is in ROI of camera picture (around 600x600 pixels).
This shouldnt take longer than 50ms per frame. I dont know if thats even possible though. So if a correct way to do this would take a bit longer than that, I would just do the work in a seperate thread and only analyze like every fifth camera frame or so.
Would appreciate any hints or code examples on how to achieve that. Thank you!
With logo detection, I would highly recommend using OpenCV HaarClassifier. It is easy to generate training samples from a collection of images of the logo, or one logo image with many distortions.
If you can use a few rules like the minimum and maximum size of the logo to be detected, and possible regions on the image where it can appear, you can run the detector at a speed better than you mention with ORB.
Just started learning graphics in Android Studio and started out by making a growing graph(x^2). It turned out pretty well, but it goes out of the bitmap box quite fast and I was wondering if it is possible to start scaling it while it tries to grow outside the boundaries.
Here is a good example of what I mean. Whenever the graph line starts to exit the boundaries of the box, all the graph starts to scale.
Is that possible to do with bitmap or any other way in Android Studio? And if so, then how?
This is pretty open ended but IMO this all depends on what you're trying to do and how big everything can scale.
Typically what I would say is that your bitmap shouldn't scale up, your graph should scale down. This keeps the memory footprint of the bitmap small which will be important to run on low memory devices. IMO you should use paths and then draw them on your canvas and change the stroke to make them smaller as needed. Then they can scale up and it wont matter if it draws offscreen as it's not actually making the bitmap bigger. To learn how to do that you should check out Google's documentation!
If you want to use a bitmap then You should read the suggestions here as well. Also you'll probably have to get into tiling/region decoding in order to load everything efficiently when zooming in on the image:
I have a very large hi-res map which I want to use in an application (imagesize is around 80 mb).
I would like to know the following:
How can I load this image the best way possible? I know it will take some seconds to load the image (which is ok) but I would like to notify the user of the progress. I would like to use a determined mode and show this in some sort of JProgressBar to the user. This should reflect the number of bytes that have been loaded or something like that. Is there any Image loading method that can provide this functionality (like ImageIO.read())?
Because the map is of very high resolution I would like to offer the user to scroll to zoom in and out. How can I do this the best way? I know for a fact that rescaling a BufferedImage the standard way would take a VERY long time for such a big file. Is there any efficient way of doing this?
Thank you for your input!
kind regards,
Héctor van den Boorn
p.s. The image will be drawn on the canvas of a JPanel.
Hi Andrew, Thank you so much for your help; everything worked out perfectly and is loading quick.
Without your expertise and explanation I would have still been working on this so you've earned the bounty fair and square.
What I did was the following; using the imagemagick I created multiple images of different resolution and at the start of execution I load only the smallest res. image. The rest are loaded in seperate threads so execution is not stalled. Using the information you provided me I then use the appropriate images when zooming in or out. I'm a bit sceptical of using the tiles because I need to draw my own images on top of the map and I couldn't find the paint function in the external jar you told me to use, so I ended up using something simple; when zooming or panning the rescale mode is set to fast and when you're not zooming or panning the rescale is set to smooth for pixel-perfect images (just like you suggested), but this turns out to be fast enough and I don't need tiles (altough I do see that with even larger images this would be necesarry and I understand the information you've given me).
So thanks again and everything is working perfectly :)
There are two approaches you should (simultaneously) take:
Downscaling your image into various sizes. You should downscale your image at a series of lower resolutions (1/2, 1/4, 1/8, etc until the image is about the largest likely screen resolution). When the user first opens the image, you show the lower resolution image. This will load fast and allow the user to pan. When the user zooms in, you use a higher resolution image. You can use ImageMagick for this: http://www.imagemagick.org/Usage/resize/
Tile your larger images. This breaks down the single, large image into a large number of small images in a grid pattern. When a user zooms in on an area, you compute which tiles the user is looking at, and you render only them, not the other areas of the image. You can use ImageMagick to do split an image into tile, eg ImageMagick. What is the correct way to dice an image into sub-tiles. The documentation is http://www.imagemagick.org/Usage/crop/#crop_tile
(Providing a cache of appropriately sized and tiles images is what allows GoogleEarth and countless other mapping applications, to render so fast, yet zoom into the map at incredibly high resolution)
Once you have your tiles, you can use one of several engines in Java:
https://wiki.openstreetmap.org/wiki/Tirex
http://www.slick2d.org/wiki/index.php/Tiled
There may be others as well.
You can implement arbitrary zooming (suitable for pinch-to-zoom or similar) within this framework. Within the zoom limits you allow, your algorithm would be something like:
For the zoom level chosen by the user, choose the closest higher resolution cache. For example, if you have 100%, 50%, 25% and 12.5% tiles, and the user chooses 33% zoom, select the 50% tiles
Set the layout for the tiles so the tile squares have the correct size for the chosen zoom (this might be a single tile at lowest zoom levels). For example, at 33% zoom using 50% tiles, with the tiles being 100 pixels square, the grid will be 67 pixel squares
Individually load and scale the tile images to fit the screen (this can be multi-threaded which works well on modern CPU architectures)
There are a couple of points to note:
The scaling algorithm changes when you reach the greatest resolution you have tiles for.
Up to 100% zooming for the image, use bilinear or bicubic scaling. This provides excellent appearance for photographs with little jaggedness
Above 100%, you probably want to show the pixels, so nearest-neighbour might be a good choice
For higher fidelity, use a higher scale tile and downscale > 50%. For example, suppose you have tiles prepared at 100%, 50%, 25% and 12.5%. To show 40% zoom, don't scale down the 50% tiles; instead use the 100% tiles and scale them down to 40%. This is useful:
If your images are textual or diagrams (i.e. the raster images containing many straight lines). Scaling these type of images will often produce nasty artefacts if you don't oversample
If you need very high fidelity on photographic-style images
If you need to render a preview of the zoom (eg while the user is still pinching-and-zooming), grab a screenshot at the start of the gesture and zoom that. It matters much more that the animation is smooth than the zoom preview is pixel-perfect.
Selection of the right size of tile is important. Very large tiles (<1 per screen) is slow to render. Too small tiles creates other overheads and often produces nasty rendering artefacts where you see the screen filling up randomly. A good compromise between performance and complexity is to make the tiles about a quarter of the full-screen size.
When using these techniques, the images should load very much faster and so the progress bar is not so important. If it is, then you need to register a IIOReadProgressListener on the ImageReader:
ImageReader.addIIOReadProgressListener()
From the JavaDoc:
An interface used by ImageReader implementations to notify callers of their image and thumbnail reading methods of progress.
This interface receives general indications of decoding progress (via the imageProgress and thumbnailProgress methods), and events indicating when an entire image has been updated (via the imageStarted, imageComplete, thumbnailStarted and thumbnailComplete methods). Applications that wish to be informed of pixel updates as they happen (for example, during progressive decoding), should provide an IIOReadUpdateListener.
I am developing a game on android.Like tower defense.
I am using surface view.I am using some image as bitmap.(Spritesheets, tilesets, buttons, backgrounds,efects vs.)
Now images are nearly 5-6 mb.And i get this error when i run my game:
Bitmap size exceeds VM budget
19464192-byte external allocation too large for this process.
I call images like that
BitmapFactory.decodeResource(res, id)
and i put it to array.
I can't scale images.I am using all of them.
I tried that
options.inPurgeable=true;
and it work but the image is loading very slowly.I load a spritesheet with that and when it is loading, i get very very low fps.
What can I do?
I've had this problem too; there's really no solution other than to reduce the number/size of bitmaps that you have loaded at once. Some older Android devices only allocate 16MB to the heap for your whole application, and bitmaps are stored in memory uncompressed once you load them, so it's not hard to exceed 16MB with large backgrounds, etc. (An 854x480, 32-bit bitmap is about 1.6MB uncompressed.)
In my game I was able to get around it by only loading bitmaps that I was going to use in the current level (e.g. I have a single Bitmap object for the background that gets reloaded from resources each time it changes, rather than maintaining multiple Bitmaps in memory. I just maintain an int that tracks which resource I have loaded currently.)
Your sprite sheet is huge, so I think you're right that you'll need to reduce the size of your animations. Alternatively, loading from resources is decently fast, so you might be able to get away with doing something like only loading the animation strip for the character's current direction, and have him pause slightly when he turns while you replace it with the new animation strip. That might get complicated though.
Also, I highly recommend testing your app on the emulator with a VM heap set to 16mb, to make sure you've fixed the problem for all devices. (The emulator usually defaults to 24mb, so it's easy for that to go untested and generate some 1-star reviews after release.)
I am not a game dev however I would like to think I know Android enough.
Loading images of the size is almost certain to throw errors. Why are the images that file size?
There is an example at http://p-xr.com/android-tutorial-how-to-paint-animate-loop-and-remove-a-sprite/. If you notice he has an explosion sprite of only ~200Kb. Even a more detailed image would not take much more file space.
OK some suggestions:
Are you loading all your spritesheets onto a single sheet or is
each spritesheet in a seperate file? If they are all on one I would
split them up.
Lower the resolution of the images, an Android device is portable
and some only have a low resolution screen. For example the HTC
Wildfire has a resolution of 240x320 (LDPI device) and is quite a
common device. You have not stated the image dimensions so we can't be sure if this is practical.
Finally; I am not a game programmer but I found this tutorial (part of the same series) quite enlightening - http://p-xr.com/android-tutorial-2d-canvas-graphics/. I wonder if you are applying a pattern that is not appropriate for Android, however without code I cannot say.
Right something a little off topic but worth noting...
People under estimate the power of the View. While there is a certain amount of logic to using a SurfaceView, the standard View will do quite a lot on its own. A SurfaceView more often than not requires an underlying thread to run (that you will have to setup yourself) in order to make it work. A View however calls onDraw(), which can be utilized in a variety of ways including the postinvalidate() method (see What does postInvalidate() do?).
In any case it might be worth checking out this tutorial http://mindtherobot.com/blog/272/android-custom-ui-making-a-vintage-thermometer/. Personally, it was an excellent example of a custom View and what you can do with them. I rewrote a few sections and made a pocket watch app.
I'm writing a game in Java, LJGWL (OpenGL). I'm using a library that handles a lot of messy details for me, but need to find a lot faster way to do this.
Basically I want to set every pixel on the screen to say a random color as fast a possible. The "random colors" is just an Array [][] that gets updated every 2-3 seconds. I've tried drawing rects and using images, both are pretty slow for what I want to do.
I think I want to learn how to write a GPU shader? That is the fastest way to do this? LJGWL exposes OpenGL api to java. Any basic tutorials on how to get started with OpenGL shaders? Or should I dynamically create a texture of some sort and then just throw up the entire texture, would that be faster?
If it were the case that you were statically displaying the same image, than using a texture or display list would suffice. But as you want to frequently update it, shaders really are the best option. Shader code executes on the GPU and modifies data in GRAM, so you have no bottle neck transferring from CPU to GPU. The next best thing would probably be a Pixel or Frame Buffer Object. Buffer Objects let you read/write to GRAM via DMA (without having to go through the CPU) so they can be pretty fast.
I haven't written any shaders yet, so I can't recommend any good resources. But SongHo's OpenGL pages are a good place to learn about Buffer Objects. (His examples are in C++ though)
Textures are the fastest way to draw something on screen, draw a texture mapped quad into the screen, it should be fast enough. When you need to reupload the texture data, use glTexSubimage2D to update it.
No need to use shaders.
I've yet to do any work with shaders in OpenGL, but given the same scenario in multiple occasions, I handled it with a texture I threw up across the screen on top, and it worked quite effectively.
I don't know how you are drawing your pixels exactly, but this limit you hit could be because of the amount of data you transfer (inefficiently?). Updating a screen full of pixels every 2-3 seconds shouldn't be hard at all. Although shaders bring you closer to the graphics card, they will never make inefficient methods fast, so...
Why is your code so slow?
What code? What code exactly did you try? What texture did you use, render to, ...?
Is it slow? How slow? How fast do you expect it to be?
How quickly can one get 1920x1080(?) pixels in video ram, what's your hardware, drivers, OS?
I think you need to edit/repost before we can help you solve your problem. Just because it is slow, is no guarantee at all that shaders will even be one bit faster.