camtrans.cpp
Go to the documentation of this file.
00001 /**************************************************************************************************
00002  Software License Agreement (BSD License)
00003 
00004  Copyright (c) 2011-2013, LAR toolkit developers - University of Aveiro - http://lars.mec.ua.pt
00005  All rights reserved.
00006 
00007  Redistribution and use in source and binary forms, with or without modification, are permitted
00008  provided that the following conditions are met:
00009 
00010   *Redistributions of source code must retain the above copyright notice, this list of
00011    conditions and the following disclaimer.
00012   *Redistributions in binary form must reproduce the above copyright notice, this list of
00013    conditions and the following disclaimer in the documentation and/or other materials provided
00014    with the distribution.
00015   *Neither the name of the University of Aveiro nor the names of its contributors may be used to
00016    endorse or promote products derived from this software without specific prior written permission.
00017  
00018  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
00019  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
00020  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
00021  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00024  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00025  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 ***************************************************************************************************/
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <math.h>
00036 #include <string.h>
00037 
00038 #include "small_linalg.h"
00039 #include "rotations.h"
00040 
00041 #include "camtrans.h"
00042 
00043 #define CAMERA_EPSILON 1e-10
00044 
00045 // Function that produces values for the warp tables
00046 typedef void (*warp_func_t)(const double, const double, const void*,
00047                             double*, double*);
00048 
00049 
00050 // Structure for spherical distortion model
00051 typedef struct {
00052   double w;   // Original image width
00053   double h;   // Original image height
00054   double cx;  // Center of distortion (normalized coords)
00055   double cy;
00056   double a;   // Spherical distortion parameter
00057 
00058   // Temporaries for faster computation
00059   double inv_w;
00060   double x_trans;
00061   double y_trans;
00062 } SphericalDistortion;
00063 
00064 
00065 // Construct spherical distortion object, initialized with parameters
00066 static SphericalDistortion*
00067 spherical_distortion_create (const double w, const double h,
00068                              const double cx, const double cy,
00069                              const double a)
00070 {
00071   SphericalDistortion* dist =
00072     (SphericalDistortion*)malloc(sizeof(SphericalDistortion));
00073   dist->w = w;
00074   dist->h = h;
00075   dist->cx = cx;
00076   dist->cy = cy;
00077   dist->a = a*a*a*a;
00078   dist->inv_w = 1/w;
00079   dist->x_trans = 0.5 + cx;
00080   dist->y_trans = 0.5*h/w + cy;  
00081   return dist;
00082 }
00083 
00084 // Destructor
00085 static void
00086 spherical_distortion_destroy(SphericalDistortion* dist)
00087 {
00088   free(dist);
00089 }
00090 
00091 
00092 // Undistort according to spherical model
00093 static void
00094 spherical_undistort_func(const double x, const double y, const void* data,
00095                          double* ox, double* oy)
00096 {
00097   SphericalDistortion* dist = (SphericalDistortion*)data;
00098 
00099   *ox = x * dist->inv_w - dist->x_trans;
00100   *oy = y * dist->inv_w - dist->y_trans;
00101 
00102   double r2 = *ox * *ox + *oy * *oy;
00103   double new_r2 = r2/(1 - r2*dist->a);
00104 
00105   double ratio;
00106   if (fabs(r2) < 1e-8)
00107     ratio = 0;
00108   else
00109     ratio = new_r2/r2;
00110 
00111   if (ratio >= 0) {
00112     ratio = sqrt(ratio);
00113     *ox = (*ox*ratio + dist->x_trans)*dist->w;
00114     *oy = (*oy*ratio + dist->y_trans)*dist->w;
00115   }
00116   else {
00117     *ox = *oy = -1e50;
00118   }
00119 }
00120 
00121 
00122 // Distort according to spherical model
00123 static void
00124 spherical_distort_func(const double x, const double y, const void* data,
00125                        double* ox, double* oy)
00126 {
00127   SphericalDistortion* dist = (SphericalDistortion*)data;
00128 
00129   *ox = x * dist->inv_w - dist->x_trans;
00130   *oy = y * dist->inv_w - dist->y_trans;
00131 
00132   double r2 = *ox * *ox + *oy * *oy;
00133   double new_r2 = r2/(1 + r2*dist->a);
00134 
00135   double ratio;
00136   if (fabs(r2) < 1e-8)
00137     ratio = 0;
00138   else
00139     ratio = new_r2/r2;
00140 
00141   ratio = sqrt(ratio);
00142   *ox = (*ox*ratio + dist->x_trans)*dist->w;
00143   *oy = (*oy*ratio + dist->y_trans)*dist->w;
00144 }
00145 
00146 
00147 
00148 
00149 // Structure to hold camera data
00150 struct _CamTrans {
00151   double width;             // Image width in pixels
00152   double height;            // Image height in pixels
00153 
00154   double position[3];       // Position in world (sensor) coords
00155   double orientation[4];    // Orientation in world (sensor) coords as
00156                             // quaternion
00157   double fx;                // Focal length in x (pixels)
00158   double fy;                // Focal length in y (pixels)
00159   double cx;                // Principal point x (pixels)
00160   double cy;                // Principal point y (pixels)
00161   double skew;              // Pixel skew
00162 
00163   double matx[12];          // Aggregate 3x4 camera projection matrix
00164   double inv_matx[9];       // Inverse of 3x3 submatrix of matx
00165 
00166   warp_func_t undist_func;  // Undistortion function
00167   warp_func_t dist_func;    // Distortion function
00168   void* dist_data;          // Distortion/undistortion data
00169 };
00170 
00171 CamTrans * 
00172 camtrans_new_spherical (double width, double height, 
00173         double fx, double fy, 
00174         double cx, double cy, double skew,
00175         const double position[3], const double orientation_quat[4],
00176         const double distortion_cx, const double distortion_cy,
00177         double distortion_param)
00178 {
00179     CamTrans *self = (CamTrans*)malloc (sizeof (CamTrans));
00180     self->width = width;
00181     self->height = height;
00182     self->fx = fx;
00183     self->fy = fy;
00184     self->cx = cx;
00185     self->cy = cy;
00186     self->skew = skew;
00187     self->position[0] = position[0];
00188     self->position[1] = position[1];
00189     self->position[2] = position[2];
00190     self->orientation[0] = orientation_quat[0];
00191     self->orientation[1] = orientation_quat[1];
00192     self->orientation[2] = orientation_quat[2];
00193     self->orientation[3] = orientation_quat[3];
00194 
00195     SphericalDistortion* dist_data;
00196     dist_data = spherical_distortion_create(self->width, self->height,
00197                                           distortion_cx, distortion_cy,
00198                                           distortion_param);
00199 
00200     // Create distortion/undistortion objects
00201     self->dist_data = (void*)dist_data;
00202     self->undist_func = spherical_undistort_func;
00203     self->dist_func = spherical_distort_func;
00204 
00205     // Compute internal matrix representations
00206     camtrans_compute_matrices (self);
00207     return self;
00208 }
00209 
00210 // Destructor
00211 void camtrans_destroy (CamTrans* t)
00212 {
00213     if (NULL != t) {
00214         spherical_distortion_destroy((SphericalDistortion*)t->dist_data);
00215         free(t);
00216     }
00217 }
00218 
00219 
00220 void 
00221 camtrans_compute_matrices (CamTrans *t) 
00222 {
00223     double rot[9];
00224     double rot_trans[9];
00225     rot_quat_to_matrix(t->orientation, rot);
00226     matrix_transpose_3x3d (rot, rot_trans);
00227 
00228     double tmp_34[] = {
00229         1, 0, 0, -t->position[0],
00230         0, 1, 0, -t->position[1],
00231         0, 0, 1, -t->position[2],
00232     };
00233     double pinhole[] = {
00234         t->fx, t->skew, t->cx,
00235         0,     t->fy,   t->cy,
00236         0,     0,       1 
00237     };
00238 
00239     double tmp_33[9];
00240     matrix_multiply_3x3_3x3 (pinhole, rot_trans, tmp_33);
00241     matrix_multiply (tmp_33, 3, 3, tmp_34, 3, 4, t->matx);
00242     double m[9] = {
00243         t->matx[0], t->matx[1], t->matx[2], 
00244         t->matx[4], t->matx[5], t->matx[6], 
00245         t->matx[8], t->matx[9], t->matx[10]
00246     };
00247     int status = matrix_inverse_3x3d (m, t->inv_matx);
00248     if (0 != status) {
00249         //fprintf (stderr, "WARNING: camera matrix is singular (%s:%d)\n",
00250                 //__FILE__, __LINE__);
00251     }
00252 }
00253 
00254 // Gets camera position in sensor coordinates
00255 void camtrans_get_position (const CamTrans* t,
00256                                     double pos[3]) {
00257   pos[0] = t->position[0];
00258   pos[1] = t->position[1];
00259   pos[2] = t->position[2];
00260 }
00261 
00262 void camtrans_get_orientation (const CamTrans *t,
00263                                        double orientation[4]) 
00264 {
00265     orientation[0] = t->orientation[0];
00266     orientation[1] = t->orientation[1];
00267     orientation[2] = t->orientation[2];
00268     orientation[3] = t->orientation[3];
00269 }
00270 
00271 void camtrans_get_world_to_cam_matrix (const CamTrans *t, double matrix[12])
00272 {
00273     int i;
00274     for (i = 0; i < 12; ++i)
00275         matrix[i] = t->matx[i];
00276 }
00277 
00278 void camtrans_get_cam_to_world_matrix (const CamTrans *t, double matrix[9])
00279 {
00280     int i;
00281     for (i = 0; i < 9; ++i)
00282         matrix[i] = t->inv_matx[i];
00283 }
00284 
00285 double 
00286 camtrans_get_focal_length_x (const CamTrans *t)
00287 {
00288     return t->fx;
00289 }
00290 double 
00291 camtrans_get_focal_length_y (const CamTrans *t)
00292 {
00293     return t->fy;
00294 }
00295 double 
00296 camtrans_get_image_width (const CamTrans *t)
00297 {
00298     return t->width;
00299 }
00300 double 
00301 camtrans_get_image_height (const CamTrans *t)
00302 {
00303     return t->height;
00304 }
00305 double 
00306 camtrans_get_principal_x (const CamTrans *t)
00307 {
00308     return t->cx;
00309 }
00310 double 
00311 camtrans_get_principal_y (const CamTrans *t)
00312 {
00313     return t->cy;
00314 }
00315 
00316 double
00317 camtrans_get_width (const CamTrans *t)
00318 {
00319     return t->width;
00320 }
00321 
00322 double
00323 camtrans_get_height (const CamTrans *t)
00324 {
00325     return t->height;
00326 }
00327 
00328 void
00329 camtrans_get_distortion_center (const CamTrans *t,
00330                                 double *x,
00331                                 double *y)
00332 {
00333     SphericalDistortion* dist_data = (SphericalDistortion*)t->dist_data;
00334     *x = dist_data->cx;
00335     *y = dist_data->cy;
00336 }
00337 
00338 
00339 
00340 void
00341 camtrans_scale_image (CamTrans *t,
00342                               const double scale_factor)
00343 {
00344     // Image size
00345     t->width *= scale_factor;
00346     t->height *= scale_factor;
00347 
00348     // Pinhole parameters
00349     t->cx *= scale_factor;
00350     t->cy *= scale_factor;
00351     t->fx *= scale_factor;
00352     t->fy *= scale_factor;
00353     t->skew *= scale_factor;
00354 
00355     // Projection matrix
00356     int i;
00357     for (i = 0; i < 8; ++i)
00358       t->matx[i] *= scale_factor;
00359 
00360     // Inverse projection matrix
00361     double inv_scale_factor = 1/scale_factor;
00362     for (i = 0; i < 3; ++i) {
00363       t->inv_matx[3*i+0] *= inv_scale_factor;
00364       t->inv_matx[3*i+1] *= inv_scale_factor;
00365     }
00366 
00367     // Distortion data
00368     SphericalDistortion* dist_data = (SphericalDistortion*)t->dist_data;
00369     dist_data->w *= scale_factor;
00370     dist_data->h *= scale_factor;
00371     dist_data->inv_w *= inv_scale_factor;
00372 }
00373 
00374 void
00375 camtrans_rotate_camera (CamTrans *t,
00376                         const double q[4]) {
00377     // Update orientation quaternion
00378     double tmp_q[4];
00379     rot_quat_mult (tmp_q, t->orientation, q);
00380     t->orientation[0] = tmp_q[0];
00381     t->orientation[1] = tmp_q[1];
00382     t->orientation[2] = tmp_q[2];
00383     t->orientation[3] = tmp_q[3];
00384 
00385     // Update all internal matrices
00386     camtrans_compute_matrices (t);
00387 }
00388 
00389 void
00390 camtrans_set_distortion_center (CamTrans *t,
00391                                 const double cx, const double cy)
00392 {
00393     SphericalDistortion* dist_data = (SphericalDistortion*)t->dist_data;
00394     dist_data->cx = cx;
00395     dist_data->cy = cy;
00396     dist_data->x_trans = 0.5 + cx;
00397     dist_data->y_trans = 0.5*t->height/t->width + cy;  
00398 }
00399 
00400 
00401 
00402 
00403 
00404 int 
00405 camtrans_undistort_pixel (const CamTrans* cam,
00406                                   const double x, const double y,
00407                                   double* ox, double* oy)
00408 {
00409     cam->undist_func(x,y,cam->dist_data,ox,oy);
00410     return 0;
00411 }
00412 
00413 
00414 
00415 int 
00416 camtrans_distort_pixel (const CamTrans* cam,
00417                                 const double x, const double y,
00418                                 double* ox, double* oy)
00419 {
00420     cam->dist_func(x,y,cam->dist_data,ox,oy);
00421     return 0;
00422 }
00423 
00424 int camtrans_pixel_to_ray (const CamTrans* cam,
00425                                   const double x, const double y,
00426                                   double ray[3]) {
00427     double u, v;
00428     int ret;
00429 
00430     ret = camtrans_undistort_pixel(cam, x, y, &u, &v);
00431     if (ret < 0)
00432         return ret;
00433 
00434     const double* inv = cam->inv_matx;
00435 
00436     ray[0] = u*inv[0] + v*inv[1] + inv[2];
00437     ray[1] = u*inv[3] + v*inv[4] + inv[5];
00438     ray[2] = u*inv[6] + v*inv[7] + inv[8];
00439 
00440     return 0;
00441 }
00442 
00443 int 
00444 camtrans_project_point (const CamTrans* cam,
00445                                 const double * p_world,
00446                                 const int distort,
00447                                 double* ox, double* oy, double *oz)
00448 {
00449     double tx, ty, tz;
00450 
00451     double x = p_world[0];
00452     double y = p_world[1];
00453     double z = p_world[2];
00454 
00455     const double* m = cam->matx;
00456     tx = m[0]*x + m[1]*y + m[2]*z + m[3];
00457     ty = m[4]*x + m[5]*y + m[6]*z + m[7];
00458     tz = m[8]*x + m[9]*y + m[10]*z + m[11];
00459 
00460     if (fabs (tz) < CAMERA_EPSILON) return -1;
00461 
00462     double inv_z = 1/tz;
00463     tx *= inv_z;
00464     ty *= inv_z;
00465     if (oz) *oz = tz;
00466 
00467     if (distort != 0)
00468         return camtrans_distort_pixel(cam,tx,ty,ox,oy);
00469     else {
00470         if (ox) *ox = tx;
00471         if (oy) *oy = ty;
00472         return 0;
00473     }
00474 }
00475 
00476 
00477 
00478 int camtrans_project_line (const CamTrans *cam,
00479                            const double *l_world,
00480                            double *ox, double *oy, double *oz)
00481 {
00482     double tx, ty, tz;
00483 
00484     double x = l_world[0];
00485     double y = l_world[1];
00486     double z = l_world[2];
00487 
00488     // Multiply by inverse transpose of 3x3 projection matrix
00489     const double* m = cam->inv_matx;
00490     tx = m[0]*x + m[3]*y + m[6]*z;
00491     ty = m[1]*x + m[4]*y + m[7]*z;
00492     tz = m[2]*x + m[5]*y + m[8]*z;
00493 
00494     double inv_mag = sqrt(tx*tx + ty*ty);
00495     if (inv_mag < CAMERA_EPSILON)
00496       return -1;
00497 
00498     inv_mag = 1/inv_mag;
00499     *ox = tx*inv_mag;
00500     *oy = ty*inv_mag;
00501     *oz = tz*inv_mag;
00502     return 0;
00503 }


mit_darpa_logs_player
Author(s): Miguel Oliveira
autogenerated on Thu Nov 20 2014 11:35:44