📄 cal_main.c
字号:
/*******************************************************************************\* ** This file contains routines for calibrating Tsai's 11 parameter camera model. ** The camera model is based on the pin hole model of 3D-2D perspective ** projection with 1st order radial lens distortion. The model consists of ** 5 internal (also called intrinsic or interior) camera parameters: ** ** f - effective focal length of the pin hole camera ** kappa1 - 1st order radial lens distortion coefficient ** Cx, Cy - coordinates of center of radial lens distortion ** (also used as the piercing point of the camera coordinate ** frame's Z axis with the camera's sensor plane) ** sx - uncertainty factor for scale of horizontal scanline ** ** and 6 external (also called extrinsic or exterior) camera parameters: ** ** Rx, Ry, Rz, Tx, Ty, Tz - rotational and translational components of ** the transform between the world's coordinate ** frame and the camera's coordinate frame. ** ** Data for model calibration consists of the (x,y,z) world coordinates of a ** feature point (in mm) and the corresponding coordinates (Xf,Yf) (in pixels) ** of the feature point in the image. Two types of calibration are available: ** ** coplanar - all of the calibration points lie in a single plane ** non-coplanar - the calibration points do not lie in a single plane ** ** This file contains routines for two levels of calibration. The first level ** of calibration is a direct implementation of Tsai's algorithm in which only ** the f, Tz and kappa1 parameters are optimized for. The routines are: ** ** coplanar_calibration () ** noncoplanar_calibration () ** ** The second level of calibration optimizes for everything. This level is ** very slow but provides the most accurate calibration. The routines are: ** ** coplanar_calibration_with_full_optimization () ** noncoplanar_calibration_with_full_optimization () ** ** Routines are also provided for initializing camera parameter variables ** for five of our camera/frame grabber systems. These routines are: ** ** initialize_photometrics_parms () ** initialize_general_imaging_mos5300_matrox_parms () ** initialize_panasonic_gp_mf702_matrox_parms () ** initialize_sony_xc75_matrox_parms () ** initialize_sony_xc77_matrox_parms () ** initialize_sony_xc57_androx_parms () ** ** ** External routines ** ----------------- ** ** Nonlinear optimization for these camera calibration routines is performed ** by the MINPACK lmdif subroutine. lmdif uses a modified Levenberg-Marquardt ** with a jacobian calculated by a forward-difference approximation. ** The MINPACK FORTRAN routines were translated into C generated using f2c. ** ** Matrix operations (inversions, multiplications, etc.) are also provided by ** external routines. ** ** ** Extra notes ** ----------- ** ** An explanation of the basic algorithms and description of the variables ** can be found in several publications, including: ** ** "An Efficient and Accurate Camera Calibration Technique for 3D Machine ** Vision", Roger Y. Tsai, Proceedings of IEEE Conference on Computer Vision ** and Pattern Recognition, Miami Beach, FL, 1986, pages 364-374. ** ** and ** ** "A versatile Camera Calibration Technique for High-Accuracy 3D Machine ** Vision Metrology Using Off-the-Shelf TV Cameras and Lenses", Roger Y. Tsai, ** IEEE Journal of Robotics and Automation, Vol. RA-3, No. 4, August 1987, ** pages 323-344. ** ** ** Notation ** -------- ** ** The camera's X axis runs along increasing column coordinates in the ** image/frame. The Y axis runs along increasing row coordinates. ** ** pix == image/frame grabber picture element ** sel == camera sensor element ** ** Internal routines starting with "cc_" are for coplanar calibration. ** Internal routines starting with "ncc_" are for noncoplanar calibration. ** ** ** History ** ------- ** ** 20-May-95 Reg Willson (rgwillson@mmm.com) at 3M St. Paul, MN ** Return the error to lmdif rather than the squared error. ** lmdif calculates the squared error internally during optimization. ** Before this change calibration was essentially optimizing error^4. ** Put transform and evaluation routines into separate files. ** ** 02-Apr-95 Reg Willson (rgwillson@mmm.com) at 3M St. Paul, MN ** Rewrite memory allocation to avoid memory alignment problems ** on some machines. ** Strip out IMSL code. MINPACK seems to work fine. ** Filename changes for DOS port. ** ** 04-Jun-94 Reg Willson (rgwillson@mmm.com) at 3M St. Paul, MN ** Replaced ncc_compute_Xdp_and_Ydp with ncc_compute_Xd_Yd_and_r_squared. ** (effectively propagates the 22-Mar-94 to the non-coplanar routines) ** Added alternate macro definitions for less common math functions. ** ** 25-Mar-94 Torfi Thorhallsson (torfit@verk.hi.is) at the University of Iceland** Added a new version of the routines: ** cc_compute_exact_f_and_Tz () ** cc_five_parm_optimization_with_late_distortion_removal () ** cc_five_parm_optimization_with_early_distortion_removal () ** cc_nic_optimization () ** cc_full_optimization () ** ncc_compute_exact_f_and_Tz () ** ncc_nic_optimization () ** ncc_full_optimization () ** ** The new routines use the *public domain* MINPACK library for ** optimization instead of the commercial IMSL library. ** To select the new routines, compile this file with the flag -DMINPACK ** ** 22-Mar-94 Torfi Thorhallsson (torfit@verk.hi.is) at the University of Iceland** Fixed a bug in cc_nic_optimization_error and cc_full_optimization_error.** A division by cp.sx was missing. ** ** 15-Feb-94 Reg Willson (rgw@cs.cmu.edu) at Carnegie-Mellon University ** Included Frederic Devernay's (<Frederic.Devernay@sophia.inria.fr>) ** significantly improved routine for converting from undistorted to ** distorted sensor coordinates. Rather than iteratively solving a ** system of two non-linear equations to perform the conversion, the ** new routine algebraically solves a cubic polynomial in Rd (using ** the Cardan method). ** ** 14-Feb-94 Reg Willson (rgw@cs.cmu.edu) at Carnegie-Mellon University ** Fixed a coding bug in ncc_compute_R and ncc_compute_better_R. ** The r4, r5, and r6 terms should not be divided by cp.sx. ** Bug reported by: Volker Rodehorst <vr@cs.tu-berlin.de> ** ** 04-Jul-93 Reg Willson (rgw@cs.cmu.edu) at Carnegie-Mellon University ** Added new routines to evaluate the accuracy of camera calibration. ** ** Added check for coordinate handedness problem in calibration data. ** ** 01-May-93 Reg Willson (rgw@cs.cmu.edu) at Carnegie-Mellon University ** For efficiency the non-linear optimizations are now all based on ** the minimization of squared error in undistorted image coordinates ** instead of the squared error in distorted image coordinates. ** ** New routine for inverse perspective projection. ** ** 14-Feb-93 Reg Willson (rgw@cs.cmu.edu) at Carnegie-Mellon University ** Bug fixes and speed ups. ** ** 07-Feb-93 Reg Willson (rgw@cs.cmu.edu) at Carnegie-Mellon University ** Original implementation. ** *\*******************************************************************************/#include <stdlib.h>#include <stdio.h>#include <math.h>#include <errno.h>#include "matrix/matrix.h"#include "cal_main.h"#include "minpack/f2c.h"/* Variables used by the subroutines for I/O (perhaps not the best way of doing this) */struct camera_parameters cp;struct calibration_data cd;struct calibration_constants cc;/* Local working storage */double Xd[MAX_POINTS], Yd[MAX_POINTS], r_squared[MAX_POINTS], U[7];char camera_type[256] = "unknown";/************************************************************************/.
void initialize_photometrics_parms (){ strcpy (camera_type, "Photometrics Star I"); cp.Ncx = 576; /* [sel] */ cp.Nfx = 576; /* [pix] */ cp.dx = 0.023; /* [mm/sel] */ cp.dy = 0.023; /* [mm/sel] */ cp.dpx = cp.dx * cp.Ncx / cp.Nfx; /* [mm/pix] */ cp.dpy = cp.dy; /* [mm/pix] */ cp.Cx = 576 / 2; /* [pix] */ cp.Cy = 384 / 2; /* [pix] */ cp.sx = 1.0; /* [] */ /* something a bit more realistic */ cp.Cx = 258.0; cp.Cy = 204.0;}/************************************************************************/void initialize_general_imaging_mos5300_matrox_parms (){ strcpy (camera_type, "General Imaging MOS5300 + Matrox"); cp.Ncx = 649; /* [sel] */ cp.Nfx = 512; /* [pix] */ cp.dx = 0.015; /* [mm/sel] */ cp.dy = 0.015; /* [mm/sel] */ cp.dpx = cp.dx * cp.Ncx / cp.Nfx; /* [mm/pix] */ cp.dpy = cp.dy; /* [mm/pix] */ cp.Cx = 512 / 2; /* [pix] */ cp.Cy = 480 / 2; /* [pix] */ cp.sx = 1.0; /* [] */}/************************************************************************/void initialize_panasonic_gp_mf702_matrox_parms (){ strcpy (camera_type, "Panasonic GP-MF702 + Matrox"); cp.Ncx = 649; /* [sel] */ cp.Nfx = 512; /* [pix] */ cp.dx = 0.015; /* [mm/sel] */ cp.dy = 0.015; /* [mm/sel] */ cp.dpx = cp.dx * cp.Ncx / cp.Nfx; /* [mm/pix] */ cp.dpy = cp.dy; /* [mm/pix] */ cp.Cx = 268; /* [pix] */ cp.Cy = 248; /* [pix] */ cp.sx = 1.078647; /* [] */}/************************************************************************/void initialize_sony_xc75_matrox_parms (){ strcpy (camera_type, "Sony XC75 + Matrox"); cp.Ncx = 768; /* [sel] */ cp.Nfx = 512; /* [pix] */ cp.dx = 0.0084; /* [mm/sel] */ cp.dy = 0.0098; /* [mm/sel] */ cp.dpx = cp.dx * cp.Ncx / cp.Nfx; /* [mm/pix] */ cp.dpy = cp.dy; /* [mm/pix] */ cp.Cx = 512 / 2; /* [pix] */ cp.Cy = 480 / 2; /* [pix] */ cp.sx = 1.0; /* [] */}/************************************************************************/void initialize_sony_xc77_matrox_parms (){ strcpy (camera_type, "Sony XC77 + Matrox"); cp.Ncx = 768; /* [sel] */ cp.Nfx = 512; /* [pix] */ cp.dx = 0.011; /* [mm/sel] */ cp.dy = 0.013; /* [mm/sel] */ cp.dpx = cp.dx * cp.Ncx / cp.Nfx; /* [mm/pix] */ cp.dpy = cp.dy; /* [mm/pix] */ cp.Cx = 512 / 2; /* [pix] */ cp.Cy = 480 / 2; /* [pix] */ cp.sx = 1.0; /* [] */}/************************************************************************/void initialize_sony_xc57_androx_parms (){ strcpy (camera_type, "Sony XC57 + Androx"); cp.Ncx = 510; /* [sel] */ cp.Nfx = 512; /* [pix] */ cp.dx = 0.017; /* [mm/sel] */ cp.dy = 0.013; /* [mm/sel] */ cp.dpx = cp.dx * cp.Ncx / cp.Nfx; /* [mm/pix] */ cp.dpy = cp.dy; /* [mm/pix] */ cp.Cx = 512 / 2; /* [pix] */ cp.Cy = 480 / 2; /* [pix] */ cp.sx = 1.107914; /* [] */}/************************************************************************//* John Krumm, 9 November 1993 *//* This assumes that every other row, starting with the second row from *//* the top, has been removed. The Xap Shot CCD only has 250 lines, and *//* it inserts new rows in between the real rows to make a full size *//* picture. Its algorithm for making these new rows isn't very good, *//* so it's best just to throw them away. *//* The camera's specs give the CCD size as 6.4(V)x4.8(H) mm. *//* A call to the manufacturer found that the CCD has 250 rows *//* and 782 columns. It is underscanned to 242 rows and 739 columns. *//************************************************************************/void initialize_xapshot_matrox_parms (){ strcpy (camera_type, "Canon Xap Shot"); cp.Ncx = 739; /* [sel] */ cp.Nfx = 512; /* [pix] */ cp.dx = 6.4 / 782.0; /* [mm/sel] */ cp.dy = 4.8 / 250.0; /* [mm/sel] */ cp.dpx = cp.dx * cp.Ncx / cp.Nfx; /* [mm/pix] */ cp.dpy = cp.dy; /* [mm/pix] */ cp.Cx = 512 / 2; /* [pix] */ cp.Cy = 240 / 2; /* [pix] */ cp.sx = 1.027753; /* from noncoplanar calibration *//* [] */}/***********************************************************************\* This routine solves for the roll, pitch and yaw angles (in radians) ** for a given orthonormal rotation matrix (from Richard P. Paul, ** Robot Manipulators: Mathematics, Programming and Control, p70). ** Note 1, should the rotation matrix not be orthonormal these will not ** be the "best fit" roll, pitch and yaw angles. ** Note 2, there are actually two possible solutions for the matrix. ** The second solution can be found by adding 180 degrees to Rz before ** Ry and Rx are calculated. *\***********************************************************************/void solve_RPY_transform (){ double sg, cg; cc.Rz = atan2 (cc.r4, cc.r1); SINCOS (cc.Rz, sg, cg); cc.Ry = atan2 (-cc.r7, cc.r1 * cg + cc.r4 * sg); cc.Rx = atan2 (cc.r3 * sg - cc.r6 * cg, cc.r5 * cg - cc.r2 * sg);}/***********************************************************************\* This routine simply takes the roll, pitch and yaw angles and fills in ** the rotation matrix elements r1-r9. *\***********************************************************************/void apply_RPY_transform (){ double sa, ca, sb, cb, sg, cg; SINCOS (cc.Rx, sa, ca); SINCOS (cc.Ry, sb, cb); SINCOS (cc.Rz, sg, cg); cc.r1 = cb * cg; cc.r2 = cg * sa * sb - ca * sg; cc.r3 = sa * sg + ca * cg * sb; cc.r4 = cb * sg; cc.r5 = sa * sb * sg + ca * cg; cc.r6 = ca * sb * sg - cg * sa; cc.r7 = -sb; cc.r8 = cb * sa; cc.r9 = ca * cb;}/***********************************************************************\* Routines for coplanar camera calibration *\***********************************************************************/void cc_compute_Xd_Yd_and_r_squared (){ int i; double Xd_, Yd_; for (i = 0; i < cd.point_count; i++) { Xd[i] = Xd_ = cp.dpx * (cd.Xf[i] - cp.Cx) / cp.sx; /* [mm] */ Yd[i] = Yd_ = cp.dpy * (cd.Yf[i] - cp.Cy); /* [mm] */ r_squared[i] = SQR (Xd_) + SQR (Yd_); /* [mm^2] */ }}void cc_compute_U (){ int i; dmat M, a, b; M = newdmat (0, (cd.point_count - 1), 0, 4, &errno); if (errno) { fprintf (stderr, "cc compute U: unable to allocate matrix M\n"); exit (-1); } a = newdmat (0, 4, 0, 0, &errno); if (errno) { fprintf (stderr, "cc compute U: unable to allocate vector a\n"); exit (-1); } b = newdmat (0, (cd.point_count - 1), 0, 0, &errno); if (errno) { fprintf (stderr, "cc compute U: unable to allocate vector b\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -