Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for fast image distortion algorithms

I am trying to implement an application which uses shpere distortion filter. I am using an the algorithm from here which changes pixels location by getPixel() and setpixel() methods. My problem is it is too slow for Android devices and there are applications which implements same sphere(and others) filter way faster than my approach. ( for example Picsay Pro app) Could anyone share or give direction to find or implement fast distortion algorithms.

Actual filter that implements the algorithm:

public boolean sphereFilter(Bitmap b, boolean bSmoothing)
{   
    int nWidth = b.getWidth();
    int nHeight = b.getHeight();

    Point  [][] pt = new Point[nWidth][nHeight];
    Point mid = new Point();
    mid.x = nWidth/2;
    mid.y = nHeight/2;

    double theta, radius;
    double newX, newY;

    for (int x = 0; x < nWidth; ++x)
        for (int y = 0; y < nHeight; ++y)
        {
            pt[x][y]= new Point();
        }

    for (int x = 0; x < nWidth; ++x)
        for (int y = 0; y < nHeight; ++y)
        {
            int trueX = x - mid.x;
            int trueY = y - mid.y;
            theta = Math.atan2((trueY),(trueX));

            radius = Math.sqrt(trueX*trueX + trueY*trueY);

            double newRadius = radius * radius/(Math.max(mid.x, mid.y));

            newX = mid.x + (newRadius * Math.cos(theta));

            if (newX > 0 && newX < nWidth)
            {
                pt[x][y].x = (int) newX;
            }
            else
            {
                pt[x][y].x = 0;
                pt[x][y].y = 0;
            }

            newY = mid.y + (newRadius * Math.sin(theta));

            if (newY > 0 && newY < nHeight && newX > 0 && newX < nWidth)
            {                   
                pt[x][ y].y = (int) newY;
            }
            else
            {
                pt[x][y].x = pt[x][y].y = 0;
            }
        }
    offsetFilterAbs(b, pt);
    return true;
}

The code that replaces the calculated pixels' positions.

public boolean offsetFilterAbs(Bitmap b, Point[][] offset )
{
        int nWidth = b.getWidth();
        int nHeight = b.getHeight();

        int xOffset, yOffset;

        for(int y=0;y < nHeight;++y)
        {
            for(int x=0; x < nWidth; ++x )
            {   
                xOffset = offset[x][y].x;
                yOffset = offset[x][y].y;

                if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth)
                {
                    b.setPixel(x, y, b.getPixel(xOffset, yOffset));
                }                   
            }               
        }

    return true;
}
like image 509
Tony Avatar asked Apr 04 '11 18:04

Tony


1 Answers

I am currently using same algorithm with the one on your link already and it is still too slow for android devices

From my link in the comments above:

Given
r = Sqrt((x - 0.5)^2 + (y - 0.5)^2)
a = ArcTan2(y - 0.5, x - 0.5)
n = Bulge factor (default = 1)

Set
x' = r^n * Cos(a) + 0.5 
y' = r^n * Sin(a) + 0.5 

(Remember that, in this equation, x and y span from 0 to 1. If your dimensions span from 0 to w, replace 0.5 with w/2)

Using a bit of math, we can see that

Cos(a) = Cos(ArcTan2(y - 0.5, x - 0.5))
       = (x - 0.5)/r
Sin(a) = Sin(ArcTan2(y - 0.5, x - 0.5))
       = (y - 0.5)/r

This makes the final resulting equation

r = (x - 0.5)^2 + (y - 0.5)^2
n = Bulge factor (default = 0)

Set
x' = r^n * (x - 0.5) + 0.5
y' = r^n * (y - 0.5) + 0.5

(I removed the square-root since we take the result to a real-power anyways... so really to make this equivalent we should use n/2 instead of n, but since we are defining "bulge-factor," we can just leave out the extra division)

With only a handful of multiplications and a single real-exponentiation, this is probably the fastest you can hope to get.

like image 177
BlueRaja - Danny Pflughoeft Avatar answered Sep 29 '22 16:09

BlueRaja - Danny Pflughoeft