Go to the documentation of this file.00001 #include "rrel_orthogonal_regression.h"
00002
00003 #include <vnl/vnl_matrix.h>
00004 #include <vnl/vnl_math.h>
00005 #include <vnl/vnl_vector.h>
00006 #include <vnl/algo/vnl_svd.h>
00007
00008 #include <vcl_cassert.h>
00009 #include <vcl_iostream.h>
00010 #include <vcl_vector.h>
00011
00012 rrel_orthogonal_regression::rrel_orthogonal_regression( const vnl_matrix<double>& pts )
00013 : vars_( pts )
00014 {
00015 unsigned int num_pts = pts.rows ();
00016 set_param_dof( pts.cols() );
00017 if ( param_dof() > num_pts )
00018 vcl_cerr << "\nrrel_orthogonal_regression::rrel_orthogonal_regression WARNING:\n"
00019 << "DoF ("<<param_dof()<<") is greater than the number of data points ("
00020 << num_pts << ").\nAn infinite set of equally valid solutions exists.\n";
00021 set_num_samples_for_fit( param_dof() );
00022 }
00023
00024
00025 rrel_orthogonal_regression::rrel_orthogonal_regression( const vcl_vector<vnl_vector<double> >& pts )
00026 : vars_( pts.size(),pts[0].size() )
00027 {
00028 unsigned int num_pts = vars_.rows();
00029
00030 for (unsigned int i=0;i<num_pts;i++)
00031 vars_.set_row(i, pts[i]);
00032
00033 set_param_dof( vars_.cols() );
00034 if ( param_dof() > num_pts )
00035 vcl_cerr << "\nrrel_orthogonal_regression::rrel_orthogonal_regression WARNING:\n"
00036 << "DoF ("<<param_dof()<<") is greater than the number of data points ("
00037 << num_pts << ").\nAn infinite set of equally valid solutions exists.\n";
00038 set_num_samples_for_fit( param_dof() );
00039 }
00040
00041
00042 rrel_orthogonal_regression::~rrel_orthogonal_regression()
00043 {
00044 }
00045
00046 unsigned int
00047 rrel_orthogonal_regression::num_samples( ) const
00048 {
00049 return vars_.rows();
00050 }
00051
00052 bool
00053 rrel_orthogonal_regression::fit_from_minimal_set( const vcl_vector<int>& point_indices,
00054 vnl_vector<double>& params ) const
00055 {
00056 if ( point_indices.size() != param_dof() ) {
00057 vcl_cerr << "rrel_orthogonal_regression::fit_from_minimal_sample The number of point "
00058 << "indices must agree with the fit degrees of freedom.\n";
00059 return false;
00060 }
00061
00062
00063
00064 vnl_matrix<double> A(param_dof(), param_dof()+1, 1);
00065 for (unsigned int i=0; i<param_dof(); ++i) {
00066 int index = point_indices[i];
00067 for ( unsigned int j=0; j<param_dof(); ++j) {
00068 A(i,j) = vars_(index, j);
00069 }
00070 }
00071 vnl_svd<double> svd( A, 1.0e-8 );
00072 if ( (unsigned int)svd.rank() < param_dof() ) {
00073 vcl_cerr << "rrel_orthogonal_regression:: singular fit!\n";
00074 return false;
00075 }
00076 else {
00077 params = svd.nullvector();
00078 params /= vcl_sqrt( 1 - vnl_math_sqr( params[ params.size()-1 ] ) );
00079 }
00080 return true;
00081 }
00082
00083
00084 void
00085 rrel_orthogonal_regression::compute_residuals( const vnl_vector<double>& params,
00086 vcl_vector<double>& residuals ) const
00087 {
00088
00089
00090 assert( residuals.size() == vars_.rows() );
00091
00092 vnl_vector<double> norm(params.size()-1);
00093 for (unsigned int i=0; i<params.size()-1; i++)
00094 norm[i] = params[i];
00095 assert(norm.two_norm() > 0.99 && norm.two_norm() < 1.01);
00096 for ( unsigned int i=0; i<vars_.rows(); ++i ) {
00097 residuals[i] = dot_product(norm, vars_.get_row(i) ) + params[params.size()-1];
00098 }
00099 }
00100
00101
00102
00103
00104 bool
00105 rrel_orthogonal_regression::weighted_least_squares_fit( vnl_vector<double>& params,
00106 vnl_matrix<double>& ,
00107 const vcl_vector<double> *weights ) const
00108 {
00109
00110
00111
00112
00113
00114 assert( !weights || weights->size() == vars_.rows() );
00115
00116 vnl_vector<double> sum_vect(vars_.cols(), 0.0);
00117 vnl_matrix<double> A(vars_.cols(), vars_.cols());
00118 vnl_vector<double> avg;
00119 vnl_matrix<double> shift_vars( vars_.rows(), vars_.cols() );
00120
00121 if (weights) {
00122 double sum_weight=0;
00123 for (unsigned int i=0; i<vars_.rows(); ++i) {
00124 sum_vect += vars_.get_row(i) * (*weights)[i];
00125 sum_weight += (*weights)[i];
00126 }
00127 avg = sum_vect / sum_weight;
00128 for (unsigned int i=0; i<vars_.rows(); ++i)
00129 shift_vars.set_row(i, (vars_.get_row(i)-avg) * vcl_sqrt((*weights)[i]));
00130 }
00131 else {
00132 for (unsigned int i=0; i<vars_.rows(); ++i)
00133 sum_vect += vars_.get_row(i);
00134 avg = sum_vect / vars_.rows();
00135 for (unsigned int i=0; i<vars_.rows(); ++i)
00136 shift_vars.set_row(i, vars_.get_row(i) -avg);
00137 }
00138
00139 A = shift_vars.transpose() * shift_vars;
00140
00141 vnl_svd<double> svd( A, 1.0e-8 );
00142
00143 if ( (unsigned int)svd.rank() < param_dof() - 1 ) {
00144 vcl_cerr << "rrel_orthogonal_regression::WeightedLeastSquaresFit --- singularity!\n";
00145 return false;
00146 }
00147 else {
00148 vnl_vector<double> norm = svd.nullvector();
00149 params.set_size(norm.size()+1);
00150 for (unsigned int i=0; i<norm.size(); ++i) {
00151 params[i] = norm[i];
00152 }
00153 params[norm.size()] = -1*dot_product(norm, avg);
00154 return true;
00155 }
00156 }
00157
00158
00159 void
00160 rrel_orthogonal_regression::print_points() const
00161 {
00162 vcl_cout << "\nrrel_orthogonal_regression::print_points:\n"
00163 << " param_dof() = " << param_dof() << '\n'
00164 << " num_pts = " << vars_.rows() << "\n\n"
00165 << " i vars_\n"
00166 << " = =========\n";
00167 for ( unsigned int i=0; i<vars_.rows(); ++i ) {
00168 vcl_cout << ' ' << i << " " << vars_.get_row (i) << '\n';
00169 }
00170 }