> I've read a lot on the PanoTools lens correction model in this user group
> and over the Internet, however I still have a lot of questions. All its
> disadvantages were discussed several times, but I could not a detailed
> description of the mechanism itself.
> I have calibrated a fisheye lens using Kannala model, which is basically a
> polynomial R(theta), where R is the polar coordinates radius of current
> point. Now I have a need to work with this calibration in PTGui. We use
> Canon APS-C matrix crop-factor 1.62, 4272x2848 matrix in the landscape
> mode, 8 mm Sigma fisheyes.
> I need to express PanoTools model as a function R(theta). To accomplish
> this, I can iterate all possible thetas in the [0, pi/2] range and find the
> radius R, corresponding to it. This is how I do it:
> 1) calculate undistorted equidistant radius (used both by Panotools and
> PTGui, not by Hugin, right?) R_undist = f*theta*m as undistorted radius in
> pixels. I take m as a mm-to-pixel conversion factor from camera
> specification: matrix width is 22.2 mm = 4272 pixels.
> 2) convert it to PTGui units using the condition r=1 when r=width/2 (this
> is taken from PTGui documentation). r = R_undist / (width/2).
> 3) solve quartic equation in PTGui units: a*r^4 + b*r^3 + c*r^2 +
> (1-a-b-c)*r - Rundist = 0 , which gives us r - the distorted radius
> 4) convert distorted radius to pixels: r_dist_px = r_dist*(width/2), so we
> have a r(theta) mapping.
> For backprojection theta(R) we have to do the same it the opposite
> 1) Convert R to PTGui units: r = R/(width/2)
> 2) Apply the undistorting polynomial: r_undist =
> 3) Convert r_undist back to pixels, and then to mm : r_undist_mm =
> 4) Taking f*theta model into account, return r_undist_mm / f as a
> backprojection angle theta.
> This looks logical, but doesn't work. The radiuses don't get distorted and
> undistorted as expected. I've also found this intriguing code in math.c of
> libpano13. Why are the coefficients used with r, and not polynomially? The
> same thing can be found in "inv_radial" function, where the polynomial is
> solved. Maybe I misunderstand the whole model?
> int radial( double x_dest, double y_dest, double* x_src, double* y_src,
>> void* params)
>> // params: double coefficients, scale, correction_radius
>> register double r, scale;
>> r = (sqrt( x_dest*x_dest + y_dest*y_dest )) / ((double*)params); // r
>> = r_px/scale
>> if( r < ((double*)params) )
>> scale = ((((double*)params) * r + ((double*)params)) * r +
>> ((double*)params)) * r + ((double*)params); // scale
>> = a*r+b*r+c*r+d
>> scale = 1000.0;
>> *x_src = x_dest * scale ;
>> *y_src = y_dest * scale ;
>> return 1;
> I've also tried to understand the conversion from fov to f and back. This
> is what Joost, the author of PTGui, exactly told me:
>> Yes PTGui still uses the f*theta projection.
>> This is how PTGui calculates the horz fov:
>> cropwidth_mm is the diameter of the cropping circle, or the width of the
>> I realize that this is not consistent with the equidistant formula but it
>> does match the fov for practical lenses.
> However, when I use the diameter of crop circle as cropwidth_**mm (4500
> px in my case), it doesn't work correctly. I empirically found, that the
> mistake is linear, and the correct conversion formula is f =
> 0.967555562*D/(4*m*sin(radians(fov)/4)) or hfov=4*asin(0.967555562*D/(4*m*focallength)),
> where D is the crop width in pixels, m the scale coefficient desribed
> earlier. The fact that the mistake is linear makes me think I use a
> different value of m? Or maybe it's more complicated.
> I've contacted the author of PTGui himself, he has answered some of my
> questions, but was not willing to solve the problems, so I decided to try
> to get advice in this group.
> Thanks in advance for any help,