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 See license.txt for more information. 00011 00012 Version 0.3.0 (2014-07-04) 00013 */ 00014 00019 #ifndef ICP_HPP_7908314317 00020 #define ICP_HPP_7908314317 00021 00022 00023 #include <cmath> 00024 #include <cstddef> 00025 #include <limits> 00026 #include <vector> 00027 00028 #include <Eigen/Core> 00029 #include <Eigen/Dense> 00030 #include <flann/flann.hpp> 00031 00032 #include "Coordinate.hpp" 00033 #include "ErrorObj.hpp" 00034 #include "EstimateTransformation3D.hpp" 00035 #include "Signals.hpp" 00036 #include "Tools.hpp" 00037 #include "Transform2D.hpp" 00038 #include "Transform3D.hpp" 00039 00040 00041 namespace TRTK 00042 { 00043 00044 00046 // IcpInterface // 00048 00049 00226 template <class ValueType> 00227 class IcpInterface 00228 { 00229 public: 00230 typedef Eigen::Matrix<ValueType, Eigen::Dynamic, Eigen::Dynamic> Matrix; 00231 00232 virtual ~IcpInterface() = 0; 00233 00234 virtual void setSourcePoints(const std::vector<Coordinate<ValueType> > & source_points) = 0; 00235 virtual void setTargetPoints(const std::vector<Coordinate<ValueType> > & target_points) = 0; 00236 virtual void setInitialEstimation(const Matrix & transformation) = 0; 00237 virtual void setEstimationAlgorithm(EstimateTransformation3D<ValueType> & estimator) = 0; 00238 virtual void setMaximumNumberIterations(unsigned number) = 0; 00239 virtual void setMaximumRMSE(ValueType value) = 0; 00240 virtual void setEpsApproximate(float value) = 0; 00241 00242 virtual ValueType compute() = 0; 00243 00244 virtual void abortComputation() = 0; 00245 00246 virtual const Matrix & getTransformation() = 0; 00247 }; 00248 00249 00250 template<class ValueType> 00251 IcpInterface<ValueType>::~IcpInterface() 00252 { 00253 } 00254 00255 00257 // IcpBase // 00259 00260 00276 template<class ValueType> 00277 class IcpBase : public IcpInterface<ValueType> 00278 { 00279 public: 00280 typedef IcpInterface<ValueType> super; 00281 typedef typename super::Matrix Matrix; 00282 00283 IcpBase(unsigned dimension); 00284 ~IcpBase(); 00285 00286 void setSourcePoints(const std::vector<Coordinate<ValueType> > & source_points); 00287 void setTargetPoints(const std::vector<Coordinate<ValueType> > & target_points); 00288 void setInitialEstimation(const Matrix & transformation); 00289 void setEstimationAlgorithm(EstimateTransformation3D<ValueType> & estimator); 00290 void setMaximumNumberIterations(unsigned number); 00291 void setMaximumRMSE(ValueType value); 00292 void setEpsApproximate(float value); 00293 00294 virtual ValueType compute() = 0; // returns the RMSE 00295 00296 void abortComputation(); 00297 00298 const Matrix & getTransformation(); 00299 00300 Signal<unsigned> progress; 00301 00302 protected: 00303 unsigned dimension; 00304 00305 const std::vector<Coordinate<ValueType> > * source_points; 00306 00307 flann::Matrix<ValueType> target_points; 00308 flann::Matrix<ValueType> query_point; 00309 flann::Matrix<ValueType> distances; 00310 flann::Matrix<int> indices; 00311 flann::Index<flann::L2<ValueType> > * tree; 00312 float eps; 00313 00314 EstimateTransformation3D<ValueType> * estimator; 00315 00316 unsigned maximum_number_iterations; 00317 00318 ValueType maximum_rms_error; 00319 00320 Matrix transformation; 00321 00322 volatile bool abort; 00323 }; 00324 00325 00326 template<class ValueType> 00327 IcpBase<ValueType>::IcpBase(unsigned dimension) : 00328 dimension(dimension), 00329 tree(NULL), 00330 eps(0), 00331 estimator(NULL), 00332 maximum_number_iterations(20), 00333 maximum_rms_error(0), 00334 abort(false) 00335 { 00336 } 00337 00338 00339 template<class ValueType> 00340 IcpBase<ValueType>::~IcpBase() 00341 { 00342 if (tree != NULL) delete tree; 00343 00344 delete[] target_points.ptr(); 00345 delete[] query_point.ptr(); 00346 delete[] distances.ptr(); 00347 delete[] indices.ptr(); 00348 } 00349 00350 00351 template<class ValueType> 00352 void IcpBase<ValueType>::abortComputation() 00353 { 00354 abort = true; 00355 } 00356 00357 00358 template<class ValueType> 00359 inline const typename IcpBase<ValueType>::Matrix & IcpBase<ValueType>::getTransformation() 00360 { 00361 return transformation; 00362 } 00363 00364 00365 template<class ValueType> 00366 void IcpBase<ValueType>::setEpsApproximate(float value) 00367 { 00368 assert(eps >= 0); 00369 eps = value; 00370 } 00371 00372 00373 template<class ValueType> 00374 void IcpBase<ValueType>::setEstimationAlgorithm(EstimateTransformation3D<ValueType> & estimator) 00375 { 00376 this->estimator = &estimator; 00377 } 00378 00379 00380 template<class ValueType> 00381 void IcpBase<ValueType>::setInitialEstimation(const Matrix & transformation) 00382 { 00383 this->transformation = transformation; 00384 } 00385 00386 00387 template<class ValueType> 00388 void IcpBase<ValueType>::setMaximumNumberIterations(unsigned number) 00389 { 00390 maximum_number_iterations = number; 00391 } 00392 00393 00394 template<class ValueType> 00395 void IcpBase<ValueType>::setMaximumRMSE(ValueType value) 00396 { 00397 maximum_rms_error = value; 00398 } 00399 00400 00403 template<class ValueType> 00404 void IcpBase<ValueType>::setSourcePoints(const std::vector<Coordinate<ValueType> > & source_points) 00405 { 00406 this->source_points = &source_points; 00407 } 00408 00409 00412 template<class ValueType> 00413 void IcpBase<ValueType>::setTargetPoints(const std::vector<Coordinate<ValueType> > & target_points) 00414 { 00415 if (target_points.size() == 0) 00416 { 00417 throw std::runtime_error("IcpBase::setTargetPoints(): The input data may not be emtpy."); 00418 } 00419 00420 // Copy the target points. 00421 00422 const unsigned number_points = target_points.size(); 00423 00424 delete[] this->target_points.ptr(); 00425 this->target_points = flann::Matrix<ValueType>(new ValueType[number_points * dimension], number_points, dimension); 00426 00427 for (unsigned i = 0; i < number_points; ++i) 00428 { 00429 for (unsigned j = 0; j < dimension; ++j) 00430 { 00431 this->target_points[i][j] = target_points[i][j]; 00432 } 00433 } 00434 00435 // Setup tree. 00436 00437 if (tree != NULL) delete tree; 00438 00439 tree = new flann::Index<flann::L2<ValueType> >(this->target_points, flann::KDTreeSingleIndexParams()); 00440 tree->buildIndex(); 00441 } 00442 00443 00445 // Icp3D // 00447 00448 00470 template <class ValueType> 00471 class Icp3D : public IcpBase<ValueType> 00472 { 00473 public: 00474 Icp3D(); 00475 ValueType compute(); 00476 00477 private: 00478 typedef IcpBase<ValueType> super; 00479 00480 using super::abort; 00481 using super::distances; 00482 using super::estimator; 00483 using super::indices; 00484 using super::maximum_number_iterations; 00485 using super::maximum_rms_error; 00486 using super::query_point; 00487 using super::source_points; 00488 using super::target_points; 00489 using super::transformation; 00490 using super::tree; 00491 }; 00492 00493 00494 template<class ValueType> 00495 Icp3D<ValueType>::Icp3D() : IcpBase<ValueType>(3) 00496 { 00497 transformation = Transform3D<ValueType>().getTransformationMatrix(); 00498 00499 distances = flann::Matrix<ValueType>(new ValueType[1], 1, 1); 00500 indices = flann::Matrix<int>(new int[1], 1, 1); 00501 query_point = flann::Matrix<ValueType>(new ValueType[3], 1, 3); 00502 } 00503 00504 00510 template<class ValueType> 00511 ValueType Icp3D<ValueType>::compute() 00512 { 00513 if (tree->size() == 0) 00514 { 00515 throw std::range_error("Icp3D::compute(): No target points are given."); 00516 } 00517 00518 // Initialize some variables. 00519 00520 using std::ceil; 00521 using std::max; 00522 using std::min; 00523 00524 abort = false; 00525 00526 const unsigned size = source_points->size(); 00527 00528 std::vector<Coordinate<ValueType> > transformed_source_points; 00529 std::vector<Coordinate<ValueType> > target_points; 00530 00531 Coordinate<ValueType> target_point(0, 0, 0); 00532 00533 estimator->setSourcePoints(*source_points); 00534 00535 std::vector<ValueType> rmse(maximum_number_iterations); // used to compute the progress 00536 00537 // Iterate. 00538 00539 unsigned i = 0; 00540 00541 while (i < maximum_number_iterations && !abort) 00542 { 00543 transformed_source_points.clear(); 00544 transformed_source_points.reserve(size); 00545 00546 target_points.clear(); 00547 target_points.reserve(size); 00548 00549 // Transform the source points with the actual transformation estimation 00550 // and search for the corresponding points in the target set. 00551 00552 Transform3D<ValueType> transform(transformation); 00553 00554 for (unsigned n = 0; n < size; ++n) 00555 { 00556 Coordinate<ValueType> transformed_source_point = transform * (*source_points)[n]; 00557 00558 transformed_source_points.push_back(transformed_source_point); 00559 00560 const Coordinate<ValueType> & point = transformed_source_points[n]; 00561 00562 query_point[0][0] = point.x(); 00563 query_point[0][1] = point.y(); 00564 query_point[0][2] = point.z(); 00565 00566 tree->knnSearch(query_point, indices, distances, 1, flann::SearchParams(128, super::eps)); 00567 00568 target_point.x() = super::target_points[indices[0][0]][0]; 00569 target_point.y() = super::target_points[indices[0][0]][1]; 00570 target_point.z() = super::target_points[indices[0][0]][2]; 00571 00572 target_points.push_back(target_point); 00573 } 00574 00575 // Estimate a new transformation. 00576 00577 estimator->setTargetPoints(target_points); 00578 estimator->compute(); 00579 00580 transformation = estimator->getTransformationMatrix(); 00581 00582 // Compute the actual progress [0, ..., 100] using a simple heuristic. 00583 // 00584 // 1. A lower bound is given by the current iteration and the maximum 00585 // number of iterations. 00586 // 00587 // 2. The convergence rate of the ICP is assumed to be linear. Estimate 00588 // the iteration N when the RMS will be smaller than the given root 00589 // mean square error bound. Note: N cannot be greater than the 00590 // maximum number of iterations. 00591 00592 unsigned progress = 0; 00593 00594 unsigned lower_bound = unsigned(100.0 * (i + 1) / maximum_number_iterations); 00595 00596 rmse[i] = estimator->getRMS(); 00597 00598 if (i > 0) 00599 { 00600 // rmse_bound > y = m * x + b, m := (rmse[i] - rmse[0]) / i, m < 0, b := rmse[0] 00601 // ==> N := ceil(x) = ceil((rmse_bound - rmse[0]) / ((rmse[i] - rmse[0]) / i)) 00602 00603 using std::numeric_limits; 00604 ValueType epsilon = numeric_limits<ValueType>::epsilon(); 00605 00606 ValueType m = (rmse[i] - rmse[0]) / i - epsilon; 00607 ValueType N = (maximum_rms_error - rmse[0]) / m; 00608 N = N > 0 ? ceil(N) : 0; 00609 00610 progress = N > 0 ? unsigned(100.0 * i / N) : 100; //if the current RMS is lower than the given error bound (last case), we are done (progress = 100%) 00611 progress = min<unsigned>(progress, 100); // progress can at most be 100 00612 } 00613 00614 progress = max(lower_bound, progress); 00615 00616 super::progress.send(progress); 00617 00618 // Iterate + stop criterion. 00619 00620 if (rmse[i++] < maximum_rms_error) 00621 { 00622 if (progress < 100) 00623 { 00624 super::progress.send(100); 00625 } 00626 00627 break; 00628 } 00629 } 00630 00631 return estimator->getRMS(); 00632 } 00633 00634 00636 // IcpTrimmed3D // 00638 00639 00640 00674 template <class ValueType> 00675 class IcpTrimmed3D : public IcpBase<ValueType> 00676 { 00677 public: 00678 IcpTrimmed3D(); 00679 ValueType compute(); 00680 00681 void setMinimumOverlap(ValueType value); 00682 00683 00684 private: 00685 typedef IcpBase<ValueType> super; 00686 00687 using super::abort; 00688 using super::distances; 00689 using super::estimator; 00690 using super::indices; 00691 using super::maximum_number_iterations; 00692 using super::maximum_rms_error; 00693 using super::query_point; 00694 using super::source_points; 00695 using super::target_points; 00696 using super::transformation; 00697 using super::tree; 00698 00699 ValueType m_minimumOverlap; 00700 }; 00701 00702 template<class ValueType> 00703 IcpTrimmed3D<ValueType>::IcpTrimmed3D() : 00704 IcpBase<ValueType>(3), 00705 m_minimumOverlap(0.3) 00706 { 00707 transformation = Transform3D<ValueType>().getTransformationMatrix(); 00708 00709 distances = flann::Matrix<ValueType>(new ValueType[1], 1, 1); 00710 indices = flann::Matrix<int>(new int[1], 1, 1); 00711 query_point = flann::Matrix<ValueType>(new ValueType[3], 1, 3); 00712 } 00713 00714 00715 template<class ValueType> 00716 ValueType IcpTrimmed3D<ValueType>::compute() 00717 { 00718 if (tree->size() == 0) 00719 { 00720 throw std::range_error("IcpTrimmed3D::compute(): No target points are given."); 00721 } 00722 00723 // Initialize some variables. 00724 00725 using std::ceil; 00726 using std::max; 00727 using std::min; 00728 00729 abort = false; 00730 00731 const unsigned size = source_points->size(); 00732 00733 std::vector<Coordinate<ValueType> > transformed_source_points; 00734 std::vector<Coordinate<ValueType> > trimmed_source_points; 00735 std::vector<Coordinate<ValueType> > target_points; 00736 std::vector<Coordinate<ValueType> > trimmed_target_points; 00737 std::vector<ValueType> individual_distances; 00738 00739 Coordinate<ValueType> target_point(0, 0, 0); 00740 00741 //estimator->setSourcePoints(*source_points); 00742 00743 std::vector<ValueType> rmse(maximum_number_iterations); // used to compute the progress 00744 00745 // Iterate. 00746 00747 unsigned i = 0; 00748 00749 while (i < maximum_number_iterations && !abort) 00750 { 00751 transformed_source_points.clear(); 00752 transformed_source_points.reserve(size); 00753 00754 trimmed_source_points.clear(); 00755 trimmed_source_points.reserve(size); 00756 00757 target_points.clear(); 00758 target_points.reserve(size); 00759 00760 individual_distances.clear(); 00761 individual_distances.reserve(size); 00762 00763 // Transform the source points with the actual transformation estimation 00764 // and search for the corresponding points in the target set. 00765 00766 Transform3D<ValueType> transform(transformation); 00767 00768 for (unsigned n = 0; n < size; ++n) 00769 { 00770 Coordinate<ValueType> transformed_source_point = transform * (*source_points)[n]; 00771 00772 transformed_source_points.push_back(transformed_source_point); 00773 00774 const Coordinate<ValueType> & point = transformed_source_points[n]; 00775 00776 query_point[0][0] = point.x(); 00777 query_point[0][1] = point.y(); 00778 query_point[0][2] = point.z(); 00779 00780 tree->knnSearch(query_point, indices, distances, 1, flann::SearchParams(128, super::eps)); 00781 00782 target_point.x() = super::target_points[indices[0][0]][0]; 00783 target_point.y() = super::target_points[indices[0][0]][1]; 00784 target_point.z() = super::target_points[indices[0][0]][2]; 00785 00786 // compute distance of transformed source and target 00787 ValueType d = (transformed_source_point - target_point).squaredNorm(); 00788 individual_distances.push_back(d); 00789 trimmed_source_points.push_back((*source_points)[n]); 00790 target_points.push_back(target_point); 00791 } 00792 00793 estimator->setSourcePoints(trimmed_source_points); 00794 estimator->setTargetPoints(target_points); 00795 00796 // sorting takes too long for large point clouds 00797 // use approximation instead 00798 00799 if (m_minimumOverlap < 1) 00800 { 00801 // find maximumAllowedDistance: 00802 // find minimum and maximum 00803 double maxDistance = 0; 00804 double minDistance = std::numeric_limits<double>::max(); 00805 00806 if (m_minimumOverlap > 0.5) 00807 { 00808 for (unsigned n = 0; n < size; ++n) 00809 { 00810 if (individual_distances[n]>maxDistance) maxDistance = individual_distances[n]; 00811 if (individual_distances[n]<minDistance) minDistance = individual_distances[n]; 00812 } 00813 } 00814 else 00815 { 00816 // improve accuracy: consider distances smaller than the average only 00817 for (unsigned n = 0; n < size; ++n) 00818 { 00819 maxDistance += individual_distances[n]; 00820 if (individual_distances[n]<minDistance) minDistance = individual_distances[n]; 00821 } 00822 maxDistance /= size; 00823 } 00824 00825 // find maximum allowed distance 00826 double maximumAllowedDistance; 00827 double minimumNumPoints = m_minimumOverlap*size; 00828 00829 double distanceDistribution[10000]; 00830 for (int i = 0; i<10000; i++) 00831 { 00832 distanceDistribution[i] = 0; 00833 } 00834 for (unsigned n = 0; n < size; ++n) 00835 { 00836 if (individual_distances[n]<=maxDistance) 00837 { 00838 distanceDistribution[(int) ((individual_distances[n]-minDistance)/(maxDistance-minDistance)*9999)]++; 00839 } 00840 } 00841 double distanceDistributionAccumulated[10000]; 00842 distanceDistributionAccumulated[0] = distanceDistribution[0]; 00843 int i; 00844 for (i = 1; i<10000; i++) 00845 { 00846 distanceDistributionAccumulated[i] = distanceDistributionAccumulated[i-1] + distanceDistribution[i]; 00847 if (distanceDistributionAccumulated[i] >= minimumNumPoints) 00848 break; 00849 } 00850 maximumAllowedDistance = ((double) i+0.5)/9999 * (maxDistance-minDistance) + minDistance; 00851 00852 trimmed_target_points.clear(); 00853 trimmed_target_points.reserve(size); 00854 00855 trimmed_source_points.clear(); 00856 00857 for (unsigned n = 0; n < size; ++n) 00858 { 00859 if (individual_distances[n]<=maximumAllowedDistance) 00860 { 00861 trimmed_source_points.push_back((*source_points)[n]); 00862 trimmed_target_points.push_back(target_points[n]); 00863 } 00864 } 00865 00866 estimator->setSourcePoints(trimmed_source_points); 00867 estimator->setTargetPoints(trimmed_target_points); 00868 } 00869 00870 // Estimate a new transformation. 00871 estimator->compute(); 00872 00873 transformation = estimator->getTransformationMatrix(); 00874 00875 // Compute the actual progress [0, ..., 100] using a simple heuristic. 00876 // 00877 // 1. A lower bound is given by the current iteration and the maximum 00878 // number of iterations. 00879 // 00880 // 2. The convergence rate of the ICP is assumed to be linear. Estimate 00881 // the iteration N when the RMS will be smaller than the given root 00882 // mean square error bound. Note: N cannot be greater than the 00883 // maximum number of iterations. 00884 00885 unsigned progress = 0; 00886 00887 unsigned lower_bound = unsigned(100.0 * (i + 1) / maximum_number_iterations); 00888 00889 rmse[i] = estimator->getRMS(); 00890 00891 if (i > 0) 00892 { 00893 // rmse_bound > y = m * x + b, m := (rmse[i] - rmse[0]) / i, m < 0, b := rmse[0] 00894 // ==> N := ceil(x) = ceil((rmse_bound - rmse[0]) / ((rmse[i] - rmse[0]) / i)) 00895 00896 using std::numeric_limits; 00897 ValueType epsilon = numeric_limits<ValueType>::epsilon(); 00898 00899 ValueType m = (rmse[i] - rmse[0]) / i - epsilon; 00900 ValueType N = (maximum_rms_error - rmse[0]) / m; 00901 N = N > 0 ? ceil(N) : 0; 00902 00903 progress = N > 0 ? unsigned(100.0 * i / N) : 100; //if the current RMS is lower than the given error bound (last case), we are done (progress = 100%) 00904 progress = min<unsigned>(progress, 100); // progress can at most be 100 00905 } 00906 00907 progress = max(lower_bound, progress); 00908 00909 super::progress.send(progress); 00910 00911 // Iterate + stop criterion. 00912 00913 if (rmse[i++] < maximum_rms_error) 00914 { 00915 if (progress < 100) 00916 { 00917 super::progress.send(100); 00918 } 00919 00920 break; 00921 } 00922 } 00923 00924 return estimator->getRMS(); 00925 } 00926 00927 00930 template<class ValueType> 00931 void IcpTrimmed3D<ValueType>::setMinimumOverlap(ValueType value) 00932 { 00933 m_minimumOverlap = value; 00934 } 00935 00936 00938 // RandomSampleIcp3D // 00940 00941 00984 template <class ValueType> 00985 class RandomSampleIcp3D : public IcpBase<ValueType> 00986 { 00987 public: 00988 RandomSampleIcp3D(); 00989 ValueType compute(); 00990 00991 void setMaximumNumberIterationsFirstStage(unsigned value); 00992 void setMaximumNumberIterationsSecondStage(unsigned value); 00993 void setPercentage(unsigned value); 00994 00995 private: 00996 typedef IcpBase<ValueType> super; 00997 typedef typename super::Matrix Matrix; 00998 00999 using super::abort; 01000 using super::distances; 01001 using super::estimator; 01002 using super::indices; 01003 using super::maximum_number_iterations; 01004 using super::maximum_rms_error; 01005 using super::query_point; 01006 using super::source_points; 01007 using super::target_points; 01008 using super::transformation; 01009 using super::tree; 01010 01011 unsigned maximum_number_iterations_first_stage; 01012 unsigned percentage; 01013 }; 01014 01015 01016 template<class ValueType> 01017 RandomSampleIcp3D<ValueType>::RandomSampleIcp3D() : 01018 IcpBase<ValueType>(3), 01019 maximum_number_iterations_first_stage(20), 01020 percentage(50) 01021 { 01022 transformation = Transform3D<ValueType>().getTransformationMatrix(); 01023 01024 distances = flann::Matrix<ValueType>(new ValueType[1], 1, 1); 01025 indices = flann::Matrix<int>(new int[1], 1, 1); 01026 query_point = flann::Matrix<ValueType>(new ValueType[3], 1, 3); 01027 01028 maximum_number_iterations = 20; 01029 } 01030 01031 01037 template<class ValueType> 01038 ValueType RandomSampleIcp3D<ValueType>::compute() 01039 { 01040 if (tree->size() == 0) 01041 { 01042 throw std::range_error("RandomSampleIcp3D::compute(): No target points are given."); 01043 } 01044 01045 // Initialize some variables. 01046 01047 using std::ceil; 01048 using std::max; 01049 using std::min; 01050 using std::numeric_limits; 01051 01052 abort = false; 01053 01054 const unsigned size = source_points->size(); 01055 01056 std::vector<Coordinate<ValueType> > source_points; // note, this hides the class member 01057 std::vector<Coordinate<ValueType> > transformed_source_points; 01058 std::vector<Coordinate<ValueType> > target_points; 01059 01060 Coordinate<ValueType> target_point(0, 0, 0); 01061 01062 Matrix best_estimate = transformation; 01063 01064 ValueType least_rmse = numeric_limits<ValueType>::max(); 01065 01066 unsigned maximum_number_iterations_per_stage = max(maximum_number_iterations, maximum_number_iterations_first_stage); 01067 unsigned maximum_number_iterations_overall = maximum_number_iterations + maximum_number_iterations_first_stage; 01068 01069 std::vector<ValueType> rmse(maximum_number_iterations_per_stage); // used to compute the progress 01070 01071 ValueType ratio = ValueType(maximum_number_iterations_first_stage) / ValueType(maximum_number_iterations_overall); 01072 01073 // PHASE 1 --> Randomly selected subsets are taken to "feed" the classical ICP algorithm. 01074 01075 // Iterate. 01076 01077 unsigned i = 0; 01078 01079 while (i < maximum_number_iterations_first_stage && !abort) 01080 { 01081 source_points.clear(); 01082 source_points.reserve(size); 01083 01084 transformed_source_points.clear(); 01085 transformed_source_points.reserve(size); 01086 01087 target_points.clear(); 01088 target_points.reserve(size); 01089 01090 // Transform the source points with the actual transformation estimation 01091 // and search for the corresponding points in the target set. 01092 01093 Transform3D<ValueType> transform(transformation); 01094 01095 for (unsigned n = 0; n < size; ++n) 01096 { 01097 if (Tools::rand(0u, 100u) > percentage) continue; // randomly select points 01098 01099 Coordinate<ValueType> source_point = (*this->source_points)[n]; 01100 01101 source_points.push_back(source_point); 01102 01103 Coordinate<ValueType> transformed_source_point = transform * source_point; 01104 01105 transformed_source_points.push_back(transformed_source_point); 01106 01107 const Coordinate<ValueType> & point = transformed_source_point; 01108 01109 query_point[0][0] = point.x(); 01110 query_point[0][1] = point.y(); 01111 query_point[0][2] = point.z(); 01112 01113 tree->knnSearch(query_point, indices, distances, 1, flann::SearchParams(128, super::eps)); 01114 01115 target_point.x() = super::target_points[indices[0][0]][0]; 01116 target_point.y() = super::target_points[indices[0][0]][1]; 01117 target_point.z() = super::target_points[indices[0][0]][2]; 01118 01119 target_points.push_back(target_point); 01120 } 01121 01122 // Estimate a new transformation. 01123 01124 estimator->setSourcePoints(source_points); 01125 estimator->setTargetPoints(target_points); 01126 estimator->compute(); 01127 01128 transformation = estimator->getTransformationMatrix(); 01129 01130 // Store the estimation if its RMSE is lesser than a previous one. 01131 01132 if (estimator->getRMS() < least_rmse) 01133 { 01134 least_rmse = estimator->getRMS(); 01135 best_estimate = estimator->getTransformationMatrix(); 01136 } 01137 01138 // Compute the actual progress [0, ..., 100] using a simple heuristic. 01139 // 01140 // 1. A lower bound is given by the current iteration and the maximum 01141 // number of iterations. 01142 // 01143 // 2. The convergence rate of the ICP is assumed to be linear. Estimate 01144 // the iteration N when the RMS will be smaller than the given root 01145 // mean square error bound. Note: N cannot be greater than the 01146 // maximum number of iterations. 01147 01148 unsigned progress = 0; 01149 01150 unsigned lower_bound = unsigned(100.0 * (i + 1) / maximum_number_iterations_first_stage); 01151 01152 rmse[i] = estimator->getRMS(); 01153 01154 if (i > 0) 01155 { 01156 // rmse_bound > y = m * x + b, m := (rmse[i] - rmse[0]) / i, m < 0, b := rmse[0] 01157 // ==> N := ceil(x) = ceil((rmse_bound - rmse[0]) / ((rmse[i] - rmse[0]) / i)) 01158 01159 ValueType epsilon = numeric_limits<ValueType>::epsilon(); 01160 01161 ValueType m = (rmse[i] - rmse[0]) / i - epsilon; 01162 ValueType N = (maximum_rms_error - rmse[0]) / m; 01163 N = N > 0 ? ceil(N) : 0; 01164 01165 progress = N > 0 ? unsigned(100.0 * i / N) : 100; //if the current RMS is lower than the given error bound (last case), we are done (progress = 100%) 01166 progress = min<unsigned>(progress, 100); // progress can at most be 100 01167 } 01168 01169 progress = max(lower_bound, progress); 01170 01171 super::progress.send(unsigned(progress * ratio)); 01172 01173 // Iterate + stop criterion. 01174 01175 if (rmse[i++] < maximum_rms_error) 01176 { 01177 if (progress < 100) 01178 { 01179 super::progress.send(unsigned(100 * ratio)); 01180 } 01181 01182 break; 01183 } 01184 } 01185 01186 // Use the best transformation estimate for the next phase. 01187 01188 transformation = best_estimate; 01189 01190 // Clean up some no longer used variables. 01191 01192 source_points.clear(); 01193 source_points.reserve(0); 01194 01195 // PHASE 2 01196 01197 estimator->setSourcePoints(*this->source_points); 01198 01199 // Iterate. 01200 01201 i = 0; 01202 01203 while (i < maximum_number_iterations && !abort) 01204 { 01205 transformed_source_points.clear(); 01206 transformed_source_points.reserve(size); 01207 01208 target_points.clear(); 01209 target_points.reserve(size); 01210 01211 // Transform the source points with the actual transformation estimation 01212 // and search for the corresponding points in the target set. 01213 01214 Transform3D<ValueType> transform(transformation); 01215 01216 for (unsigned n = 0; n < size; ++n) 01217 { 01218 Coordinate<ValueType> transformed_source_point = transform * (*this->source_points)[n]; 01219 01220 transformed_source_points.push_back(transformed_source_point); 01221 01222 const Coordinate<ValueType> & point = transformed_source_points[n]; 01223 01224 query_point[0][0] = point.x(); 01225 query_point[0][1] = point.y(); 01226 query_point[0][2] = point.z(); 01227 01228 tree->knnSearch(query_point, indices, distances, 1, flann::SearchParams(128, super::eps)); 01229 01230 target_point.x() = super::target_points[indices[0][0]][0]; 01231 target_point.y() = super::target_points[indices[0][0]][1]; 01232 target_point.z() = super::target_points[indices[0][0]][2]; 01233 01234 target_points.push_back(target_point); 01235 } 01236 01237 // Estimate a new transformation. 01238 01239 estimator->setTargetPoints(target_points); 01240 estimator->compute(); 01241 01242 transformation = estimator->getTransformationMatrix(); 01243 01244 // Compute the actual progress [0, ..., 100] using a simple heuristic. 01245 // 01246 // 1. A lower bound is given by the current iteration and the maximum 01247 // number of iterations. 01248 // 01249 // 2. The convergence rate of the ICP is assumed to be linear. Estimate 01250 // the iteration N when the RMS will be smaller than the given root 01251 // mean square error bound. Note: N cannot be greater than the 01252 // maximum number of iterations. 01253 01254 unsigned progress = 0; 01255 01256 unsigned lower_bound = unsigned(100.0 * (i + 1) / maximum_number_iterations); 01257 01258 rmse[i] = estimator->getRMS(); 01259 01260 if (i > 0) 01261 { 01262 // rmse_bound > y = m * x + b, m := (rmse[i] - rmse[0]) / i, m < 0, b := rmse[0] 01263 // ==> N := ceil(x) = ceil((rmse_bound - rmse[0]) / ((rmse[i] - rmse[0]) / i)) 01264 01265 ValueType epsilon = numeric_limits<ValueType>::epsilon(); 01266 01267 ValueType m = (rmse[i] - rmse[0]) / i - epsilon; 01268 ValueType N = (maximum_rms_error - rmse[0]) / m; 01269 N = N > 0 ? ceil(N) : 0; 01270 01271 progress = N > 0 ? unsigned(100.0 * i / N) : 100; //if the current RMS is lower than the given error bound (last case), we are done (progress = 100%) 01272 progress = min<unsigned>(progress, 100); // progress can at most be 100 01273 } 01274 01275 progress = max(lower_bound, progress); 01276 01277 super::progress.send(unsigned(100 * ratio + progress * (1 - ratio))); 01278 01279 // Iterate + stop criterion. 01280 01281 if (rmse[i++] < maximum_rms_error) 01282 { 01283 if (progress < 100) 01284 { 01285 super::progress.send(100); 01286 } 01287 01288 break; 01289 } 01290 } 01291 01292 return estimator->getRMS(); 01293 } 01294 01295 01296 template<class ValueType> 01297 void RandomSampleIcp3D<ValueType>::setMaximumNumberIterationsFirstStage(unsigned value) 01298 { 01299 maximum_number_iterations_first_stage = value; 01300 } 01301 01302 01303 template<class ValueType> 01304 void RandomSampleIcp3D<ValueType>::setMaximumNumberIterationsSecondStage(unsigned value) 01305 { 01306 maximum_number_iterations = value; 01307 } 01308 01309 01310 template<class ValueType> 01311 void RandomSampleIcp3D<ValueType>::setPercentage(unsigned value) 01312 { 01313 assert(percentage <= 100); 01314 percentage = std::min(value, 100u); 01315 } 01316 01317 01318 } // namespace TRTK 01319 01320 01321 #endif // ICP_HPP_7908314317
Documentation generated by Doxygen