00001 /* 00002 Copyright (C) 2010 - 2014 Christoph Haenisch 00003 00004 Chair of Medical Engineering (mediTEC) 00005 RWTH Aachen University 00006 Pauwelsstr. 20 00007 52074 Aachen 00008 Germany 00009 00010 Version 0.1.1 (2011-11-10) 00011 */ 00012 00019 #ifndef ESTIMATE_SIMILARITY_TRANSFORMATION_2D_HPP_7322190897 00020 #define ESTIMATE_SIMILARITY_TRANSFORMATION_2D_HPP_7322190897 00021 00022 00023 #include <cmath> 00024 #include <vector> 00025 00026 #include <Eigen/Core> 00027 #include <Eigen/Dense> 00028 #include <Eigen/StdVector> 00029 00030 #include "Coordinate.hpp" 00031 #include "ErrorObj.hpp" 00032 #include "EstimateTransformation2D.hpp" 00033 00034 00035 namespace TRTK 00036 { 00037 00038 00191 template <class T> 00192 class EstimateSimilarityTransformation2D : public EstimateTransformation2D<T> 00193 { 00194 private: 00195 00196 typedef EstimateTransformation2D<T> super; 00197 00198 public: 00199 00200 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 00201 00202 typedef T value_type; 00203 00204 typedef typename super::VectorXT VectorXT; 00205 typedef typename super::MatrixXT MatrixXT; 00206 typedef typename super::Vector2T Vector2T; 00207 typedef typename super::Vector3T Vector3T; 00208 typedef typename super::Vector4T Vector4T; 00209 typedef typename super::RowVector2T RowVector2T; 00210 typedef typename super::RowVector3T RowVector3T; 00211 typedef typename super::Matrix2T Matrix2T; 00212 typedef typename super::Matrix3T Matrix3T; 00213 typedef typename super::Matrix4T Matrix4T; 00214 00215 using super::NOT_ENOUGH_POINTS; 00216 using super::UNEQUAL_NUMBER_OF_POINTS; 00217 using super::UNKNOWN_ERROR; 00218 using super::WRONG_POINT_SIZE; 00219 00220 EstimateSimilarityTransformation2D(); 00221 00222 EstimateSimilarityTransformation2D(const std::vector<Coordinate<T> > & source_points, 00223 const std::vector<Coordinate<T> > & target_points); 00224 00225 EstimateSimilarityTransformation2D(const std::vector<Vector2T, Eigen::aligned_allocator<Vector2T> > & source_points, 00226 const std::vector<Vector2T, Eigen::aligned_allocator<Vector2T> > & target_points); 00227 00228 EstimateSimilarityTransformation2D(const std::vector<Vector3T> & source_points, 00229 const std::vector<Vector3T> & target_points); 00230 00231 virtual ~EstimateSimilarityTransformation2D(); 00232 00233 virtual void compute(); 00234 00235 Matrix2T getRotationMatrix() const; 00236 Vector2T getTranslationVector() const; 00237 00238 value_type getRotationAngle() const; 00239 value_type getScalingFactor() const; 00240 00241 private: 00242 00243 value_type rotation_angle; 00244 value_type scaling_factor; 00245 }; 00246 00247 00253 template <class T> 00254 EstimateSimilarityTransformation2D<T>::EstimateSimilarityTransformation2D() : 00255 rotation_angle(0), 00256 scaling_factor(0) 00257 { 00258 } 00259 00260 00282 template <class T> 00283 EstimateSimilarityTransformation2D<T>::EstimateSimilarityTransformation2D(const std::vector<Coordinate<T> > & source_points, 00284 const std::vector<Coordinate<T> > & target_points) : 00285 rotation_angle(0), 00286 scaling_factor(0) 00287 00288 { 00289 super::setSourcePoints(source_points); 00290 super::setTargetPoints(target_points); 00291 } 00292 00293 00307 template <class T> 00308 EstimateSimilarityTransformation2D<T>::EstimateSimilarityTransformation2D(const std::vector<Vector2T, Eigen::aligned_allocator<Vector2T> > & source_points, 00309 const std::vector<Vector2T, Eigen::aligned_allocator<Vector2T> > & target_points) : 00310 rotation_angle(0), 00311 scaling_factor(0) 00312 { 00313 super::setSourcePoints(source_points); 00314 super::setTargetPoints(target_points); 00315 } 00316 00317 00331 template <class T> 00332 EstimateSimilarityTransformation2D<T>::EstimateSimilarityTransformation2D(const std::vector<Vector3T> & source_points, 00333 const std::vector<Vector3T> & target_points) : 00334 rotation_angle(0), 00335 scaling_factor(0) 00336 { 00337 super::setSourcePoints(source_points); 00338 super::setTargetPoints(target_points); 00339 } 00340 00341 00347 template <class T> 00348 EstimateSimilarityTransformation2D<T>::~EstimateSimilarityTransformation2D() 00349 { 00350 } 00351 00352 00373 template <class T> 00374 void EstimateSimilarityTransformation2D<T>::compute() 00375 { 00376 if (super::m_source_points.size() != super::m_target_points.size()) 00377 { 00378 ErrorObj error; 00379 error.setClassName("EstimateSimilarityTransformation2D<T>"); 00380 error.setFunctionName("compute"); 00381 error.setErrorMessage("Point sets must have the same cardinality."); 00382 error.setErrorCode(UNEQUAL_NUMBER_OF_POINTS); 00383 throw error; 00384 } 00385 00386 if (super::m_source_points.cols() < 2 || super::m_target_points.cols() < 2) 00387 { 00388 ErrorObj error; 00389 error.setClassName("EstimateSimilarityTransformation2D<T>"); 00390 error.setFunctionName("compute"); 00391 error.setErrorMessage("Not enough points to compute transformation matrix."); 00392 error.setErrorCode(NOT_ENOUGH_POINTS); 00393 throw error; 00394 } 00395 00396 /* 00397 00398 Explanation of the algorithm: 00399 00400 By using homogeneous coordinates a rigid transformation can be described as follows: 00401 00402 | alpha*cos(phi) -alpha*sin(phi) t_x | | source_x | | target_x | 00403 | alpha*sin(phi) alpha*cos(phi) t_y | * | source_y | = | target_y | 00404 | 0 0 1 | | 1 | | 1 | 00405 00406 The equation can be rewritten as: 00407 00408 | alpha * cos(phi) | 00409 | source_x -source_y 1 0 | * | alpha * sin(phi) | = | target_x | 00410 | source_y source_x 0 1 | | t_x | | target_y | 00411 | t_Y | 00412 00413 Or in short: A * x = b 00414 00415 By using more and more points this leads to an over-determined system, which can 00416 be solved via the pseudo inverse (i.e. A becomes A = [A1 A2 A3 ...]^T): 00417 00418 <==> A * x = b 00419 <==> A^T * A * x = A^T * b 00420 <==> inverse(A^T * A) * A^T * A * x = x = inverse(A^T * A) * A^T * b 00421 00422 Thus: 00423 00424 x = pseudo_inverse * b = [inverse(A^T * A) * A^T] * b 00425 00426 ==> phi = atan2(x(1), x(0)) (angle of rotation) 00427 ==> alpha = sqrt(x(0) * x(0) + x(1) * x(1)) (scaling factor) 00428 00429 */ 00430 00431 using std::atan2; 00432 using std::cos; 00433 using std::sin; 00434 00435 const int number_points = super::m_source_points.cols(); 00436 00437 // fill matrix A with the above described entries 00438 00439 MatrixXT A(2*number_points, 4); 00440 00441 A.setZero(); 00442 A.block(0*number_points, 0, number_points, 1) = super::m_source_points.block(0, 0, 1, number_points).transpose(); 00443 A.block(0*number_points, 1, number_points, 1) = -super::m_source_points.block(1, 0, 1, number_points).transpose(); 00444 A.block(0*number_points, 2, number_points, 1) = VectorXT::Ones(number_points); 00445 A.block(1*number_points, 0, number_points, 1) = super::m_source_points.block(1, 0, 1, number_points).transpose(); 00446 A.block(1*number_points, 1, number_points, 1) = super::m_source_points.block(0, 0, 1, number_points).transpose(); 00447 A.block(1*number_points, 3, number_points, 1) = VectorXT::Ones(number_points); 00448 00449 // fill vector b 00450 00451 VectorXT b(2*number_points, 1); 00452 b.block(0*number_points, 0, number_points, 1) = super::m_target_points.block(0, 0, 1, number_points).transpose(); 00453 b.block(1*number_points, 0, number_points, 1) = super::m_target_points.block(1, 0, 1, number_points).transpose(); 00454 00455 // compute pseudo inverse 00456 00457 MatrixXT pseudo_inverse = (A.transpose() * A).inverse() * A.transpose(); 00458 00459 // compute vector x whose components are/contain the sought transformation entries 00460 00461 VectorXT x = pseudo_inverse * b; 00462 00463 // compute the angle of rotation as well as the scaling factor 00464 00465 rotation_angle = atan2(x(1), x(0)); // cos(phi) and sin(phi) by oneself might diverge from each other 00466 00467 using std::sqrt; 00468 scaling_factor = sqrt(x(0) * x(0) + x(1) * x(1)); 00469 00470 super::m_transformation_matrix(0, 0) = scaling_factor * cos(rotation_angle); 00471 super::m_transformation_matrix(0, 1) = scaling_factor * -sin(rotation_angle); 00472 super::m_transformation_matrix(0, 2) = x(2); 00473 super::m_transformation_matrix(1, 0) = scaling_factor * sin(rotation_angle); 00474 super::m_transformation_matrix(1, 1) = scaling_factor * cos(rotation_angle); 00475 super::m_transformation_matrix(1, 2) = x(3); 00476 super::m_transformation_matrix(2, 0) = 0; 00477 super::m_transformation_matrix(2, 1) = 0; 00478 super::m_transformation_matrix(2, 2) = 1; 00479 } 00480 00481 00491 template <class T> 00492 typename EstimateSimilarityTransformation2D<T>::Matrix2T EstimateSimilarityTransformation2D<T>::getRotationMatrix() const 00493 { 00494 return super::m_transformation_matrix.block(0, 0, 2, 2); 00495 } 00496 00497 00505 template <class T> 00506 typename EstimateSimilarityTransformation2D<T>::Vector2T EstimateSimilarityTransformation2D<T>::getTranslationVector() const 00507 { 00508 return super::m_transformation_matrix.block(0, 2, 2, 1); 00509 } 00510 00511 00519 template <class T> 00520 typename EstimateSimilarityTransformation2D<T>::value_type EstimateSimilarityTransformation2D<T>::getRotationAngle() const 00521 { 00522 return rotation_angle; 00523 } 00524 00525 00533 template <class T> 00534 typename EstimateSimilarityTransformation2D<T>::value_type EstimateSimilarityTransformation2D<T>::getScalingFactor() const 00535 { 00536 return scaling_factor; 00537 } 00538 00539 00540 } // namespace TRTK 00541 00542 00543 #endif // ESTIMATE_SIMILARITY_TRANSFORMATION_2D_HPP_7322190897
Documentation generated by Doxygen