00001 //: 00002 // \file 00003 // \author Tim Cootes 00004 // \brief Algorithm to estimate 3D shape basis from multiple 2D views 00005 00006 #ifndef m2d3_ortho_flexible_builder_h_ 00007 #define m2d3_ortho_flexible_builder_h_ 00008 00009 #include <vnl/vnl_matrix.h> 00010 #include <vnl/vnl_vector.h> 00011 00012 #include <vcl_vector.h> 00013 00014 #include <vgl/vgl_point_3d.h> 00015 #include <vgl/vgl_point_2d.h> 00016 00017 //: Algorithm to estimate 3D shape basis from multiple 2D views. 00018 // ses the method of Xiao, Chai and Kanade (CVPR 2004). 00019 // Generates projection matrix, P, and 3D point matrix P3D, such that 00020 // P2D = P.P3D. Uncertainty in projection is constrained by setting 00021 // the projection for the first shape to the identity (1 0 0; 0 1 0) 00022 // 00023 // The ambiguity in the sign of the z ordinates is fixed by arranging that 00024 // the first non-zero z ordinate should be negative. 00025 // 00026 // Note that the 2D point sets will be normalised so that their CoG is 00027 // at the origin. The resulting 3D shape bases will also have their 00028 // CoG at the origin. 00029 class m23d_ortho_flexible_builder 00030 { 00031 private: 00032 //: 3(1+m) x np matrix, each column containing one 3D point 00033 vnl_matrix<double> P3D_; 00034 00035 //: The 2ns x 3(1+m) projection matrix 00036 // Each 2x3 sub-matrix is a scaled orthographic projection matrix 00037 vnl_matrix<double> P_; 00038 00039 //: The CoG of each shape supplied to reconstruct() 00040 // This has been subtracted from each example to centre on the origin 00041 // Centred data stored in P2Dc_ 00042 vcl_vector<vgl_point_2d<double> > cog_; 00043 00044 //: Centred version of the 2D views supplied to reconstruct() 00045 // Each 2D shape has been translated so that its CoG is at the origin 00046 vnl_matrix<double> P2Dc_; 00047 00048 //: The 2ns x 3 matrix. Each 2x3 block is the projection for a given view. 00049 // Each 2x3 sub-matrix is a scaled orthographic projection matrix 00050 vnl_matrix<double> pure_P_; 00051 00052 //: ns x (m+1) matrix, each row of which contains the weights for a shape 00053 vnl_matrix<double> coeffs_; 00054 00055 //: Mean 3D shape as a 3 x np matrix 00056 vnl_matrix<double> mean_shape_; 00057 00058 //: Mean coefficients 00059 vnl_vector<double> mean_coeffs_; 00060 00061 //: Take copy of 2D points and remove CoG from each 00062 void set_view_data(const vnl_matrix<double>& P2D); 00063 00064 //: Decompose centred view data to get initial estimate of shape/projection 00065 // Uncertain up to an affine transformation 00066 void initial_decomposition(unsigned n_modes); 00067 00068 //: Disambiguate the ambiguity in the sign of the z ordinates 00069 // First non-zero element should be negative. 00070 void disambiguate_z(); 00071 00072 //: Modify projection matrices so they are scaled orthographic projections 00073 // P = s(I|0)*R 00074 void make_pure_projections(); 00075 00076 //: Compute the mean 3D shape 00077 void compute_mean(vnl_matrix<double>& mean_shape, 00078 vnl_vector<double>& mean_coeffs); 00079 00080 //: Return 3d pts given 3*np matrix 00081 void mat_to_3d_pts(vcl_vector< vgl_point_3d<double> >& pts, 00082 const vnl_matrix<double>& M) const; 00083 00084 public: 00085 00086 //: Reconstruct structure from set of 2d pts 00087 // formulates measurement matrix P2D then calls reconstruct() function 00088 void reconstruct(const vcl_vector< vcl_vector< vgl_point_2d<double> > >& pt_vec_list, 00089 const unsigned& n_modes ); 00090 00091 00092 //: Reconstruct approximate structure of 3D points given multiple 2D views 00093 // Data assumed to be scaled orthographic projections 00094 // The result is stored in the shape_3d() matrix. 00095 // The estimated projection matrices are stored in the projections() matrix 00096 // However, the projection matrices are not necessarily consistent. 00097 // Call refine() to ensure consistancy, (or use reconstruct(P2D,n_modes) 00098 // This is exposed to aid testing and debugging. 00099 // \param P2D 2ns x np matrix. Rows contain alternating x's and y's from 2D shapes 00100 void partial_reconstruct(const vnl_matrix<double>& P2D, unsigned n_modes); 00101 00102 //: Reconstruct structure of 3D points given multiple 2D views 00103 // Data assumed to be scaled orthographic projections 00104 // The result is stored in the shape_3d() matrix. 00105 // The estimated projection matrices are stored in the projections() matrix 00106 // The first (n_modes+1) views are assumed to define a basis for the 00107 // modes. This might not be ideal. Use reconstruct() to automatically 00108 // select views which form a good basis. 00109 // \param P2D 2ns x np matrix. Rows contain alternating x's and y's from 2D shapes 00110 void reconstruct_with_first_as_basis(const vnl_matrix<double>& P2D, unsigned n_modes); 00111 00112 //: Reconstruct structure of 3D points given multiple 2D views 00113 // Data assumed to be scaled orthographic projections 00114 // The result is stored in the shape_3d() matrix. 00115 // The estimated projection matrices are stored in the projections() matrix 00116 // Automatically select views which form a good basis. 00117 // \param P2D 2ns x np matrix. Rows contain alternating x's and y's from 2D shapes 00118 void reconstruct(const vnl_matrix<double>& P2D, unsigned n_modes); 00119 00120 //: Return 3(m+1) x np matrix, each column containing modes for one 3D point 00121 // Points are centred on the origin. 00122 // Each 3 rows contains one of the (1+m) bases. 00123 const vnl_matrix<double>& shape_3d() const { return P3D_; } 00124 00125 //: The 2ns x 3(m+1) projection matrix 00126 // Each 2x3 sub-matrix is a scaled orthographic projection matrix 00127 const vnl_matrix<double>& projections() const { return P_; } 00128 00129 //: Centred version of the 2D views supplied to reconstruct() 00130 // Each 2D shape has been translated so that its CoG is at the origin 00131 const vnl_matrix<double>& centred_views() const { return P2Dc_; } 00132 00133 //: The 2ns x 3 matrix. Each 2x3 block is the projection for a given view. 00134 // Each 2x3 sub-matrix is a scaled orthographic projection matrix 00135 const vnl_matrix<double>& pure_projections() const { return pure_P_; } 00136 00137 //: ns x (m+1) matrix, each row of which contains the weights for a shape 00138 const vnl_matrix<double>& coeffs() const { return coeffs_; } 00139 00140 //: Refine estimates of projection and structure 00141 void refine(); 00142 00143 //: Apply rotation matrices to each 3 columns of P (and inverse to rows of B) 00144 // Matrix selected so that projection matrices in each 3 cols have same 00145 // effective rotation. 00146 void correct_coord_frame(vnl_matrix<double>& P, 00147 vnl_matrix<double>& B); 00148 00149 //: Compute correction matrix so that M1.G has suitable projection properties 00150 void compute_correction(const vnl_matrix<double>& M1, 00151 vnl_matrix<double>& G); 00152 00153 //: Return mean 3D shape as a 3 x np matrix 00154 const vnl_matrix<double>& mean_shape() const { return mean_shape_; } 00155 00156 //: Return 3D shape i as a 3 x np matrix 00157 vnl_matrix<double> shape(unsigned i) const; 00158 00159 //: Mean coefficients 00160 const vnl_vector<double>& mean_coeffs() const { return mean_coeffs_; } 00161 00162 #if 0 00163 //: Get back 3d pts rotated and shifted for each frame 00164 void recon_shapes(vcl_vector< vcl_vector< vgl_point_3d<double> > >& pt_vec_list ) const; 00165 #endif // 0 00166 00167 //: Return 3d pts given 3*np matrix 00168 void get_shape_3d_pts( vcl_vector< vgl_point_3d<double> >& pts ) const; 00169 }; 00170 00171 #endif // m2d3_ortho_flexible_builder_h_