Sunday, April 29, 2012

Fisheye lens equation - Simple fisheye effect with one function


I am interested in many kind of computer algorithms, including algorithms for computer graphics, digital image processing and 3D-graphics.

In one of my projects I needed to have "fish eye lens" like effect, and tried to find easy equation or ready function from the internet. To my surprise, there were not complete functions available, just theories and images how it can be achieved. 

Here is a brief tutorial and loop how to create fish eye -effect to any image. The function is written in Java, but as you can see, it is easily rewritten with any programming language. 

If you find this article and function useful and you will use it in your own projects, please refer where the source came. In any case, leave a comment. Questions and requests are welcome!

What is fish eye effect?

Fish eye effect is a mirror effect which happens when the image is drawn on to a surface of a sphere or a hemisphere. The surface does not need to be a perfect sphere, it can also be paraboloid or have other kind of curve as a surface.

Common effect is, that the image is "zoomed" in the center and "shrink" at the edges. The image is usually round (because we are dealing with spheres) but the image can also be clipped to be square.

Mathematics

What we need is a function which maps any pixel from the image to a surface of a sphere. 

In this fish eye effect, we are not using equations for a sphere, but an equation for unit circle:

x^2 + y^2 = 1 
Solving y
y^2 = 1 - x^2
and then finally
y = sqrt(1 - x^2) 

Because we are limiting all our values between 0.0 and 1.0, we can create values for nice arc when x goes from 0.0 to 1.0.


For example, in the image we have marked x-position 0.75, and we can calculate y-position substituting x in y = sqrt(1 - x^2), which gives us y = 0.66.

For our purpose, we will flip the curve with subtracting the result from 1.0:

d = 1 - sqrt(1 - x^2)

This curve will give us values for the difference of the distance of the source pixel and destination pixel, from the center of the image, when mapping from plane to sphere. 

The new distance is then the original distance added with the difference:

r' = r + d  (r' > r)

Polar coordinates

The normal screen coordinates (two dimensional Cartesian coordinates, simply x- and y-axis) are difficult when dealing with trigonometric functions, because the input values are typically between -1 to 1 and the angles are in radians from 0 to 2*PI.

Everything becomes more easier when you change the screen coordinates (x,y) to polar coordinates (r, theta). This is done with simple functions:

From Cartesian to polar:

    r = sqrt(y^2 + x^2)
    theta = atan2(y, x)
    
From polar to Cartesian:

    x = r cos(theta)
    y = r sin(theta)

In polar coordinates, any point in the image can be accessed with the angle (theta) and distance from center (r).

Now we are able to map any (x,y) pixel to polar coordinate (r,theta), then CHANGE the r, and map it back to (x',y'), and the pixel remains at the same line going through center of the image!

Algorithm 

What we need:
  1. the distance from center of the source image to any pixel (x,y) in the same image
  2. the position (x', y') where the pixel belongs in the fish eye image
In the following pseudo code, we are using polar coordinates. The key part in the whole process is to use polar coordinates and this fact: The actual pixel translation from 2D-image to sphere surface is done with manipulating the distance from center (r).

Pseudo code:

for each pixel (x,y)
    normalize (x,y) to (nx, ny) to be in range [-1,1]
    calculate distance from (nx, ny) to center (0,0)
    convert (nx,ny) to polar coordinates
    calculate new distance from center on the sphere surface
        The new distance is r' = r + (1 - sqrt(1 -r^2)) / 2
    translate (nx, ny) back to screen coordinates (x',y')


The image above shows how Points P1 and P2 will be displaced to P1' and P2', so that the angle remains the same. In other words, the point is displaced along the original line towards the edge of the unit circle. The distance from the center tells us how big is the displacement. In the center and near the center the displacement value is zero or almost zero. Near the edges displacement value grows towards value of 1.0.


The image above gives the idea behind the displacement value. For every pixel in the result image plane, there is a pixel from source image plane. In here, the source image plane is stretched and curved. It may be easier to understand, if you think a one single line instead of the plane. Along that line, the pixels are almost normal at the center, but towards the ends, the pixels are fetched further and further away from the center.

Most important thing


The most important thing is to understand, that for each result pixel, there is a source pixel, on the same line going through the center, but with a greater distance.

The source 

