New Mathmap Script for Panini Projection

6 messages Options
Embed this post
Permalink
Tom Sharpless

New Mathmap Script for Panini Projection

Reply Threaded More More options
Print post
Permalink
Now that MathMap version 1.3 works on Windows, more of you may be interested in trying this new MathMap script for converting an equirectangular image to the generalized Panini projection, as implemented in the Panini viewer.  Unlike Panini, it generates full resolution output.

To run it you need to install Gimp for Windows
http://www.gimp.org/windows/
and MathMap 1.3.5
http://www.complang.tuwien.ac.at/schani/mathmap/

Enjoy! -- Tom

filter eqr_pan_ts (
image in,
float FoV: 15-320 (150),
float eye: 0-1.5 (1),
float pan: -180-180 (0),
float vsh: -1-1 (0))
#
# equirectangular to panini per Tom Sharpless's interpretation
# of the projection implemented in his OpenGL program "Panini",
# namely a rectilinear projection of a 3D cylindrical image.
# Gives images identical to Panini version 0.7, except without
# the black holes at zenith & nadir, smaller range of eye point
# positions, and slightly different limit on fov vs. eye pos.
#
# angular scale factors
Sppr = W / (2*pi); # source pixels/radian
d = eye + 1;
wfov = pi * min( FoV, 160 * d ) / 180; # radians
Drpp = 2*d*tan(wfov/(2*d)) / W;
# destination coordinates in radians
xr = x * Drpp; yr = (y - Y * vsh) * Drpp;
# project from dest to source
azi = d * atan( xr, d);
alt = atan( yr * (eye + cos(azi)), d );
# source coordinates in pixels
sx = Sppr*azi; sy = Sppr*alt;
# pan & interpolate
sx = sx + W*pan/360;
if sx > X then sx = sx - W end;
if sx < -X then sx = sx + W end;
in(xy:[sx, sy])
end

Tom Sharpless

Re: New Mathmap Script for Panini Projection

Reply Threaded More More options
Print post
Permalink


And for completeness here is my older MathMap script, PVSqueeze, for compressing the bulges at top and bottom of a Panini image, and a description of how to use it.

Cheers, Tom

