00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include "HomgNorm2D.h"
00009 #include <vcl_iostream.h>
00010 #include <vnl/vnl_math.h>
00011 #include <vgl/vgl_homg_point_2d.h>
00012 #include <vgl/algo/vgl_homg_operators_2d.h>
00013
00014
00015 HomgNorm2D::HomgNorm2D(vcl_vector<vgl_homg_point_2d<double> > const& points, bool unit_omega):
00016 normalized_(points.size()),
00017 unit_omega_(unit_omega)
00018 {
00019 normalize(points);
00020 }
00021
00022 HomgNorm2D::HomgNorm2D(const vcl_vector<HomgPoint2D>& points, bool unit_omega):
00023 normalized_(points.size()),
00024 unit_omega_(unit_omega)
00025 {
00026 normalize(points);
00027 }
00028
00029
00030 HomgNorm2D::~HomgNorm2D()
00031 {
00032 }
00033
00034 static bool paranoid = true;
00035 static void centre(const vcl_vector<HomgPoint2D>& in, vcl_vector<HomgPoint2D>& out, double* cx_out, double* cy_out);
00036 static void centre(vcl_vector<vgl_homg_point_2d<double> > const& in, vcl_vector<HomgPoint2D>& out, double&, double&);
00037 static double scale_xyroot2(const vcl_vector<HomgPoint2D>& in, vcl_vector<HomgPoint2D>& out);
00038
00039
00040
00041
00042 void HomgNorm2D::normalize(vcl_vector<vgl_homg_point_2d<double> > const& points)
00043 {
00044
00045 normalized_.resize(points.size());
00046
00047 double cx, cy;
00048 centre(points, normalized_, cx, cy);
00049
00050 double diameter = scale_xyroot2(normalized_, normalized_);
00051 if (diameter == 0) {
00052 vcl_cerr << "HomgNorm2D: All points coincident\n";
00053 diameter = 1;
00054 was_coincident_=true;
00055 }
00056 else
00057 was_coincident_=false;
00058
00059 SimilarityMetric::set_center_and_scale(cx, cy, 1/diameter);
00060
00061 if (paranoid) {
00062 SimilarityMetric::scale_matrices(1/diameter);
00063 for (unsigned i = 0; i < points.size(); ++i) {
00064 vnl_double_3 ni = normalized_[i].get_vector();
00065 vgl_homg_point_2d<double> mi = SimilarityMetric::imagehomg_to_homg(points[i]);
00066 ni[0] -= mi.x(); ni[1] -= mi.y(); ni[2] -= mi.w();
00067 double l = ni.magnitude();
00068 if (l > 1e-12) {
00069 vcl_cerr << "HomgNorm2D: "
00070 << "d = " << diameter
00071 << ", ni = " << normalized_[i].get_vector()
00072 << ", mi = " << mi
00073 << ", Residual = " << ni
00074 << " (mag = " << l << ")\n";
00075 }
00076 }
00077 }
00078
00079 if (unit_omega_) {
00080
00081 for (unsigned i = 0; i < normalized_.size(); ++i) {
00082 HomgPoint2D& p = normalized_[i];
00083 double x = p.x();
00084 double y = p.y();
00085 double w = p.w();
00086
00087 if (w == 0) {
00088
00089
00090 double scaling = vcl_sqrt(3.0) / vnl_math_hypot(x, y);
00091 x *= scaling;
00092 y *= scaling;
00093 } else {
00094 x /= w;
00095 y /= w;
00096 w = 1.0;
00097 }
00098 p.set(x,y,w);
00099 }
00100 }
00101 }
00102
00103 void HomgNorm2D::normalize(const vcl_vector<HomgPoint2D>& points)
00104 {
00105
00106 normalized_.resize(points.size());
00107
00108 #if 0
00109 for (unsigned i = 0; i < points.size(); ++i)
00110 vcl_cerr << points[i].get_vector() << vcl_endl;
00111 #endif
00112
00113 double cx, cy;
00114 centre(points, normalized_, &cx, &cy);
00115
00116 double diameter = scale_xyroot2(normalized_, normalized_);
00117 if (diameter == 0) {
00118 vcl_cerr << "HomgNorm2D: All points coincident\n";
00119 diameter = 1;
00120 was_coincident_=true;
00121 }
00122 else
00123 was_coincident_=false;
00124
00125 SimilarityMetric::set_center_and_scale(cx, cy, 1/diameter);
00126
00127
00128 if (paranoid) {
00129 SimilarityMetric::scale_matrices(1/diameter);
00130 for (unsigned i = 0; i < points.size(); ++i) {
00131 vnl_double_3 ni = normalized_[i].get_vector();
00132 vnl_double_3 mi = SimilarityMetric::imagehomg_to_homg(points[i]).get_vector();
00133 vnl_double_3 residual = ni - mi;
00134 double l = residual.magnitude();
00135 if (l > 1e-12) {
00136
00137 vcl_cerr << "HomgNorm2D: "
00138 << "d = " << diameter
00139 << "ni = " << ni
00140 << "mi = " << mi
00141 << "Residual = " << residual
00142 << " mag = " << l << vcl_endl;
00143 }
00144 }
00145 }
00146
00147 if (unit_omega_) {
00148
00149 for (unsigned i = 0; i < normalized_.size(); ++i) {
00150 HomgPoint2D& p = normalized_[i];
00151 double x = p.x();
00152 double y = p.y();
00153 double w = p.w();
00154
00155 if (w == 0) {
00156
00157
00158 double scaling = vcl_sqrt(3.0) / vnl_math_hypot(x, y);
00159 x *= scaling;
00160 y *= scaling;
00161 } else {
00162 x /= w;
00163 y /= w;
00164 w = 1.0;
00165 }
00166 p.set(x,y,w);
00167 }
00168 }
00169 }
00170
00171 static void centre(const vcl_vector<HomgPoint2D>& in,
00172 vcl_vector<HomgPoint2D>& out,
00173 double *cx, double *cy)
00174 {
00175
00176 double cog_x = 0;
00177 double cog_y = 0;
00178 unsigned cog_count = 0;
00179 unsigned n = in.size();
00180 for (unsigned i = 0; i < n; ++i) {
00181 const HomgPoint2D& p = in[i];
00182 double x,y;
00183 if (p.get_nonhomogeneous(x, y)) {
00184 cog_x += x;
00185 cog_y += y;
00186 ++cog_count;
00187 }
00188 }
00189 if (cog_count > 0) {
00190 cog_x /= (double) cog_count;
00191 cog_y /= (double) cog_count;
00192 }
00193
00194
00195 *cx = cog_x;
00196 *cy = cog_y;
00197
00198
00199 vnl_double_3x3 C;
00200 C.set_identity();
00201 C(0,2) = -cog_x;
00202 C(1,2) = -cog_y;
00203
00204
00205 {
00206 for (unsigned i = 0; i < n; ++i)
00207 out[i].set(C * in[i].get_vector());
00208 }
00209
00210
00211 if (paranoid) {
00212 cog_x = 0;
00213 cog_y = 0;
00214 for (unsigned i = 0; i < n; ++i) {
00215 const HomgPoint2D& p = out[i];
00216 double x,y;
00217 if (p.get_nonhomogeneous(x, y)) {
00218 cog_x += x;
00219 cog_y += y;
00220 }
00221 }
00222 if (vnl_math_hypot(cog_x, cog_y) > 1e-10)
00223 vcl_cerr << "HomgNorm2D: expected (0,0) computed (" << cog_x << "," << cog_y << ")\n";
00224 }
00225 }
00226
00227 static void centre(vcl_vector<vgl_homg_point_2d<double> > const& in,
00228 vcl_vector<HomgPoint2D>& out,
00229 double& cx, double& cy)
00230 {
00231
00232 double cog_x = 0;
00233 double cog_y = 0;
00234 unsigned cog_count = 0;
00235 unsigned n = in.size();
00236 for (unsigned i = 0; i < n; ++i) {
00237 vgl_homg_point_2d<double> const& p = in[i];
00238 if (p.w() != 0.0) {
00239 cog_x += p.x()/p.w();
00240 cog_y += p.y()/p.w();
00241 ++cog_count;
00242 }
00243 }
00244 if (cog_count > 0) {
00245 cog_x /= (double) cog_count;
00246 cog_y /= (double) cog_count;
00247 }
00248
00249
00250 cx = cog_x;
00251 cy = cog_y;
00252
00253
00254 vnl_double_3x3 C;
00255 C.set_identity();
00256 C(0,2) = -cog_x;
00257 C(1,2) = -cog_y;
00258
00259
00260 for (unsigned i = 0; i < n; ++i)
00261 {
00262 vgl_homg_point_2d<double> q = C * in[i];
00263 out[i].set(q.x(),q.y(),q.w());
00264 }
00265
00266
00267 if (paranoid) {
00268 cog_x = 0;
00269 cog_y = 0;
00270 for (unsigned i = 0; i < n; ++i) {
00271 const HomgPoint2D& p = out[i];
00272 double x,y;
00273 if (p.get_nonhomogeneous(x, y)) {
00274 cog_x += x;
00275 cog_y += y;
00276 }
00277 }
00278 if (vnl_math_hypot(cog_x, cog_y) > 1e-10)
00279 vcl_cerr << "HomgNorm2D: expected (0,0) computed (" << cog_x << "," << cog_y << ")\n";
00280 }
00281 }
00282
00283
00284
00285
00286 static double scale_xyroot2(const vcl_vector<HomgPoint2D>& in,
00287 vcl_vector<HomgPoint2D>& out)
00288 {
00289 double magnitude = 0;
00290 unsigned numfinite = 0;
00291 for (unsigned i = 0; i < in.size(); ++i) {
00292 const HomgPoint2D& p = in[i];
00293 double x,y;
00294 if (p.get_nonhomogeneous(x, y)) {
00295 magnitude += vnl_math_hypot(x, y);
00296 ++numfinite;
00297 }
00298 }
00299
00300
00301 double diameter = 1;
00302 if (numfinite > 0) {
00303 magnitude /= (double) numfinite;
00304 diameter = magnitude / vcl_sqrt(2.0);
00305 }
00306
00307
00308 {
00309 for (unsigned i = 0; i < in.size(); ++i)
00310 out[i].set(in[i].x(), in[i].y(), in[i].w() * diameter);
00311 }
00312
00313 if (paranoid) {
00314 magnitude = 0;
00315 numfinite = 0;
00316 for (unsigned i = 0; i < in.size(); ++i) {
00317 const HomgPoint2D& p = out[i];
00318 double x,y;
00319 if (p.get_nonhomogeneous(x, y)) {
00320 magnitude += vnl_math_hypot(x, y);
00321 ++numfinite;
00322 }
00323 }
00324 if (numfinite > 0) magnitude /= numfinite;
00325 const double expected = vcl_sqrt(2.0);
00326 if (vnl_math_abs(expected - magnitude) > 1e-13)
00327 vcl_cerr << "HomgNorm2D: Expected magnitude " << expected << " computed magnitude " << magnitude << vcl_endl;
00328 }
00329
00330
00331 return diameter;
00332 }