00001 /* 00002 * Copyright (c) 2008 Radu Bogdan Rusu <rusu -=- cs.tum.edu> 00003 * 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are met: 00008 * 00009 * * Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * * Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00016 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00017 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00019 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00020 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00021 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00023 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00024 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00025 * POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 * $Id$ 00028 * 00029 */ 00030 00033 #include <algorithm> 00034 #include <cfloat> 00035 #include <door_handle_detector/sample_consensus/lmeds.h> 00036 00037 namespace sample_consensus 00038 { 00040 00044 LMedS::LMedS (SACModel *model, double threshold) : SAC (model) 00045 { 00046 this->threshold_ = threshold; 00047 // Maximum number of trials before we give up. 00048 this->max_iterations_ = 50; 00049 00050 this->iterations_ = 0; 00051 } 00052 00054 00057 LMedS::LMedS (SACModel* model) : SAC (model) { } 00058 00060 00063 bool 00064 LMedS::computeModel (int debug) 00065 { 00066 iterations_ = 0; 00067 double d_best_penalty = DBL_MAX; 00068 00069 std::vector<int> best_model; 00070 std::vector<int> best_inliers; 00071 std::vector<int> selection; 00072 std::vector<double> distances; 00073 00074 // Iterate 00075 while (iterations_ < max_iterations_) 00076 { 00077 // Get X samples which satisfy the model criteria 00078 sac_model_->getSamples (iterations_, selection); 00079 00080 if (selection.size () == 0) break; 00081 00082 // Search for inliers in the point cloud for the current plane model M 00083 sac_model_->computeModelCoefficients (selection); 00084 00085 double d_cur_penalty = 0; 00086 // d_cur_penalty = sum (min (dist, threshold)) 00087 00088 // Iterate through the 3d points and calculate the distances from them to the model 00089 sac_model_->getDistancesToModel (sac_model_->getModelCoefficients (), distances); 00090 if (distances.size () == 0) 00091 { 00092 iterations_ += 1; 00093 continue; 00094 } 00095 00096 std::sort (distances.begin (), distances.end ()); 00097 00098 // d_cur_penalty = median (distances) 00099 int mid = sac_model_->getIndices ()->size () / 2; 00100 00101 // Do we have a "middle" point or should we "estimate" one ? 00102 if (sac_model_->getIndices ()->size () % 2 == 0) 00103 d_cur_penalty = (sqrt (distances[mid-1]) + sqrt (distances[mid])) / 2; 00104 else 00105 d_cur_penalty = sqrt (distances[mid]); 00106 00107 // Better match ? 00108 if (d_cur_penalty < d_best_penalty) 00109 { 00110 d_best_penalty = d_cur_penalty; 00111 best_model = selection; 00112 } 00113 00114 iterations_ += 1; 00115 if (debug > 1) 00116 std::cerr << "[LMedS::computeModel] Trial " << iterations_ << " out of "<< max_iterations_ << ". Best penalty is : " << d_best_penalty << "." << std::endl; 00117 } 00118 00119 if (best_model.size () != 0) 00120 { 00121 // Classify the data points into inliers and outliers 00122 // Sigma = 1.4826 * (1 + 5 / (n-d)) * sqrt (M) 00123 // NOTE: See "Robust Regression Methods for Computer Vision: A Review" 00124 // double sigma = 1.4826 * (1 + 5 / (sac_model_->getIndices ()->size () - best_model.size ())) * sqrt (d_best_penalty); 00125 // double threshold = 2.5 * sigma; 00126 00127 sac_model_->computeModelCoefficients (best_model); 00128 // Iterate through the 3d points and calculate the distances from them to the model 00129 std::vector<double> distances; 00130 sac_model_->getDistancesToModel (sac_model_->getModelCoefficients (), distances); 00131 if (distances.size () == 0) 00132 ROS_WARN ("Distances to model _after_ model estimation have size 0!"); 00133 00134 best_inliers.resize (sac_model_->getIndices ()->size ()); 00135 int n_inliers_count = 0; 00136 for (unsigned int i = 0; i < sac_model_->getIndices ()->size (); i++) 00137 { 00138 // if (distances[i] <= threshold) 00139 if (distances[i] <= threshold_) 00140 { 00141 best_inliers[n_inliers_count] = sac_model_->getIndices ()->at (i); 00142 n_inliers_count++; 00143 } 00144 } 00145 best_inliers.resize (n_inliers_count); 00146 00147 if (debug > 0) 00148 std::cerr << "[LMedS::computeModel] Model found: " << n_inliers_count << " inliers" << std::endl; 00149 sac_model_->setBestModel (best_model); 00150 sac_model_->setBestInliers (best_inliers); 00151 return (true); 00152 } 00153 else 00154 if (debug > 0) 00155 std::cerr << "[LMedS::computeModel] Unable to find a solution!" << std::endl; 00156 return (false); 00157 } 00158 }