resectionsolver.cpp
Go to the documentation of this file.
00001 
00018 #include "MathHelpers/Resectionsolver/resectionsolver.h"
00019 #include <math.h>
00020 #include "MathHelpers/Resectionsolver/poly34.h"
00021 #include <vector>
00022 #include <iostream>
00023 #ifndef Q_MOC_RUN
00024 #include <ros/ros.h>
00025 #endif
00026 
00027 ResectionSolver::ResectionSolver(boost::shared_ptr<Calibration_Object> calibrationObject, boost::shared_ptr<FeasibilityChecker> feasibilityChecker)
00028 {
00029     this->calibrationObject = calibrationObject;
00030     this->feasibilityChecker = feasibilityChecker;
00031 }
00032 
00033 unsigned int ResectionSolver::solve(const Eigen::Vector2d& base_A, const Eigen::Vector2d& base_B, const Eigen::Vector2d& base_C)
00034 {
00035     solutions_a.clear();
00036     solutions_b.clear();
00037     solutions_c.clear();
00038     solve_for_lengths((base_A-base_B).norm(), (base_B-base_C).norm(), (base_C-base_A).norm());
00039     solutions.clear();
00040 
00041     for (int i = (int)solutions_a.size()-1; i >= 0; i--)
00042     {
00043         if (feasibilityChecker->checkFeasibility_sideLengths(solutions_a[i],solutions_c[i],solutions_b[i]))
00044         {
00045             Eigen::Vector3d top;
00046             top = solve_for_top(base_A, base_B, base_C, solutions_b[i], solutions_c[i],solutions_a[i]);
00047             solutions.push_back(top);
00048         }
00049         else
00050         {
00051             ROS_INFO_STREAM(solutions_a[i] << ", " << solutions_b[i] << ", " << solutions_c[i] << " erased");
00052             solutions_a.erase(solutions_a.begin()+i);
00053             solutions_b.erase(solutions_b.begin()+i);
00054             solutions_c.erase(solutions_c.begin()+i);
00055         }
00056 
00057     }
00058     return solutions.size() ;
00059 }
00060 
00061 //Formel aus "New Non-iterative Solution of the Perspective 3-Point Problem" / Huaien ZENG
00062 Eigen::Vector3d ResectionSolver::solve_for_top(const Eigen::Vector2d& base_A, const Eigen::Vector2d& base_B, const Eigen::Vector2d& base_C, double length_AS, double length_BS, double length_CS)
00063 {
00064     Eigen::Vector2d base_B_new, base_C_new;
00065     base_B_new = base_B - base_A;
00066     base_C_new = base_C - base_A;
00067     double alpha, beta;
00068     alpha = (pow(base_B_new[0],2.0) + pow(base_B_new[1],2.0) + pow(length_AS,2.0) - pow(length_BS,2.0)) / 2.0;
00069     // Hinweis: für die Formel von beta steht an dieser Stelle x*x - y*y, sollte aber x*x - z*z heißen
00070     beta = (pow(base_C_new[0],2.0) + pow(base_C_new[1],2.0) + pow(length_AS,2.0) - pow(length_CS,2.0)) / 2.0;
00071     double X, Y, Z;
00072     Y = (alpha*base_C_new[0]-beta*base_B_new[0])/(base_B_new[1]*base_C_new[0]-base_C_new[1]*base_B_new[0]);
00073     if (base_B_new[0] != 0.0)
00074     {
00075         X = (alpha - Y*base_B_new[1])/base_B_new[0];
00076     }
00077     else
00078     {
00079         X = (beta - Y*base_C_new[1])/base_C_new[0];
00080     }
00081     // da die Höhe Z als positiver Wert definiert ist kann hier von einer eindeutigen Lösung für Z ausgegangen werden
00082     Z = sqrt(pow(length_CS, 2.0) - pow(X - base_C_new[0], 2.0) - pow(Y - base_C_new[1], 2.0));
00083     return Eigen::Vector3d(X + base_A[0], Y + base_A[1], Z);
00084 }
00085 
00086 
00087 //Code from https://github.com/Itseez/opencv/blob/master/modules/calib3d/src/p3p.cpp
00088 //http://iplimage.com/blog/p3p-perspective-point-overview/
00089 int ResectionSolver::solve_for_lengths(double side_A, double side_B, double side_C)
00090 {
00091     ROS_DEBUG_STREAM("Sides: " << side_A << ", " << side_B << ", " << side_C);
00092 
00093     double p = cos(calibrationObject->top_angle_ab) * 2;
00094     double q = cos(calibrationObject->top_angle_bc) * 2;
00095     double r = cos(calibrationObject->top_angle_ca) * 2;
00096 
00097     double inv_d22 = 1. / (side_C * side_C);
00098     double a = inv_d22 * (side_A * side_A);
00099     double b = inv_d22 * (side_B * side_B);
00100 
00101     double a2 = a * a, b2 = b * b, p2 = p * p, q2 = q * q, r2 = r * r;
00102     double pr = p * r, pqr = q * pr;
00103 
00104     // Check reality condition (the four points should not be coplanar)
00105     if (p2 + q2 + r2 - pqr - 1 == 0)
00106         return 0;
00107 
00108     double ab = a * b, a_2 = 2*a;
00109 
00110     double A = -2 * b + b2 + a2 + 1 + ab*(2 - r2) - a_2;
00111 
00112     // Check reality condition
00113     if (A == 0) return 0;
00114 
00115     double a_4 = 4*a;
00116 
00117     double B = q*(-2*(ab + a2 + 1 - b) + r2*ab + a_4) + pr*(b - b2 + ab);
00118     double C = q2 + b2*(r2 + p2 - 2) - b*(p2 + pqr) - ab*(r2 + pqr) + (a2 - a_2)*(2 + q2) + 2;
00119     double D = pr*(ab-b2+b) + q*((p2-2)*b + 2 * (ab - a2) + a_4 - 2);
00120     double E = 1 + 2*(b - a - ab) + b2 - b*p2 + a2;
00121 
00122     double temp = (p2*(a-1+b) + r2*(a-1-b) + pqr - a*pqr);
00123     double b0 = b * temp * temp;
00124     // Check reality condition
00125     if (b0 == 0)
00126         return 0;
00127 
00128     double real_roots[4];
00129     int n = SolveP4(real_roots, B/A, C/A,D/A, E/A);
00130 
00131     if (n == 0)
00132         return 0;
00133 
00134     int nb_solutions = 0;
00135     double r3 = r2*r, pr2 = p*r2, r3q = r3 * q;
00136     double inv_b0 = 1. / b0;
00137 
00138     // For each solution of x
00139     for(int i = 0; i < n; i++) {
00140         double x = real_roots[i];
00141 
00142         // Check reality condition
00143         if (x <= 0)
00144             continue;
00145 
00146         double x2 = x*x;
00147 
00148         double b1 =
00149             ((1-a-b)*x2 + (q*a-q)*x + 1 - a + b) *
00150             (((r3*(a2 + ab*(2 - r2) - a_2 + b2 - 2*b + 1)) * x +
00151 
00152             (r3q*(2*(b-a2) + a_4 + ab*(r2 - 2) - 2) + pr2*(1 + a2 + 2*(ab-a-b) + r2*(b - b2) + b2))) * x2 +
00153 
00154             (r3*(q2*(1-2*a+a2) + r2*(b2-ab) - a_4 + 2*(a2 - b2) + 2) + r*p2*(b2 + 2*(ab - b - a) + 1 + a2) + pr2*q*(a_4 + 2*(b - ab - a2) - 2 - r2*b)) * x +
00155 
00156             2*r3q*(a_2 - b - a2 + ab - 1) + pr2*(q2 - a_4 + 2*(a2 - b2) + r2*b + q2*(a2 - a_2) + 2) +
00157             p2*(p*(2*(ab - a - b) + a2 + b2 + 1) + 2*q*r*(b + a_2 - a2 - ab - 1)));
00158 
00159         // Check reality condition
00160         if (b1 <= 0)
00161             continue;
00162 
00163         double y = inv_b0 * b1;
00164         double v = x2 + y*y - x*y*r;
00165 
00166         if (v <= 0)
00167             continue;
00168 
00169         double Z = side_C / sqrt(v);
00170         double X = x * Z;
00171         double Y = y * Z;
00172 
00173         solutions_a.push_back(X);
00174         solutions_b.push_back(Y);
00175         solutions_c.push_back(Z);
00176 
00177         nb_solutions++;
00178     }
00179 
00180     return nb_solutions;
00181 }
00182 
00183 
00184 Eigen::Matrix4d ResectionSolver::calculateTransformationMatrix(const Eigen::Vector2d& base_A, const Eigen::Vector2d& base_B, const Eigen::Vector2d& base_C, const Eigen::Vector3d& solution)
00185 {
00186     Eigen::Matrix4d *transformation = new Eigen::Matrix4d();
00187     //Transformationsmatrix berechnen
00188     Eigen::Vector3d x_axis, y_axis, z_axis;
00189     //Z-Achse entspricht dem Vektor vom Schnitt-Punkt 2 bis zu Spitze des Tetraeders
00190     z_axis = Eigen::Vector3d(solution[0] - base_B[0], solution[1] - base_B[1], solution[2]);
00191     z_axis.normalize();
00192 
00193     Eigen::Vector3d basePoint = solution - z_axis * calibrationObject->side_b;
00194     //X- und Y-Achse entsprechen den beiden vorderen Seiten an der Basis des Tetraeders
00195     //Die Basispunkte können durch die Vektoren zur Spitze hin und den Kantenlängen des Tetraeders bestimmt werden
00196     x_axis = Eigen::Vector3d(base_A[0] - solution[0], base_A[1] - solution[1], -solution[2]);
00197     y_axis = Eigen::Vector3d(base_C[0] - solution[0], base_C[1] - solution[1], -solution[2]);
00198     x_axis.normalize();
00199     y_axis.normalize();
00200     x_axis = solution + x_axis * calibrationObject->side_a - basePoint;
00201     y_axis = solution + y_axis * calibrationObject->side_c - basePoint;
00202     //Orthonormalisierunsgverfahren um sicherzustellen, dass die Vektoren tatsächlich eine orthonormale Basis bilden
00203     x_axis = x_axis - x_axis.dot(z_axis)*z_axis;
00204     x_axis.normalize();
00205     y_axis = y_axis - y_axis.dot(z_axis)*z_axis - y_axis.dot(x_axis)*x_axis;
00206     y_axis.normalize();
00207 
00208     (*transformation)(0,0) = x_axis[0];
00209     (*transformation)(1,0) = x_axis[1];
00210     (*transformation)(2,0) = x_axis[2];
00211     (*transformation)(3,0) = 0.0;
00212     (*transformation)(0,1) = y_axis[0];
00213     (*transformation)(1,1) = y_axis[1];
00214     (*transformation)(2,1) = y_axis[2];
00215     (*transformation)(3,1) = 0.0;
00216     (*transformation)(0,2) = z_axis[0];
00217     (*transformation)(1,2) = z_axis[1];
00218     (*transformation)(2,2) = z_axis[2];
00219     (*transformation)(3,2) = 0.0;
00220     (*transformation)(0,3) = solution[0];
00221     (*transformation)(1,3) = solution[1];
00222     (*transformation)(2,3) = solution[2];
00223     (*transformation)(3,3) = 1.0;
00224 
00225     return *transformation;
00226 }
00227 
00228 
00229 


asr_mild_calibration_tool
Author(s): Aumann Florian, Heller Florian, Meißner Pascal
autogenerated on Thu Jun 6 2019 21:22:44