Bitmap / TimingLogger

Blurring Images – Part 4

Previously in this series we’ve looked at blurring an image using RenderScript, and a technique for analysing performance to work out where the bottlenecks are in the process. We found that the actual bur operation was extremely quick in RenderScript, but we did have an overhead of marshalling bitmaps from the Java memory space across to the RenderScript memory space and back again. In this article we’ll take a look at performing the blur in Java to remove the marshalling between memory spaces, and see if we can get better performance that way.

Firstly, I must admit that I haven’t done an exhaustive test of lots of different blur algorithms in Java. It is highly likely that there are more efficient algorithms around than the one that I have picked. The one I have chosen comes from a stackoverflow answer in which the author, Yahel Bouaziz, clearly understands the models involved, and claims it is quite fast. Also, there is a comment saying that it’s much faster than other methods.

I’m not going to reproduce the method here as it is available in the source, neither am I going to offer an explanation of different blur algorithms, and how Yahel’s code works as it would detract from the point of this series which is about performing blurs, and comparing the performance of different techniques. If you want more information on this, there is an excellent guide to Java image Processing which uses AWT libraries, so won’t port directly to Android, but is a great starting point for learning about the different types of blur algorithms.

We’ll use a different method to envelope Yahel’s function, and we’ll include a TimingLogger so that we can measure the performance:

private void blurJava(Bitmap bkg, View view, int radius) {
	TimingLogger tl = new TimingLogger(TAG, "blur");

	Bitmap overlay = Bitmap.createBitmap(
		view.getMeasuredWidth(), 
		view.getMeasuredHeight(), 
		Bitmap.Config.ARGB_8888);
	tl.addSplit("Bitmap.createBitmap()");

	Canvas canvas = new Canvas(overlay);
	tl.addSplit("new Canvas()");
	canvas.drawBitmap(bkg, -view.getLeft(),
		-view.getTop(), null);
	tl.addSplit("canvas.drawBitmap()");

	Bitmap blurred = fastblur(overlay, radius);
	tl.addSplit("fastblur()");

	view.setBackground(new BitmapDrawable(
		getResources(), blurred));
	tl.addSplit("view.setBackground()");

	tl.dumpToLog();
}

If we run this we can see the following:

part4

I must agree with Yehel that it looks really nice, but how about the all important performance:

blur: begin
blur:      0 ms, Bitmap.createBitmap()
blur:      0 ms, new Canvas()
blur:      1 ms, canvas.drawBitmap()
blur:      125 ms, fastblur()
blur:      0 ms, view.setBackground()
blur: end, 126 ms

This was executed on the exact same device as the benchmarking of the RenderScript blur that we did previously. While we saved on the overhead of marshalling to and from RenderScript memory space, the blur operation itself took over two and a quarter times longer than the entire operation, inclusive of the marshalling, in RenderScript. That is not to suggest that Yehel’s method is inefficient, it just doesn’t have the advantage of running directly on the GPU, which is there to perform this kind of computationally heavy task.

Hopefully it should now be fairly clear that RenderScript offers us a significant performance improvement when performing this kind of operation and, while the marshalling between memory spaces appears to be an overhead, the performance gain that we can achieve more than compensates for that. In the next article we’ll take a deeper look at frame rates when performing animations and begin to explore whether it is possible to get our blurred background animating smoothly.

The source code for this article is available here.

© 2014, Mark Allison. All rights reserved.

Copyright © 2014 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

1 Comment

  1. Thanks for the sample. I am trying to change the image after 2secs and blur that but it is not effective.

    new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
    mImage.setImageResource(R.drawable.profile);
    new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
    Drawable drawable = mImage.getDrawable();
    if (drawable != null && drawable instanceof BitmapDrawable) {
    Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
    if (bitmap != null) {
    blur(bitmap, mText, 25);
    }
    }
    }
    },200);

    }
    }, 2000);

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.