00001
00024 #include "ccny_rgbd/apps/keyframe_mapper.h"
00025
00026 namespace ccny_rgbd {
00027
00028 KeyframeMapper::KeyframeMapper(
00029 const ros::NodeHandle& nh,
00030 const ros::NodeHandle& nh_private):
00031 nh_(nh),
00032 nh_private_(nh_private),
00033 graph_detector_(nh_, nh_private_)
00034 {
00035 ROS_INFO("Starting RGBD Keyframe Mapper");
00036
00037
00038
00039 graph_solver_ = new KeyframeGraphSolverG2O(nh, nh_private);
00040
00041
00042
00043 if (!nh_private_.getParam ("queue_size", queue_size_))
00044 queue_size_ = 5;
00045 if (!nh_private_.getParam ("fixed_frame", fixed_frame_))
00046 fixed_frame_ = "/odom";
00047 if (!nh_private_.getParam ("pcd_map_res", pcd_map_res_))
00048 pcd_map_res_ = 0.01;
00049 if (!nh_private_.getParam ("octomap_res", octomap_res_))
00050 octomap_res_ = 0.05;
00051 if (!nh_private_.getParam ("octomap_with_color", octomap_with_color_))
00052 octomap_with_color_ = true;
00053 if (!nh_private_.getParam ("kf_dist_eps", kf_dist_eps_))
00054 kf_dist_eps_ = 0.10;
00055 if (!nh_private_.getParam ("kf_angle_eps", kf_angle_eps_))
00056 kf_angle_eps_ = 10.0 * M_PI / 180.0;
00057
00058
00059
00060 keyframes_pub_ = nh_.advertise<PointCloudT>(
00061 "keyframes", queue_size_);
00062 poses_pub_ = nh_.advertise<visualization_msgs::Marker>(
00063 "keyframe_poses", queue_size_);
00064 kf_assoc_pub_ = nh_.advertise<visualization_msgs::Marker>(
00065 "keyframe_associations", queue_size_);
00066 path_pub_ = nh_.advertise<PathMsg>(
00067 "keyframe_path", queue_size_);
00068
00069
00070 pub_keyframe_service_ = nh_.advertiseService(
00071 "publish_keyframe", &KeyframeMapper::publishKeyframeSrvCallback, this);
00072 pub_keyframes_service_ = nh_.advertiseService(
00073 "publish_keyframes", &KeyframeMapper::publishKeyframesSrvCallback, this);
00074 save_kf_service_ = nh_.advertiseService(
00075 "save_keyframes", &KeyframeMapper::saveKeyframesSrvCallback, this);
00076 load_kf_service_ = nh_.advertiseService(
00077 "load_keyframes", &KeyframeMapper::loadKeyframesSrvCallback, this);
00078
00079 save_pcd_map_service_ = nh_.advertiseService(
00080 "save_pcd_map", &KeyframeMapper::savePcdMapSrvCallback, this);
00081
00082 save_octomap_service_ = nh_.advertiseService(
00083 "save_octomap", &KeyframeMapper::saveOctomapSrvCallback, this);
00084
00085 add_manual_keyframe_service_ = nh_.advertiseService(
00086 "add_manual_keyframe", &KeyframeMapper::addManualKeyframeSrvCallback, this);
00087 generate_graph_service_ = nh_.advertiseService(
00088 "generate_graph", &KeyframeMapper::generateGraphSrvCallback, this);
00089 solve_graph_service_ = nh_.advertiseService(
00090 "solve_graph", &KeyframeMapper::solveGraphSrvCallback, this);
00091
00092
00093
00094 ImageTransport rgb_it(nh_);
00095 ImageTransport depth_it(nh_);
00096
00097 sub_rgb_.subscribe(rgb_it, "/rgbd/rgb", queue_size_);
00098 sub_depth_.subscribe(depth_it, "/rgbd/depth", queue_size_);
00099 sub_info_.subscribe(nh_, "/rgbd/info", queue_size_);
00100
00101
00102 sync_.reset(new RGBDSynchronizer3(
00103 RGBDSyncPolicy3(queue_size_), sub_rgb_, sub_depth_, sub_info_));
00104
00105 sync_->registerCallback(boost::bind(&KeyframeMapper::RGBDCallback, this, _1, _2, _3));
00106 }
00107
00108 KeyframeMapper::~KeyframeMapper()
00109 {
00110 delete graph_solver_;
00111 }
00112
00113 void KeyframeMapper::RGBDCallback(
00114 const ImageMsg::ConstPtr& rgb_msg,
00115 const ImageMsg::ConstPtr& depth_msg,
00116 const CameraInfoMsg::ConstPtr& info_msg)
00117 {
00118 tf::StampedTransform transform;
00119
00120 const ros::Time& time = rgb_msg->header.stamp;
00121
00122 try{
00123 tf_listener_.waitForTransform(
00124 fixed_frame_, rgb_msg->header.frame_id, time, ros::Duration(0.1));
00125 tf_listener_.lookupTransform(
00126 fixed_frame_, rgb_msg->header.frame_id, time, transform);
00127 }
00128 catch(...)
00129 {
00130 return;
00131 }
00132 RGBDFrame frame(rgb_msg, depth_msg, info_msg);
00133 bool result = processFrame(frame, transform);
00134 if (result) publishKeyframeData(keyframes_.size() - 1);
00135 }
00136
00137 bool KeyframeMapper::processFrame(
00138 const RGBDFrame& frame,
00139 const tf::Transform& pose)
00140 {
00141 bool result;
00142
00143 if(keyframes_.empty() || manual_add_)
00144 {
00145 result = true;
00146 }
00147 else
00148 {
00149 double dist, angle;
00150 getTfDifference(pose, keyframes_.back().pose, dist, angle);
00151
00152 if (dist > kf_dist_eps_ || angle > kf_angle_eps_)
00153 result = true;
00154 else
00155 result = false;
00156 }
00157
00158 if (result)
00159 {
00160 addKeyframe(frame, pose);
00161 publishPath();
00162 }
00163 return result;
00164 }
00165
00166 void KeyframeMapper::addKeyframe(
00167 const RGBDFrame& frame,
00168 const tf::Transform& pose)
00169 {
00170 RGBDKeyframe keyframe(frame);
00171 keyframe.pose = pose;
00172
00173 if (manual_add_)
00174 {
00175 ROS_INFO("Adding frame manually");
00176 manual_add_ = false;
00177 keyframe.manually_added = true;
00178 }
00179 keyframes_.push_back(keyframe);
00180 }
00181
00182 bool KeyframeMapper::publishKeyframeSrvCallback(
00183 PublishKeyframe::Request& request,
00184 PublishKeyframe::Response& response)
00185 {
00186 int kf_idx = request.id;
00187
00188 if (kf_idx >= 0 && kf_idx < (int)keyframes_.size())
00189 {
00190 ROS_INFO("Publishing keyframe %d", kf_idx);
00191 publishKeyframeData(kf_idx);
00192 publishKeyframePose(kf_idx);
00193 return true;
00194 }
00195 else
00196 {
00197 ROS_ERROR("Index out of range");
00198 return false;
00199 }
00200 }
00201
00202 bool KeyframeMapper::publishKeyframesSrvCallback(
00203 PublishKeyframes::Request& request,
00204 PublishKeyframes::Response& response)
00205 {
00206
00207
00208
00209 bool found_match = false;
00210
00211 boost::regex expression(request.re);
00212
00213 for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00214 {
00215 std::stringstream ss;
00216 ss << kf_idx;
00217 std::string kf_idx_string = ss.str();
00218
00219 boost::smatch match;
00220
00221 if(boost::regex_match(kf_idx_string, match, expression))
00222 {
00223 found_match = true;
00224 ROS_INFO("Publishing keyframe %d", kf_idx);
00225 publishKeyframeData(kf_idx);
00226 publishKeyframePose(kf_idx);
00227 usleep(25000);
00228 }
00229 }
00230
00231 return found_match;
00232 }
00233
00234 void KeyframeMapper::publishKeyframeData(int i)
00235 {
00236 RGBDKeyframe& keyframe = keyframes_[i];
00237
00238
00239 PointCloudT cloud;
00240 keyframe.constructDensePointCloud(cloud);
00241
00242
00243 PointCloudT cloud_ff;
00244 pcl::transformPointCloud(cloud, cloud_ff, eigenFromTf(keyframe.pose));
00245
00246 cloud_ff.header.frame_id = fixed_frame_;
00247
00248 keyframes_pub_.publish(cloud_ff);
00249 }
00250
00251 void KeyframeMapper::publishKeyframeAssociations()
00252 {
00253 visualization_msgs::Marker marker;
00254 marker.header.stamp = ros::Time::now();
00255 marker.header.frame_id = fixed_frame_;
00256 marker.id = 0;
00257 marker.type = visualization_msgs::Marker::LINE_LIST;
00258 marker.action = visualization_msgs::Marker::ADD;
00259
00260 marker.points.resize(associations_.size() * 2);
00261
00262 marker.color.a = 1.0;
00263
00264 for (unsigned int as_idx = 0; as_idx < associations_.size(); ++as_idx)
00265 {
00266
00267 const KeyframeAssociation& association = associations_[as_idx];
00268 int kf_idx_a = association.kf_idx_a;
00269 int kf_idx_b = association.kf_idx_b;
00270 RGBDKeyframe& keyframe_a = keyframes_[kf_idx_a];
00271 RGBDKeyframe& keyframe_b = keyframes_[kf_idx_b];
00272
00273 int idx_start = as_idx*2;
00274 int idx_end = as_idx*2 + 1;
00275
00276
00277 marker.points[idx_start].x = keyframe_a.pose.getOrigin().getX();
00278 marker.points[idx_start].y = keyframe_a.pose.getOrigin().getY();
00279 marker.points[idx_start].z = keyframe_a.pose.getOrigin().getZ();
00280
00281
00282 marker.points[idx_end].x = keyframe_b.pose.getOrigin().getX();
00283 marker.points[idx_end].y = keyframe_b.pose.getOrigin().getY();
00284 marker.points[idx_end].z = keyframe_b.pose.getOrigin().getZ();
00285
00286 if (association.type == KeyframeAssociation::VO)
00287 {
00288 marker.ns = "VO";
00289 marker.scale.x = 0.002;
00290
00291 marker.color.r = 0.0;
00292 marker.color.g = 1.0;
00293 marker.color.b = 0.0;
00294 }
00295 else if (association.type == KeyframeAssociation::RANSAC)
00296 {
00297 marker.ns = "RANSAC";
00298 marker.scale.x = 0.002;
00299
00300 marker.color.r = 1.0;
00301 marker.color.g = 1.0;
00302 marker.color.b = 0.0;
00303 }
00304
00305 kf_assoc_pub_.publish(marker);
00306 }
00307 }
00308
00309 void KeyframeMapper::publishKeyframePoses()
00310 {
00311 for(unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00312 {
00313 publishKeyframePose(kf_idx);
00314 }
00315 }
00316
00317 void KeyframeMapper::publishKeyframePose(int i)
00318 {
00319 RGBDKeyframe& keyframe = keyframes_[i];
00320
00321
00322
00323 visualization_msgs::Marker marker;
00324 marker.header.stamp = ros::Time::now();
00325 marker.header.frame_id = fixed_frame_;
00326 marker.ns = "keyframe_poses";
00327 marker.id = i;
00328 marker.type = visualization_msgs::Marker::ARROW;
00329 marker.action = visualization_msgs::Marker::ADD;
00330
00331 marker.points.resize(2);
00332
00333
00334 marker.points[0].x = keyframe.pose.getOrigin().getX();
00335 marker.points[0].y = keyframe.pose.getOrigin().getY();
00336 marker.points[0].z = keyframe.pose.getOrigin().getZ();
00337
00338
00339 tf::Transform ep;
00340 ep.setIdentity();
00341 ep.setOrigin(tf::Vector3(0.00, 0.00, 0.12));
00342 ep = keyframe.pose * ep;
00343
00344 marker.points[1].x = ep.getOrigin().getX();
00345 marker.points[1].y = ep.getOrigin().getY();
00346 marker.points[1].z = ep.getOrigin().getZ();
00347
00348 marker.scale.x = 0.02;
00349 marker.scale.y = 0.05;
00350
00351 marker.color.a = 1.0;
00352 marker.color.r = 0.0;
00353 marker.color.g = 1.0;
00354 marker.color.b = 0.0;
00355
00356 poses_pub_.publish(marker);
00357
00358
00359
00360 visualization_msgs::Marker marker_text;
00361 marker_text.header.stamp = ros::Time::now();
00362 marker_text.header.frame_id = fixed_frame_;
00363 marker_text.ns = "keyframe_indexes";
00364 marker_text.id = i;
00365 marker_text.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00366 marker_text.action = visualization_msgs::Marker::ADD;
00367
00368 tf::poseTFToMsg(keyframe.pose, marker_text.pose);
00369
00370 marker_text.pose.position.z -= 0.05;
00371
00372 char label[6];
00373 sprintf(label, "%d", i);
00374 marker_text.text = label;
00375
00376 marker_text.color.a = 1.0;
00377 marker_text.color.r = 1.0;
00378 marker_text.color.g = 1.0;
00379 marker_text.color.b = 0.0;
00380
00381 marker_text.scale.z = 0.05;
00382
00383 poses_pub_.publish(marker_text);
00384 }
00385
00386 bool KeyframeMapper::saveKeyframesSrvCallback(
00387 Save::Request& request,
00388 Save::Response& response)
00389 {
00390 ROS_INFO("Saving keyframes...");
00391 std::string path = request.filename;
00392 bool result = saveKeyframes(keyframes_, path);
00393
00394 if (result) ROS_INFO("Keyframes saved to %s", path.c_str());
00395 else ROS_ERROR("Keyframe saving failed!");
00396
00397 return result;
00398 }
00399
00400 bool KeyframeMapper::loadKeyframesSrvCallback(
00401 Load::Request& request,
00402 Load::Response& response)
00403 {
00404 ROS_INFO("Loading keyframes...");
00405 std::string path = request.filename;
00406 bool result = loadKeyframes(keyframes_, path);
00407
00408 if (result) ROS_INFO("Keyframes loaded successfully");
00409 else ROS_ERROR("Keyframe loading failed!");
00410
00411 return result;
00412 }
00413
00414 bool KeyframeMapper::savePcdMapSrvCallback(
00415 Save::Request& request,
00416 Save::Response& response)
00417 {
00418 ROS_INFO("Saving map as pcd...");
00419 const std::string& path = request.filename;
00420 bool result = savePcdMap(path);
00421
00422 if (result) ROS_INFO("Pcd map saved to %s", path.c_str());
00423 else ROS_ERROR("Pcd map saving failed");
00424
00425 return result;
00426 }
00427
00428 bool KeyframeMapper::saveOctomapSrvCallback(
00429 Save::Request& request,
00430 Save::Response& response)
00431 {
00432 ROS_INFO("Saving map as Octomap...");
00433 const std::string& path = request.filename;
00434 bool result = saveOctomap(path);
00435
00436 if (result) ROS_INFO("Octomap saved to %s", path.c_str());
00437 else ROS_ERROR("Octomap saving failed");
00438
00439 return result;
00440 }
00441
00442 bool KeyframeMapper::addManualKeyframeSrvCallback(
00443 AddManualKeyframe::Request& request,
00444 AddManualKeyframe::Response& response)
00445 {
00446 manual_add_ = true;
00447
00448 return true;
00449 }
00450
00451 bool KeyframeMapper::generateGraphSrvCallback(
00452 GenerateGraph::Request& request,
00453 GenerateGraph::Response& response)
00454 {
00455 associations_.clear();
00456 graph_detector_.generateKeyframeAssociations(keyframes_, associations_);
00457
00458 publishKeyframePoses();
00459 publishKeyframeAssociations();
00460
00461 return true;
00462 }
00463
00464 bool KeyframeMapper::solveGraphSrvCallback(
00465 SolveGraph::Request& request,
00466 SolveGraph::Response& response)
00467 {
00468 graph_solver_->solve(keyframes_, associations_);
00469
00470 publishKeyframePoses();
00471 publishKeyframeAssociations();
00472
00473 return true;
00474 }
00475
00476 bool KeyframeMapper::savePcdMap(const std::string& path)
00477 {
00478 PointCloudT pcd_map;
00479 buildPcdMap(pcd_map);
00480
00481
00482 pcl::PCDWriter writer;
00483 int result_pcd = writer.writeBinary<PointT>(path, pcd_map);
00484
00485 return result_pcd;
00486 }
00487
00488 void KeyframeMapper::buildPcdMap(PointCloudT& map_cloud)
00489 {
00490 PointCloudT::Ptr aggregate_cloud(new PointCloudT());
00491 aggregate_cloud->header.frame_id = fixed_frame_;
00492
00493
00494 for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00495 {
00496 const RGBDKeyframe& keyframe = keyframes_[kf_idx];
00497
00498 PointCloudT cloud;
00499 keyframe.constructDensePointCloud(cloud);
00500
00501 PointCloudT cloud_tf;
00502 pcl::transformPointCloud(cloud, cloud_tf, eigenFromTf(keyframe.pose));
00503 cloud_tf.header.frame_id = fixed_frame_;
00504
00505 *aggregate_cloud += cloud_tf;
00506 }
00507
00508
00509 pcl::VoxelGrid<PointT> vgf;
00510 vgf.setInputCloud(aggregate_cloud);
00511 vgf.setLeafSize(pcd_map_res_, pcd_map_res_, pcd_map_res_);
00512 vgf.filter(map_cloud);
00513 }
00514
00515 bool KeyframeMapper::saveOctomap(const std::string& path)
00516 {
00517 bool result;
00518
00519 if (octomap_with_color_)
00520 {
00521 octomap::ColorOcTree tree(octomap_res_);
00522 buildColorOctomap(tree);
00523 result = tree.write(path);
00524 }
00525 else
00526 {
00527 octomap::OcTree tree(octomap_res_);
00528 buildOctomap(tree);
00529 result = tree.write(path);
00530 }
00531
00532 return result;
00533 }
00534
00535 void KeyframeMapper::buildOctomap(octomap::OcTree& tree)
00536 {
00537 ROS_INFO("Building Octomap...");
00538
00539 octomap::point3d sensor_origin(0.0, 0.0, 0.0);
00540
00541 for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00542 {
00543 ROS_INFO("Processing keyframe %u", kf_idx);
00544 const RGBDKeyframe& keyframe = keyframes_[kf_idx];
00545
00546 PointCloudT cloud;
00547 keyframe.constructDensePointCloud(cloud);
00548
00549 octomap::pose6d frame_origin = poseTfToOctomap(keyframe.pose);
00550
00551
00552 octomap::Pointcloud octomap_cloud;
00553 for (unsigned int pt_idx = 0; pt_idx < cloud.points.size(); ++pt_idx)
00554 {
00555 const PointT& p = cloud.points[pt_idx];
00556 if (!std::isnan(p.z))
00557 octomap_cloud.push_back(p.x, p.y, p.z);
00558 }
00559
00560 tree.insertScan(octomap_cloud, sensor_origin, frame_origin);
00561 }
00562 }
00563
00564 void KeyframeMapper::buildColorOctomap(octomap::ColorOcTree& tree)
00565 {
00566 ROS_INFO("Building Octomap with color...");
00567
00568 octomap::point3d sensor_origin(0.0, 0.0, 0.0);
00569
00570 for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00571 {
00572 ROS_INFO("Processing keyframe %u", kf_idx);
00573 const RGBDKeyframe& keyframe = keyframes_[kf_idx];
00574
00575 PointCloudT cloud;
00576 keyframe.constructDensePointCloud(cloud);
00577
00578 octomap::pose6d frame_origin = poseTfToOctomap(keyframe.pose);
00579
00580
00581 octomap::Pointcloud octomap_cloud;
00582 for (unsigned int pt_idx = 0; pt_idx < cloud.points.size(); ++pt_idx)
00583 {
00584 const PointT& p = cloud.points[pt_idx];
00585 if (!std::isnan(p.z))
00586 octomap_cloud.push_back(p.x, p.y, p.z);
00587 }
00588
00589
00590 tree.insertScan(octomap_cloud, sensor_origin, frame_origin);
00591
00592
00593 PointCloudT cloud_tf;
00594 pcl::transformPointCloud(cloud, cloud_tf, eigenFromTf(keyframe.pose));
00595 for (unsigned int pt_idx = 0; pt_idx < cloud_tf.points.size(); ++pt_idx)
00596 {
00597 const PointT& p = cloud_tf.points[pt_idx];
00598 if (!std::isnan(p.z))
00599 {
00600 octomap::point3d endpoint(p.x, p.y, p.z);
00601 octomap::ColorOcTreeNode* n = tree.search(endpoint);
00602 if (n) n->setColor(p.r, p.g, p.b);
00603 }
00604 }
00605
00606 tree.updateInnerOccupancy();
00607 }
00608 }
00609
00610 void KeyframeMapper::publishPath()
00611 {
00612 path_msg_.header.frame_id = fixed_frame_;
00613 path_msg_.poses.clear();
00614 path_msg_.poses.resize(keyframes_.size());
00615
00616 for(unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++ kf_idx)
00617 {
00618 const RGBDKeyframe& keyframe = keyframes_[kf_idx];
00619 geometry_msgs::PoseStamped& pose_stamped = path_msg_.poses[kf_idx];
00620
00621 pose_stamped.header.stamp = keyframe.header.stamp;
00622 pose_stamped.header.frame_id = fixed_frame_;
00623 tf::poseTFToMsg(keyframe.pose, pose_stamped.pose);
00624 }
00625
00626 path_pub_.publish(path_msg_);
00627 }
00628
00629 }