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
00045 template <typename PointSource, typename PointTarget> void
00046 pcl::IterativeClosestPointNonLinear<PointSource, PointTarget>::estimateRigidTransformationLM (
00047 const PointCloudSource &cloud_src, const PointCloudTarget &cloud_tgt, Eigen::Matrix4f &transformation_matrix)
00048 {
00049 boost::mutex::scoped_lock lock (tmp_mutex_);
00050
00051 int n_unknowns = 6;
00052
00053 if (cloud_src.points.size () != cloud_tgt.points.size ())
00054 {
00055 ROS_ERROR ("[pcl::IterativeClosestPointNonLinear::estimateRigidTransformationLM] Number or points in source (%zu) differs than target (%zu)!", cloud_src.points.size (), cloud_tgt.points.size ());
00056 return;
00057 }
00058 if (cloud_src.points.size () < 4)
00059 {
00060 ROS_ERROR ("[pcl::IterativeClosestPointNonLinear::estimateRigidTransformationLM] Need at least 4 points to estimate a transform! Source and target have %zu points!", cloud_src.points.size ());
00061 return;
00062 }
00063
00064 int m = cloud_src.points.size ();
00065 double *fvec = new double[m];
00066 int *iwa = new int[n_unknowns];
00067 int lwa = m * n_unknowns + 5 * n_unknowns + m;
00068 double *wa = new double[lwa];
00069
00070
00071 double *x = new double[n_unknowns];
00072
00073 x[0] = 0; x[1] = 0; x[2] = 0;
00074
00075 x[3] = 0; x[4] = 0; x[5] = 0;
00076
00077
00078 tmp_src_ = &cloud_src;
00079 tmp_tgt_ = &cloud_tgt;
00080
00081
00082 double tol = sqrt (dpmpar (1));
00083
00084
00085
00086 int info = lmdif1 (&pcl::IterativeClosestPointNonLinear<PointSource, PointTarget>::functionToOptimize, this, m, n_unknowns, x, fvec, tol, iwa, wa, lwa);
00087
00088
00089 ROS_DEBUG ("[pcl::%s::estimateRigidTransformationLM] LM solver finished with exit code %i, having a residual norm of %g. ",
00090
00091 getClassName ().c_str (), info, enorm (m, fvec));
00092
00093
00094 delete [] wa; delete [] fvec;
00095
00096 transformation_matrix.setZero ();
00097
00098
00099
00100 Eigen::Quaternionf q (0, x[3], x[4], x[5]);
00101 q.w () = sqrt (1 - q.dot (q));
00102 transformation_matrix.topLeftCorner<3, 3> () = q.toRotationMatrix ();
00103
00104 Eigen::Vector4f t (x[4], x[5], x[6], 1.0);
00105 transformation_matrix.block <4, 1> (0, 3) = t;
00106
00107 tmp_src_ = tmp_tgt_ = NULL;
00108
00109 delete[] iwa;
00110 delete[] x;
00111 }
00112
00114
00122 template <typename PointSource, typename PointTarget> void
00123 pcl::IterativeClosestPointNonLinear<PointSource, PointTarget>::estimateRigidTransformationLM (
00124 const PointCloudSource &cloud_src, const std::vector<int> &indices_src, const PointCloudTarget &cloud_tgt, const std::vector<int> &indices_tgt, Eigen::Matrix4f &transformation_matrix)
00125 {
00126 boost::mutex::scoped_lock lock (tmp_mutex_);
00127
00128 int n_unknowns = 6;
00129
00130 if (indices_src.size () != indices_tgt.size ())
00131 {
00132 ROS_ERROR ("[pcl::IterativeClosestPointNonLinear::estimateRigidTransformationLM] Number or points in source (%zu) differs than target (%zu)!", indices_src.size (), indices_tgt.size ());
00133 return;
00134 }
00135 if (indices_src.size () < 4)
00136 {
00137 ROS_ERROR ("[pcl::IterativeClosestPointNonLinear::estimateRigidTransformationLM] Need at least 4 points to estimate a transform! Source and target have %zu points!", indices_src.size ());
00138 return;
00139 }
00140
00141 int m = indices_src.size ();
00142 double *fvec = new double[m];
00143 int *iwa = new int[n_unknowns];
00144 int lwa = m * n_unknowns + 5 * n_unknowns + m;
00145 double *wa = new double[lwa];
00146
00147
00148 double *x = new double[n_unknowns];
00149
00150 x[0] = 0; x[1] = 0; x[2] = 0;
00151
00152 x[3] = 0; x[4] = 0; x[5] = 0;
00153
00154
00155 tmp_src_ = &cloud_src;
00156 tmp_tgt_ = &cloud_tgt;
00157 tmp_idx_src_ = &indices_src;
00158 tmp_idx_tgt_ = &indices_tgt;
00159
00160
00161 double tol = sqrt (dpmpar (1));
00162
00163
00164 int info = lmdif1 (&pcl::IterativeClosestPointNonLinear<PointSource, PointTarget>::functionToOptimizeIndices, this, m, n_unknowns, x, fvec, tol, iwa, wa, lwa);
00165
00166
00167 ROS_DEBUG ("[pcl::%s::estimateRigidTransformationLM] LM solver finished with exit code %i, having a residual norm of %g. ",
00168
00169 getClassName ().c_str (), info, enorm (m, fvec));
00170
00171
00172 delete [] wa; delete [] fvec;
00173
00174 transformation_matrix.setZero ();
00175
00176
00177
00178 Eigen::Quaternionf q (0, x[3], x[4], x[5]);
00179 q.w () = sqrt (1 - q.dot (q));
00180 transformation_matrix.topLeftCorner<3, 3> () = q.toRotationMatrix ();
00181
00182 Eigen::Vector4f t (x[0], x[1], x[2], 1.0);
00183 transformation_matrix.block <4, 1> (0, 3) = t;
00184
00185 tmp_src_ = tmp_tgt_ = NULL;
00186 tmp_idx_src_ = tmp_idx_tgt_ = NULL;
00187
00188 delete[] iwa;
00189 delete[] x;
00190 }
00191
00193
00196 template <typename PointSource, typename PointTarget> void
00197 pcl::IterativeClosestPointNonLinear<PointSource, PointTarget>::computeTransformation (PointCloudSource &output)
00198 {
00199
00200 std::vector<int> nn_indices (1);
00201 std::vector<float> nn_dists (1);
00202
00203
00204 PointCloudTarget input_corresp;
00205 input_corresp.points.resize (indices_->size ());
00206
00207 nr_iterations_ = 0;
00208 converged_ = false;
00209 double dist_threshold = corr_dist_threshold_ * corr_dist_threshold_;
00210
00211 while (!converged_)
00212 {
00213
00214 previous_transformation_ = transformation_;
00215
00216 int cnt = 0;
00217 std::vector<int> source_indices (indices_->size ());
00218 std::vector<int> target_indices (indices_->size ());
00219
00220
00221 for (size_t idx = 0; idx < indices_->size (); ++idx)
00222 {
00223 if (!searchForNeighbors (output, idx, nn_indices, nn_dists))
00224 {
00225 ROS_ERROR ("[pcl::%s::computeTransformation] Unable to find a nearest neighbor in the target dataset for point %d in the source!", getClassName ().c_str (), (*indices_)[idx]);
00226 return;
00227 }
00228
00229
00230 if (nn_dists[0] < dist_threshold)
00231 {
00232 source_indices[cnt] = idx;
00233 target_indices[cnt] = nn_indices[0];
00234 cnt++;
00235 }
00236
00237
00238 }
00239 if (cnt < min_number_correspondences_)
00240 {
00241 ROS_ERROR ("[pcl::%s::computeTransformation] Not enough correspondences found. Relax your threshold parameters.", getClassName ().c_str ());
00242 converged_ = false;
00243 return;
00244 }
00245
00246
00247 source_indices.resize (cnt); target_indices.resize (cnt);
00248
00249 std::vector<int> source_indices_good;
00250 std::vector<int> target_indices_good;
00251 {
00252
00253
00254 typedef typename SampleConsensusModelRegistration<PointSource>::Ptr SampleConsensusModelRegistrationPtr;
00255 SampleConsensusModelRegistrationPtr model;
00256 model.reset (new SampleConsensusModelRegistration<PointSource> (output.makeShared (), source_indices));
00257
00258 model->setInputTarget (target_, target_indices);
00259
00260 RandomSampleConsensus<PointSource> sac (model, inlier_threshold_);
00261 sac.setMaxIterations (1000);
00262
00263
00264 if (!sac.computeModel ())
00265 {
00266 source_indices_good = source_indices;
00267 target_indices_good = target_indices;
00268 }
00269 else
00270 {
00271 std::vector<int> inliers;
00272
00273 sac.getInliers (inliers);
00274 source_indices_good.resize (inliers.size ());
00275 target_indices_good.resize (inliers.size ());
00276
00277 for (size_t i = 0; i < inliers.size (); ++i)
00278 {
00279 source_indices_good[i] = source_indices[inliers[i]];
00280 target_indices_good[i] = target_indices[inliers[i]];
00281 }
00282 }
00283 }
00284
00285
00286 cnt = (int)source_indices_good.size ();
00287 if (cnt < min_number_correspondences_)
00288 {
00289 ROS_ERROR ("[pcl::%s::computeTransformation] Not enough correspondences found. Relax your threshold parameters.", getClassName ().c_str ());
00290 converged_ = false;
00291 return;
00292 }
00293
00294 ROS_DEBUG ("[pcl::%s::computeTransformation] Number of correspondences %d [%f%%] out of %zu points [100.0%%], RANSAC rejected: %zu [%f%%].", getClassName ().c_str (), cnt, (cnt * 100.0) / indices_->size (), indices_->size (), source_indices.size () - cnt, (source_indices.size () - cnt) * 100.0 / source_indices.size ());
00295
00296
00297 estimateRigidTransformationLM (output, source_indices_good, *target_, target_indices_good, transformation_);
00298
00299
00300
00301 transformPointCloud (output, output, transformation_);
00302
00303
00304 final_transformation_ = transformation_ * final_transformation_;
00305
00306 nr_iterations_++;
00307
00308 if (nr_iterations_ >= max_iterations_ ||
00309 fabs ((transformation_ - previous_transformation_).sum ()) < transformation_epsilon_)
00310 {
00311 converged_ = true;
00312 ROS_DEBUG ("[pcl::%s::computeTransformation] Convergence reached. Number of iterations: %d out of %d. Transformation difference: %f",
00313 getClassName ().c_str (), nr_iterations_, max_iterations_, fabs ((transformation_ - previous_transformation_).sum ()));
00314 }
00315 }
00316 }
00317
00319
00327 template <typename PointSource, typename PointTarget> inline int
00328 pcl::IterativeClosestPointNonLinear<PointSource, PointTarget>::functionToOptimize (void *p, int m, int n, const double *x, double *fvec, int iflag)
00329 {
00330 IterativeClosestPointNonLinear *model = (IterativeClosestPointNonLinear*)p;
00331
00332
00333 Eigen::Vector4f t (x[0], x[1], x[2], 1.0);
00334
00335 Eigen::Quaternionf q (0, x[3], x[4], x[5]);
00336 q.w () = sqrt (1 - q.dot (q));
00337
00338
00339
00340
00341 Eigen::Matrix4f transformation_matrix = Eigen::Matrix4f::Zero ();
00342 transformation_matrix.topLeftCorner<3, 3> () = q.toRotationMatrix ();
00343 transformation_matrix.block <4, 1> (0, 3) = t;
00344
00345 double sigma = model->getMaxCorrespondenceDistance ();
00346 for (int i = 0; i < m; ++i)
00347 {
00348
00349 Vector4fMapConst p_src = model->tmp_src_->points[i].getVector4fMap ();
00350
00351 Vector4fMapConst p_tgt = model->tmp_tgt_->points[i].getVector4fMap ();
00352
00353 Eigen::Vector4f pp = transformation_matrix * p_src;
00354
00355
00356
00357
00358 fvec[i] = model->distHuber (pp, p_tgt, sigma);
00359 }
00360 return (0);
00361 }
00362
00364
00368 template <typename PointSource, typename PointTarget> inline double
00369 pcl::IterativeClosestPointNonLinear<PointSource, PointTarget>::computeMedian (double *fvec, int m)
00370 {
00371 double median;
00372
00373 std::vector<double> data (m);
00374 memcpy (&data[0], fvec, sizeof (double) * m);
00375
00376 std::sort (data.begin (), data.end ());
00377
00378 int mid = data.size () / 2;
00379 if (data.size () % 2 == 0)
00380 median = (data[mid-1] + data[mid]) / 2.0;
00381 else
00382 median = data[mid];
00383 return (median);
00384 }
00385
00387
00395 template <typename PointSource, typename PointTarget> inline int
00396 pcl::IterativeClosestPointNonLinear<PointSource, PointTarget>::functionToOptimizeIndices (void *p, int m, int n, const double *x, double *fvec, int iflag)
00397 {
00398 IterativeClosestPointNonLinear *model = (IterativeClosestPointNonLinear*)p;
00399
00400
00401 Eigen::Vector4f t (x[0], x[1], x[2], 1.0);
00402
00403 Eigen::Quaternionf q (0, x[3], x[4], x[5]);
00404 q.w () = sqrt (1 - q.dot (q));
00405
00406
00407
00408
00409
00410 Eigen::Matrix4f transformation_matrix = Eigen::Matrix4f::Zero ();
00411 transformation_matrix.topLeftCorner<3, 3> () = q.toRotationMatrix ();
00412 transformation_matrix.block <4, 1> (0, 3) = t;
00413
00414
00415 for (int i = 0; i < m; ++i)
00416 {
00417
00418 Vector4fMapConst p_src = model->tmp_src_->points[(*model->tmp_idx_src_)[i]].getVector4fMap ();
00419
00420 Vector4fMapConst p_tgt = model->tmp_tgt_->points[(*model->tmp_idx_tgt_)[i]].getVector4fMap ();
00421
00422 Eigen::Vector4f pp = transformation_matrix * p_src;
00423
00424
00425
00426 fvec[i] = model->distL1 (pp, p_tgt);
00427
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 return (0);
00442 }
00443