public static int[] fisheye(int[] srcpixels, double w, double h) {

    /*
     *    Fish eye effect
     *    tejopa, 2012-04-29
     *    http://popscan.blogspot.com
     *    http://www.eemeli.de
     */

    // create the result data
    int[] dstpixels = new int[(int)(w*h)];            
    // for each row
    for (int y=0;y<h;y++) {                                
        // normalize y coordinate to -1 ... 1
        double ny = ((2*y)/h)-1;                        
        // pre calculate ny*ny
        double ny2 = ny*ny;                                
        // for each column
        for (int x=0;x<w;x++) {                            
            // normalize x coordinate to -1 ... 1
            double nx = ((2*x)/w)-1;                    
            // pre calculate nx*nx
            double nx2 = nx*nx;
            // calculate distance from center (0,0)
            // this will include circle or ellipse shape portion
            // of the image, depending on image dimensions
            // you can experiment with images with different dimensions
            double r = Math.sqrt(nx2+ny2);                
            // discard pixels outside from circle!
            if (0.0<=r&&r<=1.0) {                            
                double nr = Math.sqrt(1.0-r*r);            
                // new distance is between 0 ... 1
                nr = (r + (1.0-nr)) / 2.0;
                // discard radius greater than 1.0
                if (nr<=1.0) {
                    // calculate the angle for polar coordinates
                    double theta = Math.atan2(ny,nx);         
                    // calculate new x position with new distance in same angle
                    double nxn = nr*Math.cos(theta);        
                    // calculate new y position with new distance in same angle
                    double nyn = nr*Math.sin(theta);        
                    // map from -1 ... 1 to image coordinates
                    int x2 = (int)(((nxn+1)*w)/2.0);        
                    // map from -1 ... 1 to image coordinates
                    int y2 = (int)(((nyn+1)*h)/2.0);        
                    // find (x2,y2) position from source pixels
                    int srcpos = (int)(y2*w+x2);            
                    // make sure that position stays within arrays
                    if (srcpos>=0 & srcpos < w*h) {
                        // get new pixel (x2,y2) and put it to target array at (x,y)
                        dstpixels[(int)(y*w+x)] = srcpixels[srcpos];    
                    }
                }
            }
        }
    }
    //return result pixels
    return dstpixels;

Example pictures 

Original

After applying fish eye function

 

Angry Birds theme park opened!

The world's first Angry Birds land will be opened in Tampere, Finland, within few weeks. However, theme park guests are already able to take rides in some of the attractions.



More videos from here:
http://www.aamulehti.fi/Kotimaa/1194739901549/artikkeli/katso+videot+talta+nayttaa+sarkanniemen+angry+birds+land.html

and here:
http://www.hs.fi/kotimaa/S%C3%A4rk%C3%A4nniemess%C3%A4+aukesi+Angry+Birds+-seikkailupuisto/a1305560876496

Wednesday, April 18, 2012

Fruit Ninja Clip-ons

I really don't know how big thing Fruit Ninja is here in Finland, but in any case they are now selling Fruit Ninja related toys at the supermarket.



Monday, April 16, 2012

Angry Birds collectible figurines

Latest additions to our local supermarket's toy section. 

I think I enjoy going through the shelves and new toys as much as my kids!






Monday, April 9, 2012

Angry Hockey Bird

I just need to keep my pocket camera always with me or upgrade my phone to a one with a better camera.

It seems that there are a lot of things I would like to take photos of, but my old Nokia camera phone performs badly both in low light and in bright light. Sorry for the image quality in these photos.

This is one of the latest Angry Birds, the Hockey Bird! It is created by Rovio (so it is legit!) for the Ice Hockey Championships 2012 held in Finland.







There is also a stamp with Hockey Bird in it: http://www.posti.fi/english/current/2012/20120221_hockeybird.html
 



Friday, April 6, 2012

Marco, Mario's and Luigi's brother?

I noticed this package on the shelf of our local supermarket.

With a little googling, I found out that I am not the first one to notice the resemblance between Marco, the character from pasta bag and Mario, the game character from Nintendo games.





Funny Superman burger van

These photos were taken on one of my trips to Taipei, Taiwan.

I enjoy taking long walks through the city and going through small alleys. The main streets have shops for luxury items and global brands and high quality restaurants, but immediately next to these shopping areas there are businesses targeted for locals. The price level for anything drops dramatically and they have clearly invested less to the environment and presentation.

This "Superman burger van" was parked in one of those alleys...







Wednesday, April 4, 2012

Amazing wall painting

I have planned to photograph this wall for some time now, and now when I had the possibility I took it. Unfortunately it was snowing a bit, so there are some white artifacts (snow flakes!) in the picture.

Colors and perspective are fixed in GIMP to improve the image.

In the painting you can see an old man, standing or kneeling in the field of flowers, holding his hat, in a position which makes me think that man is in grief. The blue serpent is laughing behind the man and has its tail around old man's arm.



More images about this painting

- http://graffart.eu/blog/2011/05/aryz-turku-finland/

- http://www.aryz.es/outdoor/page/4

The same wall used to have "Pepsi" wall painting on it. The old painting can be still seen from Google maps.

- Google Maps link


Tuesday, April 3, 2012

Samsung widget "Picture Frame" is showing image that does not exist

I recently tested Samsung Galaxy Tab 10.1, and also my kids got a chance to try it out.

Of course they immediately took some silly photos and some how managed to put them into the "Picture Frame" widget which was shown on the home screen, immediately after opening the device.

As the device is not actually mine to keep, I needed to remove the photos my kids took. I used gallery to search the images and deleted the chosen image files. To my surprise, the removed photos were still displayed on the widget!

I tried many different things, I removed all the gallery related caches and image indexes, but the photos were still persistent in the widget.

Finally I removed the whole widget from the desktop by keeping the widget selected for a few seconds, and then dragging the widget on top of the trashcan icon in the upper right corner. After removing the widget, I added it back again and added some photos from the gallery to it. And no more silly photos were shown!

This was the only procedure I could find to remove unwanted and already deleted images from "Picture Frame" widget on Samsung Galaxy Tab 10.1. I guess the widget makes some kind of own cache to the disk, but I was not able to find another way to remove/clear the cache than removing the widget and adding it back again.