Friday, December 28, 2012

OpenCV - Fun with remap

OpenCV has an re-map function that lets you map pixels of an image from one position to another. It can be used to create interesting artefacts with images, correct distortions or create different lens effects.

The remap function (documented here) takes the source and destination images, two arrays that specify where each pixel of the destination comes from, and a set of flags that control interpolation behavior.

Interpolation, as you must have realized, is a critical factor here. Interpolation is required since the function that we use to map the source to destination is likely to create gaps and overlaps in the destination. So we must have some way to fill the gaps and derive the final value of a pixel based on multiple pixels of the source. OpenCV provides a few interpolation functions that can be chosen from using the flags.

The other interesting thing in this API is that the pixel maps we need to provide are not maps from source to destination. Rather we say for each pixel in the destination, which source pixel it comes from. Now the source pixel we provide here is a float variable. Thus it can lie not directly on a pixel, but rather on a point in-between a few pixels. The OpenCV interpolation functions then calculate the destination pixel value using this position information and the surrounding pixel values with the chosen interpolation function.

Below is a simple program using re-map that maps a rectangular image into a circle. Here, to calculate the mapping we do the following simple geometry calculation:
  • shift the origin (0,0 coordinate) to the center of the image
  • convert the cartesian x-y coordinates to polar r-theta form
  • determine the length of the line with the same theta that touches the border of the rectangle
  • retain the theta, but scale the r value based on how much the line has to shrink to fit into the circle.
  • convert the modified r-theta values back into x-y coordinates

Here are the results:

Source Image
Result Image
(Image credits for the source image goes to the owners mentioned on the image. I just picked it up for illustration purposes.)

If you expected a fish-eye effect, this is not it. We just mapped the rectangle to a circle, and therefore you would see a pinching effect at the corners because the diagonals get compressed the most. For the fish-eye effect, we should probably map the rectangle to a sphere and then project it to a 2D surface. I'll probably take that up the next time. If you just play around with different mapping functions, you can create several interesting effects of your own.

Here is the source code gist for the circle map:


Umesh Tarsariya said...

nice post
Tips Via Blogging

Lentin Joseph said...

Nice post, actually this principle can be used for another purpose. We can reduce the fish eye reduction of an image using this function. Can you just modify this function to do the reverse of this process. So it can be used for fish eye reduction, that is very useful in image processing

Lentin Joseph said...

Nice post.
Actually the reverse of this process can be useful for the fish eye reduction. Can you do a modification for doing the reverse of this process? Or do you have any idea about how we can do that?

Tanmay said...

Hi Lentin. Yes the reverse can be used to reduce fish eye effect. I thing the changes should be as simple as taking the inverse of the ratios calculated in the make_circle_map function.

Actually it would be a good generalization to take a weight to adjust the degree of fish eye effect being applied as a parameter. The sign of this degree value can be used to either apply a fish eye effect or remove it from the image.

Do let me know if that works.