00001
00002 #ifndef vgl_h_matrix_2d_txx_
00003 #define vgl_h_matrix_2d_txx_
00004
00005 #include "vgl_h_matrix_2d.h"
00006 #include <vnl/vnl_inverse.h>
00007 #include <vnl/vnl_vector_fixed.h>
00008 #include <vnl/algo/vnl_svd.h>
00009 #include <vcl_limits.h>
00010 #include <vcl_cstdlib.h>
00011 #include <vcl_fstream.h>
00012 #include <vcl_cassert.h>
00013 # include <vcl_deprecated.h>
00014
00015 template <class T>
00016 vgl_h_matrix_2d<T>::vgl_h_matrix_2d(vcl_istream& s)
00017 {
00018 t12_matrix_.read_ascii(s);
00019 }
00020
00021 template <class T>
00022 vgl_h_matrix_2d<T>::vgl_h_matrix_2d(char const* filename)
00023 {
00024 vcl_ifstream f(filename);
00025 if (!f.good())
00026 vcl_cerr << "vgl_h_matrix_2d::read: Error opening " << filename << vcl_endl;
00027 else
00028 t12_matrix_.read_ascii(f);
00029 }
00030
00031 template <class T>
00032 vgl_h_matrix_2d<T>::vgl_h_matrix_2d(vcl_vector<vgl_homg_point_2d<T> > const& points1,
00033 vcl_vector<vgl_homg_point_2d<T> > const& points2)
00034 {
00035 vnl_matrix<T> W;
00036 assert(points1.size() == points2.size());
00037 unsigned int numpoints = points1.size();
00038 if (numpoints < 4)
00039 {
00040 vcl_cerr << "\nvhl_h_matrix_2d - minimum of 4 points required\n";
00041 vcl_exit(0);
00042 }
00043
00044 W.set_size(2*numpoints, 9);
00045
00046 for (unsigned int i = 0; i < numpoints; ++i)
00047 {
00048 T x1 = points1[i].x(), y1 = points1[i].y(), w1 = points1[i].w();
00049 T x2 = points2[i].x(), y2 = points2[i].y(), w2 = points2[i].w();
00050
00051 W[i*2][0]=x1*w2; W[i*2][1]=y1*w2; W[i*2][2]=w1*w2;
00052 W[i*2][3]=0.0; W[i*2][4]=0.0; W[i*2][5]=0.0;
00053 W[i*2][6]=-x1*x2; W[i*2][7]=-y1*x2; W[i*2][8]=-w1*x2;
00054
00055 W[i*2+1][0]=0.0; W[i*2+1][1]=0.0; W[i*2+1][2]=0.0;
00056 W[i*2+1][3]=x1*w2; W[i*2+1][4]=y1*w2; W[i*2+1][5]=w1*w2;
00057 W[i*2+1][6]=-x1*y2; W[i*2+1][7]=-y1*y2; W[i*2+1][8]=-w1*y2;
00058 }
00059
00060 vnl_svd<T> SVD(W);
00061 t12_matrix_ = vnl_matrix_fixed<T,3,3>(SVD.nullvector().data_block());
00062 }
00063
00064 template <class T>
00065 vgl_h_matrix_2d<T>::vgl_h_matrix_2d(vnl_matrix_fixed<T,2,2> const& M,
00066 vnl_vector_fixed<T,2> const& m)
00067 {
00068 for (int r = 0; r < 2; ++r) {
00069 for (int c = 0; c < 2; ++c)
00070 (t12_matrix_)(r, c) = M(r,c);
00071 (t12_matrix_)(r, 2) = m(r);
00072 }
00073 for (int c = 0; c < 2; ++c)
00074 (t12_matrix_)(2,c) = 0;
00075 (t12_matrix_)(2,2) = 1;
00076 }
00077
00078
00079
00080
00081 template <class T>
00082 vgl_homg_point_2d<T>
00083 vgl_h_matrix_2d<T>::operator()(vgl_homg_point_2d<T> const& p) const
00084 {
00085 vnl_vector_fixed<T,3> v2 = t12_matrix_ * vnl_vector_fixed<T,3>(p.x(), p.y(), p.w());
00086 return vgl_homg_point_2d<T>(v2[0], v2[1], v2[2]);
00087 }
00088
00089 template <class T>
00090 vgl_homg_line_2d<T>
00091 vgl_h_matrix_2d<T>::correlation(vgl_homg_point_2d<T> const& p) const
00092 {
00093 vnl_vector_fixed<T,3> v2 = t12_matrix_ * vnl_vector_fixed<T,3>(p.x(), p.y(), p.w());
00094 return vgl_homg_line_2d<T>(v2[0], v2[1], v2[2]);
00095 }
00096
00097 template <class T>
00098 vgl_homg_line_2d<T>
00099 vgl_h_matrix_2d<T>::preimage(vgl_homg_line_2d<T> const& l) const
00100 {
00101 vnl_vector_fixed<T,3> v2 = t12_matrix_.transpose() * vnl_vector_fixed<T,3>(l.a(), l.b(), l.c());
00102 return vgl_homg_line_2d<T>(v2[0], v2[1], v2[2]);
00103 }
00104
00105 template <class T>
00106 vgl_homg_point_2d<T>
00107 vgl_h_matrix_2d<T>::correlation(vgl_homg_line_2d<T> const& l) const
00108 {
00109 vnl_vector_fixed<T,3> v2 = t12_matrix_ * vnl_vector_fixed<T,3>(l.a(), l.b(), l.c());
00110 return vgl_homg_point_2d<T>(v2[0], v2[1], v2[2]);
00111 }
00112
00113 template <class T>
00114 vgl_conic<T>
00115 vgl_h_matrix_2d<T>::operator() (vgl_conic<T> const& C) const
00116 {
00117 T a=C.a(), b=C.b()/2, c = C.c(), d = C.d()/2, e = C.e()/2, f = C.f();
00118 vnl_matrix_fixed<T,3,3> M, Mp;
00119 M(0,0) = a; M(0,1) = b; M(0,2) = d;
00120 M(1,0) = b; M(1,1) = c; M(1,2) = e;
00121 M(2,0) = d; M(2,1) = e; M(2,2) = f;
00122 Mp = (t12_matrix_.transpose())*M*t12_matrix_;
00123 return vgl_conic<T>(Mp(0,0),(Mp(0,1)+Mp(1,0)),Mp(1,1),(Mp(0,2)+Mp(2,0)),
00124 (Mp(1,2)+Mp(2,1)), Mp(2,2));
00125 }
00126
00127 template <class T>
00128 vgl_conic<T>
00129 vgl_h_matrix_2d<T>::preimage(vgl_conic<T> const& C) const
00130 {
00131 T a=C.a(), b=C.b()/2, c = C.c(), d = C.d()/2, e = C.e()/2, f = C.f();
00132 vnl_matrix_fixed<T,3,3> M, Mp;
00133 M(0,0) = a; M(0,1) = b; M(0,2) = d;
00134 M(1,0) = b; M(1,1) = c; M(1,2) = e;
00135 M(2,0) = d; M(2,1) = e; M(2,2) = f;
00136 Mp = vnl_inverse_transpose(t12_matrix_)*M*vnl_inverse(t12_matrix_);
00137 return vgl_conic<T>(Mp(0,0),(Mp(0,1)+Mp(1,0)),Mp(1,1),(Mp(0,2)+Mp(2,0)),
00138 (Mp(1,2)+Mp(2,1)), Mp(2,2));
00139 }
00140
00141
00142 template <class T>
00143 vgl_homg_point_2d<T>
00144 vgl_h_matrix_2d<T>::preimage(vgl_homg_point_2d<T> const& p) const
00145 {
00146 vnl_vector_fixed<T,3> v = vnl_inverse(t12_matrix_) * vnl_vector_fixed<T,3>(p.x(), p.y(), p.w());
00147 return vgl_homg_point_2d<T>(v[0], v[1], v[2]);
00148 }
00149
00150 template <class T>
00151 vgl_homg_line_2d<T>
00152 vgl_h_matrix_2d<T>::operator()(vgl_homg_line_2d<T> const& l) const
00153 {
00154 vnl_vector_fixed<T,3> v = vnl_inverse_transpose(t12_matrix_) * vnl_vector_fixed<T,3>(l.a(), l.b(), l.c());
00155 return vgl_homg_line_2d<T>(v[0], v[1], v[2]);
00156 }
00157
00158 template <class T>
00159 vcl_ostream& operator<<(vcl_ostream& s, vgl_h_matrix_2d<T> const& h)
00160 {
00161 return s << h.get_matrix();
00162 }
00163
00164 template <class T>
00165 bool vgl_h_matrix_2d<T>::read(vcl_istream& s)
00166 {
00167 t12_matrix_.read_ascii(s);
00168 return s.good() || s.eof();
00169 }
00170
00171 template <class T>
00172 bool vgl_h_matrix_2d<T>::read(char const* filename)
00173 {
00174 vcl_ifstream f(filename);
00175 if (!f.good())
00176 vcl_cerr << "vgl_h_matrix_2d::read: Error opening " << filename << vcl_endl;
00177 return read(f);
00178 }
00179
00180
00181
00182 template <class T>
00183 T vgl_h_matrix_2d<T>::get(unsigned int row_index, unsigned int col_index) const
00184 {
00185 return t12_matrix_. get(row_index, col_index);
00186 }
00187
00188 template <class T>
00189 void vgl_h_matrix_2d<T>::get(T* H) const
00190 {
00191 for (T const* iter = t12_matrix_.begin(); iter < t12_matrix_.end(); ++iter)
00192 *H++ = *iter;
00193 }
00194
00195 template <class T>
00196 void vgl_h_matrix_2d<T>::get(vnl_matrix_fixed<T,3,3>* H) const
00197 {
00198 *H = t12_matrix_;
00199 }
00200
00201 template <class T>
00202 void vgl_h_matrix_2d<T>::get(vnl_matrix<T>* H) const
00203 {
00204 VXL_DEPRECATED("vgl_h_matrix_2d<T>::get(vnl_matrix<T>*) const");
00205 *H = t12_matrix_.as_ref();
00206 }
00207
00208 template <class T>
00209 vgl_h_matrix_2d<T>&
00210 vgl_h_matrix_2d<T>::set_identity()
00211 {
00212 t12_matrix_.set_identity();
00213 return *this;
00214 }
00215
00216 template <class T>
00217 vgl_h_matrix_2d<T>&
00218 vgl_h_matrix_2d<T>::set(const T* H)
00219 {
00220 for (T* iter = t12_matrix_.begin(); iter < t12_matrix_.end(); ++iter)
00221 *iter = *H++;
00222 return *this;
00223 }
00224
00225 template <class T>
00226 vgl_h_matrix_2d<T>&
00227 vgl_h_matrix_2d<T>::set(vnl_matrix_fixed<T,3,3> const& H)
00228 {
00229 t12_matrix_ = H;
00230 return *this;
00231 }
00232
00233
00234 template <class T>
00235 bool vgl_h_matrix_2d<T>::
00236 projective_basis(vcl_vector<vgl_homg_point_2d<T> > const& points)
00237 {
00238 if (points.size()!=4)
00239 return false;
00240 vnl_vector_fixed<T,3> p0(points[0].x(), points[0].y(), points[0].w());
00241 vnl_vector_fixed<T,3> p1(points[1].x(), points[1].y(), points[1].w());
00242 vnl_vector_fixed<T,3> p2(points[2].x(), points[2].y(), points[2].w());
00243 vnl_vector_fixed<T,3> p3(points[3].x(), points[3].y(), points[3].w());
00244 vnl_matrix_fixed<T,3,4> point_matrix;
00245 point_matrix.set_column(0, p0);
00246 point_matrix.set_column(1, p1);
00247 point_matrix.set_column(2, p2);
00248 point_matrix.set_column(3, p3);
00249
00250 if (! point_matrix.is_finite() || point_matrix.has_nans())
00251 {
00252 vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00253 << " given points have infinite or NaN values\n";
00254 this->set_identity();
00255 return false;
00256 }
00257 vnl_svd<T> svd1(point_matrix.as_ref(), 1e-8);
00258 if (svd1.rank() < 3)
00259 {
00260 vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00261 << " At least three out of the four points are nearly collinear\n";
00262 this->set_identity();
00263 return false;
00264 }
00265
00266 vnl_matrix_fixed<T,3,3> back_matrix;
00267 back_matrix.set_column(0, p0);
00268 back_matrix.set_column(1, p1);
00269 back_matrix.set_column(2, p2);
00270
00271 vnl_vector_fixed<T,3> scales_vector = vnl_inverse(back_matrix) * p3;
00272
00273 back_matrix.set_column(0, scales_vector[0] * p0);
00274 back_matrix.set_column(1, scales_vector[1] * p1);
00275 back_matrix.set_column(2, scales_vector[2] * p2);
00276
00277 if (! back_matrix.is_finite() || back_matrix.has_nans())
00278 {
00279 vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00280 << " back matrix has infinite or NaN values\n";
00281 this->set_identity();
00282 return false;
00283 }
00284 this->set(vnl_inverse(back_matrix));
00285 return true;
00286 }
00287
00288 template <class T>
00289 bool vgl_h_matrix_2d<T>::is_rotation() const
00290 {
00291 return t12_matrix_.get(0,2) == (T)0
00292 && t12_matrix_.get(1,2) == (T)0
00293 && this->is_euclidean();
00294 }
00295
00296 template <class T>
00297 bool vgl_h_matrix_2d<T>::is_euclidean() const
00298 {
00299 if ( t12_matrix_.get(2,0) != (T)0 ||
00300 t12_matrix_.get(2,1) != (T)0 ||
00301 t12_matrix_.get(2,2) != (T)1 )
00302 return false;
00303
00304
00305 vnl_matrix_fixed<T,2,2> R = get_upper_2x2_matrix();
00306 R *= R.transpose();
00307 R(0,0) -= T(1);
00308 R(1,1) -= T(1);
00309 return R.absolute_value_max() <= 10*vcl_numeric_limits<T>::epsilon();
00310 }
00311
00312 template <class T>
00313 bool vgl_h_matrix_2d<T>::is_identity() const
00314 {
00315 return t12_matrix_.is_identity();
00316 }
00317
00318
00319 template <class T>
00320 bool vgl_h_matrix_2d<T>::projective_basis(vcl_vector<vgl_homg_line_2d<T> > const& lines
00321 #ifdef VCL_VC_6
00322 ,int dummy
00323 #endif
00324 )
00325 {
00326 if (lines.size()!=4)
00327 return false;
00328 vnl_vector_fixed<T,3> l0(lines[0].a(), lines[0].b(), lines[0].c());
00329 vnl_vector_fixed<T,3> l1(lines[1].a(), lines[1].b(), lines[1].c());
00330 vnl_vector_fixed<T,3> l2(lines[2].a(), lines[2].b(), lines[2].c());
00331 vnl_vector_fixed<T,3> l3(lines[3].a(), lines[3].b(), lines[3].c());
00332 vnl_matrix_fixed<T,3,4> line_matrix;
00333 line_matrix.set_column(0, l0);
00334 line_matrix.set_column(1, l1);
00335 line_matrix.set_column(2, l2);
00336 line_matrix.set_column(3, l3);
00337
00338 if (! line_matrix.is_finite() || line_matrix.has_nans())
00339 {
00340 vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00341 << " given lines have infinite or NaN values\n";
00342 this->set_identity();
00343 return false;
00344 }
00345 vnl_svd<T> svd1(line_matrix.as_ref(), 1e-8);
00346 if (svd1.rank() < 3)
00347 {
00348 vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00349 << " At least three out of the four lines are nearly concurrent\n";
00350 this->set_identity();
00351 return false;
00352 }
00353
00354 vnl_matrix_fixed<T,3,3> back_matrix;
00355 back_matrix.set_column(0, l0);
00356 back_matrix.set_column(1, l1);
00357 back_matrix.set_column(2, l2);
00358 vnl_vector_fixed<T,3> scales_vector = vnl_inverse(back_matrix) * l3;
00359 back_matrix.set_row(0, scales_vector[0] * l0);
00360 back_matrix.set_row(1, scales_vector[1] * l1);
00361 back_matrix.set_row(2, scales_vector[2] * l2);
00362
00363 if (! back_matrix.is_finite() || back_matrix.has_nans())
00364 {
00365 vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00366 << " back matrix has infinite or NaN values\n";
00367 this->set_identity();
00368 return false;
00369 }
00370 this->set(back_matrix);
00371 return true;
00372 }
00373
00374 template <class T>
00375 vgl_h_matrix_2d<T>
00376 vgl_h_matrix_2d<T>::get_inverse() const
00377 {
00378 return vgl_h_matrix_2d<T>(vnl_inverse(t12_matrix_));
00379 }
00380
00381
00382 template <class T>
00383 vgl_h_matrix_2d<T>&
00384 vgl_h_matrix_2d<T>::set_translation(T tx, T ty)
00385 {
00386 t12_matrix_[0][2] = tx; t12_matrix_[1][2] = ty;
00387 return *this;
00388 }
00389
00390 template <class T>
00391 vgl_h_matrix_2d<T>&
00392 vgl_h_matrix_2d<T>::set_rotation(T theta)
00393 {
00394 double theta_d = (double)theta;
00395 double c = vcl_cos(theta_d), s = vcl_sin(theta_d);
00396 t12_matrix_[0][0] = (T)c; t12_matrix_[0][1] = -(T)s;
00397 t12_matrix_[1][0] = (T)s; t12_matrix_[1][1] = (T)c;
00398 return *this;
00399 }
00400
00401 template <class T>
00402 vgl_h_matrix_2d<T>&
00403 vgl_h_matrix_2d<T>::set_scale(T scale)
00404 {
00405 for (unsigned r = 0; r<2; ++r)
00406 for (unsigned c = 0; c<3; ++c)
00407 t12_matrix_[r][c]*=scale;
00408 return *this;
00409 }
00410
00411 template <class T>
00412 vgl_h_matrix_2d<T>&
00413 vgl_h_matrix_2d<T>::set_similarity(T s, T theta,
00414 T tx, T ty)
00415 {
00416 T a=s*vcl_cos(theta);
00417 T b=s*vcl_sin(theta);
00418 t12_matrix_[0][0] = a; t12_matrix_[0][1] = -b; t12_matrix_[0][2] = tx;
00419 t12_matrix_[1][0] = b; t12_matrix_[1][1] = a; t12_matrix_[1][2] = ty;
00420 t12_matrix_[2][0]=T(0); t12_matrix_[2][1]=T(0); t12_matrix_[2][2] = T(1);
00421 return *this;
00422 }
00423
00424 template <class T>
00425 vgl_h_matrix_2d<T>&
00426 vgl_h_matrix_2d<T>::set_aspect_ratio(T aspect_ratio)
00427 {
00428 for (unsigned c = 0; c<3; ++c)
00429 t12_matrix_[1][c]*=aspect_ratio;
00430 return *this;
00431 }
00432
00433
00434 template <class T>
00435 vgl_h_matrix_2d<T>&
00436 vgl_h_matrix_2d<T>::set_affine(vnl_matrix_fixed<T,2,3> const& M23)
00437 {
00438 for (unsigned r = 0; r<2; ++r)
00439 for (unsigned c = 0; c<3; ++c)
00440 t12_matrix_[r][c] = M23[r][c];
00441 t12_matrix_[2][0] = T(0); t12_matrix_[2][1] = T(0); t12_matrix_[2][2] = T(1);
00442 return *this;
00443 }
00444
00445 template <class T>
00446 vgl_h_matrix_2d<T>&
00447 vgl_h_matrix_2d<T>::set_affine(vnl_matrix<T> const& M23)
00448 {
00449 VXL_DEPRECATED("vgl_h_matrix_2d<T>::set_affine(vnl_matrix<T> const&)");
00450 assert (M23.rows()==2 && M23.columns()==3);
00451 for (unsigned r = 0; r<2; ++r)
00452 for (unsigned c = 0; c<3; ++c)
00453 t12_matrix_[r][c] = M23[r][c];
00454 t12_matrix_[2][0] = T(0); t12_matrix_[2][1] = T(0); t12_matrix_[2][2] = T(1);
00455 return *this;
00456 }
00457
00458 template <class T>
00459 vgl_h_matrix_2d<T>
00460 vgl_h_matrix_2d<T>::get_upper_2x2() const
00461 {
00462
00463 T d = t12_matrix_[2][2];
00464 assert(d<-1e-9 || d>1e-9);
00465 vnl_matrix_fixed<T,3,3> m(0.0);
00466 for (unsigned r = 0; r<2; ++r)
00467 for (unsigned c = 0; c<2; ++c)
00468 m[r][c] = t12_matrix_[r][c]/d;
00469 m[2][2]=1.0;
00470 return vgl_h_matrix_2d<T>(m);
00471 }
00472
00473 template <class T>
00474 vnl_matrix_fixed<T,2,2>
00475 vgl_h_matrix_2d<T>::get_upper_2x2_matrix() const
00476 {
00477 vnl_matrix_fixed<T,2,2> R;
00478 vgl_h_matrix_2d<T> m = this->get_upper_2x2();
00479 for (unsigned r = 0; r<3; ++r)
00480 for (unsigned c = 0; c<3; ++c)
00481 R[r][c] = m.get(r,c);
00482 return R;
00483 }
00484
00485 template <class T>
00486 vgl_homg_point_2d<T>
00487 vgl_h_matrix_2d<T>::get_translation() const
00488 {
00489
00490 T d = t12_matrix_[2][2];
00491 assert(d<-1e-9 || d>1e-9);
00492 return vgl_homg_point_2d<T>(t12_matrix_[0][2]/d,
00493 t12_matrix_[1][2]/d,
00494 (T)1);
00495 }
00496
00497 template <class T>
00498 vnl_vector_fixed<T,2>
00499 vgl_h_matrix_2d<T>::get_translation_vector() const
00500 {
00501 vgl_homg_point_2d<T> p = this->get_translation();
00502 return vnl_vector_fixed<T,2>(p.x(), p.y());
00503 }
00504
00505
00506 #undef VGL_H_MATRIX_2D_INSTANTIATE
00507 #define VGL_H_MATRIX_2D_INSTANTIATE(T) \
00508 template class vgl_h_matrix_2d<T >; \
00509 template vcl_ostream& operator << (vcl_ostream& s, vgl_h_matrix_2d<T > const& h); \
00510 template vcl_istream& operator >> (vcl_istream& s, vgl_h_matrix_2d<T >& h)
00511
00512 #endif // vgl_h_matrix_2d_txx_