contrib/oxl/mvl/SimilarityMetric.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/SimilarityMetric.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "SimilarityMetric.h"
00009 
00010 #include <vcl_iostream.h>
00011 #include <vnl/vnl_math.h>
00012 
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 
00025 //: Default constructor sets parameters for an identity transformation.
00026 SimilarityMetric::SimilarityMetric()
00027 {
00028   centre_x_ = 0;
00029   centre_y_ = 0;
00030   inv_scale_ = 1;
00031   scale_ = 1;
00032 
00033   make_matrices();
00034 }
00035 
00036 //: Create a SimilarityMetric that transforms according to (x,y) -> (x - cx, y - cy) * scale
00037 SimilarityMetric::SimilarityMetric(double cx, double cy, double scale)
00038 {
00039   centre_x_ = cx;
00040   centre_y_ = cy;
00041   inv_scale_ = 1 / scale;
00042   scale_ = scale;
00043 
00044   make_matrices();
00045 }
00046 
00047 //: Create a SimilarityMetric that transforms coordinates in the range (0..xsize, 0..ysize) to the square (-1..1, -1..1)
00048 SimilarityMetric::SimilarityMetric(int xsize, int ysize)
00049 {
00050   set_from_rectangle(xsize, ysize);
00051 }
00052 
00053 //: Set transform to "(x,y) -> (x - xsize/2, y - ysize/2) / ((xsize+ysize)/2)"
00054 void SimilarityMetric::set_from_rectangle(int xsize, int ysize)
00055 {
00056   centre_x_ = xsize * 0.5;
00057   centre_y_ = ysize * 0.5;
00058   inv_scale_ = (xsize + ysize) * 0.5;
00059   scale_ = 1.0 / inv_scale_;
00060 
00061   make_matrices();
00062 }
00063 
00064 //: Set transform to "(x,y) -> (x - cx, y - cy) * scale"
00065 // For example, (640 / 2, 480 / 2, 2.0 / (640 + 480))
00066 void SimilarityMetric::set_center_and_scale(double cx, double cy, double scale)
00067 {
00068   centre_x_ = cx;
00069   centre_y_ = cy;
00070   inv_scale_ = 1 / scale;
00071   scale_ = scale;
00072 
00073   make_matrices();
00074 }
00075 
00076 void SimilarityMetric::make_matrices()
00077 {
00078   cond_matrix (0, 0) = inv_scale_;
00079   cond_matrix (0, 1) = 0;
00080   cond_matrix (0, 2) = centre_x_;
00081 
00082   cond_matrix (1, 0) = 0;
00083   cond_matrix (1, 1) = inv_scale_;
00084   cond_matrix (1, 2) = centre_y_;
00085 
00086   cond_matrix (2, 0) = 0;
00087   cond_matrix (2, 1) = 0;
00088   cond_matrix (2, 2) = 1.0;
00089 
00090   inv_cond_matrix (0, 0) = scale_;
00091   inv_cond_matrix (0, 1) = 0;
00092   inv_cond_matrix (0, 2) = -centre_x_ * scale_;
00093 
00094   inv_cond_matrix (1, 0) = 0;
00095   inv_cond_matrix (1, 1) = scale_;
00096   inv_cond_matrix (1, 2) = -centre_y_ * scale_;
00097 
00098   inv_cond_matrix (2, 0) = 0;
00099   inv_cond_matrix (2, 1) = 0;
00100   inv_cond_matrix (2, 2) = 1.0;
00101 }
00102 
00103 //: Destructor
00104 SimilarityMetric::~SimilarityMetric()
00105 {
00106 }
00107 
00108 //: One line printout
00109 void SimilarityMetric::print(char* msg) const
00110 {
00111   vcl_cerr<<msg<<": SimilarityMetric ("<<centre_x_<<','<<centre_y_<<", "<<inv_scale_<<")\n";
00112 }
00113 
00114 //: One line printout
00115 vcl_ostream& SimilarityMetric::print(vcl_ostream& s) const
00116 {
00117   return s<<"[SimilarityMetric ("<<centre_x_<<','<<centre_y_<<"), "<<inv_scale_ << ']';
00118 }
00119 
00120 // IMPLEMENTATION OF SimilarityMetric
00121 
00122 //: Convert 2D image point $(x,y)$ to homogeneous coordinates.
00123 // The precise transformation is $(x,y) \rightarrow (x - cx, y - cy, f)$
00124 vgl_homg_point_2d<double> SimilarityMetric::image_to_homg(vgl_point_2d<double> const& p) const
00125 {
00126   double nx = p.x();
00127   double ny = p.y();
00128 
00129   // homogenize point
00130   return vgl_homg_point_2d<double>(nx - centre_x_, ny - centre_y_, inv_scale_);
00131 }
00132 
00133 //: Convert 2D point $(x,y)$ to homogeneous coordinates.
00134 // The precise transformation is
00135 // $(x,y) \rightarrow (x - cx, y - cy, f)$
00136 HomgPoint2D SimilarityMetric::image_to_homg(double x, double y) const
00137 {
00138   double nx = x;
00139   double ny = y;
00140 
00141   // homogenize point
00142   return HomgPoint2D(nx - centre_x_, ny - centre_y_, inv_scale_);
00143 }
00144 
00145 //: Convert conditioned point p to image coordinates
00146 vgl_point_2d<double> SimilarityMetric::homg_to_image(vgl_homg_point_2d<double> const& p) const
00147 {
00148   return vgl_point_2d<double>(p.x()/p.w()*inv_scale_+centre_x_, p.y()/p.w()*inv_scale_+centre_y_);
00149 }
00150 
00151 //: Decondition homogeneous point.
00152 vnl_double_2 SimilarityMetric::homg_to_image(const HomgPoint2D& p) const
00153 {
00154   double x,y;
00155   p.get_nonhomogeneous(x, y);
00156   x = x * inv_scale_;
00157   y = y * inv_scale_;
00158 
00159   return vnl_double_2(x + centre_x_, y + centre_y_);
00160 }
00161 
00162 //: Condition the 2D point p
00163 HomgPoint2D SimilarityMetric::image_to_homg(const vnl_double_2& p) const
00164 {
00165   return image_to_homg(p[0], p[1]);
00166 }
00167 
00168 //: Transform homogeneous point to image coordinates, leaving it in homogeneous form.
00169 vgl_homg_point_2d<double> SimilarityMetric::homg_to_imagehomg(vgl_homg_point_2d<double> const& x) const
00170 {
00171   return cond_matrix * x;
00172 }
00173 
00174 //: Transform homogeneous point to image coordinates, leaving it in homogeneous form.
00175 HomgPoint2D SimilarityMetric::homg_to_imagehomg(const HomgPoint2D& x) const
00176 {
00177   // ho_cam2std_aspect_point
00178   return HomgPoint2D(cond_matrix * x.get_vector());
00179 }
00180 
00181 //: Transform homogeneous point in image coordinates to conditioned coordinates.
00182 vgl_homg_point_2d<double> SimilarityMetric::imagehomg_to_homg(vgl_homg_point_2d<double> const& x) const
00183 {
00184   // ho_std2cam_aspect_point
00185   return inv_cond_matrix * x;
00186 }
00187 HomgPoint2D SimilarityMetric::imagehomg_to_homg(const HomgPoint2D& x) const
00188 {
00189   // ho_std2cam_aspect_point
00190   return HomgPoint2D(inv_cond_matrix * x.get_vector());
00191 }
00192 
00193 //: Compute distance (in image coordinates) between points supplied in conditioned coordinates.
00194 double SimilarityMetric::distance_squared(vgl_homg_point_2d<double> const& p1,
00195                                           vgl_homg_point_2d<double> const& p2) const
00196 {
00197   double x1 = p1.x() / p1.w();
00198   double y1 = p1.y() / p1.w();
00199 
00200   double x2 = p2.x() / p2.w();
00201   double y2 = p2.y() / p2.w();
00202 
00203   return vnl_math_sqr (inv_scale_) * (vnl_math_sqr (x1 - x2) + vnl_math_sqr (y1 - y2));
00204 }
00205 //: Compute distance (in image coordinates) between points supplied in conditioned coordinates.
00206 double SimilarityMetric::distance_squared(HomgPoint2D const& p1, HomgPoint2D const& p2) const
00207 {
00208   // ho_triveccam_noaspect_distance_squared
00209   double x1 = p1.x() / p1.w();
00210   double y1 = p1.y() / p1.w();
00211 
00212   double x2 = p2.x() / p2.w();
00213   double y2 = p2.y() / p2.w();
00214 
00215   return vnl_math_sqr (inv_scale_) * (vnl_math_sqr (x1 - x2) + vnl_math_sqr (y1 - y2));
00216 }
00217 
00218 //: Get distance between a line segment and an infinite line.
00219 //  The metric used is the maximum of the two endpoint perp distances.
00220 double SimilarityMetric::distance_squared(vgl_line_segment_2d<double> const& segment,
00221                                           vgl_homg_line_2d<double> const& line) const
00222 {
00223   return vnl_math_max(this->perp_dist_squared(vgl_homg_point_2d<double>(segment.point1()), line),
00224                       this->perp_dist_squared(vgl_homg_point_2d<double>(segment.point2()), line));
00225 }
00226 //: Get distance between a line segment and an infinite line.
00227 //  The metric used is the maximum of the two endpoint perp distances.
00228 double SimilarityMetric::distance_squared(const HomgLineSeg2D& segment, const HomgLine2D& line) const
00229 {
00230   return vnl_math_max(this->perp_dist_squared(segment.get_point1(), line),
00231                       this->perp_dist_squared(segment.get_point2(), line));
00232 }
00233 
00234 //: Compute perpendicular distance (in image coordinates) from point to line (supplied in conditioned coordinates).
00235 double SimilarityMetric::perp_dist_squared(vgl_homg_point_2d<double> const& p,
00236                                            vgl_homg_line_2d<double> const& l) const
00237 {
00238   if (p.ideal()) {
00239     vcl_cerr << "SimilarityMetric::perp_dist_squared -- point at infinity\n";
00240     return Homg::infinity;
00241   }
00242 
00243   if (l.ideal()) {
00244     vcl_cerr << "SimilarityMetric::perp_dist_squared -- line at infinity\n";
00245     return Homg::infinity;
00246   }
00247 
00248   double numerator = vnl_math_sqr(p.x()*l.a()+p.y()*l.b()+p.w()*l.c());
00249   double denominator = (vnl_math_sqr(l.a()) + vnl_math_sqr(l.b())) * vnl_math_sqr(p.w() * scale_);
00250 
00251   return numerator / denominator;
00252 }
00253 double SimilarityMetric::perp_dist_squared(HomgPoint2D const & p, HomgLine2D const & l) const
00254 {
00255   // ho_triveccam_aspect_perpdistance_squared
00256 
00257   // pcp separated
00258   if (p.ideal()) {
00259     vcl_cerr << "SimilarityMetric::perp_dist_squared -- point at infinity\n";
00260     return Homg::infinity;
00261   }
00262 
00263   if (l.ideal()) {
00264     vcl_cerr << "SimilarityMetric::perp_dist_squared -- line at infinity\n";
00265     return Homg::infinity;
00266   }
00267 
00268   double numerator = vnl_math_sqr(HomgOperator2D::dot(l, p));
00269   double denominator = (vnl_math_sqr(l.x()) + vnl_math_sqr(l.y()))
00270     * vnl_math_sqr(p.w() * scale_);
00271 
00272   return numerator / denominator;
00273 }
00274 
00275 //: Multiply all components of the transform matrix by "s".
00276 // This routine is likely to be used only by programs which need
00277 // special control over the exact form of their output.
00278 void SimilarityMetric::scale_matrices(double s)
00279 {
00280   cond_matrix *= s;
00281   inv_cond_matrix *= (1/s);
00282 }
00283 
00284 bool SimilarityMetric::can_invert_distance() const
00285 {
00286   return true;
00287 }
00288 
00289 double SimilarityMetric::image_to_homg_distance(double image_distance) const
00290 {
00291   return image_distance * scale_;
00292 }
00293 
00294 double SimilarityMetric::homg_to_image_distance(double image_distance) const
00295 {
00296   return image_distance * inv_scale_;
00297 }