user1565904
user1565904

Reputation: 49

Gaussian blur in android is pretty slow

I'm trying to implement a simple Gaussian blur in android and it works pretty slow :( here's the relevant code:

double rSum = 0;
double gSum = 0;
double bSum = 0;
double weightSum = 0;

for(int y = 0; y < originalImage.height ; y++){
    for(int x = 0; x < originalImage.width ; x++){
        int newPixel;

        rSum = 0;
        gSum = 0;
        bSum = 0;
        weightSum = 1;

        for(int row = y-FRAME_OFFSET ; row <= y+FRAME_OFFSET ; row++){
            for(int col = x-FRAME_OFFSET ; col <= x+FRAME_OFFSET ; col++){
                if(originalImage.inBounds(col, row)){
                    double weight = weights[(x-col)*(x-col) + (y-row)*(y-row)];
                    weightSum += weight;

                    int pixel = originalImage.at(col, row);

                    int red =  (pixel >> 16) & 0xFF ;
                    int green = (pixel >> 8) & 0xFF ;
                    int blue = pixel & 0xFF ;

                    rSum += red * weight;
                    gSum += green * weight;
                    bSum += blue * weight;  

                }
            }
        }

        rSum /= weightSum;
        gSum /= weightSum;
        bSum /= weightSum;

        newPixel = Color.rgb((int)rSum, (int)gSum, (int)bSum);                  

        maskedImage.set(x, y, newPixel);
    }
}

If i use this algorithm with frame FRAME_OFFSET (radius) of 15 it takes about 3 minutes(!) on a 512x512 image, and it get worst as i increase the offset. My guess is that it's a caching problem as when i calculate the new pixel i'm accessing pixels in different rows that's probably not in the cache.

Any help/improvements will be appreciated.

Please note that i need to implement this algorithm by myself and not use an existing implementation.

Thanks.

Upvotes: 3

Views: 2399

Answers (2)

Francesco Callari
Francesco Callari

Reputation: 11785

The 2D Gaussian blur kernel is linearly separable, meaning that it can be expressed as the outer (column-times-row) product of two 1D kernels, one for the image rows and one for the columns. So any straightforward implementation that uses this property should be O(kMN) for an MN image and a kk kernel, and be implemented as a two pass algorithm, with each pass performing a 1D convolution, first along the image rows, then along the image columns.

In some cases the 1D step can be speeded up by taking advantage of certain properties of the Gaussian kernel itself, that allow the computation of the weight coefficients to be done incrementally using integer operations only. This is the fastest implementation that I am aware of - and it can be easily ported to Java on Android: Incremental Computation of the Gaussian.

Upvotes: 2

Vansuita Jr.
Vansuita Jr.

Reputation: 2099

Use this lib: https://github.com/jrvansuita/GaussianBlur

Implement like this:

//Asynchronous with scaleDown and changing radius
GaussianBlur.with(context).size(300).radius(10).put(R.mipmap.your_image, imageView);

Upvotes: 0

Related Questions