contrib/oxl/mvl/HomgMetric.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/HomgMetric.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "HomgMetric.h"
00009 
00010 #include <vcl_iostream.h>
00011 #include <vnl/vnl_math.h>
00012 #include <vnl/vnl_transpose.h>
00013 #include <vnl/vnl_identity_3x3.h>
00014 #include <vnl/vnl_double_2.h>
00015 #include <vgl/vgl_point_2d.h>
00016 #include <vgl/vgl_homg_point_2d.h>
00017 #include <vgl/vgl_homg_line_2d.h>
00018 #include <vgl/vgl_line_segment_2d.h>
00019 #include <vgl/algo/vgl_homg_operators_2d.h>
00020 
00021 #include <mvl/HomgPoint2D.h>
00022 #include <mvl/HomgLine2D.h>
00023 #include <mvl/HomgLineSeg2D.h>
00024 #include <mvl/HomgOperator2D.h>
00025 #include <mvl/ImageMetric.h>
00026 
00027 #include <mvl/PMatrix.h>
00028 #include <mvl/FMatrix.h>
00029 #include <mvl/HMatrix2D.h>
00030 #include <mvl/TriTensor.h>
00031 
00032 // ** Constructors / Destructor
00033 
00034 HomgMetric::HomgMetric(const ImageMetric* metric)
00035 {
00036   metric_ = metric;
00037 }
00038 
00039 HomgMetric::~HomgMetric()
00040 {
00041   // metric_;
00042 }
00043 
00044 //: Print HomgMetric to vcl_ostream.
00045 vcl_ostream& HomgMetric::print(vcl_ostream & s) const
00046 {
00047   if (metric_)
00048     s << "[HomgMetric: " << *metric_ << ']';
00049   else
00050     s << "[HomgMetric: Null ImageMetric]";
00051 
00052   return s;
00053 }
00054 
00055 // ** Conversion to/from homogeneous coordinates
00056 vgl_point_2d<double> HomgMetric::homg_to_image(vgl_homg_point_2d<double> const& p) const
00057 {
00058   if (metric_) return metric_->homg_to_image(p);
00059   else return vgl_point_2d<double>(p.x()/p.w(), p.y()/p.w());
00060 }
00061 
00062 vnl_double_2 HomgMetric::homg_to_image(const HomgPoint2D& p) const
00063 {
00064   if (metric_) return metric_->homg_to_image(p);
00065   else return vnl_double_2(p.x()/p.w(), p.y()/p.w());
00066 }
00067 
00068 void HomgMetric::homg_to_image(const HomgPoint2D& homg, double* ix, double* iy) const
00069 {
00070   if (metric_) {
00071     vnl_double_2 p = metric_->homg_to_image(homg);
00072     *ix = p[0];
00073     *iy = p[1];
00074   } else {
00075     homg.get_nonhomogeneous(*ix, *iy);
00076   }
00077 }
00078 
00079 void HomgMetric::homg_to_image(vgl_homg_point_2d<double> const& homg, double& ix, double& iy) const
00080 {
00081   if (metric_) {
00082     vgl_point_2d<double> p = metric_->homg_to_image(homg);
00083     ix = p.x(); iy = p.y();
00084   } else {
00085     ix = homg.x()/homg.w();
00086     iy = homg.y()/homg.w();
00087   }
00088 }
00089 
00090 vgl_homg_point_2d<double> HomgMetric::homg_to_imagehomg(vgl_homg_point_2d<double> const& p) const
00091 {
00092   if (metric_) return metric_->homg_to_imagehomg(p);
00093   else return p;
00094 }
00095 
00096 HomgPoint2D HomgMetric::homg_to_imagehomg(const HomgPoint2D& p) const
00097 {
00098   if (metric_) return metric_->homg_to_imagehomg(p);
00099   else return p;
00100 }
00101 
00102 
00103 vgl_homg_point_2d<double> HomgMetric::image_to_homg(vgl_point_2d<double> const& p) const
00104 {
00105   if (metric_) return metric_->image_to_homg(p);
00106   else return vgl_homg_point_2d<double>(p.x(), p.y(), 1.0);
00107 }
00108 
00109 HomgPoint2D HomgMetric::image_to_homg(const vnl_double_2& p) const
00110 {
00111   if (metric_) return metric_->image_to_homg(p);
00112   else return HomgPoint2D(p[0], p[1], 1.0);
00113 }
00114 
00115 HomgPoint2D HomgMetric::image_to_homg(double x, double y) const
00116 {
00117   if (metric_) return metric_->image_to_homg(x, y);
00118   else return HomgPoint2D(x, y, 1.0);
00119 }
00120 
00121 vgl_homg_point_2d<double> HomgMetric::imagehomg_to_homg(vgl_homg_point_2d<double> const& p) const
00122 {
00123   if (metric_) return metric_->imagehomg_to_homg(p);
00124   else return p;
00125 }
00126 
00127 HomgPoint2D HomgMetric::imagehomg_to_homg(const HomgPoint2D& p) const
00128 {
00129   if (metric_) return metric_->imagehomg_to_homg(p);
00130   else return p;
00131 }
00132 
00133 
00134 vgl_homg_line_2d<double> HomgMetric::homg_to_image_line(vgl_homg_line_2d<double> const& l) const
00135 {
00136   if (metric_) return metric_->homg_to_image_line(l);
00137   else return l;
00138 }
00139 
00140 HomgLine2D HomgMetric::homg_to_image_line(const HomgLine2D& l) const
00141 {
00142   if (metric_) return metric_->homg_to_image_line(l);
00143   else return l;
00144 }
00145 
00146 vgl_homg_line_2d<double> HomgMetric::image_to_homg_line(vgl_homg_line_2d<double> const& l) const
00147 {
00148   if (metric_) return metric_->image_to_homg_line(l);
00149   else return l;
00150 }
00151 
00152 HomgLine2D HomgMetric::image_to_homg_line(const HomgLine2D& l) const
00153 {
00154   if (metric_) return metric_->image_to_homg_line(l);
00155   else return l;
00156 }
00157 
00158 HomgLineSeg2D HomgMetric::image_to_homg_line(const HomgLineSeg2D& l) const
00159 {
00160   if (metric_) return metric_->image_to_homg_line(l);
00161   else return l;
00162 }
00163 
00164 HomgLineSeg2D HomgMetric::homg_line_to_image(const HomgLineSeg2D& l) const
00165 {
00166   if (metric_) return metric_->homg_line_to_image(l);
00167   else return l;
00168 }
00169 
00170 // ** Measurements
00171 double HomgMetric::perp_dist_squared(vgl_homg_point_2d<double> const& p,
00172                                      vgl_homg_line_2d<double> const& l) const
00173 {
00174   if (metric_) return metric_->perp_dist_squared(p, l);
00175   else return vgl_homg_operators_2d<double>::perp_dist_squared(p, l);
00176 }
00177 
00178 double HomgMetric::perp_dist_squared(const HomgPoint2D& p, const HomgLine2D& l) const
00179 {
00180   if (metric_) return metric_->perp_dist_squared(p, l);
00181   else return HomgOperator2D::perp_dist_squared(p, l);
00182 }
00183 
00184 vgl_homg_point_2d<double> HomgMetric::perp_projection(vgl_homg_line_2d<double> const& l,
00185                                                       vgl_homg_point_2d<double> const& p) const
00186 {
00187   if (metric_) return metric_->perp_projection(l, p);
00188   else return vgl_homg_operators_2d<double>::perp_projection(l, p);
00189 }
00190 
00191 HomgPoint2D HomgMetric::perp_projection(const HomgLine2D& l, const HomgPoint2D& p) const
00192 {
00193   if (metric_) return metric_->perp_projection(l, p);
00194   else return HomgOperator2D::perp_projection(l, p);
00195 }
00196 
00197 double HomgMetric::distance_squared(vgl_homg_point_2d<double> const& p1,
00198                                     vgl_homg_point_2d<double> const& p2) const
00199 {
00200   if (metric_) return metric_->distance_squared(p1, p2);
00201   else return vgl_homg_operators_2d<double>::distance_squared(p1, p2);
00202 }
00203 
00204 double HomgMetric::distance_squared(double x1, double y1, double x2, double y2) const
00205 {
00206   HomgPoint2D p1(x1,y1,1.0);
00207   HomgPoint2D p2(x2,y2,1.0);
00208   if (metric_) return metric_->distance_squared(p1, p2);
00209   else return HomgOperator2D::distance_squared(p1, p2);
00210 }
00211 
00212 double HomgMetric::distance_squared(const HomgPoint2D& p1, const HomgPoint2D& p2) const
00213 {
00214   if (metric_) return metric_->distance_squared(p1, p2);
00215   else return HomgOperator2D::distance_squared(p1, p2);
00216 }
00217 
00218 double HomgMetric::distance_squared(vgl_line_segment_2d<double> const& segment,
00219                                     vgl_homg_line_2d<double> const& line) const
00220 {
00221   if (metric_) return metric_->distance_squared(segment, line);
00222   else {
00223     double r1 = vgl_homg_operators_2d<double>::perp_dist_squared(vgl_homg_point_2d<double>(segment.point1()), line),
00224            r2 = vgl_homg_operators_2d<double>::perp_dist_squared(vgl_homg_point_2d<double>(segment.point2()), line);
00225     return r1 > r2 ? r1 : r2;
00226   }
00227 }
00228 
00229 double HomgMetric::distance_squared(const HomgLineSeg2D& segment, const HomgLine2D& line) const
00230 {
00231   if (metric_) return metric_->distance_squared(segment, line);
00232   else return HomgOperator2D::distance_squared(segment, line);
00233 }
00234 
00235 bool HomgMetric::is_within_distance(vgl_homg_point_2d<double> const& p1,
00236                                     vgl_homg_point_2d<double> const& p2,
00237                                     double distance) const
00238 {
00239   if (metric_) return metric_->is_within_distance(p1, p2, distance);
00240   else return vgl_homg_operators_2d<double>::is_within_distance(p1, p2, distance);
00241 }
00242 
00243 bool HomgMetric::is_within_distance(const HomgPoint2D& p1, const HomgPoint2D& p2, double distance) const
00244 {
00245   if (metric_) return metric_->is_within_distance(p1, p2, distance);
00246   else return HomgOperator2D::is_within_distance(p1, p2, distance);
00247 }
00248 
00249 // == SPEEDUPS AVAILABLE FOR CERTAIN SYSTEMS. ==
00250 
00251 //: Return true if the conditioner's action can be described by a planar homography.
00252 bool HomgMetric::is_linear() const
00253 {
00254   if (metric_) return metric_->is_linear();
00255   else return true;
00256 }
00257 
00258 //: Return the planar homography C s.t. C x converts x from conditioned to image coordinates.
00259 vnl_double_3x3 HomgMetric::get_C() const
00260 {
00261   static vnl_identity_3x3 I;
00262   if (metric_) return metric_->get_C();
00263   else return I;
00264 }
00265 
00266 //: Return $C^{-1}$.
00267 vnl_double_3x3 HomgMetric::get_C_inverse() const
00268 {
00269   static vnl_identity_3x3 I;
00270   if (metric_) return metric_->get_C_inverse();
00271   else return I;
00272 }
00273 
00274 // == CONVERTING DISTANCES ==
00275 
00276 //: Return true if the metric is rotationally symmetric, i.e. can invert distances.
00277 bool HomgMetric::can_invert_distance() const
00278 {
00279   if (metric_) return metric_->can_invert_distance();
00280   else return true;
00281 }
00282 
00283 //: Given that can_invert_distance is true, convert an image distance (in pixels) to a conditioned distance.
00284 double HomgMetric::image_to_homg_distance(double image_distance) const
00285 {
00286   if (metric_) return metric_->image_to_homg_distance(image_distance);
00287   else return image_distance;
00288 }
00289 
00290 //: Convert a conditioned distance to an image distance.
00291 double HomgMetric::homg_to_image_distance(double image_distance) const
00292 {
00293   if (metric_) return metric_->homg_to_image_distance(image_distance);
00294   else return image_distance;
00295 }
00296 
00297 //: As above, but for squared distances
00298 double HomgMetric::image_to_homg_distance_sqr(double image_distance_2) const
00299 {
00300   if (metric_)
00301     return vnl_math_sqr(metric_->image_to_homg_distance(vcl_sqrt(image_distance_2)));
00302   else
00303     return image_distance_2;
00304 }
00305 
00306 //: As above, but for squared distances
00307 double HomgMetric::homg_to_image_distance_sqr(double image_distance) const
00308 {
00309   if (metric_)
00310     return vnl_math_sqr(metric_->homg_to_image_distance(vcl_sqrt(image_distance)));
00311   else
00312     return image_distance;
00313 }
00314 
00315 static vcl_ostream& warning(char const * fn)
00316 {
00317   return vcl_cerr << "HomgMetric::" << fn << "() WARNING: ";
00318 }
00319 
00320 // Static functions to condition/decondition image relations-----------------
00321 
00322 //: Convert a P matrix to image coordinates if possible.
00323 PMatrix HomgMetric::homg_to_image_P(const PMatrix& P, const HomgMetric& c)
00324 {
00325   if (!c.is_linear()) warning("homg_to_image_P") << "ImageMetric for image 1 is nonlinear\n";
00326   return PMatrix(c.get_C() * P.get_matrix());
00327 }
00328 
00329 PMatrix HomgMetric::image_to_homg_P(const PMatrix& P, const HomgMetric& c)
00330 {
00331   if (!c.is_linear()) warning("homg_to_image_P") << "ImageMetric for image 1 is nonlinear\n";
00332   return PMatrix(c.get_C_inverse() * P.get_matrix());
00333 }
00334 
00335 //: Decondition a fundamental matrix (convert it from conditioned to image coordinates).
00336 // If not possible, print a warning and do it approximately.
00337 FMatrix HomgMetric::homg_to_image_F(const FMatrix& F, const HomgMetric& c1, const HomgMetric& c2)
00338 {
00339   if (!c1.is_linear()) warning("homg_to_image_F") << "ImageMetric for image 1 is nonlinear\n";
00340   if (!c2.is_linear()) warning("homg_to_image_F") << "ImageMetric for image 2 is nonlinear\n";
00341 
00342   vnl_double_3x3 C1inv = c1.get_C_inverse();
00343   vnl_double_3x3 C2inv = c2.get_C_inverse();
00344   return FMatrix(vnl_transpose(C2inv) * F.get_matrix() * C1inv);
00345 }
00346 
00347 //: Condition a fundamental matrix.
00348 FMatrix HomgMetric::image_to_homg_F(const FMatrix& F, const HomgMetric& c1, const HomgMetric& c2)
00349 {
00350   if (!c1.is_linear()) warning("image_to_homg_F") << "ImageMetric for image 1 is nonlinear\n";
00351   if (!c2.is_linear()) warning("image_to_homg_F") << "ImageMetric for image 2 is nonlinear\n";
00352 
00353   vnl_double_3x3 C1 = c1.get_C();
00354   vnl_double_3x3 C2 = c2.get_C();
00355   return FMatrix(vnl_transpose(C2) * F.get_matrix() * C1);
00356 }
00357 
00358 //: Decondition a planar homography.
00359 HMatrix2D HomgMetric::homg_to_image_H(const HMatrix2D& H, const HomgMetric& c1, const HomgMetric& c2)
00360 {
00361   if (!c1.is_linear()) warning("homg_to_image_H") << "ImageMetric for image 1 is nonlinear\n";
00362   if (!c2.is_linear()) warning("homg_to_image_H") << "ImageMetric for image 2 is nonlinear\n";
00363 
00364   vnl_double_3x3 C1i = c1.get_C_inverse();
00365   vnl_double_3x3 C2 = c2.get_C();
00366   return HMatrix2D(C2 * H.get_matrix() * C1i);
00367 }
00368 
00369 //: Condition a planar homography.
00370 HMatrix2D HomgMetric::image_to_homg_H(const HMatrix2D& H, const HomgMetric& c1, const HomgMetric& c2)
00371 {
00372   if (!c1.is_linear()) warning("image_to_homg_H") << "ImageMetric for image 1 is nonlinear\n";
00373   if (!c2.is_linear()) warning("image_to_homg_H") << "ImageMetric for image 2 is nonlinear\n";
00374 
00375   vnl_double_3x3 C1 = c1.get_C();
00376   vnl_double_3x3 C2i = c2.get_C_inverse();
00377   return HMatrix2D(C2i * H.get_matrix() * C1);
00378 }
00379 
00380 //: Decondition a trifocal tensor.
00381 TriTensor HomgMetric::homg_to_image_T(const TriTensor& T, const HomgMetric& c1, const HomgMetric& c2, const HomgMetric& c3)
00382 {
00383   // Need line conditioners, so it's inverse transpose
00384   vnl_double_3x3 C1i = c1.get_C_inverse();
00385   vnl_double_3x3 C2 = c2.get_C();
00386   vnl_double_3x3 C3 = c3.get_C();
00387 
00388   return T.decondition(C1i.transpose().as_ref(), C2.transpose().as_ref(), C3.transpose().as_ref());
00389 }
00390 
00391 //: Condition a trifocal tensor.
00392 TriTensor HomgMetric::image_to_homg_T(const TriTensor& T, const HomgMetric& c1, const HomgMetric& c2, const HomgMetric& c3)
00393 {
00394   // Need line conditioners, so it's inverse transpose
00395   vnl_double_3x3 C1 = c1.get_C();
00396   vnl_double_3x3 C2i = c2.get_C_inverse();
00397   vnl_double_3x3 C3i = c3.get_C_inverse();
00398 
00399   return T.decondition(C1.transpose().as_ref(), C2i.transpose().as_ref(), C3i.transpose().as_ref());
00400 }