Filter: Fish-Eye Lens

Source: [HOLZ88:34-35,60-61], [DEVE01], [CLAE97]

When I first started this project, I wanted to write my own filter to solve an artistic problem—one not modeled after something I read in a book or used in Photoshop®. The first idea that came to mind was this notion of a ‘raindrop’ effect. The effect would in some way resemble what one would see when looking out a window after it had rained, that is, a few raindrops would be on the window. That filter is discussed later, but before I could dive into that, I needed some more background. The fish-eye lens effect was done as an artist does preliminary ‘studies’ before producing a final piece of art. In looking though a raindrop, or at condensation on a glass, the image under the drop of water is distorted, or magnified. It seemed natural to model this distortion on a fish-eye lens effect, which yes, is also modeled after a Photoshop® filter. The idea comes from a fish-eye lens that is used in photography to produce an image with a 180-degree view. For our purposes, the effect is that the image appears to bulge outward, ideally, as if it was pushed out from behind using a sphere.

This effect is done by a geometric transformation of pixels within a certain area. In this case, the area is the largest circle that will fit inscribed in the center of the image. The key to this filter lies in using the right transformation function. I found about three different functions and by trial and error determined which was the best for my purposes. All of the functions involved first converting the coordinates of my image pixels from Cartesian to polar coordinates. The function I have implemented here is described in [DEVE01], which the author credits to Basu and Licardie. It is modeled on the actual optic structure of a fish’s eye, that the resolution is highest in the center and degrades toward the periphery [DEVE01]:

   new_radius = s log(1 + w(old_radius))

I could not find the definition of s and w in the literature. From trial and error, w appears to be the amount of curvature, or how much the center of the image is pushed forward. I found acceptable values for w to be in the range [0.001..0.1]. Knowing if old_radius was the maximum radius (R), new_radius would be mapped to the same R, and having already selected w, I solved the above equation for s in terms of R and w in order to find the parameter for the equation. Since R will vary depending on the image, and w will vary depending on the user input (curvature is an option in the fish-eye dialog box), s is calculated at run-time based on the following:

   s = R / log(w*R+1)

From an idea I got in [HOLZ88:34-35], I decided to see what would happen if I used the inverse of the fish-eye function. One would assume that the resulting image would appear to be pushed in, instead of being pushed out. Indeed that is the effect (the user has this option in the dialog box). Here is the inverse function:

   new_radius = ( e^(old_radius / s) – 1) / w )

Below is the basic algorithm for the fish-eye effect (w is used as w). For more implementation detail, the reader is referred to the code filters.cpp from the downloadable project.

   R = (min(image_width, image_height)) / 2;
   Get w from user;
   s = R / log(w*R+1);
   for every pixel in the image do
   {
      polarpixel = currentpixel in polar coordinates (r(adius), a(ngle));
      if (polarpixel.r < R)
      {
         polarpixel.r = s * log(1+w*r);
         filterpixel = polarpixel in Cartesian coordinates;
      }
      else
      filterpixel = currentpixel; // leave pixels outside R alone
   }

The details about converting to and from Cartesian and polar coordinates are left for discussion in the next filter.


Fish-eye (default settings) on original with superimposed grid


Return to the list of filters
 


© 2001 Jason Waltman