I've been searching the past three days for a built-in, hardware-accelerated way of bluring a bitmap with android. I stumbled upon certain work-arounds like shrinking the bitmap and scaling it up again, but this method produced low quality results which were not suitable for my image recognition requirements. I also read that implementing convolution with shaders or JNI is a good way to go, but I cannot believe that there is no built-in solution in the Android framework for this very common purpose. Currently I've ended up with a self-written convolution implementation in Java, but it is awkwardly slow. My question is:
BlurView can be used as a regular FrameLayout. It blurs its underlying content and draws it as a background for its children. BlurView redraws its blurred content when changes in view hierarchy are detected (draw() called). It honors its position and size changes, including view animation and property animation.
I finally found a suitable solution:
However, the documentation on the ScriptIntrinsicBlur
class is very rare and I've spent some more time on figuring out the correct invocation arguments. For bluring an ordinary ARGB_8888
-typed bitmap named photo
, here they are:
final RenderScript rs = RenderScript.create( myAndroidContext ); final Allocation input = Allocation.createFromBitmap( rs, photo, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT ); final Allocation output = Allocation.createTyped( rs, input.getType() ); final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create( rs, Element.U8_4( rs ) ); script.setRadius( myBlurRadius /* e.g. 3.f */ ); script.setInput( input ); script.forEach( output ); output.copyTo( photo );
Probably the most demanding requirement is live blur, meaning you blur live as the view changes. In this situation a blur should not take longer than 10 or so ms (to have some playroom onto the 16ms/60fps) to look smooth. It is possible to achieve this effect with the right settings, even on not so high end devices (galaxy s3 and even slower).
Here is how to improve performance in descending importance:
Use downscaled images: This decreases the pixels to blur enormously. Also it works for you when you want a real blurred image. Also image loading and memory consumption is drastically lowered.
Use Renderscript ScriptIntrinsicBlur - there is probably not a better/faster solution in Android as of 2014. One mistake I often see is that the Renderscript context is not reused, but created everytime the blur algorithm is used. Mind you that RenderScript.create(this);
takes around 20ms on a Nexus 5, so you want to avoid this.
Reuse Bitmaps: don't create unnecessary instances and always use the same instance. When you need really fast blur, garbage collection plays a major role (taking a good 10-20 ms for collection some bitmaps). Also crop and blur only what you need.
For a live blur, probably because of context switching, it's not possible to blur in another thread (even with threadpools), only the main thread was fast enough to keep the view updated timely, with threads I saw lags of 100-300ms
on more tips see my other post here https://stackoverflow.com/a/23119957/774398
btw. I did a simple live blur in this app: github, Playstore
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With