00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include "HomgOperator2D.h"
00009
00010 #include <vcl_cassert.h>
00011 #include <vcl_iostream.h>
00012 #include <vcl_vector.h>
00013
00014 #include <vnl/vnl_math.h>
00015 #include <vnl/vnl_matrix.h>
00016 #include <vnl/algo/vnl_scatter_3x3.h>
00017 #include <vnl/algo/vnl_svd.h>
00018
00019 #include <mvl/HomgLine2D.h>
00020 #include <mvl/HomgPoint2D.h>
00021 #include <mvl/HomgLineSeg2D.h>
00022
00023
00024
00025
00026
00027 void HomgOperator2D::cross(const Homg2D& a, const Homg2D& b, Homg2D* a_cross_b)
00028 {
00029 double x1 = a.x();
00030 double y1 = a.y();
00031 double w1 = a.w();
00032
00033 double x2 = b.x();
00034 double y2 = b.y();
00035 double w2 = b.w();
00036
00037 a_cross_b->set (y1 * w2 - w1 * y2,
00038 w1 * x2 - x1 * w2,
00039 x1 * y2 - y1 * x2);
00040 }
00041
00042
00043
00044 double HomgOperator2D::dot(const Homg2D& a, const Homg2D& b)
00045 {
00046 double x1 = a.x();
00047 double y1 = a.y();
00048 double w1 = a.w();
00049
00050 double x2 = b.x();
00051 double y2 = b.y();
00052 double w2 = b.w();
00053
00054 return x1*x2 + y1*y2 + w1*w2;
00055 }
00056
00057
00058
00059 void HomgOperator2D::unitize(Homg2D* a)
00060 {
00061 double norm = a->x()*a->x() + a->y()*a->y() + a->w()*a->w();
00062
00063 if (norm == 0.0) {
00064 vcl_cerr << "HomgOperator2D::unitize() -- Zero length vector\n";
00065 return;
00066 }
00067
00068 norm = 1.0/vcl_sqrt(norm);
00069 a->set(a->x()*norm, a->y()*norm, a->w()*norm);
00070 }
00071
00072
00073
00074
00075 double HomgOperator2D::distance_squared(const HomgPoint2D& point1,
00076 const HomgPoint2D& point2)
00077 {
00078 double x1 = point1.x();
00079 double y1 = point1.y();
00080 double z1 = point1.w();
00081
00082 double x2 = point2.x();
00083 double y2 = point2.y();
00084 double z2 = point2.w();
00085
00086 if (z1 == 0 || z2 == 0) {
00087 vcl_cerr << "HomgOperator2D::distance_squared() -- point at infinity";
00088 return Homg::infinity;
00089 }
00090
00091 double scale1 = 1.0/z1;
00092 double scale2 = 1.0/z2;
00093
00094 return vnl_math_sqr (x1 * scale1 - x2 * scale2) +
00095 vnl_math_sqr (y1 * scale1 - y2 * scale2);
00096 }
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 double HomgOperator2D::perp_dist_squared (const HomgPoint2D& point, const HomgLine2D& line)
00107 {
00108 if (line.ideal(0.0) || point.ideal(0.0)) {
00109 vcl_cerr << "HomgOperator2D::perp_dist_squared() -- line or point at infinity\n";
00110 return Homg::infinity;
00111 }
00112
00113 double numerator = vnl_math_sqr (dot(line, point));
00114 double denominator = (vnl_math_sqr(line.x()) + vnl_math_sqr(line.y())) * vnl_math_sqr(point.w());
00115
00116 return numerator / denominator;
00117 }
00118
00119
00120
00121 double HomgOperator2D::distance_squared(const HomgLineSeg2D& segment, const HomgLine2D& line)
00122 {
00123 return vnl_math_max(perp_dist_squared(segment.get_point1(), line),
00124 perp_dist_squared(segment.get_point2(), line));
00125 }
00126
00127
00128
00129 double HomgOperator2D::distance(const HomgLineSeg2D& ls, const HomgLineSeg2D& ll, double OVERLAP_THRESH)
00130 {
00131 double norm = vcl_sqrt(ll.get_line().x()*ll.get_line().x()+ll.get_line().y()*ll.get_line().y());
00132 HomgLine2D lll;
00133 lll.set(ll.get_line().x()/norm,ll.get_line().y()/norm,ll.get_line().w()/norm);
00134 double dist1 = ls.get_point1().x()/ls.get_point1().w() * lll.x() +
00135 ls.get_point1().y()/ls.get_point1().w() * lll.y() + lll.w();
00136 double dist2 = ls.get_point2().x()/ls.get_point2().w() * lll.x() +
00137 ls.get_point2().y()/ls.get_point2().w() * lll.y() + lll.w();
00138 #ifdef DEBUG
00139 vcl_cerr << "dist 1 is " <<dist1 << " dist 2 is " <<dist2 << vcl_endl;
00140 #endif
00141 double dist = (vcl_fabs(dist1) + vcl_fabs(dist2))/2;
00142
00143
00144
00145
00146
00147 vnl_double_2 p1(ls.get_point1().x()/ls.get_point1().w()-dist1*lll.x(),
00148 ls.get_point1().y()/ls.get_point1().w()-dist1*lll.y());
00149
00150 vnl_double_2 p2(ls.get_point2().x()/ls.get_point2().w()-dist2*(lll.x()),
00151 ls.get_point2().y()/ls.get_point2().w()-dist2*(lll.y()));
00152
00153 vnl_double_2 p3(ll.get_point1().x()/ll.get_point1().w(),
00154 ll.get_point1().y()/ll.get_point1().w());
00155
00156 vnl_double_2 p4(ll.get_point2().x()/ll.get_point2().w(),
00157 ll.get_point2().y()/ll.get_point2().w());
00158
00159 vnl_double_2 v1 = p2 - p1, v2 = p3 - p1, v3 = p4 - p1;
00160 double r3 = v2(0)/v1(0); if (r3 > 1) r3 = 1; else if (r3 < 0) r3 =0;
00161 double r4 = v3(0)/v1(0); if (r4 > 1) r4 = 1; else if (r4 < 0) r4 =0;
00162
00163 double r = vcl_fabs(r3-r4) * v1.two_norm();
00164
00165 if (r < OVERLAP_THRESH)
00166 dist = 1000000;
00167
00168 return dist;
00169 }
00170
00171
00172
00173
00174
00175 double HomgOperator2D::distance_squared (const HomgLineSeg2D& lineseg, const HomgPoint2D& p)
00176 {
00177 const HomgPoint2D& p1 = lineseg.get_point1();
00178 const HomgPoint2D& p2 = lineseg.get_point2();
00179
00180 double p1x = p1[0] / p1[2];
00181 double p1y = p1[1] / p1[2];
00182
00183 double p2x = p2[0] / p2[2];
00184 double p2y = p2[1] / p2[2];
00185
00186 double dx = p2x - p1x;
00187 double dy = p2y - p1y;
00188
00189 double l = vcl_sqrt(dx*dx + dy*dy);
00190
00191 double px = p[0] / p[2];
00192 double py = p[1] / p[2];
00193
00194 double d = ((px - p1x)*dx + (py - p1y)*dy);
00195 if (d < 0)
00196 return distance_squared(p, p1);
00197 if (d > l)
00198 return distance_squared(p, p2);
00199
00200 return perp_dist_squared(p, lineseg);
00201 }
00202
00203
00204
00205
00206
00207 double HomgOperator2D::line_angle(const HomgLine2D& line)
00208 {
00209 return vcl_atan2(line.y(), line.x());
00210 }
00211
00212
00213
00214 double HomgOperator2D::abs_angle(const HomgLine2D& line1, const HomgLine2D& line2)
00215 {
00216 double angle1 = line_angle (line1);
00217 double angle2 = line_angle (line2);
00218
00219 double diff = vnl_math_abs(angle2 - angle1);
00220
00221 if (diff > vnl_math::pi)
00222 diff -= vnl_math::pi;
00223
00224 if (diff > vnl_math::pi/2)
00225 return vnl_math::pi - diff;
00226 else
00227 return diff;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 double HomgOperator2D::angle_between_oriented_lines (const HomgLine2D& line1,
00239 const HomgLine2D& line2)
00240 {
00241 double angle1 = line_angle (line1);
00242 double angle2 = line_angle (line2);
00243
00244 double diff = angle2 - angle1;
00245
00246 if (diff > vnl_math::pi)
00247 return diff - 2.0 * vnl_math::pi;
00248
00249 if (diff < -vnl_math::pi)
00250 return diff + 2.0 * vnl_math::pi;
00251
00252 return diff;
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262 HomgLine2D HomgOperator2D::join (const HomgPoint2D& point1, const HomgPoint2D& point2)
00263 {
00264 HomgLine2D answer;
00265 cross(point1, point2, &answer);
00266 return answer;
00267 }
00268
00269
00270
00271
00272
00273
00274
00275 HomgLine2D HomgOperator2D::join_oriented (const HomgPoint2D& point1, const HomgPoint2D& point2)
00276 {
00277 double x1 = point1.x();
00278 double y1 = point1.y();
00279 double w1 = point1.w();
00280 bool s1 = w1 < 0;
00281
00282 double x2 = point2.x();
00283 double y2 = point2.y();
00284 double w2 = point2.w();
00285 bool s2 = w2 < 0;
00286
00287 if (s1 ^ s2)
00288 return HomgLine2D(-y1 * w2 + w1 * y2, -w1 * x2 + x1 * w2, -x1 * y2 + y1 * x2);
00289 else
00290 return HomgLine2D( y1 * w2 - w1 * y2, w1 * x2 - x1 * w2, x1 * y2 - y1 * x2);
00291 }
00292
00293
00294
00295
00296
00297
00298 HomgPoint2D HomgOperator2D::intersection (const HomgLine2D& line1, const HomgLine2D& line2)
00299 {
00300 HomgPoint2D answer;
00301 cross(line1, line2, &answer);
00302 return answer;
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 HomgLine2D HomgOperator2D::perp_line_through_point (const HomgLine2D& line,
00317 const HomgPoint2D& point)
00318 {
00319 HomgLine2D direction(line.x(), line.y(), 0);
00320 HomgLine2D answer;
00321 cross(direction, point, &answer);
00322 unitize(&answer);
00323 return answer;
00324 }
00325
00326
00327
00328
00329
00330
00331 HomgPoint2D HomgOperator2D::perp_projection (const HomgLine2D& line,
00332 const HomgPoint2D& point)
00333 {
00334 HomgLine2D perpline = perp_line_through_point (line, point);
00335 HomgPoint2D answer;
00336 cross(line, perpline, &answer);
00337 unitize(&answer);
00338 return answer;
00339 }
00340
00341
00342 HomgPoint2D HomgOperator2D::midpoint (const HomgPoint2D& p1, const HomgPoint2D& p2)
00343 {
00344 return HomgPoint2D(p1 * (1/(2*p1[2])) + p2*(1/(2*p2[2])));
00345 }
00346
00347
00348
00349
00350 static vnl_vector<double> most_orthogonal_vector(const vcl_vector<HomgLine2D>& inpoints)
00351 {
00352 vnl_scatter_3x3<double> scatter_matrix;
00353
00354 for (unsigned i = 0; i < inpoints.size(); i++)
00355 scatter_matrix.add_outer_product(inpoints[i].get_vector());
00356
00357 return scatter_matrix.minimum_eigenvector().as_ref();
00358 }
00359
00360 static vnl_vector<double> most_orthogonal_vector_svd(const vcl_vector<HomgLine2D>& lines)
00361 {
00362 vnl_matrix<double> D(lines.size(), 3);
00363
00364 for (unsigned i = 0; i < lines.size(); i++)
00365 D.set_row(i, lines[i].get_vector().as_ref());
00366
00367 vnl_svd<double> svd(D);
00368 vcl_cerr << "[movrank " << svd.W() << ']';
00369
00370 return svd.nullvector();
00371 }
00372
00373 bool lines_to_point_use_svd = false;
00374
00375
00376
00377
00378
00379
00380 HomgPoint2D HomgOperator2D::lines_to_point(const vcl_vector<HomgLine2D>& lines)
00381 {
00382
00383 assert(lines.size() >= 2);
00384
00385 if (lines_to_point_use_svd)
00386 return HomgPoint2D(most_orthogonal_vector_svd(lines));
00387 else
00388 return HomgPoint2D(most_orthogonal_vector(lines));
00389 }
00390
00391
00392
00393
00394
00395
00396
00397 HomgLineSeg2D HomgOperator2D::clip_line_to_lineseg(const HomgLine2D& line,
00398 double x0, double y0,
00399 double x1, double y1)
00400 {
00401 double nx = line.x();
00402 double ny = line.y();
00403 double nz = line.w();
00404
00405 bool intersect_lr = vnl_math_abs(ny) > vnl_math_abs(nx);
00406
00407 if (intersect_lr) {
00408
00409 HomgPoint2D p1(x0 * ny, -(nz + x0 * nx), ny);
00410 HomgPoint2D p2(x1 * ny, -(nz + x1 * nx), ny);
00411 return HomgLineSeg2D(p1, p2);
00412 }
00413 else {
00414 HomgPoint2D p1(-(nz + y0 * ny), y0 * nx, nx);
00415 HomgPoint2D p2(-(nz + y1 * ny), y1 * nx, nx);
00416 return HomgLineSeg2D(p1, p2);
00417 }
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 double HomgOperator2D::CrossRatio(const Homg2D& a, const Homg2D& b, const Homg2D& c, const Homg2D& d)
00438 {
00439 double x1 = a.x(), y1 = a.y(), w1 = a.w();
00440 double x2 = b.x(), y2 = b.y(), w2 = b.w();
00441 double x3 = c.x(), y3 = c.y(), w3 = c.w();
00442 double x4 = d.x(), y4 = d.y(), w4 = d.w();
00443 double x = x1 - x2; if (x<0) x = -x;
00444 double y = y1 - y2; if (y<0) y = -y;
00445 double n = (x>y) ? (x1*w3-x3*w1)*(x2*w4-x4*w2) : (y1*w3-y3*w1)*(y2*w4-y4*w2);
00446 double m = (x>y) ? (x1*w4-x4*w1)*(x2*w3-x3*w2) : (y1*w4-y4*w1)*(y2*w3-y3*w2);
00447 if (n == 0 && m == 0)
00448 vcl_cerr << "CrossRatio not defined: three of the given points coincide\n";
00449 return n/m;
00450 }
00451
00452
00453
00454
00455 Homg2D HomgOperator2D::Conjugate(const Homg2D& a, const Homg2D& b, const Homg2D& c, double cr)
00456
00457 {
00458 double x1 = a.x(), y1 = a.y(), w1 = a.w();
00459 double x2 = b.x(), y2 = b.y(), w2 = b.w();
00460 double x3 = c.x(), y3 = c.y(), w3 = c.w();
00461 double kx = x1*w3 - x3*w1, mx = x2*w3 - x3*w2, nx = kx*w2-cr*mx*w1;
00462 double ky = y1*w3 - y3*w1, my = y2*w3 - y3*w2, ny = ky*w2-cr*my*w1;
00463 return Homg2D((x2*kx-cr*x1*mx)*ny, (y2*ky-cr*y1*my)*nx, nx*ny);
00464 }