1 #include "rgrl_trans_similarity.h"
2 //:
3 // \file
4 // \author Amitha Perera
5 // \date   Feb 2003
6 
7 #include <cassert>
8 #include <utility>
9 
10 #ifdef _MSC_VER
11 #  include "vcl_msvc_warnings.h"
12 #endif
13 #include "vnl/vnl_fastops.h"
14 #include <vnl/algo/vnl_svd.h>
15 #include <rgrl/rgrl_util.h>
16 
17 rgrl_trans_similarity::
rgrl_trans_similarity(unsigned int dimension)18 rgrl_trans_similarity( unsigned int dimension )
19   : A_( vnl_matrix<double>( dimension, dimension, vnl_matrix_identity ) ),
20     trans_( vnl_vector<double>( dimension, 0.0 ) ),
21     from_centre_( dimension, 0.0 )
22 {
23 }
24 
rgrl_trans_similarity(vnl_matrix<double> rot_and_scale,vnl_vector<double> const & in_trans)25 rgrl_trans_similarity::rgrl_trans_similarity(vnl_matrix<double> rot_and_scale,
26                                              vnl_vector<double> const &in_trans)
27     : A_(std::move(rot_and_scale)), trans_(in_trans),
28       from_centre_(in_trans.size(), 0.0) {
29   assert ( A_.rows() == A_.cols() );
30   assert ( A_.rows() == trans_.size() );
31   // assert ( ( A_.rows() != 2 || covar_.rows() == 4 ) ); // 2d has 4 params
32   // assert ( ( A_.rows() != 3 || covar_.rows() == 7 ) ); // 3d has 7 params
33 }
34 
rgrl_trans_similarity(vnl_matrix<double> rot_and_scale,vnl_vector<double> const & in_trans,vnl_matrix<double> const & in_covar)35 rgrl_trans_similarity::rgrl_trans_similarity(vnl_matrix<double> rot_and_scale,
36                                              vnl_vector<double> const &in_trans,
37                                              vnl_matrix<double> const &in_covar)
38     : rgrl_transformation(in_covar), A_(std::move(rot_and_scale)),
39       trans_(in_trans), from_centre_(in_trans.size(), 0.0) {
40   assert ( A_.rows() == A_.cols() );
41   assert ( A_.rows() == trans_.size() );
42   if ( is_covar_set() ) {
43     assert ( covar_.rows() == covar_.cols() );
44     assert ( ( A_.rows() != 2 || covar_.rows() == 4 ) ); // 2d has 4 params
45     assert ( ( A_.rows() != 3 || covar_.rows() == 7 ) ); // 3d has 7 params
46   }
47 }
48 
rgrl_trans_similarity(vnl_matrix<double> in_A,vnl_vector<double> const & in_trans,vnl_matrix<double> const & in_covar,vnl_vector<double> in_from_centre,vnl_vector<double> const & in_to_centre)49 rgrl_trans_similarity::rgrl_trans_similarity(
50     vnl_matrix<double> in_A, vnl_vector<double> const &in_trans,
51     vnl_matrix<double> const &in_covar, vnl_vector<double> in_from_centre,
52     vnl_vector<double> const &in_to_centre)
53     : rgrl_transformation(in_covar), A_(std::move(in_A)),
54       trans_(in_trans + in_to_centre), from_centre_(std::move(in_from_centre)) {
55   assert ( A_.rows() == A_.cols() );
56   assert ( A_.rows() == trans_.size() );
57   assert ( from_centre_.size() == trans_.size() );
58   if ( is_covar_set() ) {
59     assert ( covar_.rows() == covar_.cols() );
60     assert ( ( A_.rows() != 2 || covar_.rows() == 4 ) ); // 2d has 4 params
61     assert ( ( A_.rows() != 3 || covar_.rows() == 7 ) ); // 3d has 7 params
62   }
63 }
64 
65 void
66 rgrl_trans_similarity::
map_loc(vnl_vector<double> const & from,vnl_vector<double> & to) const67 map_loc( vnl_vector<double> const& from,
68          vnl_vector<double>      & to   ) const
69 {
70   assert ( from.size() == A_.rows() );
71   // for efficiency, rewrite the following as:
72   // to = A_ * (from-from_centre_) + trans_;
73   //
74   vnl_fastops::Ab( to, A_, from-from_centre_ );
75   to += trans_;
76 }
77 
map_dir(vnl_vector<double> const & from_loc,vnl_vector<double> const & from_dir,vnl_vector<double> & to_dir) const78 void rgrl_trans_similarity::map_dir(vnl_vector<double> const & from_loc,
79                                     vnl_vector<double> const &from_dir,
80                                     vnl_vector<double> &to_dir) const {
81   assert ( from_loc.size() == A_.cols() );
82   assert ( from_dir.size() == A_.cols() );
83   to_dir = A_ * from_dir;
84   to_dir.normalize();
85 }
86 
87 vnl_matrix<double>
88 rgrl_trans_similarity::
transfer_error_covar(vnl_vector<double> const & p) const89 transfer_error_covar( vnl_vector<double> const& p  ) const
90 {
91   assert ( is_covar_set() );
92   assert ( p.size() == 2);  // only deal with 2D for now
93   assert ( A_.rows() == 2); // only deal with 2D for now
94 
95   vnl_matrix<double> temp( 2, 4, 0.0 );
96   temp(0,0) = p[0]-from_centre_[0];
97   temp(0,1) = from_centre_[1] - p[1];
98   temp(0,2) = 1;
99   temp(1,0) = p[1]-from_centre_[1];
100   temp(1,1) = p[0] - from_centre_[0];
101   temp(1,3) = 1;
102 
103   return temp * covar_ * temp.transpose();
104 }
105 
106 vnl_matrix<double> const&
107 rgrl_trans_similarity::
A() const108 A() const
109 {
110   return A_;
111 }
112 
113 double
114 rgrl_trans_similarity::
scaling() const115 scaling() const
116 {
117   assert( A_.rows() && A_.cols() );
118   vnl_vector<double> tmp = A_.get_column(0);
119   return tmp.magnitude();
120 }
121 
122 vnl_vector<double>
123 rgrl_trans_similarity::
t() const124 t() const
125 {
126   return trans_ - A_ * from_centre_;
127 }
128 
129 void
130 rgrl_trans_similarity::
inv_map(const vnl_vector<double> & to,bool initialize_next,const vnl_vector<double> & to_delta,vnl_vector<double> & from,vnl_vector<double> & from_next_est) const131 inv_map( const vnl_vector<double>& to,
132          bool initialize_next,
133          const vnl_vector<double>& to_delta,
134          vnl_vector<double>& from,
135          vnl_vector<double>& from_next_est) const
136 {
137   constexpr double epsilon = 0.01;
138   vnl_vector<double> to_est = this->map_location(from);
139 
140   // compute the inverse of the Jacobian, which is the A_^-1
141   vnl_svd<double> svd( A_ );
142   vnl_matrix<double> J_inv = svd.inverse();
143 
144   // update from to become true inv_map of to, based on A^-1 and (to - to_est)
145   if (vnl_vector_ssd(to, to_est) > epsilon*epsilon) {
146     from += J_inv * (to - to_est);
147   }
148   if ( initialize_next ) {
149     from_next_est = from + (J_inv * to_delta);
150   }
151 }
152 
153 void
154 rgrl_trans_similarity::
inv_map(const vnl_vector<double> & to,vnl_vector<double> & from) const155 inv_map( const vnl_vector<double>& to,
156          vnl_vector<double>& from ) const
157 {
158   vnl_svd<double> svd( A_ );
159   from = svd.inverse()*to - svd.inverse()*trans_ + from_centre_;
160 }
161 
162 rgrl_transformation_sptr
163 rgrl_trans_similarity::
inverse_transform() const164 inverse_transform( ) const
165 {
166   vnl_svd<double> svd( A() );
167   vnl_matrix<double> invA = svd.inverse();
168   rgrl_transformation_sptr result =  new rgrl_trans_similarity( invA, -invA * t() );
169 
170   const unsigned m = scaling_factors_.size();
171   if ( m > 0 ) {
172     vnl_vector<double> scaling( m );
173     for ( unsigned int i=0; i<m; ++i )
174       scaling[i] = 1.0 / scaling_factors_[i];
175     result->set_scaling_factors( scaling );
176   }
177 
178   return result;
179 }
180 
181 
182 void
183 rgrl_trans_similarity::
jacobian_wrt_loc(vnl_matrix<double> & jac,vnl_vector<double> const &) const184 jacobian_wrt_loc( vnl_matrix<double>& jac, vnl_vector<double> const& /*from_loc*/ ) const
185 {
186   jac = A_;
187 }
188 
189 rgrl_transformation_sptr
190 rgrl_trans_similarity::
scale_by(double scale) const191 scale_by( double scale ) const
192 {
193   rgrl_transformation_sptr xform
194     = new rgrl_trans_similarity( A_, trans_ * scale,
195                                  covar_, from_centre_ * scale,
196                                  vnl_vector<double>(from_centre_.size(), 0.0) );
197   xform->set_scaling_factors( this->scaling_factors() );
198   return xform;
199 }
200 
201 void
202 rgrl_trans_similarity::
write(std::ostream & os) const203 write( std::ostream& os ) const
204 {
205   // tag
206   os << "SIMILARITY\n"
207   // parameters
208      << t().size() << std::endl
209      << A_ << trans_ << ' ' << from_centre_ << std::endl;
210 
211   // parent
212   rgrl_transformation::write( os );
213 }
214 
215 bool
216 rgrl_trans_similarity::
read(std::istream & is)217 read( std::istream& is )
218 {
219   int dim;
220 
221   // skip empty lines
222   rgrl_util_skip_empty_lines( is );
223 
224   std::string str;
225   std::getline( is, str );
226 
227   // The token should appear at the beginning of line
228   if ( str.find( "SIMILARITY" ) != 0 ) {
229     WarningMacro( "The tag is not SIMILARITY. reading is aborted.\n" );
230     return false;
231   }
232 
233   // input global xform
234   dim=-1;
235   is >> dim;
236   if ( dim > 0 ) {
237     A_.set_size( dim, dim );
238     trans_.set_size( dim );
239     from_centre_.set_size( dim );
240     is >> A_ >> trans_ >> from_centre_;
241   }
242 
243   // parent
244   return is.good() && rgrl_transformation::read( is );
245 }
246 
247 //: make a clone copy
248 rgrl_transformation_sptr
249 rgrl_trans_similarity::
clone() const250 clone() const
251 {
252   return new rgrl_trans_similarity( *this );
253 }
254