00001
00002
00003
00004
00005
00006 #include "msm_zoom_aligner.h"
00007 #include <vnl/vnl_vector.h>
00008 #include <vsl/vsl_binary_loader.h>
00009 #include <vcl_cstddef.h>
00010 #include <vcl_cassert.h>
00011
00012
00013
00014
00015 vnl_vector<double> msm_zoom_aligner::inverse(const vnl_vector<double>& t) const
00016 {
00017 vnl_vector<double> q(3);
00018 double s=vcl_exp(t[0]);
00019 q[0]=-t[0];
00020 q[1]=-t[1]/s;
00021 q[2]=-t[2]/s;
00022 return q;
00023 }
00024
00025
00026 void msm_zoom_aligner::apply_transform(const msm_points& points,
00027 const vnl_vector<double>& trans,
00028 msm_points& new_points) const
00029 {
00030 new_points=points;
00031 new_points.transform_by(vcl_exp(trans[0]),0.0,trans[1],trans[2]);
00032 }
00033
00034
00035 double msm_zoom_aligner::scale(const vnl_vector<double>& trans) const
00036 {
00037 assert(trans.size()==3);
00038 return vcl_exp(trans[0]);
00039 }
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 void msm_zoom_aligner::calc_transform_from_ref(const msm_points& ref_pts,
00055 const msm_points& pts2,
00056 vnl_vector<double>& trans) const
00057 {
00058 vgl_point_2d<double> cog2 = pts2.cog();
00059 const double* p1 = ref_pts.vector().begin();
00060 const double* p2 = pts2.vector().begin();
00061 const double* p1_end = ref_pts.vector().end();
00062
00063 double dot_sum=0.0;
00064
00065 for (;p1!=p1_end;p1+=2,p2+=2)
00066 {
00067 double dpx = p1[0];
00068 double dpy = p1[1];
00069 double dtx = p2[0]-cog2.x();
00070 double dty = p2[1]-cog2.y();
00071
00072 dot_sum += dpx*dtx + dpy*dty;
00073 }
00074
00075 trans.set_size(3);
00076 trans[0] = vcl_log(dot_sum);
00077 trans[1] = cog2.x();
00078 trans[2] = cog2.y();
00079 }
00080
00081
00082
00083 void msm_zoom_aligner::calc_transform(const msm_points& pts1,
00084 const msm_points& pts2,
00085 vnl_vector<double>& trans) const
00086 { vgl_point_2d<double> cog1 = pts1.cog();
00087 vgl_point_2d<double> cog2 = pts2.cog();
00088 const double* p1 = pts1.vector().begin();
00089 const double* p2 = pts2.vector().begin();
00090 const double* p1_end = pts1.vector().end();
00091
00092 double x2_sum=0.0;
00093 double dot_sum=0.0;
00094
00095 for (;p1!=p1_end;p1+=2,p2+=2)
00096 {
00097 double dpx = p1[0]-cog1.x();
00098 double dpy = p1[1]-cog1.y();
00099 double dtx = p2[0]-cog2.x();
00100 double dty = p2[1]-cog2.y();
00101
00102 x2_sum += dpx*dpx + dpy*dpy;
00103 dot_sum += dpx*dtx + dpy*dty;
00104 }
00105
00106 trans.set_size(3);
00107 double s = dot_sum/x2_sum;
00108 trans[0] = vcl_log(s);
00109 trans[1] = cog2.x() - s*cog1.x();
00110 trans[2] = cog2.y() - s*cog1.y();
00111 }
00112
00113
00114 inline vgl_point_2d<double> msm_wtd_cog(const msm_points& pts,
00115 const vnl_vector<double>& wts)
00116 {
00117 const double* v=pts.vector().data_block();
00118 const double* w=wts.data_block();
00119 unsigned int n=pts.size();
00120 const double* end_v=v+2*n;
00121 double cx=0.0,cy=0.0,w_sum=0.0;
00122 for (;v!=end_v;v+=2,++w)
00123 { cx+=w[0]*v[0]; cy+=w[0]*v[1]; w_sum+=w[0]; }
00124
00125 if (w_sum>0) { cx/=w_sum; cy/=w_sum; }
00126 return vgl_point_2d<double>(cx,cy);
00127 }
00128
00129
00130
00131
00132 void msm_zoom_aligner::calc_transform_wt(const msm_points& pts1,
00133 const msm_points& pts2,
00134 const vnl_vector<double>& wts,
00135 vnl_vector<double>& trans) const
00136 {
00137 vgl_point_2d<double> cog1 = msm_wtd_cog(pts1,wts);
00138 vgl_point_2d<double> cog2 = msm_wtd_cog(pts2,wts);
00139 const double* p1 = pts1.vector().begin();
00140 const double* p2 = pts2.vector().begin();
00141 const double* w=wts.data_block();
00142 assert(wts.size()==pts1.size());
00143 const double* p1_end = pts1.vector().end();
00144
00145 double x2_sum=0.0;
00146 double dot_sum=0.0;
00147
00148 for (;p1!=p1_end;p1+=2,p2+=2,++w)
00149 {
00150 double dpx = p1[0]-cog1.x();
00151 double dpy = p1[1]-cog1.y();
00152 double dtx = p2[0]-cog2.x();
00153 double dty = p2[1]-cog2.y();
00154
00155 x2_sum += w[0]*(dpx*dpx + dpy*dpy);
00156 dot_sum += w[0]*(dpx*dtx + dpy*dty);
00157 }
00158
00159 trans.set_size(3);
00160 double s = dot_sum/x2_sum;
00161 trans[0] = vcl_log(s);
00162 trans[1] = cog2.x() - s*cog1.x();
00163 trans[2] = cog2.y() - s*cog1.y();
00164 }
00165
00166
00167
00168
00169 void msm_zoom_aligner::calc_transform_wt_mat(const msm_points& pts1,
00170 const msm_points& pts2,
00171 const vcl_vector<msm_wt_mat_2d>& wt_mat,
00172 vnl_vector<double>& trans) const
00173 {
00174 assert(pts2.size()==pts1.size());
00175 assert(wt_mat.size()==pts1.size());
00176
00177 msm_wt_mat_2d w_sum(0,0,0);
00178 double x1=0.0,y1=0.0;
00179 double x2=0.0,y2=0.0;
00180 const double* p1 = pts1.vector().begin();
00181 const double* p2 = pts2.vector().begin();
00182 const double* p1_end = pts1.vector().end();
00183 vcl_vector<msm_wt_mat_2d>::const_iterator w=wt_mat.begin();
00184 for (;p1!=p1_end;p1+=2,p2+=2,++w)
00185 {
00186 double wa=w->m11(), wb=w->m12(), wc=w->m22();
00187 w_sum += (*w);
00188 x1 += wa*p1[0]+wb*p1[1];
00189 y1 += wb*p1[0]+wc*p1[1];
00190 x2 += wa*p2[0]+wb*p2[1];
00191 y2 += wb*p2[0]+wc*p2[1];
00192 }
00193 msm_wt_mat_2d w_inv = w_sum.inverse();
00194 double v11=w_inv.m11(), v12=w_inv.m12(), v22=w_inv.m22();
00195 vgl_point_2d<double> cog1(v11*x1+v12*y1,v12*x1+v22*y1);
00196 vgl_point_2d<double> cog2(v11*x2+v12*y2,v12*x2+v22*y2);
00197
00198
00199
00200 double sum1=0,txx_sum = 0;
00201
00202 p1 = pts1.vector().begin();
00203 p2 = pts2.vector().begin();
00204 w=wt_mat.begin();
00205 for (;p1!=p1_end;p1+=2,p2+=2,++w)
00206 {
00207 double dpx = p1[0]-cog1.x();
00208 double dpy = p1[1]-cog1.y();
00209 double dtx = p2[0]-cog2.x();
00210 double dty = p2[1]-cog2.y();
00211
00212 double wa=w->m11(), wb=w->m12(), wc=w->m22();
00213
00214 double wx = wa*dpx + wb*dpy;
00215 double wy = wb*dpx + wc*dpy;
00216 sum1 += dpx*wx + dpy*wy;
00217 txx_sum += dtx*wx + dty*wy;
00218 }
00219
00220 trans.set_size(3);
00221 double s = txx_sum/sum1;
00222 trans[0] = vcl_log(s);
00223 trans[1] = cog2.x() - s*cog1.x();
00224 trans[2] = cog2.y() - s*cog1.y();
00225 }
00226
00227
00228 void msm_zoom_aligner::transform_wt_mat(const vcl_vector<msm_wt_mat_2d>& wt_mat,
00229 const vnl_vector<double>& trans,
00230 vcl_vector<msm_wt_mat_2d>& new_wt_mat) const
00231 {
00232 double s=vcl_exp(trans[0]);
00233 new_wt_mat.resize(wt_mat.size());
00234 for (unsigned i=0;i<wt_mat.size();++i)
00235 new_wt_mat[i]=wt_mat[i].transform_by(s,0);
00236 }
00237
00238
00239 vnl_vector<double> msm_zoom_aligner::compose(
00240 const vnl_vector<double>& pose1,
00241 const vnl_vector<double>& pose2) const
00242 {
00243 double s1=vcl_exp(pose1[0]);
00244
00245 vnl_vector<double> p(3);
00246 p[0]= pose1[0]+pose2[0];
00247 p[1]= s1*pose2[1]+pose1[1];
00248 p[2]= s1*pose2[2]+pose1[2];
00249 return p;
00250 }
00251
00252
00253
00254
00255 void msm_zoom_aligner::normalise_shape(msm_points& points) const
00256 {
00257 vgl_point_2d<double> cog = points.cog();
00258 points.translate_by(-cog.x(),-cog.y());
00259 double L = points.vector().magnitude();
00260 if (L>1e-6) points.scale_by(1.0/L);
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270 void msm_zoom_aligner::align_set(const vcl_vector<msm_points>& points,
00271 msm_points& ref_mean_shape,
00272 vcl_vector<vnl_vector<double> >& pose_to_ref,
00273 vnl_vector<double>& average_pose) const
00274 {
00275 vcl_size_t n_shapes = points.size();
00276 assert(n_shapes>0);
00277 pose_to_ref.resize(n_shapes);
00278
00279
00280 ref_mean_shape = points[0];
00281 normalise_shape(ref_mean_shape);
00282
00283
00284 msm_points base_shape = ref_mean_shape;
00285
00286 vnl_vector<double> pose_from_ref;
00287 msm_points new_mean=ref_mean_shape;
00288 average_pose.set_size(3);
00289
00290 double change=1.0;
00291
00292 unsigned n_its=0;
00293
00294 while (change>1e-6 && n_its<10)
00295 {
00296 ref_mean_shape = new_mean;
00297 normalise_shape(ref_mean_shape);
00298
00299 average_pose.fill(0);
00300
00301 for (unsigned i=0;i<n_shapes;++i)
00302 {
00303 calc_transform_from_ref(ref_mean_shape,points[i],pose_from_ref);
00304 pose_to_ref[i]=inverse(pose_from_ref);
00305 average_pose+=pose_from_ref;
00306 }
00307
00308 mean_of_transformed(points,pose_to_ref,new_mean);
00309
00310
00311
00312 change = (new_mean.vector()-ref_mean_shape.vector()).rms();
00313 n_its++;
00314 }
00315
00316 average_pose/=n_shapes;
00317 }
00318
00319
00320
00321 vcl_string msm_zoom_aligner::is_a() const
00322 {
00323 return vcl_string("msm_zoom_aligner");
00324 }
00325
00326
00327 msm_aligner* msm_zoom_aligner::clone() const
00328 {
00329 return new msm_zoom_aligner(*this);
00330 }
00331
00332