HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Adding a Fish Eye Distortion to a Bitmap

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
distortionfishaddingeyebitmap

Problem

I have the following class that processes a Bitmap to place a fisheye distortion on it. I've run my app through TraceView and found that virtually all the processing time is spent looping through the bitmap. One developer has suggested not using float as this will slow things down where graphics are concerned. Also, using math.pow() and ceil() are not necessary?

At the moment to place the effect by looping through the entire bitmap takes around 42 seconds, yes seconds:) I've tried replacing the floats with integers and that has reduced the time to 37 secs, but the effect is no longer present on the bitmap. The argument k is originally a float and sets the level of distortion (eg 0.0002F). If I pass an integer, then the effect doesn't work.

Can anyone point me in the right direction on how to optimize this process? Once I've optimized it I'd like to look into perhaps not looping through the entire bitmap and maybe putting a bounding box around the effect or using the algorithm below that determines whether a pixel is within the circle with a radius of 150.

```
class Filters{
float xscale;
float yscale;
float xshift;
float yshift;
int [] s;
private String TAG = "Filters";
long getRadXStart = 0;
long getRadXEnd = 0;
long startSample = 0;
long endSample = 0;
public Filters(){

Log.e(TAG, "*inside filter constructor");
}

public Bitmap barrel (Bitmap input, float k){
//Log.e(TAG, "*INSIDE BARREL METHOD ");

float centerX=input.getWidth()/2; //center of distortion
float centerY=input.getHeight()/2;

int width = input.getWidth(); //image bounds
int height = input.getHeight();

Bitmap dst = Bitmap.createBitmap(width, height,input.getConfig() ); //output pic
// Log.e(TAG, "*dst bitmap created ");
xshift = calc_shift(0,centerX-1,centerX,k);

float newcenterX = width-centerX;
float xshift_2

Solution

This line will eat a lot of performance:

if( Math.sqrt( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) ) <= 150 )


First for simple squaring, write your own function:

float sqr(float x) { return x*x; }


Second and even more important, if you square the expressions on both sides (which is OK because both are positive), you don't need the expensive sqrt-Function on the left side. Simply write:

if( sqr(i - centerX) + sqr(j - centerY) <= 150*150 )


There are a lot of other little things, e.g.

float x3 = (float)(x1+(x2-x1)*0.5);


...could be...

float x3 = (x1+(x2-x1)*0.5f);


I don't know the details of the algorithm, e.g. if you could use ints in certain places, or if it would make sense to use a precalculated table for some values.

I tried to improve your version. Of course I couldn't test it...

import java.util.Arrays;

class Filters {
    float xscale;
    float yscale;
    float xshift;
    float yshift;
    int[] s = new int[4];
    int[] s1 = new int[4];
    int[] s2 = new int[4];
    int[] s3 = new int[4];
    int[] s4 = new int[4];
    private String TAG = "Filters";
    long getRadXStart = 0;
    long getRadXEnd = 0;
    long startSample = 0;
    long endSample = 0;
    float xr;
    float yr;

    public Filters() {
        //Log.e(TAG, "***********inside filter constructor");
    }

    public Bitmap barrel(Bitmap input, float k) {
        //Log.e(TAG, "***********INSIDE BARREL METHOD ");

        float centerX = input.getWidth() / 2; //center of distortion
        float centerY = input.getHeight() / 2;

        int width = input.getWidth(); //image bounds
        int height = input.getHeight();

        Bitmap dst = Bitmap.createBitmap(width, height, input.getConfig()); //output pic
        // Log.e(TAG, "***********dst bitmap created ");
        xshift = calc_shift(0, centerX - 1, centerX, k);

        float newcenterX = width - centerX;
        float xshift_2 = calc_shift(0, newcenterX - 1, newcenterX, k);

        yshift = calc_shift(0, centerY - 1, centerY, k);

        float newcenterY = height - centerY;
        float yshift_2 = calc_shift(0, newcenterY - 1, newcenterY, k);

        xscale = (width - xshift - xshift_2) / width;
        //  Log.e(TAG, "***********xscale ="+xscale);
        yscale = (height - yshift - yshift_2) / height;
        //  Log.e(TAG, "***********yscale ="+yscale);
        //  Log.e(TAG, "***********filter.barrel() about to loop through bm");

        int origPixel;
        long startLoop = System.currentTimeMillis();
        for (int j = 0; j  (arr.getHeight() - 1) || idx1 > (arr.getWidth() - 1)) {
            return;
        }

        float idx0_fl = (float) Math.floor(idx0);
        float idx0_cl = (float) Math.ceil(idx0);
        float idx1_fl = (float) Math.floor(idx1);
        float idx1_cl = (float) Math.ceil(idx1);

        getARGB(s1, arr, (int) idx0_fl, (int) idx1_fl);
        getARGB(s2, arr, (int) idx0_fl, (int) idx1_cl);
        getARGB(s3, arr, (int) idx0_cl, (int) idx1_cl);
        getARGB(s4, arr, (int) idx0_cl, (int) idx1_fl);

        float x = idx0 - idx0_fl;
        float y = idx1 - idx1_fl;

        //reordered for less multiplications
        for(int i = 0; i >> 24) & 0xFF;
        scalar[1] = (rgb >>> 16) & 0xFF;
        scalar[2] = (rgb >>> 8) & 0xFF;
        scalar[3] = rgb & 0xFF;
    }

    void getRadialXY(float x, float y, float cx, float cy, float k) {
        x = (x * xscale + xshift);
        y = (y * yscale + yshift);
        float f = k * (sqr(x - cx) + sqr(y - cy));
        xr = x + ((x - cx) * f);
        yr = y + ((y - cy) * f);
    }
    float thresh = 1;

    float calc_shift(float x1, float x2, float cx, float k) {

        float x3 = x1 + (x2 - x1) * 0.5f;
        float res1 = x1 + cube(x1 - cx) * k ;

        if (-thresh < res1 && res1 < thresh) {
            return x1;
        }

        float res3 = x3 + cube(x3 - cx) * k;
        return (res3 < 0) 
            ? calc_shift(x3, x2, cx, k)
            : calc_shift(x1, x3, cx, k);
    }
}// end of filters class

Code Snippets

if( Math.sqrt( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) ) <= 150 )
float sqr(float x) { return x*x; }
if( sqr(i - centerX) + sqr(j - centerY) <= 150*150 )
float x3 = (float)(x1+(x2-x1)*0.5);
float x3 = (x1+(x2-x1)*0.5f);

Context

StackExchange Code Review Q#3007, answer score: 3

Revisions (0)

No revisions yet.