I am a new user of MathMap and new member of this group. I have sent
some filters to Mark Probst and he suggested I should post them in this
group. So here they are, together with some explanations for those
interested in the math.
My main concern was with remapping pictures taken with a fisheye: a
Nikon 10.5 mm DX on a D300. In the past I had used Hugin to do this, but
the problem is Hugin assumes all fisheyes give an equidistant mapping,
while mine (as most modern fisheyes, I beleive) uses an equisolid angle
projection [for details on fisheye mappings, see Wikipedia:Fisheye lens,
section on Mapping function]. So with Hugin my images were somewhat
undercorrected. When I discovered MathMap, I figured out it was the
perfect tool to get the mappings right!
So here is my first filter, to convert from equisolid angle to
stereographic. Stereographic is one of my favorite fisheye mappings
because it preserves the fisheye feeling while at the same time it gets
rid of local distorsions (it is a conformal mapping of the sphere, then
small details like people's faces in a group come out undistorted):
----------------------------------------------------------------
filter fish2stereographic(image in, float zoom: 0.7-1 (0.82))
f = 10.5/23.6*W;
theta = 2*atan(r/(2*f)/zoom);
in(ra:[2*f*sin(theta/2), a])
end
----------------------------------------------------------------
Two numbers are hard-coded in this filter:
- 10.5 is the focal length of my lens in mm
- 23.6 is the width of my sensor (Nikon DX) in mm
you will have to change them to fit your particular setup. The other
stuff here is:
- f is the focal length of the lens converted into image units
- theta is the polar angle, i.e. the angle between the object in the
scene and the optical axis of the lens, theta is given by the
formula for the stereographic projection
- 2*f*sin(theta/2) is where the object got projected in the original
image, according to the equisolid angle projection my lens claims to
provide
- the zoom parameter is just for convenience, it allows me to get more
field of view while preserving the original image size
Converting into rectilinear is almost the same, but less useful: unless
you crop substantially, this projection stretches the edges of the
image too much:
----------------------------------------------------------------
filter fish2rectilinear(image in, float zoom: 0.3-1 (0.5))
f = 10.5/23.6*W;
theta = atan(r/f/zoom);
in(ra:[2*f*sin(theta/2), a])
end
----------------------------------------------------------------
The conversion to cylindrical perspective is a little bit more complex.
There may be smarter ways to do it, but the following works for me
(backwards from cylindrical to equisolid angle):
- go from cylindrical to a spherical coordinate system where y is the
polar axis, coordinates are longitude and latitude
- go from this to an Euclidean coordinate system on the unit sphere
- go from this to another spherical system having z as the polar axis,
coordinates are theta (polar angle) and phi (azimuth)
- then from this to equisolid angle
So here is the code:
----------------------------------------------------------------
filter fish2cylindrical(image in, float zoom: 0.7-1 (0.94))
f = 10.5/23.6*W;
long = x/f/zoom;
lat = atan(y/f/zoom);
xx = cos(lat) * sin(long);
yy = sin(lat);
phi = atan(yy, xx);
theta = asin(sqrt(xx*xx+yy*yy));
in(ra:[2*f*sin(theta/2), phi])
end
----------------------------------------------------------------
In the above:
- (lat, long) are the longitude and latitude of the object
- (xx, yy, zz) are it's Euclidian coordinates on the unit sphere,
but actually zz is not needed
- theta and phi are the coordinates on the second spherical system
The conversion to Mercator is almost the same, only the formula for the
latitude is different:
----------------------------------------------------------------
filter fish2mercator(image in, float zoom: 0.7-1 (0.94))
f = 10.5/23.6*W;
long = x/f/zoom;
lat = atan(sinh(y/f/zoom));
xx = cos(lat) * sin(long);
yy = sin(lat);
phi = atan(yy, xx);
theta = asin(sqrt(xx*xx+yy*yy));
in(ra:[2*f*sin(theta/2), phi])
end
----------------------------------------------------------------
I prefer Mercator over cylindrcal. They look almost the same unless the
vertical field of view gets big, in which case cylindrical stretches
vertically the objects far from the equator. Mercator does not do that
since it is a conformal mapping, just like stereographic.
Generally my choice of projection is:
- Mercator if I want some kind of panoramic view (not too big a
vertical FoV) that preserves verticals
- stereographic if I want a more isotropic view that preserves the
fisheye feeling
The other two filters are here only for completeness.
Oh, I almos forgot! You may get equirectangular if you want. Same as the
two above but for:
lat = y/f/zoom;
And if you happen to have a fiheye with an equidistant mapping? Then
replace in all of the above, in the last instruction
2*f*sin(theta/2)
by
f*theta
Regards,
Edgar.