00001 #include "rgrl_invariant_single_landmark.h"
00002 #include "rgrl_trans_similarity.h"
00003 #include "rgrl_scale.h"
00004 #include "rgrl_cast.h"
00005
00006 #include <vcl_vector.h>
00007 #include <vcl_algorithm.h>
00008 #include <vcl_cassert.h>
00009
00010 #include <vnl/vnl_math.h>
00011 #include <vnl/vnl_inverse.h>
00012 #include <vnl/vnl_double_4.h>
00013 #include <vnl/vnl_double_2.h>
00014 #include <vnl/vnl_vector.h>
00015 #include <vnl/vnl_matrix_fixed.h>
00016
00017 rgrl_invariant_single_landmark::
00018 rgrl_invariant_single_landmark(vnl_vector<double> location,
00019 vnl_vector<double> vessel_dir1,
00020 vnl_vector<double> vessel_dir2,
00021 vnl_vector<double> vessel_dir3,
00022 double width1, double width2, double width3,
00023 double angular_std,
00024 double width_ratio_std):
00025 location_(location),
00026 center_set_(false),
00027 is_estimate_set_(false)
00028 {
00029 vcl_vector< vnl_vector<double> > vessel_dirs;
00030 vessel_dirs.push_back(vessel_dir1);
00031 vessel_dirs.push_back(vessel_dir2);
00032 vessel_dirs.push_back(vessel_dir3);
00033
00034 local_widths_.push_back(width1);
00035 local_widths_.push_back(width2);
00036 local_widths_.push_back(width3);
00037
00038
00039
00040 radius_ = vnl_math_max(width1, vnl_math_max(width2, width3));
00041
00042
00043
00044
00045 vcl_vector<double> angles;
00046 reorder_vessel(vessel_dirs, local_widths_, angles);
00047
00048
00049
00050
00051 if ( angles[0] < angular_std*2)
00052 is_ambiguous_ = true;
00053
00054
00055
00056
00057 for (unsigned i = 0; i<3; i++ ) {
00058 vnl_double_2 normal = vnl_double_2(-vessel_dirs[i][1], vessel_dirs[i][0]);
00059 vnl_double_2 trace_pt = location_+radius_*vessel_dirs[i];
00060
00061 boundary_points_.push_back( trace_pt-normal*local_widths_[i]/2.0 );
00062 boundary_points_.push_back( trace_pt+normal*local_widths_[i]/2.0 );
00063 trace_normals_.push_back(normal);
00064 }
00065
00066
00067
00068 angular_invariants_.set_size(3);
00069 angular_invariants_[0] = angles[0];
00070 angular_invariants_[1] = angles[1];
00071 angular_invariants_[2] = angles[2];
00072
00073
00074 cartesian_invariants_.set_size(2);
00075 cartesian_invariants_[0] = vcl_atan(local_widths_[0]/local_widths_[1])*angular_std/width_ratio_std;
00076 cartesian_invariants_[1] = vcl_atan(local_widths_[0]/local_widths_[2])*angular_std/width_ratio_std;
00077 }
00078
00079 rgrl_invariant_single_landmark::
00080 rgrl_invariant_single_landmark(const rgrl_invariant_single_landmark& copy,
00081 double angular_std,
00082 double width_ratio_std)
00083 : rgrl_invariant(copy),
00084 location_(copy.location_),
00085 radius_(copy.radius_),
00086 center_set_(false)
00087 {
00088
00089
00090 for (unsigned int i = 0; i<3; i++) {
00091 trace_normals_.push_back(copy.trace_normals_[(i+1)%3]);
00092 local_widths_.push_back(copy.local_widths_[(i+1)%3]);
00093 boundary_points_.push_back(copy.boundary_points_[((i+1)%3)*2]);
00094 boundary_points_.push_back( copy.boundary_points_[((i+1)%3)*2+1]);
00095 }
00096
00097 angular_invariants_.set_size(3);
00098 angular_invariants_[0] = copy.angular_invariants_[1];
00099 angular_invariants_[1] = copy.angular_invariants_[2];
00100 angular_invariants_[2] = copy.angular_invariants_[0];
00101
00102 cartesian_invariants_.set_size(2);
00103 cartesian_invariants_[0] = vcl_atan(local_widths_[0]/local_widths_[1])*angular_std/width_ratio_std;
00104 cartesian_invariants_[1] = vcl_atan(local_widths_[0]/local_widths_[2])*angular_std/width_ratio_std;
00105 }
00106
00107 const vnl_double_2&
00108 rgrl_invariant_single_landmark::
00109 location() const
00110 {
00111 return location_;
00112 }
00113
00114 const vnl_double_2&
00115 rgrl_invariant_single_landmark::
00116 boundary_point_location(int i) const
00117 {
00118 assert(i >= 0 && unsigned(i)<boundary_points_.size());
00119 return boundary_points_[i];
00120 }
00121
00122 const vnl_double_2&
00123 rgrl_invariant_single_landmark::
00124 boundary_point_normal(int i) const
00125 {
00126 assert(i >= 0 && unsigned(i)<boundary_points_.size());
00127 return trace_normals_[i/2];
00128 }
00129
00130 const vnl_vector<double>&
00131 rgrl_invariant_single_landmark::
00132 cartesian_invariants() const
00133 {
00134 return cartesian_invariants_;
00135 }
00136
00137 const vnl_vector<double>&
00138 rgrl_invariant_single_landmark::
00139 angular_invariants() const
00140 {
00141 return angular_invariants_;
00142 }
00143
00144 rgrl_mask_box
00145 rgrl_invariant_single_landmark::
00146 region() const
00147 {
00148 double ratio = 5;
00149 vnl_double_2 x0(location_[0] - ratio*radius_, location_[1] - ratio*radius_);
00150 vnl_double_2 x1(location_[0] + ratio*radius_, location_[1] + ratio*radius_);
00151
00152 return rgrl_mask_box(x0.as_ref(), x1.as_ref());
00153 }
00154
00155 bool
00156 rgrl_invariant_single_landmark::
00157 estimate(rgrl_invariant_sptr from_inv,
00158 rgrl_transformation_sptr& xform,
00159 rgrl_scale_sptr& scale )
00160 {
00161 rgrl_invariant_single_landmark* from = rgrl_cast<rgrl_invariant_single_landmark*>(from_inv);
00162
00163
00164
00165
00166 vnl_matrix_fixed<double,4,4> sum_prod(0.0);
00167 vnl_matrix_fixed<double,4,1> sum_rhs(0.0);
00168
00169 unsigned int i=0;
00170 unsigned int num_boundary_points = 6;
00171 while (i < num_boundary_points) {
00172 double px, py, nx, ny, qx, qy;
00173 nx = this->boundary_point_normal(i)[0];
00174 ny = this->boundary_point_normal(i)[1];
00175
00176 px = from->boundary_point_location(i)[0] - from->center()[0];
00177 py = from->boundary_point_location(i)[1] - from->center()[1];
00178
00179 qx = this->boundary_point_location(i)[0] - this->center()[0];
00180 qy = this->boundary_point_location(i)[1] - this->center()[1];
00181
00182 ++i;
00183
00184 double elt0 = nx;
00185 double elt1 = ny;
00186 double elt2 = px*nx + py*ny;
00187 double elt3 = -py*nx + px*ny;
00188 sum_prod(0,0)+=elt0*elt0; sum_prod(0,1)+=elt0*elt1;
00189 sum_prod(0,2)+=elt0*elt2; sum_prod(0,3)+=elt0*elt3;
00190 sum_prod(1,1)+=elt1*elt1; sum_prod(1,2)+=elt1*elt2;
00191 sum_prod(1,3)+=elt1*elt3; sum_prod(2,2)+=elt2*elt2;
00192 sum_prod(2,3)+=elt2*elt3; sum_prod(3,3)+=elt3*elt3;
00193
00194 double u = nx*qx + ny*qy;
00195 sum_rhs(0,0)+=u*elt0;
00196 sum_rhs(1,0)+=u*elt1;
00197 sum_rhs(2,0)+=u*elt2;
00198 sum_rhs(3,0)+=u*elt3;
00199 }
00200
00201
00202 double px = from->location()[0] - from->center()[0];
00203 double py = from->location()[1] - from->center()[1];
00204
00205 sum_prod(0,0)+=1; sum_prod(0,1)+=0;
00206 sum_prod(0,2)+=px; sum_prod(0,3)+=-py;
00207 sum_prod(1,1)+=1; sum_prod(1,2)+=py;
00208 sum_prod(1,3)+=px; sum_prod(2,2)+=px*px+py*py;
00209 sum_prod(2,3)+=0; sum_prod(3,3)+=px*px+py*py;
00210
00211 double qx = this->location()[0] - this->center()[0];
00212 double qy = this->location()[1] - this->center()[1];
00213
00214 sum_rhs(0,0)+=qx;
00215 sum_rhs(1,0)+=qy;
00216 sum_rhs(2,0)+=px*qx+py*qy;
00217 sum_rhs(3,0)+=-py*qx+px*qy;
00218
00219
00220 for ( int i=1; i<4; ++i )
00221 for ( int j=0; j<i; ++j )
00222 sum_prod(i,j) = sum_prod(j,i);
00223
00224
00225
00226
00227 double factor0 = vnl_math_max(sum_prod(0,0),sum_prod(1,1));
00228 double factor1 = vnl_math_max(sum_prod(2,2),sum_prod(3,3));
00229 double norm_scale = vcl_sqrt(factor1 / factor0);
00230
00231 vnl_double_4 s;
00232 s(2) = s(3) = 1; s(0) = s(1) = norm_scale;
00233 for ( int i=0; i<4; i++ ) {
00234 sum_rhs(i,0) *= s(i);
00235 for ( int j=0; j<4; j++ )
00236 sum_prod(i,j) *= s(i) * s(j);
00237 }
00238
00239
00240 vnl_matrix_fixed<double,4,4> norm_covar = vnl_inverse(sum_prod);
00241 vnl_matrix_fixed<double,4,1> c_params = norm_covar * sum_rhs;
00242
00243
00244
00245 for ( int i=0; i<4; i++ ) {
00246 for ( int j=0; j<4; j++ )
00247 norm_covar(i,j) *= s(i) * s(j);
00248 }
00249 for ( int i=0; i<4; i++ ) {
00250 c_params(i,0) *= s(i);
00251 }
00252
00253
00254
00255 double tx = c_params(0,0)+this->center()[0]
00256 -c_params(2,0)*from->center()[0]
00257 +c_params(3,0)*from->center()[1];
00258 double ty = c_params(1,0)+this->center()[1]
00259 -c_params(3,0)*from->center()[0]
00260 -c_params(2,0)*from->center()[1];
00261
00262
00263
00264
00265 vnl_double_2 trans(tx, ty);
00266 vnl_matrix<double> A(2,2);
00267 A(0,0) = A(1,1) = c_params(2,0);
00268 A(0,1) = -c_params(3,0);
00269 A(1,0) = -A(0,1);
00270 rgrl_trans_similarity est_xform(A, trans.as_ref(), norm_covar.as_ref());
00271
00272
00273
00274 double obj = 0;
00275 double geometric_scale = 0;
00276 vnl_vector<double> mapped;
00277 for (unsigned int i = 0; i< num_boundary_points; i++) {
00278 est_xform.map_location(from->boundary_point_location(i).as_ref(), mapped);
00279 obj += vnl_math_sqr( dot_product((this->boundary_point_location(i) - mapped),
00280 this->boundary_point_normal(i)) );
00281 }
00282 est_xform.map_location(from->location().as_ref(), mapped);
00283 obj += (location_ - mapped).squared_magnitude();
00284
00285
00286
00287 geometric_scale = vcl_sqrt(obj/4);
00288
00289
00290
00291 xform = new rgrl_trans_similarity( est_xform.A(), est_xform.t(),
00292 est_xform.covar()*vnl_math_sqr(geometric_scale) );
00293 scale = new rgrl_scale;
00294 scale->set_geometric_scale( geometric_scale );
00295
00296 return is_estimate_set_ = true;
00297 }
00298
00299 const vnl_double_2&
00300 rgrl_invariant_single_landmark::
00301 center()
00302 {
00303 if ( center_set_ ) return center_;
00304
00305
00306 double xc = location_[0];
00307 double yc = location_[1];
00308
00309 for (unsigned int i = 0; i< boundary_points_.size(); i++) {
00310 xc += boundary_points_[i][0];
00311 yc += boundary_points_[i][1];
00312 }
00313
00314 int size = int(boundary_points_.size() + 1);
00315 xc /= size; yc /= size;
00316 center_[0] = xc;
00317 center_[1] = yc;
00318 center_set_ = true;
00319
00320 return center_;
00321 }
00322
00323
00324 void
00325 rgrl_invariant_single_landmark::
00326 reorder_vessel(vcl_vector<vnl_vector<double> >& directions,
00327 vcl_vector<double>& local_widths,
00328 vcl_vector<double>& angles)
00329 {
00330
00331 vnl_double_2 x_axis(1, 0);
00332
00333
00334 vcl_vector<vnl_vector<double> > old_dirs = directions;
00335 vcl_vector<double> old_widths = local_widths;
00336 directions.clear();
00337 local_widths.clear();
00338
00339
00340
00341 angles.clear();
00342 for (int i = 0; i<3; ++i)
00343 angles.push_back( ccw_angle_between(x_axis, old_dirs[i]) );
00344
00345
00346 vcl_vector<double> old_angles(angles);
00347 vcl_sort(angles.begin(), angles.end());
00348
00349
00350 for (int i=0; i<3; ++i){
00351 for (int j=0; j<3; ++j){
00352 if (angles[i]==old_angles[j]){
00353 directions.push_back(old_dirs[j]);
00354 local_widths.push_back(old_widths[j]);
00355 break;
00356 }
00357 }
00358 }
00359 }
00360
00361 double
00362 rgrl_invariant_single_landmark::
00363 ccw_angle_between(vnl_double_2 from, vnl_double_2 to)
00364 {
00365 double cosine = (from[0]*to[0] + from[1]*to[1])/
00366 (from.magnitude()*to.magnitude());
00367 double angle = vcl_acos(cosine);
00368 double z = from[0]*to[1] - from[1]*to[0];
00369 if (z >= 0)
00370 return angle;
00371 else
00372 return vnl_math::pi*2 - angle;
00373 }