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 #include "jsk_pcl_ros/icp_registration.h"
00037 #include <pcl/registration/icp.h>
00038 #include <pcl/registration/gicp.h>
00039 #include <pcl/registration/ndt.h>
00040 #include <pcl/registration/transformation_estimation_lm.h>
00041 #include <pcl/registration/warp_point_rigid_3d.h>
00042 #include "jsk_recognition_utils/pcl_conversion_util.h"
00043 #include <eigen_conversions/eigen_msg.h>
00044 #include <pcl/common/transforms.h>
00045 #include <eigen_conversions/eigen_msg.h>
00046 #include "jsk_pcl_ros_utils/transform_pointcloud_in_bounding_box.h"
00047 #include <image_geometry/pinhole_camera_model.h>
00048 #include <pcl/registration/correspondence_estimation_organized_projection.h>
00049 #include <pcl/registration/correspondence_estimation_normal_shooting.h>
00050 #include <jsk_recognition_utils/pcl_ros_util.h>
00051
00052 namespace jsk_pcl_ros
00053 {
00054 void ICPRegistration::onInit()
00055 {
00056 pcl::console::setVerbosityLevel(pcl::console::L_ERROR);
00057 ConnectionBasedNodelet::onInit();
00058 tf_listener_ = TfListenerSingleton::getInstance();
00060
00062 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00063 dynamic_reconfigure::Server<Config>::CallbackType f =
00064 boost::bind(
00065 &ICPRegistration::configCallback, this, _1, _2);
00066 srv_->setCallback (f);
00067 pnh_->param("use_normal", use_normal_, false);
00068 pnh_->param("align_box", align_box_, false);
00069 pnh_->param("synchronize_reference", synchronize_reference_, false);
00070 pnh_->param("transform_3dof", transform_3dof_, false);
00071 pnh_->param("use_offset_pose", use_offset_pose_, false);
00073
00075 pub_result_pose_ = advertise<geometry_msgs::PoseStamped>(*pnh_,
00076 "output_pose", 1);
00077 pub_result_cloud_ = advertise<sensor_msgs::PointCloud2>(*pnh_,
00078 "output", 1);
00079 pub_debug_source_cloud_ = advertise<sensor_msgs::PointCloud2>(*pnh_,
00080 "debug/source", 1);
00081 pub_debug_target_cloud_ = advertise<sensor_msgs::PointCloud2>(*pnh_,
00082 "debug/target", 1);
00083 pub_debug_flipped_cloud_ = advertise<sensor_msgs::PointCloud2>(*pnh_,
00084 "debug/flipped", 1);
00085 pub_debug_result_cloud_ = advertise<sensor_msgs::PointCloud2>(*pnh_,
00086 "debug/result", 1);
00087 pub_icp_result = advertise<jsk_recognition_msgs::ICPResult>(*pnh_,
00088 "icp_result", 1);
00089 pub_latest_time_ = advertise<std_msgs::Float32>(
00090 *pnh_, "output/latest_time", 1);
00091 pub_average_time_ = advertise<std_msgs::Float32>(
00092 *pnh_, "output/average_time", 1);
00093 srv_icp_align_with_box_ = pnh_->advertiseService("icp_service", &ICPRegistration::alignWithBoxService, this);
00094 srv_icp_align_ = pnh_->advertiseService(
00095 "icp_align", &ICPRegistration::alignService, this);
00096 if (!synchronize_reference_) {
00097 sub_reference_ = pnh_->subscribe("input_reference", 1,
00098 &ICPRegistration::referenceCallback,
00099 this);
00100 sub_reference_array_ = pnh_->subscribe("input_reference_array", 1,
00101 &ICPRegistration::referenceArrayCallback,
00102 this);
00103 sub_reference_add = pnh_->subscribe("input_reference_add", 1,
00104 &ICPRegistration::referenceAddCallback,
00105 this);
00106 }
00107 done_init_ = true;
00108 onInitPostProcess();
00109 }
00110
00111 void ICPRegistration::subscribe()
00112 {
00114
00116 sub_camera_info_ = pnh_->subscribe("input/camera_info", 1,
00117 &ICPRegistration::cameraInfoCallback,
00118 this);
00119 if (!synchronize_reference_) {
00120 if (align_box_) {
00121 sub_input_.subscribe(*pnh_, "input", 1);
00122 sub_box_.subscribe(*pnh_, "input_box", 1);
00123 sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00124 sync_->connectInput(sub_input_, sub_box_);
00125 sync_->registerCallback(boost::bind(
00126 &ICPRegistration::alignWithBox,
00127 this, _1, _2));
00128 }
00129 else if (use_offset_pose_) {
00130 sub_input_.subscribe(*pnh_, "input", 1);
00131 sub_offset_.subscribe(*pnh_, "input_offset", 1);
00132 sync_offset_ = boost::make_shared<message_filters::Synchronizer<OffsetSyncPolicy> >(100);
00133 sync_offset_->connectInput(sub_input_, sub_offset_);
00134 sync_offset_->registerCallback(boost::bind(&ICPRegistration::alignWithOffset, this, _1, _2));
00135 }
00136 else {
00137 sub_ = pnh_->subscribe("input", 1,
00138 &ICPRegistration::align,
00139 this);
00140 }
00141 }
00142 else {
00143 sub_sync_input_.subscribe(*pnh_, "input", 1);
00144 sub_sync_reference_.subscribe(*pnh_, "reference", 1);
00145 sync_reference_ = boost::make_shared<message_filters::Synchronizer<ReferenceSyncPolicy> >(100);
00146 sync_reference_->connectInput(sub_sync_input_, sub_sync_reference_);
00147 sync_reference_->registerCallback(boost::bind(&ICPRegistration::align, this, _1, _2));
00148 }
00149 }
00150
00151 void ICPRegistration::unsubscribe()
00152 {
00153 sub_camera_info_.shutdown();
00154 if (!synchronize_reference_) {
00155 if (align_box_) {
00156 sub_input_.unsubscribe();
00157 sub_box_.unsubscribe();
00158 }
00159 else {
00160 sub_.shutdown();
00161 }
00162 }
00163 else {
00164 sub_sync_input_.unsubscribe();
00165 sub_sync_reference_.unsubscribe();
00166 }
00167 }
00168
00169 void ICPRegistration::publishDebugCloud(
00170 ros::Publisher& pub,
00171 const pcl::PointCloud<PointT>& cloud)
00172 {
00173 if (pub.getNumSubscribers() > 0) {
00174 sensor_msgs::PointCloud2 ros_cloud;
00175 pcl::toROSMsg(cloud, ros_cloud);
00176 ros_cloud.header.frame_id = "base_link";
00177 ros_cloud.header.stamp = ros::Time::now();
00178 pub.publish(ros_cloud);
00179 }
00180 }
00181
00182 void ICPRegistration::configCallback(Config &config, uint32_t level)
00183 {
00184 boost::mutex::scoped_lock lock(mutex_);
00185 algorithm_ = config.algorithm;
00186 correspondence_algorithm_ = config.correspondence_algorithm;
00187 use_flipped_initial_pose_ = config.use_flipped_initial_pose;
00188 max_iteration_ = config.max_iteration;
00189 correspondence_distance_ = config.correspondence_distance;
00190 transform_epsilon_ = config.transform_epsilon;
00191 euclidean_fittness_epsilon_ = config.euclidean_fittness_epsilon;
00192 rotation_epsilon_ = config.rotation_epsilon;
00193 ransac_iterations_ = config.ransac_iterations;
00194 ransac_outlier_threshold_ = config.ransac_outlier_threshold;
00195 maximum_optimizer_iterations_ = config.maximum_optimizer_iterations;
00196 ndt_resolution_ = config.ndt_resolution;
00197 ndt_step_size_ = config.ndt_step_size;
00198 ndt_outlier_ratio_ = config.ndt_outlier_ratio;
00199 }
00200
00201 bool ICPRegistration::alignWithBoxService(
00202 jsk_recognition_msgs::ICPAlignWithBox::Request& req,
00203 jsk_recognition_msgs::ICPAlignWithBox::Response& res)
00204 {
00205 boost::mutex::scoped_lock lock(mutex_);
00206 if (reference_cloud_list_.size() == 0) {
00207 NODELET_FATAL("no reference is specified");
00208 return false;
00209 }
00210 try
00211 {
00212 Eigen::Affine3f offset;
00213 pcl::PointCloud<PointT>::Ptr output (new pcl::PointCloud<PointT>);
00214 jsk_pcl_ros_utils::transformPointcloudInBoundingBox<PointT>(
00215 req.target_box, req.target_cloud,
00216 *output, offset,
00217 *tf_listener_);
00218 Eigen::Affine3f inversed_offset = offset.inverse();
00219 res.result = alignPointcloudWithReferences(output, inversed_offset, req.target_cloud.header);
00220 }
00221 catch (tf2::ConnectivityException &e)
00222 {
00223 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00224 return false;
00225 }
00226 catch (tf2::InvalidArgumentException &e)
00227 {
00228 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00229 return false;
00230 }
00231 return true;
00232 }
00233
00234 bool ICPRegistration::alignService(
00235 jsk_recognition_msgs::ICPAlign::Request& req,
00236 jsk_recognition_msgs::ICPAlign::Response& res)
00237 {
00238 boost::mutex::scoped_lock lock(mutex_);
00239 std::vector<pcl::PointCloud<PointT>::Ptr> tmp_reference_cloud_list
00240 = reference_cloud_list_;
00241 try
00242 {
00243
00244 std::vector<pcl::PointCloud<PointT>::Ptr> new_references;
00245 pcl::PointCloud<PointT>::Ptr reference_cloud (new pcl::PointCloud<PointT>);
00246 pcl::fromROSMsg(req.reference_cloud, *reference_cloud);
00247 pcl::PointCloud<PointT>::Ptr non_nan_reference_cloud (new pcl::PointCloud<PointT>);
00248 for (size_t i = 0; i < reference_cloud->points.size(); i++) {
00249 PointT p = reference_cloud->points[i];
00250 if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
00251 non_nan_reference_cloud->points.push_back(p);
00252 }
00253 }
00254 new_references.push_back(non_nan_reference_cloud);
00255 reference_cloud_list_ = new_references;
00256 NODELET_INFO("reference points: %lu/%lu",
00257 non_nan_reference_cloud->points.size(),
00258 reference_cloud->points.size());
00259 Eigen::Affine3f offset = Eigen::Affine3f::Identity();
00260 pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
00261 pcl::fromROSMsg(req.target_cloud, *cloud);
00262 res.result = alignPointcloudWithReferences(cloud,
00263 offset,
00264 req.target_cloud.header);
00265 }
00266 catch (tf2::ConnectivityException &e)
00267 {
00268 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00269 reference_cloud_list_ = tmp_reference_cloud_list;
00270 return false;
00271 }
00272 catch (tf2::InvalidArgumentException &e)
00273 {
00274 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00275 reference_cloud_list_ = tmp_reference_cloud_list;
00276 return false;
00277 }
00278 reference_cloud_list_ = tmp_reference_cloud_list;
00279 return true;
00280 }
00281
00282
00283 void ICPRegistration::alignWithBox(
00284 const sensor_msgs::PointCloud2::ConstPtr& msg,
00285 const jsk_recognition_msgs::BoundingBox::ConstPtr& box_msg)
00286 {
00287 boost::mutex::scoped_lock lock(mutex_);
00288 if (!done_init_) {
00289 NODELET_WARN("not yet initialized");
00290 return;
00291 }
00292 if (reference_cloud_list_.size() == 0) {
00293 NODELET_FATAL("no reference is specified");
00294 jsk_recognition_msgs::ICPResult result;
00295 result.name = std::string("NONE");
00296 result.score = DBL_MAX;
00297 result.header = box_msg->header;
00298 result.pose = box_msg->pose;
00299 pub_icp_result.publish(result);
00300 return;
00301 }
00302 try
00303 {
00304 Eigen::Affine3f offset;
00305 pcl::PointCloud<PointT>::Ptr output (new pcl::PointCloud<PointT>);
00306 jsk_pcl_ros_utils::transformPointcloudInBoundingBox<PointT>(
00307 *box_msg, *msg,
00308 *output, offset,
00309 *tf_listener_);
00310 Eigen::Affine3f inversed_offset = offset.inverse();
00311 jsk_recognition_msgs::ICPResult result = alignPointcloudWithReferences(output, inversed_offset, msg->header);
00312 pub_icp_result.publish(result);
00313 }
00314 catch (tf2::ConnectivityException &e)
00315 {
00316 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00317 }
00318 catch (tf2::InvalidArgumentException &e)
00319 {
00320 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00321 }
00322 }
00323
00324 void ICPRegistration::alignWithOffset(
00325 const sensor_msgs::PointCloud2::ConstPtr& msg,
00326 const geometry_msgs::PoseStamped::ConstPtr& offset_msg)
00327 {
00328 boost::mutex::scoped_lock lock(mutex_);
00329 if (!done_init_) {
00330 NODELET_WARN("not yet initialized");
00331 return;
00332 }
00333 if (reference_cloud_list_.size() == 0) {
00334 NODELET_FATAL("no reference is specified");
00335 jsk_recognition_msgs::ICPResult result;
00336 result.name = std::string("NONE");
00337 result.score = DBL_MAX;
00338 result.header = offset_msg->header;
00339 result.pose = offset_msg->pose;
00340 pub_icp_result.publish(result);
00341 return;
00342 }
00343 try
00344 {
00345 if (!jsk_recognition_utils::isSameFrameId(msg->header.frame_id,
00346 offset_msg->header.frame_id)) {
00347 NODELET_ERROR("frame_id does not match. cloud: %s, pose: %s",
00348 msg->header.frame_id.c_str(),
00349 offset_msg->header.frame_id.c_str());
00350 return;
00351 }
00352 Eigen::Affine3f offset;
00353 pcl::PointCloud<PointT>::Ptr input (new pcl::PointCloud<PointT>);
00354 pcl::fromROSMsg(*msg, *input);
00355 pcl::PointCloud<PointT>::Ptr output (new pcl::PointCloud<PointT>);
00356 tf::poseMsgToEigen(offset_msg->pose, offset);
00357
00358 Eigen::Affine3f inversed_offset = offset.inverse();
00359 pcl::transformPointCloud(*input, *output, inversed_offset);
00360 jsk_recognition_msgs::ICPResult result = alignPointcloudWithReferences(output, offset, msg->header);
00361 pub_icp_result.publish(result);
00362 }
00363 catch (tf2::ConnectivityException &e)
00364 {
00365 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00366 }
00367 catch (tf2::InvalidArgumentException &e)
00368 {
00369 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00370 }
00371 }
00372
00373
00374 void ICPRegistration::align(const sensor_msgs::PointCloud2::ConstPtr& msg)
00375 {
00376 boost::mutex::scoped_lock lock(mutex_);
00377 if (!done_init_) {
00378 NODELET_WARN("not yet initialized");
00379 return;
00380 }
00381 if (reference_cloud_list_.size() == 0) {
00382 NODELET_FATAL("no reference is specified");
00383 return;
00384 }
00385
00386 pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
00387 pcl::fromROSMsg(*msg, *cloud);
00388 Eigen::Affine3f offset = Eigen::Affine3f::Identity();
00389
00390 pcl::PointCloud<PointT>::Ptr non_nan_cloud (new pcl::PointCloud<PointT>);
00391 for (size_t i = 0; i < cloud->points.size(); i++) {
00392 PointT p = cloud->points[i];
00393 if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
00394 non_nan_cloud->points.push_back(p);
00395 }
00396 }
00397 jsk_recognition_msgs::ICPResult result = alignPointcloudWithReferences(non_nan_cloud, offset, msg->header);
00398 pub_icp_result.publish(result);
00399 }
00400
00401 void ICPRegistration::align(const sensor_msgs::PointCloud2::ConstPtr& msg,
00402 const sensor_msgs::PointCloud2::ConstPtr& reference_msg)
00403 {
00404 {
00405 boost::mutex::scoped_lock lock(mutex_);
00406 if (!done_init_) {
00407 NODELET_WARN("not yet initialized");
00408 return;
00409 }
00410 reference_cloud_list_.resize(0);
00411 pcl::PointCloud<PointT>::Ptr reference_cloud (new pcl::PointCloud<PointT>);
00412 pcl::fromROSMsg(*reference_msg, *reference_cloud);
00413
00414 pcl::PointCloud<PointT>::Ptr non_nan_reference_cloud (new pcl::PointCloud<PointT>);
00415 for (size_t i = 0; i < reference_cloud->points.size(); i++) {
00416 PointT p = reference_cloud->points[i];
00417 if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
00418 non_nan_reference_cloud->points.push_back(p);
00419 }
00420 }
00421 reference_cloud_list_.push_back(non_nan_reference_cloud);
00422 }
00423 align(msg);
00424 }
00425
00426 jsk_recognition_msgs::ICPResult ICPRegistration::alignPointcloudWithReferences(
00427 pcl::PointCloud<PointT>::Ptr& cloud,
00428 const Eigen::Affine3f& offset,
00429 const std_msgs::Header& header)
00430 {
00431 jsk_recognition_utils::ScopedWallDurationReporter r
00432 = timer_.reporter(pub_latest_time_, pub_average_time_);
00433 double min_score = DBL_MAX;
00434 size_t max_index = 0;
00435 pcl::PointCloud<PointT>::Ptr best_transformed_cloud;
00436 pcl::PointCloud<PointT>::Ptr best_reference;
00437 Eigen::Affine3d best_transform_result;
00438 Eigen::Affine3f best_offset_result;
00439 jsk_recognition_msgs::ICPResult result;
00440 if (cloud->empty()) {
00441 sensor_msgs::PointCloud2 empty_cloud;
00442 empty_cloud.header = header;
00443 pub_result_cloud_.publish(empty_cloud);
00444
00445 pcl::PointCloud<PointT> empty_pcl_cloud;
00446 publishDebugCloud(pub_debug_source_cloud_, empty_pcl_cloud);
00447 publishDebugCloud(pub_debug_target_cloud_, empty_pcl_cloud);
00448 publishDebugCloud(pub_debug_result_cloud_, empty_pcl_cloud);
00449
00450 geometry_msgs::PoseStamped empty_pose;
00451 empty_pose.header = header;
00452 pub_result_pose_.publish(empty_pose);
00453
00454 result.header = header;
00455 result.score = min_score;
00456 result.name = "nan";
00457 return result;
00458 }
00459 for (size_t i = 0; i < reference_cloud_list_.size(); i++) {
00460 Eigen::Affine3f offset_result;
00461 pcl::PointCloud<PointT>::Ptr transformed_cloud(new pcl::PointCloud<PointT>);
00462 Eigen::Affine3d transform_result;
00463 double score = scorePointcloudAlignment(
00464 cloud,
00465 reference_cloud_list_[i],
00466 offset,
00467 offset_result,
00468 transformed_cloud,
00469 transform_result);
00470 if (score < min_score) {
00471 max_index = i;
00472 min_score = score;
00473 best_transform_result = transform_result;
00474 best_transformed_cloud = transformed_cloud;
00475 best_reference = reference_cloud_list_[i];
00476 best_offset_result = offset_result;
00477 }
00478 }
00479
00480 NODELET_INFO("best score is: %f", min_score);
00481 if (pub_result_cloud_.getNumSubscribers() > 0) {
00482 sensor_msgs::PointCloud2 ros_final;
00483 pcl::toROSMsg(*best_transformed_cloud, ros_final);
00484 ros_final.header = header;
00485 pub_result_cloud_.publish(ros_final);
00486 }
00487 geometry_msgs::PoseStamped ros_result_pose;
00488 ros_result_pose.header = header;
00489 tf::poseEigenToMsg(best_transform_result, ros_result_pose.pose);
00490 pub_result_pose_.publish(ros_result_pose);
00491 publishDebugCloud(pub_debug_source_cloud_, *best_reference);
00492 publishDebugCloud(pub_debug_target_cloud_, *cloud);
00493 pcl::PointCloud<PointT>::Ptr transformed_cloud_for_debug_result
00494 (new pcl::PointCloud<PointT>);
00495 pcl::transformPointCloud(
00496 *best_transformed_cloud, *transformed_cloud_for_debug_result,
00497 best_offset_result.inverse());
00498 publishDebugCloud(pub_debug_result_cloud_,
00499 *transformed_cloud_for_debug_result);
00500 result.header = ros_result_pose.header;
00501 result.pose = ros_result_pose.pose;
00502 result.score = min_score;
00503 std::stringstream ss;
00504 ss << max_index;
00505 result.name = ss.str();
00506 return result;
00507 }
00508
00509 void ICPRegistration::cameraInfoCallback(
00510 const sensor_msgs::CameraInfo::ConstPtr& msg)
00511 {
00512 boost::mutex::scoped_lock lock(mutex_);
00513 camera_info_msg_ = msg;
00514 }
00515
00516 double ICPRegistration::alignPointcloud(
00517 pcl::PointCloud<PointT>::Ptr& cloud,
00518 pcl::PointCloud<PointT>::Ptr& reference,
00519 const Eigen::Affine3f& offset,
00520 pcl::PointCloud<PointT>::Ptr& output_cloud,
00521 Eigen::Affine3d& output_transform)
00522 {
00523 if (algorithm_ == 0 || algorithm_ == 1) {
00524 return alignPointcloudWithICP(cloud, reference, offset, output_cloud, output_transform);
00525 }
00526 else {
00527 return alignPointcloudWithNDT(cloud, reference, offset, output_cloud, output_transform);
00528 }
00529 }
00530
00531
00532 double ICPRegistration::alignPointcloudWithNDT(
00533 pcl::PointCloud<PointT>::Ptr& cloud,
00534 pcl::PointCloud<PointT>::Ptr& reference,
00535 const Eigen::Affine3f& offset,
00536 pcl::PointCloud<PointT>::Ptr& output_cloud,
00537 Eigen::Affine3d& output_transform)
00538 {
00539 pcl::NormalDistributionsTransform<PointT, PointT> ndt;
00540 if (reference->points.empty ()) {
00541 NODELET_ERROR("Input Reference Cloud is empty!");
00542 return DBL_MAX;
00543 }
00544 ndt.setInputSource(reference);
00545 if (cloud->points.empty ()) {
00546 NODELET_ERROR("Input Target Cloud is empty!");
00547 return DBL_MAX;
00548 }
00549 ndt.setInputTarget(cloud);
00550 pcl::PointCloud<PointT> final;
00551 ndt.align(final);
00552 pcl::transformPointCloud(final, *output_cloud, offset);
00553 Eigen::Matrix4f transformation = ndt.getFinalTransformation ();
00554 Eigen::Matrix4d transformation_d;
00555 jsk_recognition_utils::convertMatrix4<Eigen::Matrix4f, Eigen::Matrix4d>(
00556 transformation, transformation_d);
00557 Eigen::Affine3d offsetd;
00558 convertEigenAffine3(offset, offsetd);
00559 output_transform = offsetd * Eigen::Affine3d(transformation_d);
00560 return ndt.getFitnessScore();
00561 }
00562
00563 double ICPRegistration::alignPointcloudWithICP(
00564 pcl::PointCloud<PointT>::Ptr& cloud,
00565 pcl::PointCloud<PointT>::Ptr& reference,
00566 const Eigen::Affine3f& offset,
00567 pcl::PointCloud<PointT>::Ptr& output_cloud,
00568 Eigen::Affine3d& output_transform)
00569 {
00570 pcl::IterativeClosestPoint<PointT, PointT> icp;
00571 if (use_normal_) {
00572 pcl::IterativeClosestPointWithNormals<PointT, PointT> icp_with_normal;
00573 icp = icp_with_normal;
00574 }
00575
00576
00577 if (algorithm_ == 1) {
00578 pcl::GeneralizedIterativeClosestPoint<PointT, PointT> gicp;
00579 gicp.setRotationEpsilon(rotation_epsilon_);
00580 gicp.setCorrespondenceRandomness(correspondence_randomness_);
00581 gicp.setMaximumOptimizerIterations(maximum_optimizer_iterations_);
00582 icp = gicp;
00583 }
00584 if (correspondence_algorithm_ == 1) {
00585 if (!camera_info_msg_) {
00586 NODELET_ERROR("no camera info is available yet");
00587 return DBL_MAX;
00588 }
00589 image_geometry::PinholeCameraModel model;
00590 bool model_success_p = model.fromCameraInfo(camera_info_msg_);
00591 if (!model_success_p) {
00592 NODELET_ERROR("failed to create camera model");
00593 return DBL_MAX;
00594 }
00595 pcl::registration::CorrespondenceEstimationOrganizedProjection<PointT, PointT, float>::Ptr
00596 corr_projection (new pcl::registration::CorrespondenceEstimationOrganizedProjection<PointT, PointT, float>);
00597 corr_projection->setFocalLengths(model.fx(), model.fy());
00598 corr_projection->setCameraCenters(model.cx(), model.cy());
00599 icp.setCorrespondenceEstimation(corr_projection);
00600 }
00601
00602 if (reference->points.empty ()) {
00603 NODELET_ERROR("Input Reference Cloud is empty!");
00604 return DBL_MAX;
00605 }
00606 icp.setInputSource(reference);
00607 if (cloud->points.empty ()) {
00608 NODELET_ERROR("Input Target Cloud is empty!");
00609 return DBL_MAX;
00610 }
00611 icp.setInputTarget(cloud);
00612
00613 if (transform_3dof_) {
00614 boost::shared_ptr<pcl::registration::WarpPointRigid3D<PointT, PointT> > warp_func
00615 (new pcl::registration::WarpPointRigid3D<PointT, PointT>);
00616 boost::shared_ptr<pcl::registration::TransformationEstimationLM<PointT, PointT> > te
00617 (new pcl::registration::TransformationEstimationLM<PointT, PointT>);
00618 te->setWarpFunction(warp_func);
00619 icp.setTransformationEstimation(te);
00620 }
00621
00622 icp.setMaxCorrespondenceDistance (correspondence_distance_);
00623 icp.setMaximumIterations (max_iteration_);
00624 icp.setTransformationEpsilon (transform_epsilon_);
00625 icp.setEuclideanFitnessEpsilon (euclidean_fittness_epsilon_);
00626 icp.setRANSACIterations(ransac_iterations_);
00627 icp.setRANSACOutlierRejectionThreshold(ransac_outlier_threshold_);
00628 pcl::PointCloud<PointT> final;
00629 icp.align(final);
00630 pcl::transformPointCloud(final, *output_cloud, offset);
00631
00632
00633 Eigen::Matrix4f transformation = icp.getFinalTransformation ();
00634 Eigen::Matrix4d transformation_d;
00635 jsk_recognition_utils::convertMatrix4<Eigen::Matrix4f, Eigen::Matrix4d>(
00636 transformation, transformation_d);
00637 Eigen::Affine3d offsetd;
00638 convertEigenAffine3(offset, offsetd);
00639 output_transform = offsetd * Eigen::Affine3d(transformation_d);
00640 return icp.getFitnessScore();
00641 }
00642
00643
00644 double ICPRegistration::scorePointcloudAlignment(
00645 pcl::PointCloud<PointT>::Ptr& cloud,
00646 pcl::PointCloud<PointT>::Ptr& reference,
00647 const Eigen::Affine3f& offset,
00648 Eigen::Affine3f& offset_result,
00649 pcl::PointCloud<PointT>::Ptr transformed_cloud,
00650 Eigen::Affine3d& transform_result)
00651 {
00652 pcl::PointCloud<PointT>::Ptr transformed_cloud_for_debug_result
00653 (new pcl::PointCloud<PointT>);
00654 double score = alignPointcloud(cloud, reference, offset,
00655 transformed_cloud, transform_result);
00656 pcl::transformPointCloud(
00657 *transformed_cloud, *transformed_cloud_for_debug_result,
00658 offset.inverse());
00659 offset_result = offset;
00660 if (use_flipped_initial_pose_) {
00661 pcl::PointCloud<PointT>::Ptr flipped_transformed_cloud
00662 (new pcl::PointCloud<PointT>);
00663 Eigen::Affine3d flipped_transform_result;
00664 Eigen::Affine3f flipped_offset
00665 = offset * Eigen::AngleAxisf(M_PI, Eigen::Vector3f(0, 0, 1));
00666 pcl::PointCloud<PointT>::Ptr flipped_cloud (new pcl::PointCloud<PointT>);
00667 pcl::transformPointCloud(
00668 *cloud, *flipped_cloud,
00669 Eigen::Affine3f(Eigen::AngleAxisf(M_PI, Eigen::Vector3f(0, 0, 1))));
00670 double flipped_score
00671 = alignPointcloud(flipped_cloud, reference, flipped_offset,
00672 flipped_transformed_cloud,
00673 flipped_transform_result);
00674 NODELET_INFO("flipped score: %f", flipped_score);
00675 if (flipped_score < score) {
00676 score = flipped_score;
00677 transformed_cloud = flipped_transformed_cloud;
00678 transform_result = flipped_transform_result;
00679 pcl::transformPointCloud(
00680 *transformed_cloud, *transformed_cloud_for_debug_result,
00681 flipped_offset.inverse());
00682 offset_result = flipped_offset;
00683 }
00684 }
00685 return score;
00686 }
00687
00688 void ICPRegistration::referenceCallback(
00689 const sensor_msgs::PointCloud2::ConstPtr& msg)
00690 {
00691 boost::mutex::scoped_lock lock(mutex_);
00692 if (!done_init_) {
00693 NODELET_WARN("not yet initialized");
00694 return;
00695 }
00696 reference_cloud_list_.resize(0);
00697 pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
00698 pcl::fromROSMsg(*msg, *cloud);
00699 pcl::PointCloud<PointT>::Ptr non_nan_cloud (new pcl::PointCloud<PointT>);
00700 for (size_t i = 0; i < cloud->points.size(); i++) {
00701 PointT p = cloud->points[i];
00702 if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
00703 non_nan_cloud->points.push_back(p);
00704 }
00705 }
00706 reference_cloud_list_.push_back(non_nan_cloud);
00707 }
00708
00709 void ICPRegistration::referenceArrayCallback(
00710 const jsk_recognition_msgs::PointsArray::ConstPtr& msg)
00711 {
00712 boost::mutex::scoped_lock lock(mutex_);
00713 if (!done_init_) {
00714 NODELET_WARN("not yet initialized");
00715 return;
00716 }
00717 reference_cloud_list_.resize(0);
00718 for (size_t i = 0; i < msg->cloud_list.size(); i++) {
00719 pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
00720 pcl::fromROSMsg(msg->cloud_list[i], *cloud);
00721 reference_cloud_list_.push_back(cloud);
00722 }
00723 }
00724
00725 void ICPRegistration::referenceAddCallback(
00726 const sensor_msgs::PointCloud2::ConstPtr& msg)
00727 {
00728 boost::mutex::scoped_lock lock(mutex_);
00729 if (!done_init_) {
00730 NODELET_WARN("not yet initialized");
00731 return;
00732 }
00733
00734 pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
00735 pcl::fromROSMsg(*msg, *cloud);
00736 reference_cloud_list_.push_back(cloud);
00737 ROS_INFO("reference_num: %zd", reference_cloud_list_.size()-1);
00738 }
00739 }
00740
00741 #include <pluginlib/class_list_macros.h>
00742 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::ICPRegistration, nodelet::Nodelet);