filter PVSqeeze( image in, # a Pannini view...
float hfov: 30-250 (150), # true angular width
float eyeDist: 0-2 (1), # projection parameter
float PCX: -0.25-0.25 (0), # pano center
float PCY: -0.25-0.25 (0),
float VPX: -0.25-0.25 (0), # vanishing point
float VPY: -0.20-0.20 (0),
float ULangl: 0-90 (45), # angles of the vee edges...
float LLangl: 0-90 (45),
float URangl: 0-90 (45),
float LRangl: 0-90 (45),
float UTwid: 0-0.5 (0.25), # width of transition zone
float UVlim: 0-0.5 (0), # upr edge of pure vertical zone
float LVlim: 0-0.5 (0), # lwr edge of pure vertical zone
float LTwid: 0-0.5 (0.25) # width of transition zone
)
### Flattens upper and lower Vees in a Pannini projection ###
# by a mixed vertical/radial contraction #
# 4 vee edges intersect at the vanishing point, which is not #
# necessarily at the projection center, which need not be at #
# the center of the image. #
# copyright (c) 2009 TKSharpless Anyone is hereby licensed #
# to use PVFlat in any way, but with no implied warranty #
### ###
# vee valid flags
amin = 3.0; # minimum valid vee angle
uok = 90 - ULangl >= amin && URangl >= amin;
lok = 90 - LLangl >= amin && LRangl >= amin;
# slopes and normals of the vee lines
# normals point inside the vee
th = deg2rad(180 - ULangl);
st = sin(th); ct = cos(th);
uln = v2:[ st, -ct ];
uls = if uok then st / ct else 0 end;
th = deg2rad(90 - URangl);
st = sin(th); ct = cos(th);
urn = v2:[ -st, ct ];
urs = if uok then st / ct else 0 end;
th = deg2rad(-180 + LLangl);
st = sin(th); ct = cos(th);
lln = v2:[ -st, ct ];
lls = if lok then st / ct else 0 end;
th = deg2rad(-90 + LRangl);
st = sin(th); ct = cos(th);
lrn = v2:[ st, -ct ];
lrs = if lok then st / ct else 0 end;
# Pannini projection parameters
ed = eyeDist + 1; # eye to img in pano radians
# eye to image plane in pixels
edp = 0.5 * W / tan( 0.5 * deg2rad( hfov ) / ed );
# panosphere radius in pixels
Rp = edp / ed;
# image coordinates of projection center
pcx = PCX * W;
pcy = PCY * H;
# vanishing point (PC-origin, eye radians)
vpx = (VPX - PCX) * W / edp;
vpy = (VPY - PCY) * H / edp;
# vertical/radial Y limits
vuy = UVlim * H / edp - vpy;
ruy = vuy + UTwid * H / edp - vpy ;
vly = LVlim * H / edp - vpy;
rly = vly + LTwid * H / edp - vpy ;
# panocylinder coordinates of VP (pano radians)
pth = ed * atan( vpx ); # azimuth at eye
ptz = cos( pth );
pty = vpy * (ed - 1 + ptz);
ptx = sin( pth );
vpcyl = v3:[ ptx, pty, ptz ];
# current point (PC-origin, eye radians)
ptx = (x - pcx) / edp;
pty = (y - pcy) / edp;
# ditto, VP-origin
pdx = ptx - vpx; pdy = pty - vpy;
evec = v2:[ pdx, pdy ]; # for in-vee test
# select upper or lower vee, or no corr
if pdy > 0 then
vok = if uok then
dotp( evec, uln ) > 0 && dotp( evec, urn ) > 0
else 0 end;
vls = uls; vrs = urs;
vsgn = 1;
vy = vuy; ry = ruy;
else
vok = if lok then
dotp( evec, lln ) > 0 && dotp( evec, lrn ) > 0
else 0 end;
vls = lls; vrs = lrs;
vsgn = -1;
vy = vly; ry = rly;
end;
# default remapped point
tx = x; ty = y;
# squeeze if this point is in a valid vee
if vok then
# intersections of line thru pt with vee lines
# (VP-origin img coords in eye radians)
slp = vsgn * vpx;
ldx = (pdy - slp * pdx )/ (vls - slp);
ldy = vls * ldx;
rdx = (pdy - slp * pdx) / (vrs - slp);
rdy = vrs * rdx;
# shift from VP-origin to PC-origin
lex = ldx + vpx; ley = ldy + vpy;
rex = rdx + vpx; rey = rdy + vpy;
pex = pdx + vpx; pey = pdy + vpy;
# map img points to 3D cylinder in pano radians
lth = ed * atan( lex ); # pano radians
lcz = cos( lth );
lcy = ley * (ed - 1 + lcz);
lcx = sin( lth );
rth = ed * atan( rex );
rcz = cos( rth );
rcy = rey * (ed - 1 + rcz);
rcx = sin( rth );
pth = ed * atan( pex );
ptz = cos( pth );
pty = pey * (ed - 1 + ptz);
ptx = sin( pth );
# pano plane on the intersection points (unit normal)
ppn = normalize(crossp( v3:[rcx, rcy, rcz], v3:[lcx, lcy, lcz]));
# vertical/radial blend
refp = vpcyl;
ty = vsgn * pdy;
if ty ry then
p = 1;
else
p = (ty - vy) / (ry - vy);
end;
end;
refp = refp * p + v3:[ptx, 0, ptz] * (1 - p);
# pano plane on pt and the reference point
ppp = normalize(crossp( v3:[ptx, pty, ptz], refp ));
# panosphere point on intersection of those planes
spt = crossp( ppn, ppp );
# map pano point to cylinder
cys = vsgn / abs(v2:[spt[0], spt[2]]); # sph to cyl scale
cyx = spt[0] * cys; # cylinder x
cyy = spt[1] * cys; # cylinder y
cyz = spt[2] * cys; # cylinder z
# map cyl to img
cis = edp / ( ed - 1 + cyz ); # cyl to img scale
tx = pcx + cyx * cis;
ty = pcy + cyy * cis;
end;
# source point
in(xy:[ tx,ty ])
end

How to use PVSqueeze.mm

The purpose of PVSqueeze is to correct vertical bowing at the top and
bottom of images in Pannini projection, which can spoil the natural
look of architectural images in particular. It does this by shifting
pixels in upper and lower "vees" defined by two pairs of lines
radiating from a vanishing point. The shifts are purely vertical near
the center and radially inward toward the vanishing point farther out;
the locations and widths of the transitition zones are adjustable with
enough range so that the shift can be made all vertical or all radial.

The pixel shift, which is calculated to straighten the images of
horizontal lines, depends on the the assumed parameters of the Pannini
image (horizontal field of view and viewpoint distance) which are also
adjustable. Of course the shift also depend on the positions of the
radial lines, since it must be zero along those lines.

To use PVSqueeze you need version 1.3 of the Mathmap Gimp plugin,
which is only available on Linux so far as I know. To make the script
accessible to the plugin you can either put it in the same directory
as other Mathmap scripts, or paste it into the Mathmap script window
and save it.

