patternjavaMinor
Adding a Fish Eye Distortion to a Bitmap
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
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
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
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:
First for simple squaring, write your own function:
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:
There are a lot of other little things, e.g.
...could be...
I don't know the details of the algorithm, e.g. if you could use
I tried to improve your version. Of course I couldn't test it...
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 classCode 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.