keyframe_mapper.cpp
Go to the documentation of this file.
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   // **** init variables
00038 
00039   graph_solver_ = new KeyframeGraphSolverG2O(nh, nh_private);
00040   
00041   // **** params
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   // **** publishers
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   // **** services
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   // **** subscribers
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   // Synchronize inputs.
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; // if true, add new frame
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   // regex matching - try match the request string against each
00207   // keyframe index
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   // construct a cloud from the images
00239   PointCloudT cloud;
00240   keyframe.constructDensePointCloud(cloud);
00241   
00242   // cloud transformed to the fixed frame
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     // set up shortcut references
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     // start point for the edge
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     // end point for the edge
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   // **** publish camera pose
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   // start point for the arrow
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   // end point for the arrow
00339   tf::Transform ep; 
00340   ep.setIdentity();
00341   ep.setOrigin(tf::Vector3(0.00, 0.00, 0.12)); // z = arrow length
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; // shaft radius
00349   marker.scale.y = 0.05; // head radius
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   // **** publish frame index text
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; // shaft radius
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   // write out
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   // aggregate all frames into single cloud
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   // filter cloud
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     // build octomap cloud from pcl cloud
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     // build octomap cloud from pcl cloud
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     // insert scan (only xyz considered, no colors)
00590     tree.insertScan(octomap_cloud, sensor_origin, frame_origin);
00591     
00592     // insert colors
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 } // namespace ccny_rgbd
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends


ccny_rgbd
Author(s): Ivan Dryanovski
autogenerated on Fri Apr 12 2013 20:38:48