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