Currently in an Android application that I'm developing I'm looping through the pixels of an image to blur it. This takes about 30 seconds on a 640x480 image.
While browsing apps in the Android Market I came across one that includes a blur feature and their blur is very fast (like 5 seconds) so they must be using a different method of blurring.
Anyone know a faster way other than looping through the pixels?
Android Blur Guide 2016
with Showcase/Benchmark App and Source on Github. Also check out the Blur framework I'm currently working on: Dali.
After experimenting a lot I can now safely give you some solid recommendations that will make your life easier in Android when using the Android Framework.
Load and Use downscaled Bitmap (for very blurry images)
Never use a the full size of a Bitmap. The bigger the image the more needs to be blurred and also the higher the blur radius needs to be and usually, the higher the blur radius the slower the algorithm.
This will load the bitmap with inSampleSize 8, so only 1/64 of the original image. Test what inSampleSize suits your needs, but keep it 2^n (2,4,8,...) to avoid degrading quality due to scaling. See Google doc for more
Another really big advantage is that bitmap loading will be really fast. In my early blur testings I figured that the longest time during the whole blur process was the image loading. So to load a 1920x1080 image from disk my Nexus 5 needed 500ms while the blurring only took another 250 ms or so.
Use Renderscript
Renderscript provides
ScriptIntrinsicBlur
which is a Gaussian blur filter. It has good visual quality and is just the fastest you realistically get on Android. Google claims to be "typically 2-3x faster than a multithreaded C implementation and often 10x+ faster than a Java implementation". Renderscript is really sophisticated (using fastes processing device (GPU, ISP,etc.), etc.) and there is also the v8 support library for it making it compatible down to 2.2. Well at least in theory, through my own tests and reports from other devs it seems that it is not possible to use renderscript blindly, since the hardware/driver fragmentation seems to cause problems with some devices, even with higher sdk lvl (e.g. I had troubles with the 4.1 Nexus S) so be careful and test on a lot devices. Here's a simple example that will get you startingWhen using the v8 support with Gradle, which is specifically recommended by Google "because they include the latest improvements", you only need to add 2 lines to your build script and use
android.support.v8.renderscript
with current build tools (updated syntax for android gradle plugin v14+)Simple Benchmark on a Nexus 5 - comparing RenderScript with different other java and renderscript implementations:
The average runtime per blur on different pic sizes
Megapixels per sec that can be blurred
Each value is the avg of 250 rounds. RS_GAUSS_FAST is
ScriptIntrinsicBlur
(and nearly always the fastest), others that start with RS_ are mostly convolve implementations with simple kernels. The details of the algorithms can be found here. This is not purely blurring, but a good portion is garbage collection that is measured. This can be seen in this here (ScriptIntrinsicBlur
on 100x100 image with about 500 rounds)The spikes are gc.
You can check yourself, the benchmark app is in the playstore: BlurBenchmark
Reuses Bitmap wherever possible (if prio: performance > memory footprint)
If you need multiple blurs for a live blur or similar and your memory allows it do not load the bitmap from drawables multiple times, but keep it "cached" in a member variable. In this case always try to use the same variables, to keep garbage collecting to a minimum.
Also check out the new "inBitmap" option when loading from a file or drawable which will reuse the bitmap memory and saves garbage collection time.
For blending from sharp to blur
The simple and naive method is just to use 2 imageviews, one blurred and alpha fade them. But if you want a more sophisticated look that smoothly fades from sharp to blur, then check out Roman Nurik's post about how to do it like in his Muzei app.
Basically he explains that he pre-blurs some frames with different blur extends and uses them as keyframes in an animation that looks really smooth
This is for all people who need to increase the radius of
ScriptIntrinsicBlur
to obtain a harder gaussian blur.Instead of to put the radius more than 25, you can scale down the image and get the same result. I wrote a class called
GaussianBlur
. Below you can see how to use, and the whole class implementation.Usage:
Class:
You can now use ScriptIntrinsicBlur from the RenderScript library to blur quickly. Here is how to access the RenderScript API. The following is a class I made to blur Views and Bitmaps:
EDIT (April 2014): This is a question/answer page that still gets a lot of hits it seems. I know I'm always getting upvotes for this post. But if you're reading this, you need to realize the answers posted here (both mine and the accepted answer) are out of date. If you want to implement efficient blur today, you should use RenderScript instead of the NDK or Java. RenderScript runs on Android 2.2+ (using the Android Support Library), so there's no reason not to use it.
The old answer follows, but beware as it's outdated.
For future² Googlers, here is an algorithm that I ported from Yahel's port of Quasimondo's algorithm, but using the NDK. It's based on Yahel's answer, of course. But this is running native C code, so it's faster. Much faster. Like, 40 times faster.
I find that using the NDK is how all image manipulation should be done on Android... it's somewhat annoying to implement at first (read a great tutorial on using JNI and the NDK here), but much better, and near real time for a lot of things.
For reference, using Yahel's Java function, it took 10 seconds to blur my 480x532 pixels image with a blur radius of 10. But it took 250ms using the native C version. And I'm pretty sure it can still be further optimized... I just did a dumb conversion of the java code, there's probably some manipulations that can be shortened, didn't want to spend too much time refactoring the whole thing.
Then use it like this (considering a class called com.insert.your.package.ClassName and a native function called functionToBlur, as the code above states):
It expects a RGB_8888 bitmap!
To use a RGB_565 bitmap, either create a converted copy before passing the parameter (yuck), or change the function to use a new
rgb565
type instead ofrgba
:The problem is that if you do that you can't read
.red
,.green
and.blue
of the pixel anymore, you need to read the byte properly, duh. When I needed that before, I did this:But there's probably some less dumb way of doing it. I'm not much of a low-level C coder, I'm afraid.
Nicolas POMEPUY advice. I think this link will be helpful: Blur effect for Android design
Sample project at github
We tried to implement RenderScript blur like mentioned above in different answers. We were limited to use the v8 RenderScript version and that caused us a lot of trouble.
I want to share our dirty Java-only version which is slow and should be done on a separate thread and, if possible, before usage and therefore persisted.
This solution is far from perfect but creates a reasonable blur effect based on the fact, that it draws highly transparent version of the same image on top of a barely transparent "sharp" version. The alpha depends on the distance to the origin.
You can adjust some "magic numbers" to your needs. I just wanted to share that "solution" for everybody who has issues with the v8 support version of RenderScript.