Jafar
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
pinholeTools.hpp
Go to the documentation of this file.
00001 
00013 #ifndef PINHOLE_HPP_
00014 #define PINHOLE_HPP_
00015 
00016 #include "jmath/jblas.hpp"
00017 #include "jmath/linearSolvers.hpp"
00018 #include "jmath/ublasExtra.hpp"
00019 
00020 #include "jmath/matlab.hpp"
00021 
00022 namespace jafar {
00023   namespace rtslam {
00024 
00025     using namespace jblas;
00026 
00027 
00035     namespace pinhole {
00036 
00037 
00043       template<class V>
00044       vec2 projectPointToNormalizedPlane(const V & v) {
00045 
00046         vec2 up;
00047         up(0) = v(0) / v(2);
00048         up(1) = v(1) / v(2);
00049         return up;
00050       }
00051 
00058       template<class V, class P>
00059       void projectPointToNormalizedPlane(const V & v, P & up, double & dist) {
00060 
00061         up(0) = v(0) / v(2);
00062         up(1) = v(1) / v(2);
00063         dist = ublas::norm_2(v);
00064       }
00065 
00066 
00073       template<class V, class U, class MU_v>
00074       void projectPointToNormalizedPlane(const V & v, U & up, MU_v & UP_v) {
00075 
00076         up = projectPointToNormalizedPlane(v);
00077 
00078         UP_v(0, 0) = 1.0 / v(2);
00079         UP_v(0, 1) = 0.0;
00080         UP_v(0, 2) = -v(0) / (v(2) * v(2));
00081         UP_v(1, 0) = 0.0;
00082         UP_v(1, 1) = 1.0 / v(2);
00083         UP_v(1, 2) = -v(1) / (v(2) * v(2));
00084 
00085       }
00086 
00094       template<class V, class U, class MU_v>
00095       void projectPointToNormalizedPlane(const V & v, U & up, double & dist, MU_v & UP_v) {
00096 
00097         projectPointToNormalizedPlane(v, up, dist);
00098 
00099         UP_v(0, 0) = 1.0 / v(2);
00100         UP_v(0, 1) = 0.0;
00101         UP_v(0, 2) = -v(0) / (v(2) * v(2));
00102         UP_v(1, 0) = 0.0;
00103         UP_v(1, 1) = 1.0 / v(2);
00104         UP_v(1, 2) = -v(1) / (v(2) * v(2));
00105 
00106       }
00107 
00114       template<class U>
00115       vec3 backprojectPointFromNormalizedPlane(const U & u, double depth = 1) {
00116 
00117         vec3 p;
00118         p(0) = depth * u(0);
00119         p(1) = depth * u(1);
00120         p(2) = depth;
00121         return p;
00122       }
00123 
00132       template<class U, class P, class MP_u, class MP_depth>
00133       void backprojectPointFromNormalizedPlane(const U & u, const double depth, P & p, MP_u & P_u, MP_depth & P_depth) {
00134         p = backprojectPointFromNormalizedPlane(u, depth);
00135 
00136         P_u(0, 0) = depth;
00137         P_u(0, 1) = 0.0;
00138         P_u(1, 0) = 0.0;
00139         P_u(1, 1) = depth;
00140         P_u(2, 0) = 0.0;
00141         P_u(2, 1) = 0.0;
00142 
00143         P_depth(0, 0) = u(0);
00144         P_depth(1, 0) = u(1);
00145         P_depth(2, 0) = 1.0;
00146       }
00147 
00153       template<class VD>
00154       double distortFactor(const VD & d, double r2){
00155         if (d.size() == 0) return 1.0;
00156         double s = 1.0;
00157         double r2i = 1.0;
00158         for (size_t i = 0; i < d.size(); i++) { //   here we are doing:
00159           r2i = r2i * r2; //                    r2i = r^(2*(i+1))
00160           s += d(i) * r2i; //                   s = 1 + d_0 * r^2 + d_1 * r^4 + d_2 * r^6 + ...
00161         }
00162         return s;
00163       }
00164 
00165 
00172       template<class VD, class VU>
00173       jblas::vec2 distortPoint(const VD & d, const VU & up, double r2max) {
00174         size_t n = d.size();
00175         if (n == 0)
00176           return up;
00177         else {
00178           double r2 = up(0) * up(0) + up(1) * up(1); // this is the norm squared: r2 = ||u||^2
00179           if (r2 > r2max) return up;
00180           return distortFactor(d, r2) * up;
00181 //          double s = 1.0;
00182 //          double r2i = 1.0;
00183 //          for (size_t i = 0; i < n; i++) { //   here we are doing:
00184 //            r2i = r2i * r2; //                    r2i = r^(2*(i+1))
00185 //            s += d(i) * r2i; //                   s = 1 + d_0 * r^2 + d_1 * r^4 + d_2 * r^6 + ...
00186 //          }
00187 //          return s * up; //                     finally: ud = (1 + d_0 * r^2 + d_1 * r^4 + d_2 * r^6 + ...) * u;
00188         }
00189       }
00190 
00191 
00199       template<class VD, class VUp, class VUd, class MUD_up>
00200       void distortPoint(const VD & d, const VUp & up, VUd & ud, double r2max, MUD_up & UD_up) {
00201         size_t n = d.size();
00202         jblas::vec2 R2_up;
00203         jblas::vec2 S_up;
00204 
00205         if (n > 0)
00206         {
00207           double r2 = up(0) * up(0) + up(1) * up(1); // this is the norm squared: r2 = ||u||^2
00208           if (r2 <= r2max)
00209           {
00210             double s = 1.0;
00211             double r2i = 1.0;
00212             double r2im1 = 1.0; //r2*(i-1)
00213             double S_r2 = 0.0;
00214 
00215             for (size_t i = 0; i < n; i++) { //.. here we are doing:
00216               r2i = r2i * r2; //................. r2i = r^(2*(i+1))
00217               s += d(i) * r2i; //................ s = 1 + d_0 * r^2 + d_1 * r^4 + d_2 * r^6 + ...
00218 
00219               S_r2 = S_r2 + (i + 1) * d(i) * r2im1; //jacobian of s wrt r2 : S_r2 = d_0 + 2 * d1 * r^2 + 3 * d_2 * r^4 +  ...
00220               r2im1 = r2im1 * r2;
00221             }
00222 
00223             ud = s * up; // finally ud = (1 + d_0 * r^2 + d_1 * r^4 + d_2 * r^6 + ...) * u;
00224 
00225             R2_up(0) = 2 * up(0);
00226             R2_up(1) = 2 * up(1);
00227 
00228             S_up(0) = R2_up(0) * S_r2;
00229             S_up(1) = R2_up(1) * S_r2;
00230 
00231             UD_up(0, 0) = S_up(0) * up(0) + s;
00232             UD_up(0, 1) = S_up(1) * up(0);
00233             UD_up(1, 0) = S_up(0) * up(1);
00234             UD_up(1, 1) = S_up(1) * up(1) + s;
00235 
00236             return;
00237           }
00238         }
00239         // if n==0 or r2>r2max
00240         ud = up;
00241         UD_up = jblas::identity_mat(2);
00242       }
00243 
00244       template<class VC, class VU>
00245       jblas::vec2 undistortPoint(const VC & c, const VU & ud) {
00246         size_t n = c.size();
00247         if (n == 0)
00248           return ud;
00249         else {
00250           double r2 = ud(0) * ud(0) + ud(1) * ud(1); // this is the norm squared: r2 = ||u||^2
00251           return distortFactor(c, r2) * ud;
00252 //          double s = 1.0;
00253 //          double r2i = 1.0;
00254 //          for (size_t i = 0; i < n; i++) { //   here we are doing:
00255 //            r2i = r2i * r2; //                    r2i = r^(2*(i+1))
00256 //            s += c(i) * r2i; //                   s = 1 + c_0 * r^2 + c_1 * r^4 + c_2 * r^6 + ...
00257 //          }
00258 //          return s * ud; //                     finally: up = (1 + c_0 * r^2 + c_1 * r^4 + c_2 * r^6 + ...) * u;
00259         }
00260       }
00261 
00262       template<class VC, class VUd, class VUp, class MUP_ud>
00263       void undistortPoint(const VC & c, const VUd & ud, VUp & up, MUP_ud & UP_ud) {
00264         size_t n = c.size();
00265         jblas::vec2 R2_ud;
00266         jblas::vec2 S_ud;
00267 
00268         if (n == 0) {
00269           up = ud;
00270           UP_ud = jblas::identity_mat(2);
00271         }
00272 
00273         else {
00274           double r2 = ud(0) * ud(0) + ud(1) * ud(1); // this is the norm squared: r2 = ||u||^2
00275           double s = 1.0;
00276           double r2i = 1.0;
00277           double r2im1 = 1.0; //r2*(i-1)
00278           double S_r2 = 0.0;
00279 
00280           for (size_t i = 0; i < n; i++) { //.. here we are doing:
00281             r2i = r2i * r2; //................. r2i = r^(2*(i+1))
00282             s += c(i) * r2i; //................ s = 1 + c_0 * r^2 + c_1 * r^4 + c_2 * r^6 + ...
00283 
00284             S_r2 = S_r2 + (i + 1) * c(i) * r2im1; //jacobian of s wrt r2 : S_r2 = c_0 + 2 * d1 * r^2 + 3 * c_2 * r^4 +  ...
00285             r2im1 = r2im1 * r2;
00286           }
00287 
00288           up = s * ud; // finally up = (1 + c_0 * r^2 + c_1 * r^4 + c_2 * r^6 + ...) * u;
00289 
00290           R2_ud(0) = 2 * ud(0);
00291           R2_ud(1) = 2 * ud(1);
00292 
00293           S_ud(0) = R2_ud(0) * S_r2;
00294           S_ud(1) = R2_ud(1) * S_r2;
00295 
00296           UP_ud(0, 0) = S_ud(0) * ud(0) + s;
00297           UP_ud(0, 1) = S_ud(1) * ud(0);
00298           UP_ud(1, 0) = S_ud(0) * ud(1);
00299           UP_ud(1, 1) = S_ud(1) * ud(1) + s;
00300         }
00301 
00302       }
00303 
00304 
00311       template<class VK, class VU>
00312       jblas::vec2 pixellizePoint(const VK & k, const VU & ud) {
00313         double u_0 = k(0);
00314         double v_0 = k(1);
00315         double a_u = k(2);
00316         double a_v = k(3);
00317         vec2 u;
00318         u(0) = u_0 + a_u * ud(0);
00319         u(1) = v_0 + a_v * ud(1);
00320         return u;
00321       }
00322 
00323 
00331       template<class VK, class VUd, class VU, class MU_ud>
00332       void pixellizePoint(const VK & k, const VUd & ud, VU & u, MU_ud & U_ud) {
00333         //double u_0 = k(0);
00334         //double v_0 = k(1);
00335         double a_u = k(2);
00336         double a_v = k(3);
00337 
00338         u = pixellizePoint(k, ud);
00339 
00340         U_ud(0, 0) = a_u;
00341         U_ud(0, 1) = 0;
00342         U_ud(1, 0) = 0;
00343         U_ud(1, 1) = a_v;
00344       }
00345 
00346 
00353       template<class VK, class VU>
00354       jblas::vec2 depixellizePoint(const VK & k, const VU & u) {
00355         double u_0 = k(0);
00356         double v_0 = k(1);
00357         double a_u = k(2);
00358         double a_v = k(3);
00359         vec2 ud;
00360         ud(0) = (u(0) - u_0) / a_u;
00361         ud(1) = (u(1) - v_0) / a_v;
00362         return ud;
00363       }
00364 
00365 
00373       template<class VK, class VUd, class VU, class MUD_u>
00374       void depixellizePoint(const VK & k, const VU & u, VUd & ud, MUD_u & UD_u) {
00375         //        double u_0 = k(0);
00376         //        double v_0 = k(1);
00377         double a_u = k(2);
00378         double a_v = k(3);
00379 
00380         ud = depixellizePoint(k, u);
00381 
00382         UD_u(0, 0) = 1.0 / a_u;
00383         UD_u(0, 1) = 0.0;
00384         UD_u(1, 0) = 0.0;
00385         UD_u(1, 1) = 1.0 / a_v;
00386       }
00387 
00388 
00396       template<class VK, class VD, class V>
00397       vec2 projectPoint(const VK & k, const VD & d, const V & v, double r2max) {
00398         return pixellizePoint(k, distortPoint(d, projectPointToNormalizedPlane(v), r2max));
00399       }
00400 
00408       template<class VK, class VD, class V, class U>
00409       void projectPoint(const VK & k, const VD & d, const V & v, U & u, double r2max, double & dist) {
00410         vec2 up;
00411         projectPointToNormalizedPlane(v, up, dist);
00412         u = pixellizePoint(k, distortPoint(d, up, r2max));
00413       }
00414 
00415 
00424       template<class VK, class VD, class V, class VU, class MU_v>
00425       void projectPoint(const VK & k, const VD & d, const V & v, VU & u, double r2max, MU_v & U_v) {
00426         vec2 up, ud;
00427         mat23 UP_v;
00428         mat22 UD_up, U_ud;
00429         projectPointToNormalizedPlane(v, up, UP_v);
00430         distortPoint(d, up, ud, r2max, UD_up);
00431         pixellizePoint(k, ud, u, U_ud);
00432 
00433         mat23 U_v1;
00434         U_v1 = ublas::prod(UD_up, UP_v);
00435         U_v = ublas::prod(U_ud, U_v1);
00436       }
00437 
00447       template<class VK, class VD, class V, class VU, class MU_v>
00448       void projectPoint(const VK & k, const VD & d, const V & v, VU & u, double r2max, double & dist, MU_v & U_v) {
00449         vec2 up, ud;
00450         mat23 UP_v;
00451         mat22 UD_up, U_ud;
00452         projectPointToNormalizedPlane(v, up, dist, UP_v);
00453         distortPoint(d, up, ud, r2max, UD_up);
00454         pixellizePoint(k, ud, u, U_ud);
00455 
00456         mat23 U_v1;
00457         U_v1 = ublas::prod(UD_up, UP_v);
00458         U_v = ublas::prod(U_ud, U_v1);
00459       }
00460 
00461 
00470       template<class VK, class VC, class U>
00471       vec3 backprojectPoint(const VK & k, const VC & c, const U & u, const double depth = 1.0) {
00472         return backprojectPointFromNormalizedPlane(undistortPoint(c, depixellizePoint(k, u)), depth);
00473       }
00474 
00485       template<class VK, class VC, class U, class P, class MP_u, class MP_depth>
00486       void backProjectPoint(const VK & k, const VC & c, const U & u, double depth, P & p, MP_u & P_u, MP_depth & P_depth) {
00487         vec2 up, ud;
00488         mat32 P_up;
00489         mat22 UP_ud, UD_u;
00490         depixellizePoint(k, u, ud, UD_u);
00491         undistortPoint(c, ud, up, UP_ud);
00492         backprojectPointFromNormalizedPlane(up, depth, p, P_up, P_depth);
00493 
00494         P_u = ublas::prod(P_up, ublas::prod<mat>(UP_ud, UD_u));
00495       }
00496 
00497 
00503       template<class VPix>
00504       bool isInRoi(const VPix & pix, const int x, const int y, const int width, const int height) {
00505         return ((pix(0) >= x) && (pix(0) <= x + width - 1) && (pix(1) >= y) && (pix(1) <= y + height - 1));
00506       }
00507 
00514       template<class VPix>
00515       bool isInImage(const VPix & pix, const int & width, const int & height) {
00516         return isInRoi(pix, 0, 0, width, height);
00517       }
00518 
00519 
00528       template<class Vk, class Vd, class Vc>
00529       void computeCorrectionModel(const int width, const int height, const Vk & k, const Vd & d, Vc & c, double & r_max) {
00530         size_t size = c.size();
00531 
00532         if (size != 0) {
00533 #if 0
00534           double rd_max = sqrt(k(0)*k(0) / (k(2)*k(2)) + k(1)*k(1) / (k(3)*k(3)));
00535           double r_max = 1.1 * rd_max;
00536 #else
00537           double rw = std::max(k(0), (width-k(0))), rh = std::max(k(1), (height-k(1)));
00538           double rd_max = sqrt(rw*rw / (k(2)*k(2)) + rh*rh / (k(3)*k(3))) * 0.95;
00539 
00540           // search when the distortion's slope is lower than 0.5
00541           double resolution = 0.1;
00542           double r_a = 0.0, r_b = 2.01;
00543           double r_mon, rd_mon; // monotonous
00544           for (int i = 0; i < 3; ++i)
00545           {
00546             double r, r2, prev_r = -1, ir, prev_ir = -1;
00547             bool decreased = false;
00548             for(r = r_a; r <= r_b; r += resolution)
00549             {
00550               r2 = (r*rd_max); r2 *= r2;
00551               ir = distortFactor(d, r2);
00552 //              if (i != 0 && r*ir < prev_r*prev_ir) { decreased = true; break; }
00553               if (prev_r > -0.5 && (r*ir-prev_r*prev_ir)/(r-prev_r) < 0.5) { decreased = true; break; }
00554               prev_r = r; prev_ir = ir;
00555             }
00556             if (!decreased) { r_mon = r; rd_mon = ir; break; }
00557             r_a = r-2*resolution; r_b = r;
00558             r_mon = r-resolution; rd_mon = prev_ir;
00559             resolution /= 10;
00560           }
00561           // now search for r_max
00562           if (r_mon*rd_mon > 1)
00563           {
00564             r_a = 0.9; r_b = r_mon;
00565             while (r_b-r_a > 1e-3)
00566             {
00567               double r = (r_a+r_b)/2;
00568               double r2 = (r*rd_max); r2 *= r2;
00569               double ir = distortFactor(d, r2);
00570               if (r * ir < 1.0) r_a = r; else r_b = r;
00571               //std::cout << "dichotomy " << r_a << " ; " << r_b << " (ir " << ir << ")" << std::endl;
00572             }
00573             r_max = (r_b+r_a)/2 * rd_max;
00574           } else r_max = r_mon*rd_max;
00575 #endif
00576 
00577           size_t N_samples = 200; // number of samples
00578           double iN_samples = 1 / (double) N_samples;
00579           double rd_n, rc_2, rd_2;
00580           vec rd(N_samples+1), rc(N_samples+1);
00581           mat Rd(N_samples+1, size);
00582 
00583 
00584           for (size_t sample = 0; sample <= N_samples; sample++) {
00585 
00586             rc(sample) = sample * r_max * iN_samples; // sample * rd_max / N_samples
00587             rc_2 = rc(sample) * rc(sample);
00588             rd(sample) = distortFactor(d, rc_2) * rc(sample);
00589             rd_2 = rd(sample) * rd(sample);
00590 
00591             rd_n = rd(sample); // start with rd
00592 
00593             for (size_t order = 0; order < size; order++) {
00594               rd_n *= rd_2; // increment:
00595               Rd(sample, order) = rd_n; // we have : rd^3, rd^5, rd^7, ...
00596             }
00597           }
00598 
00599 
00600           // solve Rd*c = (rc-rd) for c, with least-squares SVD method:
00601           // the result is c = pseudo_inv(Rd)*(rc-rd)
00602           //  with pseudo_inv(Rd) = (Rd'*Rd)^-1 * Rd'
00603 
00604           // this does not work:
00605           // jmath::LinearSolvers::solve_Cholesky(Rd, (rc - rd), c);
00606 
00607           // therefore we solve manually the pseudo-inverse:
00608           jblas::mat RdtRd(size,size);
00609           RdtRd = ublas::prod(ublas::trans(Rd), Rd);
00610           jblas::mat iRdtRd(size, size);
00611           jmath::ublasExtra::inv(RdtRd, iRdtRd);
00612           mat iRd = ublas::prod(iRdtRd, ublas::trans<jblas::mat>(Rd));
00613 
00614           c = ublas::prod(iRd,(rc-rd));
00615           //std::cout << "c " << c << std::endl;
00616           //std::cout << "d " << d << std::endl;
00617           //std::cout << "rd_max " << rd_max << " r_max " << r_max << std::endl;
00618         }
00619       }
00620 
00621 
00622     } // namespace pinhole
00623 
00624   } // namespace rtslam
00625 } // namespace jafar
00626 
00627 #endif /* PINHOLE_HPP_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Wed Oct 15 2014 00:37:27 for Jafar by doxygen 1.7.6.1
LAAS-CNRS