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