00001 #include "rgrl_trans_quadratic.h"
00002
00003
00004
00005
00006
00007 #include <vcl_cassert.h>
00008 #include <vnl/algo/vnl_svd.h>
00009 #include <vnl/vnl_math.h>
00010 #include <rgrl/rgrl_util.h>
00011
00012 rgrl_trans_quadratic::
00013 rgrl_trans_quadratic( unsigned int dim)
00014 : Q_( vnl_matrix<double>( dim, dim + int(dim*(dim-1)/2), 0.0 ) ),
00015 A_( vnl_matrix<double>( dim, dim, vnl_matrix_identity ) ),
00016 trans_( vnl_vector<double>( dim, 0.0 ) ),
00017 from_centre_( dim, 0.0 )
00018 {
00019 }
00020
00021 rgrl_trans_quadratic::
00022 rgrl_trans_quadratic( vnl_matrix<double> const& in_Q,
00023 vnl_matrix<double> const& in_A,
00024 vnl_vector<double> const& in_trans,
00025 vnl_matrix<double> const& in_covar )
00026 : rgrl_transformation( in_covar ),
00027 Q_( in_Q ),
00028 A_( in_A ),
00029 trans_( in_trans ),
00030 from_centre_( in_trans.size(), 0.0 )
00031 {
00032 assert ( Q_.rows() + Q_.rows()*(Q_.rows()-1)/2 == Q_.cols() );
00033 assert ( A_.rows() == A_.cols() );
00034 assert ( A_.rows() == trans_.size() );
00035 if ( is_covar_set() ) {
00036 assert ( covar_.rows() == covar_.cols() );
00037 assert ( covar_.rows() == A_.rows()* (Q_.cols()+A_.cols() + 1 ) );
00038 }
00039 }
00040
00041 rgrl_trans_quadratic::
00042 rgrl_trans_quadratic( vnl_matrix<double> const& in_Q,
00043 vnl_matrix<double> const& in_A,
00044 vnl_vector<double> const& in_trans )
00045 : Q_( in_Q ),
00046 A_( in_A ),
00047 trans_( in_trans ),
00048 from_centre_( in_trans.size(), 0.0 )
00049 {
00050 assert ( Q_.rows() + Q_.rows()*(Q_.rows()-1)/2 == Q_.cols() );
00051 assert ( A_.rows() == A_.cols() );
00052 assert ( A_.rows() == trans_.size() );
00053 }
00054
00055
00056 rgrl_trans_quadratic::
00057 rgrl_trans_quadratic( vnl_matrix<double> const& in_Q,
00058 vnl_matrix<double> const& in_A,
00059 vnl_vector<double> const& in_trans,
00060 vnl_matrix<double> const& in_covar,
00061 vnl_vector<double> const& in_from_centre,
00062 vnl_vector<double> const& in_to_centre )
00063 : rgrl_transformation( in_covar ),
00064 Q_( in_Q ),
00065 A_( in_A ),
00066 trans_( in_trans ),
00067 from_centre_( in_from_centre )
00068 {
00069 assert ( Q_.rows() + Q_.rows()*(Q_.rows()-1)/2 == Q_.cols() );
00070 assert ( A_.rows() == A_.cols() );
00071 assert ( A_.rows() == trans_.size() );
00072 assert ( from_centre_.size() == trans_.size() );
00073 if ( is_covar_set() ) {
00074 assert ( covar_.rows() == covar_.cols() );
00075 assert ( covar_.rows() == A_.rows()* ( Q_.cols() + A_.cols() + 1) );
00076 }
00077
00078
00079 vnl_vector<double> new_trans;
00080 map_loc( -in_from_centre, new_trans );
00081 trans_ = new_trans + in_to_centre;
00082
00083 if (A_.rows() == 2) {
00084 vnl_matrix<double> new_A(2,2, 0.0);
00085 new_A(0,0) = -2*in_from_centre[0]*Q_(0,0)-in_from_centre[1]*Q_(0,2)+A_(0,0);
00086 new_A(0,1) = -2*in_from_centre[1]*Q_(0,1)-in_from_centre[0]*Q_(0,2)+A_(0,1);
00087 new_A(1,0) = -2*in_from_centre[0]*Q_(1,0)-in_from_centre[1]*Q_(1,2)+A_(1,0);
00088 new_A(1,1) = -2*in_from_centre[1]*Q_(1,1)-in_from_centre[0]*Q_(1,2)+A_(1,1);
00089 A_ = new_A;
00090 }
00091 else {
00092 vnl_matrix<double> new_A(3,3, 0.0);
00093 double cx = in_from_centre[0];
00094 double cy = in_from_centre[1];
00095 double cz = in_from_centre[2];
00096
00097 new_A(0,0) = -2*cx*Q_(0,0)-cy*Q_(0,3)-cz*Q_(0,5)+A_(0,0);
00098 new_A(0,1) = -2*cy*Q_(0,1)-cx*Q_(0,3)-cz*Q_(0,4)+A_(0,1);
00099 new_A(0,2) = -2*cz*Q_(0,2)-cy*Q_(0,4)-cx*Q_(0,5)+A_(0,2);
00100
00101 new_A(1,0) = -2*cx*Q_(1,0)-cy*Q_(1,3)-cz*Q_(1,5)+A_(1,0);
00102 new_A(1,1) = -2*cy*Q_(1,1)-cx*Q_(1,3)-cz*Q_(1,4)+A_(1,1);
00103 new_A(1,2) = -2*cz*Q_(1,2)-cy*Q_(1,4)-cx*Q_(1,5)+A_(1,2);
00104
00105 new_A(2,0) = -2*cx*Q_(2,0)-cy*Q_(2,3)-cz*Q_(2,5)+A_(2,0);
00106 new_A(2,1) = -2*cy*Q_(2,1)-cx*Q_(2,3)-cz*Q_(2,4)+A_(2,1);
00107 new_A(2,2) = -2*cz*Q_(2,2)-cy*Q_(2,4)-cx*Q_(2,5)+A_(2,2);
00108
00109 A_ = new_A;
00110 }
00111 }
00112
00113 void
00114 rgrl_trans_quadratic::
00115 set_from_center( vnl_vector<double> const& from_center )
00116 {
00117 from_centre_ = from_center;
00118 }
00119
00120 void
00121 rgrl_trans_quadratic::
00122 map_loc( vnl_vector<double> const& from,
00123 vnl_vector<double> & to ) const
00124 {
00125 assert ( from.size() == A_.rows() );
00126 vnl_vector<double> hot = higher_order_terms(from);
00127 to = Q_ * hot + A_ * from + trans_;
00128 }
00129
00130
00131 void
00132 rgrl_trans_quadratic::
00133 map_dir( vnl_vector<double> const& from_loc,
00134 vnl_vector<double> const& from_dir,
00135 vnl_vector<double> & to_dir ) const
00136 {
00137 assert ( from_loc.size() == A_.cols() );
00138 assert ( from_dir.size() == A_.cols() );
00139 vnl_vector<double> to_loc_begin, to_loc_end;
00140 this->map_loc(from_loc, to_loc_begin);
00141 this->map_loc(from_loc+from_dir, to_loc_end);
00142
00143 to_dir = to_loc_end - to_loc_begin;
00144 to_dir.normalize();
00145 }
00146
00147
00148 vnl_matrix<double>
00149 rgrl_trans_quadratic::
00150 transfer_error_covar( vnl_vector<double> const& p ) const
00151 {
00152 unsigned const m = A_.rows();
00153
00154 assert ( is_covar_set() );
00155 assert ( p.size() == m );
00156 int num_terms = m+int(m*(m-1)/2) + m +1;
00157
00158 vnl_matrix<double> temp( m, m*num_terms, 0.0 );
00159 vnl_vector<double> p_centered = p - from_centre_;
00160 vnl_vector<double> hot = higher_order_terms(p_centered);
00161
00162 for ( unsigned i=0; i < m; ++i ) {
00163 unsigned off = i*num_terms;
00164 for ( unsigned j=0; j < hot.size(); ++j ) {
00165 temp(i,off+j) = hot[j];
00166 }
00167 off += hot.size();
00168 for ( unsigned j=0; j < m; ++j ) {
00169 temp(i,off+j) = p_centered[j];
00170 }
00171 temp(i,off+m) = 1.0;
00172 }
00173
00174 return temp * covar_ * temp.transpose();
00175 }
00176
00177 vnl_matrix<double> const&
00178 rgrl_trans_quadratic::
00179 Q() const
00180 {
00181 return Q_;
00182 }
00183
00184 vnl_matrix<double> const&
00185 rgrl_trans_quadratic::
00186 A() const
00187 {
00188 return A_;
00189 }
00190
00191
00192 vnl_vector<double> const&
00193 rgrl_trans_quadratic::
00194 t() const
00195 {
00196 return trans_;
00197 }
00198
00199 void
00200 rgrl_trans_quadratic::
00201 inv_map( const vnl_vector<double>& to,
00202 bool initialize_next,
00203 const vnl_vector<double>& to_delta,
00204 vnl_vector<double>& from,
00205 vnl_vector<double>& from_next_est) const
00206 {
00207 const double epsilon = 0.01;
00208 const double eps_squared = epsilon*epsilon;
00209 int t=0;
00210 const int max_t = 20;
00211 assert (to.size() == from.size());
00212 int m = to.size();
00213 vnl_vector<double> to_est = this->map_location(from);
00214 vnl_matrix<double> approx_A_inv;
00215
00216 while ( vnl_vector_ssd(to, to_est) > eps_squared && t<max_t ) {
00217 t ++ ;
00218
00219 vnl_matrix<double> approx_A = A_;
00220 vnl_matrix<double> X(Q_.cols(), Q_.rows(), 0.0);
00221 if (m == 2) {
00222 X(0,0) = 2*from[0]; X(1,1) = 2*from[1];
00223 X(2,0) = from[1]; X(2,1) = from[0];
00224 }
00225 else {
00226 X(0,0) = 2*from[0]; X(1,1) = 2*from[1]; X(2,2) = 2*from[2];
00227 X(3,0) = from[1]; X(2,1) = from[0];
00228 X(4,1) = from[2]; X(4,2) = from[1];
00229 X(5,0) = from[2]; X(5,2) = from[0];
00230 }
00231 approx_A += Q_*X;
00232 vnl_svd<double> svd(approx_A);
00233 approx_A_inv = svd.inverse();
00234
00235
00236 from += 0.95 * approx_A_inv * (to - to_est);
00237 to_est = this->map_location(from);
00238 }
00239 if ( t > max_t )
00240 DebugMacro( 0, " rgrl_trans_quadratic::inv_map()-- no convergence\n");
00241
00242 if ( initialize_next ) {
00243 if ( t == 0 ) {
00244 vnl_matrix<double> approx_A = A_;
00245 vnl_matrix<double> X(Q_.cols(), Q_.rows(), 0.0);
00246 if (m == 2) {
00247 X(0,0) = 2*from[0]; X(1,1) = 2*from[1];
00248 X(2,0) = from[1]; X(2,1) = from[0];
00249 }
00250 else {
00251 X(0,0) = 2*from[0]; X(1,1) = 2*from[1]; X(2,2) = 2*from[2];
00252 X(3,0) = from[1]; X(2,1) = from[0];
00253 X(4,1) = from[2]; X(4,2) = from[1];
00254 X(5,0) = from[2]; X(5,2) = from[0];
00255 }
00256 approx_A += Q_*X;
00257 vnl_svd<double> svd(approx_A);
00258 approx_A_inv = svd.inverse();
00259 }
00260 from_next_est = from + approx_A_inv * to_delta;
00261 }
00262 }
00263
00264 void
00265 rgrl_trans_quadratic::
00266 jacobian_wrt_loc( vnl_matrix<double>& jacobian_Q, vnl_vector<double> const& from_loc ) const
00267 {
00268 unsigned int m = trans_.size();
00269 jacobian_Q.set_size(m, m);
00270 if ( m == 2 ) {
00271 for (unsigned int i = 0; i<m; i++) {
00272 jacobian_Q(i,0) = 2*Q_(i,0)*from_loc[0] + Q_(i,2)*from_loc[1];
00273 jacobian_Q(i,1) = 2*Q_(i,1)*from_loc[1] + Q_(i,2)*from_loc[0];
00274 }
00275 }
00276 else {
00277 for (unsigned int i = 0; i<m; i++) {
00278 jacobian_Q(i,0) = 2*Q_(i,0)*from_loc[0] + Q_(i,3)*from_loc[1] + Q_(i,5)*from_loc[2];
00279 jacobian_Q(i,1) = 2*Q_(i,1)*from_loc[1] + Q_(i,3)*from_loc[0] + Q_(i,4)*from_loc[2];
00280 jacobian_Q(i,2) = 2*Q_(i,2)*from_loc[2] + Q_(i,4)*from_loc[1] + Q_(i,5)*from_loc[0];
00281 }
00282 }
00283
00284
00285 jacobian_Q += A_;
00286 }
00287
00288 rgrl_transformation_sptr
00289 rgrl_trans_quadratic::
00290 scale_by( double scale ) const
00291 {
00292 rgrl_trans_quadratic* quad = new rgrl_trans_quadratic( Q_/scale, A_,
00293 trans_ * scale,
00294 covar_);
00295 quad->set_from_center( from_centre_ * scale );
00296 quad->set_scaling_factors( this->scaling_factors() );
00297
00298 return quad;
00299 }
00300
00301 vnl_vector<double>
00302 rgrl_trans_quadratic::
00303 higher_order_terms(vnl_vector<double> p) const
00304 {
00305 int m = p.size();
00306 vnl_vector<double> higher_terms( m + int(m*(m-1)/2));
00307
00308 if (m == 3) {
00309 higher_terms[0] = vnl_math_sqr(p[0]);
00310 higher_terms[1] = vnl_math_sqr(p[1]);
00311 higher_terms[2] = vnl_math_sqr(p[2]);
00312 higher_terms[3] = p[0]*p[1];
00313 higher_terms[4] = p[1]*p[2];
00314 higher_terms[5] = p[0]*p[2];
00315 }
00316 else {
00317 higher_terms[0] = vnl_math_sqr(p[0]);
00318 higher_terms[1] = vnl_math_sqr(p[1]);
00319 higher_terms[2] = p[0]*p[1];
00320 }
00321
00322 return higher_terms;
00323 }
00324
00325 void
00326 rgrl_trans_quadratic::
00327 write( vcl_ostream& os ) const
00328 {
00329 vnl_vector<double> origin(from_centre_.size(), 0.0);
00330
00331 os << "QUADRATIC\n"
00332
00333 << t().size() << vcl_endl
00334 << Q_<< A_ << trans_ << ' ' << origin << vcl_endl;
00335
00336
00337 rgrl_transformation::write( os );
00338 }
00339
00340 bool
00341 rgrl_trans_quadratic::
00342 read( vcl_istream& is )
00343 {
00344
00345 rgrl_util_skip_empty_lines( is );
00346
00347 vcl_string str;
00348 vcl_getline( is, str );
00349
00350
00351 if ( str.find( "QUADRATIC" ) != 0 ) {
00352 WarningMacro( "The tag is not QUADRATIC. reading is aborted.\n" );
00353 return false;
00354 }
00355
00356
00357 int dim=-1;
00358 is >> dim;
00359 if ( dim > 0 ) {
00360 Q_.set_size( dim, dim + int(dim*(dim-1)/2) );
00361 A_.set_size( dim, dim );
00362 trans_.set_size( dim );
00363 from_centre_.set_size( dim );
00364 is >> Q_ >> A_ >> trans_ >> from_centre_;
00365 }
00366
00367
00368 return is.good() && rgrl_transformation::read( is );
00369 }
00370
00371 void
00372 rgrl_trans_quadratic::
00373 inv_map( vnl_vector<double> const& ,
00374 vnl_vector<double>& ) const
00375 {
00376 assert ( ! "rgrl_trans_quadratic::inv_map() is not defined" );
00377 }
00378
00379 rgrl_transformation_sptr
00380 rgrl_trans_quadratic::
00381 inverse_transform( ) const
00382 {
00383 assert ( ! "rgrl_trans_quadratic::inverse_transform() is not defined" );
00384 return 0;
00385 }
00386
00387
00388 rgrl_transformation_sptr
00389 rgrl_trans_quadratic::
00390 clone() const
00391 {
00392 return new rgrl_trans_quadratic( *this );
00393 }