Step 1: generate a Panini projection showing a nice 1-point
perspective view with the vanishing point within 15 degrees of image
center. You can do that with Panini, or a stitcher if you want higher
resolution. If you use Panini, PTGui or PTAssembler you can vary the
horizontal compression (eye distance, in Panini) to suit. In Hugin the
eye distance is fixed at 1. Try to estimate the horizontal field of
view.

Step 2: Load it into Gimp and open filter/Generic/MathMap/Mathmap (not
one of the preset script names). LoadPVSqueeze and click Preview if
necessary to see the low-res live image. Then go to the User Values
tab. Set the hfov and eyeDist sliders roughly right for your Pannini.

Step 3: Adjust the vanishing point position (VPX, VPY), and the slopes
of the 4 perspective edges (XXangl) to put them in the appropriate
places in your image. The important thing is that they are parallel to
the images of the top and bottom edges of the walls, if your image is
a room. There aren't any drawn lines, but the change of image shape is
pretty easy to see as you move the sliders. NOTE you have to set he
projection center Y identical to the VP Y by hand, or you get a black
triangle in the middle (bug; but misaligning them can help you see
just where the VP is).

Step 4: Adjust the shift transition zone controls for the upper and
lower Vees to suit. Basically you need vertical shift where you have
vertical features like columns or chair legs that must stay straight,
while radial shift better preserves patterns on the floor or ceiling.
The shift direction varies with vertical position, from vertical at
the VP to radial farther out. xVlim controls the vertical level at
which this transition starts, and xTwid the width of the transition
zone. You can set them for pure vertical or pure radial shift, or some
blend.

Step 5: Hit OK, review the full size result in the Gimp window; save
or go back and adjust some more.


DemonDuck

Re: New Mathmap Script for Panini Projection

Reply Threaded More More options
Print post
Permalink
In reply to this post by Tom Sharpless
Looking at your code I got that same numb, floating sensation
that I used to get in my advanced math classes in university... :-)

tksharpless wrote:

> Now that MathMap version 1.3 works on Windows, more of you may be interested in trying this new MathMap script for converting an equirectangular image to the generalized Panini projection, as implemented in the Panini viewer.  Unlike Panini, it generates full resolution output.
>
> To run it you need to install Gimp for Windows
> http://www.gimp.org/windows/
> and MathMap 1.3.5
> http://www.complang.tuwien.ac.at/schani/mathmap/
>
> Enjoy! -- Tom
>
>
Keith Martin-2

Re: New Mathmap Script for Panini Projection

Reply Threaded More More options
Print post
Permalink
Sometime around 6/11/09 (at 10:29 -0800) Ken Warner said:

>Looking at your code I got that same numb, floating sensation
>that I used to get in my advanced math classes in university... :-)

Or later, in the student bar? ;-P

k
Tom Sharpless

Re: New Mathmap Script for Panini Projection

Reply Threaded More More options
Print post
Permalink
In reply to this post by DemonDuck
Hey Ken

--- In [hidden email], Ken Warner <kwarner000@...> wrote:
>
> Looking at your code I got that same numb, floating sensation
> that I used to get in my advanced math classes in university... :-)
>
At least you took advanced math classes.  I get that same sensation without having had the benefit of any :-)  

Seriously, I'm bad at math, I have to draw a lot of diagrams and do a lot of testing to get code that works right.

I will admit that PVSqueeze is mind-numbing, probably unnecessarily so.  But the basic Panini is pretty straightforward.

Regards, Tom

DemonDuck

Re: Re: New Mathmap Script for Panini Projection

Reply Threaded More More options
Print post
Permalink
Looking at what you've done -- I don't think a math class would be
necessary.  It's pretty strong stuff.

"Seriously, I'm bad at math, I have to draw a lot of diagrams and do a lot of testing"

That actually means you are very good at math.  That's exactly what it takes.

When I get some time and energy, I have some equi's that would be perfect to
try with your panini filter.  I've sometimes looked at equi's and thought that
they had a nice shape as a flat picture.  If you set the viewpoint in the right
place, you can get some interesting symmetry and balance.

More later...

tksharpless wrote:

> Hey Ken
>
> --- In [hidden email], Ken Warner <kwarner000@...> wrote:
>> Looking at your code I got that same numb, floating sensation
>> that I used to get in my advanced math classes in university... :-)
>>
> At least you took advanced math classes.  I get that same sensation without having had the benefit of any :-)  
>
> Seriously, I'm bad at math, I have to draw a lot of diagrams and do a lot of testing to get code that works right.
>
> I will admit that PVSqueeze is mind-numbing, probably unnecessarily so.  But the basic Panini is pretty straightforward.
>
> Regards, Tom
>
>