00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00039 template <typename PointSource, typename PointTarget, typename FeatureT> void
00040 pcl::SampleConsensusInitialAlignment<PointSource, PointTarget, FeatureT>::setSourceFeatures (
00041 const FeatureCloudConstPtr &features)
00042 {
00043 if (features == NULL || features->points.empty ())
00044 {
00045 ROS_ERROR ("[pcl::%s::setSourceFeatures] Invalid or empty point cloud dataset given!", getClassName ().c_str ());
00046 return;
00047 }
00048 input_features_ = features;
00049 }
00050
00052 template <typename PointSource, typename PointTarget, typename FeatureT> void
00053 pcl::SampleConsensusInitialAlignment<PointSource, PointTarget, FeatureT>::setTargetFeatures (
00054 const FeatureCloudConstPtr &features)
00055 {
00056 if (features == NULL || features->points.empty ())
00057 {
00058 ROS_ERROR ("[pcl::%s::setTargetFeatures] Invalid or empty point cloud dataset given!", getClassName ().c_str ());
00059 return;
00060 }
00061 target_features_ = features;
00062 feature_tree_->setInputCloud (target_features_);
00063 }
00064
00066 template <typename PointSource, typename PointTarget, typename FeatureT> void
00067 pcl::SampleConsensusInitialAlignment<PointSource, PointTarget, FeatureT>::selectSamples (
00068 const PointCloudSource &cloud, int nr_samples, float min_sample_distance, std::vector<int> &sample_indices)
00069 {
00070 if (nr_samples > (int) cloud.points.size ())
00071 {
00072 ROS_ERROR ("[pcl::%s::selectSamples] The number of samples (%d) must not be greater than the number of points (%d)!",
00073 getClassName ().c_str (), nr_samples, (int) cloud.points.size ());
00074 return;
00075 }
00076
00077
00078 int iterations_without_a_sample = 0;
00079 int max_iterations_without_a_sample = 3 * cloud.points.size ();
00080 sample_indices.clear ();
00081 while ((int) sample_indices.size () < nr_samples)
00082 {
00083
00084 int sample_index = getRandomIndex (cloud.points.size ());
00085
00086
00087 bool valid_sample = true;
00088 for (size_t i = 0; i < sample_indices.size (); ++i)
00089 {
00090 float distance_between_samples = euclideanDistance (cloud.points[sample_index], cloud.points[sample_indices[i]]);
00091
00092 if (sample_index == sample_indices[i] || distance_between_samples < min_sample_distance)
00093 {
00094 valid_sample = false;
00095 break;
00096 }
00097 }
00098
00099
00100 if (valid_sample)
00101 {
00102 sample_indices.push_back (sample_index);
00103 iterations_without_a_sample = 0;
00104 }
00105 else
00106 {
00107 ++iterations_without_a_sample;
00108 }
00109
00110
00111 if (iterations_without_a_sample >= max_iterations_without_a_sample)
00112 {
00113 ROS_WARN ("[pcl::%s::selectSamples] No valid sample found after %d iterations. Relaxing min_sample_distance_ to %f",
00114 getClassName ().c_str (), iterations_without_a_sample, 0.5*min_sample_distance);
00115 min_sample_distance_ *= 0.5;
00116 min_sample_distance = min_sample_distance_;
00117 iterations_without_a_sample = 0;
00118 }
00119 }
00120
00121 }
00122
00123
00125 template <typename PointSource, typename PointTarget, typename FeatureT> void
00126 pcl::SampleConsensusInitialAlignment<PointSource, PointTarget, FeatureT>::findSimilarFeatures (
00127 const FeatureCloud &input_features, const std::vector<int> &sample_indices, std::vector<int> &corresponding_indices)
00128 {
00129 const int k = 10;
00130 std::vector<int> nn_indices (k);
00131 std::vector<float> nn_distances (k);
00132
00133 corresponding_indices.resize (sample_indices.size ());
00134 for (size_t i = 0; i < sample_indices.size (); ++i)
00135 {
00136
00137 feature_tree_->nearestKSearch (input_features, sample_indices[i], k, nn_indices, nn_distances);
00138
00139
00140 int random_correspondence = getRandomIndex (k);
00141 corresponding_indices[i] = nn_indices[random_correspondence];
00142 }
00143 }
00144
00146 template <typename PointSource, typename PointTarget, typename FeatureT> float
00147 pcl::SampleConsensusInitialAlignment<PointSource, PointTarget, FeatureT>::computeErrorMetric (
00148 const PointCloudSource &cloud, float threshold)
00149 {
00150 std::vector<int> nn_index (1);
00151 std::vector<float> nn_distance (1);
00152
00153 float error = 0;
00154
00155 for (size_t i = 0; i < cloud.points.size (); ++i)
00156 {
00157
00158 tree_->nearestKSearch (cloud, i, 1, nn_index, nn_distance);
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 float e = nn_distance[0];
00171 if (e <= threshold)
00172 error += e / threshold;
00173 else
00174 error += 1.0;
00175 }
00176 return (error);
00177 }
00178
00179
00181 template <typename PointSource, typename PointTarget, typename FeatureT> void
00182 pcl::SampleConsensusInitialAlignment<PointSource, PointTarget, FeatureT>::computeTransformation (PointCloudSource &output)
00183 {
00184 if (!input_features_)
00185 {
00186 ROS_ERROR ("[pcl::%s::computeTransformation] No source features were given! Call setSourceFeatures before aligning.",
00187 getClassName ().c_str ());
00188 return;
00189 }
00190 if (!target_features_)
00191 {
00192 ROS_ERROR ("[pcl::%s::computeTransformation] No target features were given! Call setTargetFeatures before aligning",
00193 getClassName ().c_str ());
00194 return;
00195 }
00196
00197 std::vector<int> sample_indices (nr_samples_);
00198 std::vector<int> corresponding_indices (nr_samples_);
00199 PointCloudSource input_transformed;
00200 float error, lowest_error (0);
00201
00202 final_transformation_ = Eigen::Matrix4f::Identity ();
00203
00204 for (int i_iter = 0; i_iter < max_iterations_; ++i_iter)
00205 {
00206
00207 selectSamples (*input_, nr_samples_, min_sample_distance_, sample_indices);
00208
00209
00210 findSimilarFeatures (*input_features_, sample_indices, corresponding_indices);
00211
00212
00213 estimateRigidTransformationSVD (*input_, sample_indices, *target_, corresponding_indices, transformation_);
00214
00215
00216 transformPointCloud (*input_, input_transformed, transformation_);
00217 error = computeErrorMetric (input_transformed, corr_dist_threshold_);
00218
00219
00220 if (i_iter == 0 || error < lowest_error)
00221 {
00222 lowest_error = error;
00223 final_transformation_ = transformation_;
00224 }
00225 }
00226
00227
00228 transformPointCloud (*input_, output, final_transformation_);
00229 }