Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleAbsoluteOrientation.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 /**
26  @example ExampleAbsoluteOrientation.cpp
27  @relates AbsoluteOrientation, AbsoluteOrientationRANSAC
28  @brief Example for similarity transformation estimation between
29  two coordinate frames from corresponding 3D points.
30 
31  AbsoluteOrientation estimates the relationship between two coordinate
32  systems using pairs of measurements of the coordinates of a number of
33  3D points in both systems. A SVD-based solution to the least-squares
34  problem for at least four points based on Horn's approach is used.
35 
36  @note The transformation between the coordinate systems is given
37  as rotation dR, translation dt, and isometric scale ds, such that
38  points X in the first coordinate system are related to points Y
39  in the second coordinate system by Y = ds*dR*X + dt.
40 
41  @see AbsoluteOrientation
42  @ingroup g_examples
43  @author esquivel
44  @date 12/2008
45  */
46 
47 #include <Base/Math/Random.hh>
48 #include <Geometry/AbsoluteOrientation.hh>
49 #include <Geometry/AbsoluteOrientationRANSAC.hh>
50 #include <Utils/Param.hh>
51 #include <iostream>
52 #include <string>
53 #include <vector>
54 
55 using namespace BIAS;
56 using namespace std;
57 
58 int main(int argc, char *argv[])
59 {
60  // register parameters
61  BIAS::Param params;
62  int* numParam = params.AddParamInt("num", "Number of 3D points", 10, 3,
63  std::numeric_limits<int>::max(), 'n', 0);
64  double* rangeParam = params.AddParamDouble("range", "Max. distance of 3D points "
65  "(in m)", 10.0, 1.e-8, 1e16, 'r', 0);
66  double* errorParam = params.AddParamDouble("error", "Max. error on 3D points "
67  "(in percent)", 0.01, 0.0, 1.0, 'e', 0);
68  bool* helpParam = params.AddParamBool("help", "Show help about parameters",
69  false, 'h', 0);
70  std::vector<std::string> methods;
71  std::vector<int> methodIDs;
72  methods.push_back("HORN");
73  methods.push_back("KABSCH");
74  methodIDs.push_back(AbsoluteOrientation::HORN_ALGORITHM);
75  methodIDs.push_back(AbsoluteOrientation::KABSCH_ALGORITHM);
76  int* methodParam = params.AddParamEnum("method", "Rotation estimation algorithm "
77  "(HORN, KABSCH)", methods, methodIDs[0],
78  &methodIDs, 'm', 0);
79  params.SetGroupName(0, "Test parameters");
80  params.ParseCommandLine(argc, argv);
81  if (*helpParam) {
82  params.Usage();
83  return 0;
84  }
85 
86  unsigned int num = *numParam; // number of 3D points
87  double range = *rangeParam; // range for 3D points (in m)
88  double noise = *errorParam; // noise for 3D points (in %)
89 
90  std::vector< BIAS::Vector3<double> > X; // 3D points in first coord. system
91  std::vector< BIAS::Vector3<double> > Y; // 3D points in second coord. system
92 
95  cout << "- Compute absolute orientation from " << num << " 3D points";
96  if (noise > 0) cout << " with noise of " << 100.0*noise << "% using ";
98  cout << "Horn's method";
99  else if (method == AbsoluteOrientation::KABSCH_ALGORITHM)
100  cout << "Kabsch algorithm";
101  else
102  cout << "undefined method";
103  cout << " for rotation estimation" << endl;
104 
105  BIAS::Random random;
106  random.Reset();
107 
108  // Compute random similarity transformation Y = ds*dR*X + dt
109  BIAS::RMatrix dR;
110  BIAS::Vector3<double> dr, dt;
111  double dphi = random.GetUniformDistributed(-0.5*M_PI, 0.5*M_PI);
112  double ds = random.GetUniformDistributed(1.0/range, range);
113  for (unsigned int k = 0; k < 3; k++) {
114  dr[k] = random.GetUniformDistributed(-range, range);
115  dt[k] = random.GetUniformDistributed(-range, range);
116  //dr[k] = random.GetNormalDistributed(0.0, range);
117  //dt[k] = random.GetNormalDistributed(0.0, range);
118  }
119  dr.Normalize();
120  dR.SetFromAxisAngle(dphi*dr);
121 
122  cout << "- Rotation dR = " << dphi*180.0/M_PI << " degree around axis ("
123  << dr[0] << ", " << dr[1] << ", " << dr[2] << ")" << endl;
124  cout << "- Translation dt = (" << dt[0] << ", " << dt[1] << ", "
125  << dt[2] << ")" << endl;
126  cout << "- Scale ds = " << ds << endl;
127 
128  // Compute random corresponding 3D points in both coordinate frames
129  X.reserve(num);
130  Y.reserve(num);
132  BIAS::Vector3<double> errx(0.0), erry(0.0);
133  for (unsigned int i = 0; i < num; i++) {
134  for (unsigned int k = 0; k < 3; k++) {
135  x[k] = random.GetUniformDistributed(-range, range);
136  //x[k] = random.GetNormalDistributed(0.0, range);
137  }
138  y = ds*dR*x + dt;
139  // Add normal distributed noise to 3D point positions
140  if (noise > 0) {
141  for (unsigned int k = 0; k < 3; k++) {
142  errx[k] = random.GetNormalDistributed(0.0, noise*range);
143  erry[k] = random.GetNormalDistributed(0.0, noise*range);
144  }
145  x.AddIP(errx);
146  y.AddIP(erry);
147  }
148  X.push_back(x);
149  Y.push_back(y);
150  cout << " [" << i+1 << "] X = (" << x[0] << ", " << x[1] << ", "
151  << x[2] << "), Y = (" << y[0] << ", " << y[1] << ", " << y[2] << ")";
152  if (noise > 0) {
153  cout << ", errors = " << errx.NormL2() << " and " << erry.NormL2();
154  }
155  cout << endl;
156  }
157 
158  // Compute absolute orientation
159  BIAS::RMatrix estR;
160  BIAS::Vector3<double> estr, estt;
161  double estphi, ests;
162  BIAS::AbsoluteOrientation estimator;
163  estimator.SetRotationAlgorithm(method);
164  int res = estimator.Compute(X, Y, estR, estt, ests);
165  if (res != 0) {
166  cout << "[ERROR] Estimation failed!" << endl << endl;
167  return -1;
168  }
169  estR.GetRotationAxisAngle(estr, estphi);
170 
171  // Compare result with ground truth and print estimation error
173  double errphi, error;
174  std::vector<double> errors;
175  BIAS::RMatrix(estR*dR.Transpose()).GetRotationAxisAngle(errr, errphi);
176  error = estimator.GetResidualErrors(errors, X, Y, estR, estt, ests);
177  cout << "- Estimated rotation dR = " << estphi*180.0/M_PI
178  << " degree around axis (" << estr[0] << ", " << estr[1] << ", "
179  << estr[2] << ")" << ", error = " << errphi*180.0/M_PI
180  << " degree (" << 100.0*fabs(errphi-dphi)/dphi << "%)" << endl;
181  cout << "- Estimated translation dt = (" << estt[0] << ", " << estt[1]
182  << ", " << estt[2] << "), error = " << (estt-dt).NormL2() << " ("
183  << 100.0*(estt-dt).NormL2()/dt.NormL2() << "%)" << endl;
184  cout << "- Estimated scale ds = " << ests << ", error = "
185  << fabs(ests-ds) << " (" << 100.0*fabs(ests-ds)/ds << "%)" << endl;
186  cout << "- Average residual error of solution = "
187  << sqrt(error/(double)num) << endl << endl;
188 
189  return 0;
190 }
Computes similarity transformation between 3D point sets.
bool * AddParamBool(const std::string &name, const std::string &help, bool deflt=false, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:305
double * AddParamDouble(const std::string &name, const std::string &help, double deflt=0.0, double min=-DBL_MAX, double max=DBL_MAX, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:351
int * AddParamEnum(const std::string &name, const std::string &help, const std::vector< std::string > &enums, const int deflt=0, const std::vector< int > *IDs=NULL, const char cmdshort=0, const int Group=GRP_NOSHOW)
Definition: Param.cpp:468
double GetUniformDistributed(const double min, const double max)
on succesive calls return uniform distributed random variable between min and max ...
Definition: Random.hh:84
int ParseCommandLine(int &argc, char *argv[])
scan command line arguments for valid parameters
Definition: Param.cpp:1028
3D rotation matrix
Definition: RMatrix.hh:49
void Usage(std::ostream &os=std::cout)
print Help-Information to stdout
Definition: Param.cpp:176
void AddIP(const T &scalar)
Addition (in place) of an scalar.
Definition: Vector3.hh:310
double GetResidualErrors(std::vector< double > &errors, const std::vector< Vector3< double > > &X, const std::vector< Vector3< double > > &Y, const RMatrix &dR, const Vector3< double > &dt, const double &ds=1.0, const std::vector< double > &w=std::vector< double >(0))
Computes residual errors of 3D point sets X and Y with respect to given rotation dR, translation dt and isometric scale ds.
void SetFromAxisAngle(Vector3< ROTATION_MATRIX_TYPE > w)
Set from rotation axis * angle (modified Rodrigues vector)
This class Param provides generic support for parameters.
Definition: Param.hh:231
int SetGroupName(const int group_id, const std::string &name)
sets the name for a group
Definition: Param.cpp:1448
Matrix3x3< T > Transpose() const
returns transposed matrix tested 12.06.2002
Definition: Matrix3x3.cpp:167
void Reset()
calls srand() with a seed generated from system call time, also initializes some other variables ...
Definition: Random.cpp:113
int * AddParamInt(const std::string &name, const std::string &help, int deflt=0, int min=std::numeric_limits< int >::min(), int max=std::numeric_limits< int >::max(), char cmdshort=0, int Group=GRP_NOSHOW)
For all adding routines:
Definition: Param.cpp:276
int GetRotationAxisAngle(Vector3< ROTATION_MATRIX_TYPE > &axis, ROTATION_MATRIX_TYPE &angle) const
Calculates angle and rotation axis representation for this rotation matrix.
double GetNormalDistributed(const double mean, const double sigma)
on succesive calls return normal distributed random variable with mean and standard deviation sigma ...
Definition: Random.hh:71
RotationEstimationMethod
Methods for rotation estimation.
void SetRotationAlgorithm(RotationEstimationMethod algorithm)
Set algorithm used for rotation estimation.
Vector3< T > & Normalize()
normalize this vector to length 1
Definition: Vector3.hh:663
class for producing random numbers from different distributions
Definition: Random.hh:51
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
Definition: Vector3.hh:633
int Compute(const std::vector< Vector3< double > > &X, const std::vector< Vector3< double > > &Y, RMatrix &dR, Vector3< double > &dt, double &ds, const std::vector< double > &w=std::vector< double >(0))
Computes rotation dR, translation dt and isometric scale ds between coordinate systems from correspon...