keyframe_mapper.cpp
Go to the documentation of this file.
00001 
00024 #include "ccny_rgbd/apps/keyframe_mapper.h"
00025 #include "aruco/aruco.h"
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   rgbd_frame_index_(0)
00034 {
00035   ROS_INFO("Starting RGBD Keyframe Mapper");
00036    
00037   // **** params
00038   
00039   initParams();
00040   
00041   // **** publishers
00042   
00043   keyframes_pub_ = nh_.advertise<PointCloudT>(
00044     "keyframes", queue_size_);
00045   poses_pub_ = nh_.advertise<visualization_msgs::Marker>( 
00046     "keyframe_poses", queue_size_);
00047   kf_assoc_pub_ = nh_.advertise<visualization_msgs::Marker>( 
00048     "keyframe_associations", queue_size_);
00049   path_pub_ = nh_.advertise<PathMsg>( 
00050     "mapper_path", queue_size_);
00051   
00052   // **** services
00053   
00054   pub_keyframe_service_ = nh_.advertiseService(
00055     "publish_keyframe", &KeyframeMapper::publishKeyframeSrvCallback, this);
00056   pub_keyframes_service_ = nh_.advertiseService(
00057     "publish_keyframes", &KeyframeMapper::publishKeyframesSrvCallback, this);
00058   save_kf_service_ = nh_.advertiseService(
00059     "save_keyframes", &KeyframeMapper::saveKeyframesSrvCallback, this);
00060   load_kf_service_ = nh_.advertiseService(
00061     "load_keyframes", &KeyframeMapper::loadKeyframesSrvCallback, this);   
00062   save_pcd_map_service_ = nh_.advertiseService(
00063     "save_pcd_map", &KeyframeMapper::savePcdMapSrvCallback, this);
00064   save_octomap_service_ = nh_.advertiseService(
00065     "save_octomap", &KeyframeMapper::saveOctomapSrvCallback, this);
00066   add_manual_keyframe_service_ = nh_.advertiseService(
00067     "add_manual_keyframe", &KeyframeMapper::addManualKeyframeSrvCallback, this);
00068   generate_graph_service_ = nh_.advertiseService(
00069     "generate_graph", &KeyframeMapper::generateGraphSrvCallback, this);
00070    solve_graph_service_ = nh_.advertiseService(
00071     "solve_graph", &KeyframeMapper::solveGraphSrvCallback, this);
00072  
00073   // **** subscribers
00074 
00075   ImageTransport rgb_it(nh_);
00076   ImageTransport depth_it(nh_);
00077 
00078   sub_rgb_.subscribe(rgb_it,     "/camera/rgb/image_rect_color",   queue_size_);
00079   sub_depth_.subscribe(depth_it, "/camera/depth_registered/image_rect_raw", queue_size_);
00080   sub_info_.subscribe(nh_,       "/camera/rgb/camera_info",  queue_size_);
00081 
00082   // Synchronize inputs.
00083   sync_.reset(new RGBDSynchronizer3(
00084                 RGBDSyncPolicy3(queue_size_), sub_rgb_, sub_depth_, sub_info_));
00085    
00086   sync_->registerCallback(boost::bind(&KeyframeMapper::RGBDCallback, this, _1, _2, _3));  
00087 }
00088 
00089 KeyframeMapper::~KeyframeMapper()
00090 {
00091 
00092 }
00093 aruco::MarkerDetector MDetector;
00094 void KeyframeMapper::initParams()
00095 {
00096   bool verbose;
00097   
00098   if (!nh_private_.getParam ("verbose", verbose))
00099     verbose = true;
00100   if (!nh_private_.getParam ("queue_size", queue_size_))
00101     queue_size_ = 5;
00102   if (!nh_private_.getParam ("fixed_frame", fixed_frame_))
00103     fixed_frame_ = "/odom";
00104   if (!nh_private_.getParam ("pcd_map_res", pcd_map_res_))
00105     pcd_map_res_ = 0.01;
00106   if (!nh_private_.getParam ("octomap_res", octomap_res_))
00107     octomap_res_ = 0.05;
00108   if (!nh_private_.getParam ("octomap_with_color", octomap_with_color_))
00109    octomap_with_color_ = true;
00110   if (!nh_private_.getParam ("kf_dist_eps", kf_dist_eps_))
00111     kf_dist_eps_  = 0.10;
00112   if (!nh_private_.getParam ("kf_angle_eps", kf_angle_eps_))
00113     kf_angle_eps_  = 10.0 * M_PI / 180.0;
00114   if (!nh_private_.getParam ("max_range", max_range_))
00115     max_range_  = 10.0;
00116   if (!nh_private_.getParam ("max_stdev", max_stdev_))
00117     max_stdev_  = 555;
00118   if (!nh_private_.getParam ("max_map_z", max_map_z_))
00119     max_map_z_ = std::numeric_limits<double>::infinity();
00120    
00121   // configure graph detection 
00122   MDetector.setThresholdParams( 10.0,7.0);
00123   MDetector.setCornerRefinementMethod(aruco::MarkerDetector::LINES);
00124 
00125   int graph_n_keypoints;        
00126   int graph_n_candidates;
00127   int graph_k_nearest_neighbors;
00128   bool graph_matcher_use_desc_ratio_test = true;
00129     
00130   if (!nh_private_.getParam ("graph/n_keypoints", graph_n_keypoints))
00131     graph_n_keypoints = 500;
00132   if (!nh_private_.getParam ("graph/n_candidates", graph_n_candidates))
00133     graph_n_candidates = 10;
00134   if (!nh_private_.getParam ("graph/k_nearest_neighbors", graph_k_nearest_neighbors))
00135     graph_k_nearest_neighbors = 4;
00136 
00137   int min_inliers = 15;
00138   graph_detector_.setNKeypoints(graph_n_keypoints);
00139   graph_detector_.setNCandidates(graph_n_candidates);   
00140   graph_detector_.setKNearestNeighbors(graph_k_nearest_neighbors);    
00141   graph_detector_.setMatcherUseDescRatioTest(graph_matcher_use_desc_ratio_test);
00142   graph_detector_.setSacMinInliers(min_inliers);
00143   graph_detector_.setSACReestimateTf(false);
00144   graph_detector_.setSACSaveResults(true);
00145   graph_detector_.setVerbose(verbose);
00146 }
00147   
00148 void KeyframeMapper::RGBDCallback(
00149   const ImageMsg::ConstPtr& rgb_msg,
00150   const ImageMsg::ConstPtr& depth_msg,
00151   const CameraInfoMsg::ConstPtr& info_msg)
00152 {
00153   tf::StampedTransform transform;
00154 
00155   const ros::Time& time = rgb_msg->header.stamp;
00156 
00157 
00158   try{
00159       tf_listener_.waitForTransform(
00160                   fixed_frame_, rgb_msg->header.frame_id, time, ros::Duration(0.1));
00161       tf_listener_.lookupTransform(
00162                   fixed_frame_, rgb_msg->header.frame_id, time, transform);
00163   }
00164   catch(...)
00165   {
00166       if(!manual_add_)
00167       {
00168           return;
00169       }
00170   }
00171 
00172   // create a new frame and increment the counter
00173   rgbdtools::RGBDFrame frame;
00174   createRGBDFrameFromROSMessages(rgb_msg, depth_msg, info_msg, frame); 
00175   frame.index = rgbd_frame_index_;
00176   rgbd_frame_index_++;
00177 
00178   int val = cv::countNonZero(frame.depth_img);
00179   if(val==0)
00180       return;
00181   std::vector<aruco::Marker> markers;
00182 
00183   cv::Mat intr, dist;
00184   convertCameraInfoToMats(info_msg, intr, dist);
00185   cv::Size CamSize;
00186   CamSize.width = info_msg->width;
00187   CamSize.height = info_msg->height;
00188 
00189   aruco::CameraParameters param(intr,dist,CamSize);
00190   MDetector.detect(frame.rgb_img,markers,param,0.20); // magic number 0.20 = marker size
00191   if (markers.size()>0)
00192       manual_add_ = true;
00193 
00194   bool result = processFrame(frame, eigenAffineFromTf(transform));
00195   if (result) publishKeyframeData(keyframes_.size() - 1);
00196   
00197   publishPath();
00198 }
00199 
00200 int triple_add=0;
00201 
00202 bool KeyframeMapper::processFrame(
00203   const rgbdtools::RGBDFrame& frame, 
00204   const AffineTransform& pose)
00205 {
00206   // add the frame pose to the path vector
00207   geometry_msgs::PoseStamped frame_pose; 
00208   tf::Transform frame_tf = tfFromEigenAffine(pose);
00209   tf::poseTFToMsg(frame_tf, frame_pose.pose);
00210  
00211   // update the header of the pose for the path
00212   frame_pose.header.frame_id = fixed_frame_;
00213   frame_pose.header.seq = frame.header.seq;
00214   frame_pose.header.stamp.sec = frame.header.stamp.sec;
00215   frame_pose.header.stamp.nsec = frame.header.stamp.nsec;
00216     
00217   path_msg_.poses.push_back(frame_pose);
00218    
00219   // determine if a new keyframe is needed
00220   bool result; 
00221 
00222   if(keyframes_.empty() || manual_add_)
00223   {
00224     result = true;
00225   }
00226   else
00227   {
00228     double dist, angle;
00229     getTfDifference(tfFromEigenAffine(pose), 
00230                     tfFromEigenAffine(keyframes_.back().pose), 
00231                     dist, angle);
00232 
00233     if (triple_add >0 || dist > kf_dist_eps_ || angle > kf_angle_eps_)
00234     {
00235         result = true;
00236 //        if (triple_add == 0)
00237 //        {
00238 //            triple_add = 2;
00239 //        }
00240 //        else
00241 //        {
00242 //            triple_add--;
00243 //        }
00244     }
00245     else 
00246       result = false;
00247   }
00248 
00249   if (result)
00250   {
00251     addKeyframe(frame, pose);
00252   }
00253   return result;
00254 }
00255 
00256 void KeyframeMapper::addKeyframe(
00257   const rgbdtools::RGBDFrame& frame, 
00258   const AffineTransform& pose)
00259 {
00260   rgbdtools::RGBDKeyframe keyframe(frame);
00261   keyframe.pose = pose;
00262   
00263   if (manual_add_)
00264   {
00265     ROS_INFO("Adding frame manually");
00266     manual_add_ = false;
00267     keyframe.manually_added = true;
00268   }
00269   keyframes_.push_back(keyframe); 
00270 }
00271 
00272 bool KeyframeMapper::publishKeyframeSrvCallback(
00273   PublishKeyframe::Request& request,
00274   PublishKeyframe::Response& response)
00275 {
00276   int kf_idx = request.id;
00277   
00278   if (kf_idx >= 0 && kf_idx < (int)keyframes_.size())
00279   {
00280     ROS_INFO("Publishing keyframe %d", kf_idx);
00281     publishKeyframeData(kf_idx);
00282     publishKeyframePose(kf_idx);
00283     return true;
00284   }
00285   else
00286   {
00287     ROS_ERROR("Index out of range");
00288     return false;  
00289   }
00290 }
00291 
00292 bool KeyframeMapper::publishKeyframesSrvCallback(
00293   PublishKeyframes::Request& request,
00294   PublishKeyframes::Response& response)
00295 { 
00296   bool found_match = false;
00297 
00298   // regex matching - try match the request string against each
00299   // keyframe index
00300   boost::regex expression(request.re);
00301   
00302   for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00303   {
00304     std::stringstream ss;
00305     ss << kf_idx;
00306     std::string kf_idx_string = ss.str();
00307       
00308     boost::smatch match;
00309     
00310     if(boost::regex_match(kf_idx_string, match, expression))
00311     {
00312       found_match = true;
00313       ROS_INFO("Publishing keyframe %d", kf_idx);
00314       publishKeyframeData(kf_idx);
00315       publishKeyframePose(kf_idx);
00316       usleep(25000);
00317     }
00318   }
00319 
00320   publishPath();
00321 
00322   return found_match;
00323 }
00324 
00325 void KeyframeMapper::publishKeyframeData(int i)
00326 {
00327   rgbdtools::RGBDKeyframe& keyframe = keyframes_[i];
00328 
00329   // construct a cloud from the images
00330   PointCloudT cloud;
00331   keyframe.constructDensePointCloud(cloud, max_range_, max_stdev_);
00332 
00333   // cloud transformed to the fixed frame
00334   PointCloudT cloud_ff; 
00335   pcl::transformPointCloud(cloud, cloud_ff, keyframe.pose);
00336 
00337   cloud_ff.header.frame_id = fixed_frame_;
00338 
00339   keyframes_pub_.publish(cloud_ff);
00340 }
00341 
00342 void KeyframeMapper::publishKeyframeAssociations()
00343 {
00344   visualization_msgs::Marker marker;
00345   marker.header.stamp = ros::Time::now();
00346   marker.header.frame_id = fixed_frame_;
00347   marker.id = 0;
00348   marker.type = visualization_msgs::Marker::LINE_LIST;
00349   marker.action = visualization_msgs::Marker::ADD;
00350 
00351   marker.points.resize(associations_.size() * 2);
00352   
00353   marker.color.a = 1.0;
00354 
00355   for (unsigned int as_idx = 0; as_idx < associations_.size(); ++as_idx)
00356   {
00357     // set up shortcut references
00358     const rgbdtools::KeyframeAssociation& association = associations_[as_idx];
00359     int kf_idx_a = association.kf_idx_a;
00360     int kf_idx_b = association.kf_idx_b;
00361     rgbdtools::RGBDKeyframe& keyframe_a = keyframes_[kf_idx_a];
00362     rgbdtools::RGBDKeyframe& keyframe_b = keyframes_[kf_idx_b];
00363 
00364     int idx_start = as_idx*2;
00365     int idx_end   = as_idx*2 + 1;
00366 
00367     tf::Transform keyframe_a_pose = tfFromEigenAffine(keyframe_a.pose);
00368     tf::Transform keyframe_b_pose = tfFromEigenAffine(keyframe_b.pose);
00369  
00370     // start point for the edge
00371     marker.points[idx_start].x = keyframe_a_pose.getOrigin().getX();  
00372     marker.points[idx_start].y = keyframe_a_pose.getOrigin().getY();
00373     marker.points[idx_start].z = keyframe_a_pose.getOrigin().getZ();
00374 
00375     // end point for the edge
00376     marker.points[idx_end].x = keyframe_b_pose.getOrigin().getX();  
00377     marker.points[idx_end].y = keyframe_b_pose.getOrigin().getY();
00378     marker.points[idx_end].z = keyframe_b_pose.getOrigin().getZ();
00379 
00380     if (association.type == rgbdtools::KeyframeAssociation::VO)
00381     {
00382       marker.ns = "VO";
00383       marker.scale.x = 0.002;
00384 
00385       marker.color.r = 0.0;
00386       marker.color.g = 1.0;
00387       marker.color.b = 0.0;
00388     }
00389     else if (association.type == rgbdtools::KeyframeAssociation::RANSAC)
00390     {
00391       marker.ns = "RANSAC";
00392       marker.scale.x = 0.002;
00393       
00394       marker.color.r = 1.0;
00395       marker.color.g = 1.0;
00396       marker.color.b = 0.0;
00397     }
00398 
00399     kf_assoc_pub_.publish(marker);
00400   }
00401 }
00402 
00403 void KeyframeMapper::publishKeyframePoses()
00404 {
00405   for(unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00406   {
00407     publishKeyframePose(kf_idx);
00408   }
00409 }
00410 
00411 void KeyframeMapper::publishKeyframePose(int i)
00412 {
00413   rgbdtools::RGBDKeyframe& keyframe = keyframes_[i];
00414 
00415   // **** publish camera pose
00416 
00417   visualization_msgs::Marker marker;
00418   marker.header.stamp = ros::Time::now();
00419   marker.header.frame_id = fixed_frame_;
00420   marker.ns = "keyframe_poses";
00421   marker.id = i;
00422   marker.type = visualization_msgs::Marker::ARROW;
00423   marker.action = visualization_msgs::Marker::ADD;
00424 
00425   marker.points.resize(2);
00426 
00427   // start point for the arrow
00428   tf::Transform keyframe_pose = tfFromEigenAffine(keyframe.pose);
00429   marker.points[0].x = keyframe_pose.getOrigin().getX();
00430   marker.points[0].y = keyframe_pose.getOrigin().getY();
00431   marker.points[0].z = keyframe_pose.getOrigin().getZ();
00432 
00433   // end point for the arrow
00434   tf::Transform ep; 
00435   ep.setIdentity();
00436   ep.setOrigin(tf::Vector3(0.00, 0.00, 0.12)); // z = arrow length
00437   ep = keyframe_pose * ep;
00438 
00439   marker.points[1].x = ep.getOrigin().getX();
00440   marker.points[1].y = ep.getOrigin().getY();
00441   marker.points[1].z = ep.getOrigin().getZ(); 
00442   
00443   marker.scale.x = 0.02; // shaft radius
00444   marker.scale.y = 0.05; // head radius
00445 
00446   marker.color.a = 1.0;
00447   marker.color.r = 0.0;
00448   marker.color.g = 1.0;
00449   marker.color.b = 0.0;
00450 
00451   poses_pub_.publish(marker);
00452 
00453   // **** publish frame index text
00454 
00455   visualization_msgs::Marker marker_text;
00456   marker_text.header.stamp = ros::Time::now();
00457   marker_text.header.frame_id = fixed_frame_;
00458   marker_text.ns = "keyframe_indexes";
00459   marker_text.id = i;
00460   marker_text.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00461   marker_text.action = visualization_msgs::Marker::ADD;
00462 
00463   tf::poseTFToMsg(keyframe_pose, marker_text.pose);
00464 
00465   marker_text.pose.position.z -= 0.05;
00466 
00467   char label[6];
00468   sprintf(label, "%d", i);
00469   marker_text.text = label;
00470 
00471   marker_text.color.a = 1.0;
00472   marker_text.color.r = 1.0;
00473   marker_text.color.g = 1.0;
00474   marker_text.color.b = 0.0;
00475 
00476   marker_text.scale.z = 0.05; // shaft radius
00477 
00478   poses_pub_.publish(marker_text);
00479 }
00480 
00481 bool KeyframeMapper::saveKeyframesSrvCallback(
00482   Save::Request& request,
00483   Save::Response& response)
00484 {
00485   std::string filepath = request.filename;
00486  
00487   ROS_INFO("Saving keyframes...");
00488   std::string filepath_keyframes = filepath + "/keyframes/";
00489   bool result_kf = saveKeyframes(keyframes_, filepath_keyframes);
00490   if (result_kf) ROS_INFO("Keyframes saved to %s", filepath.c_str());
00491   else ROS_ERROR("Keyframe saving failed!");
00492   
00493   ROS_INFO("Saving path...");
00494   bool result_path = savePath(filepath);
00495   savePathTUMFormat(filepath);
00496   if (result_path ) ROS_INFO("Path saved to %s", filepath.c_str());
00497   else ROS_ERROR("Path saving failed!");
00498   solver_.save_graph(filepath);
00499 
00500   return result_kf && result_path;
00501 }
00502 
00503 bool KeyframeMapper::loadKeyframesSrvCallback(
00504   Load::Request& request,
00505   Load::Response& response)
00506 {
00507     bool skip = false;
00508     ros::WallTime start_all = ros::WallTime::now();
00509     std::string filepath1 = request.filename;
00510     char buffer[200];
00511     std::string filepath;
00512     if(filepath1.at(filepath1.size()-1)=='!')
00513     {
00514         skip = true;
00515         int copied = filepath1.copy(buffer,filepath1.size()-1,0);
00516         buffer[copied] = '\0';
00517         filepath = buffer;
00518     }
00519     else
00520     {
00521         filepath = filepath1;
00522     }
00523     ROS_INFO("Loading keyframes...");
00524     std::string filepath_keyframes = filepath + "/keyframes/";
00525     bool result_kf = loadKeyframes(keyframes_, filepath_keyframes);
00526     if (result_kf) ROS_INFO("Keyframes loaded successfully");
00527     else ROS_ERROR("Keyframe loading failed!");
00528 
00529     ROS_INFO("Loading path...");
00530     bool result_path = loadPath(filepath);
00531     if (result_path) ROS_INFO("Path loaded successfully");
00532     else ROS_ERROR("Path loading failed!");
00533     publishKeyframePoses();
00534 //    solver_.parse((filepath).c_str());
00535     publishKeyframePoses();
00536     if(!(result_kf && result_path))
00537         return false;
00538     if(skip)
00539         return result_kf && result_path;
00540     //generate graph
00541     associations_.clear();
00542     graph_detector_.generateKeyframeAssociations(keyframes_, associations_);
00543 //    std::vector<std::vector<aruco::Marker> > markers = graph_detector_.getMarkers();
00544     ROS_INFO("%d associations detected", (int)associations_.size());
00545     publishKeyframePoses();
00546     publishKeyframeAssociations();
00547     //solve
00548     ros::WallTime start = ros::WallTime::now();
00549 //    solver_.giveMarkers(markers);
00550     solver_.solve(keyframes_, associations_);
00551 
00552     double dur = getMsDuration(start);
00553 
00554     ROS_INFO("Solving took %.1f ms", dur);
00555     publishKeyframePoses();
00556     publishKeyframeAssociations();
00557 
00558 
00559     //save
00560 
00561     filepath = request.filename + "_solved";
00562     boost::filesystem::create_directories(filepath);
00563     filepath_keyframes = filepath + "/keyframes/";
00564     boost::filesystem::create_directories(filepath_keyframes);
00565     ROS_INFO("Saving keyframes...");
00566     result_kf = saveKeyframes(keyframes_, filepath_keyframes);
00567     if (result_kf) ROS_INFO("Keyframes saved to %s", filepath_keyframes.c_str());
00568     else ROS_ERROR("Keyframe saving failed!");
00569 
00570     ROS_INFO("Saving path...");
00571     result_path = savePath(filepath);
00572     savePathTUMFormat(filepath);
00573     if (result_path ) ROS_INFO("Path saved to %s", filepath.c_str());
00574     else ROS_ERROR("Path saving failed!");
00575     solver_.save_graph(filepath);
00576 
00577 
00578 
00579     dur = getMsDuration(start_all);
00580 
00581     ROS_INFO("Everything took %.1f ms", dur);
00582     return result_kf && result_path;
00583 }
00584 
00585 bool KeyframeMapper::savePcdMapSrvCallback(
00586   Save::Request& request,
00587   Save::Response& response)
00588 {
00589   ROS_INFO("Saving map as pcd...");
00590   const std::string& path = request.filename;
00591   bool result = savePcdMap(path);
00592   
00593   if (result) ROS_INFO("Pcd map saved to %s", path.c_str());
00594   else ROS_ERROR("Pcd map saving failed");
00595 
00596   return result;
00597 }
00598 
00599 bool KeyframeMapper::saveOctomapSrvCallback(
00600   Save::Request& request,
00601   Save::Response& response)
00602 {
00603   ROS_INFO("Saving map as Octomap...");
00604   const std::string& path = request.filename;
00605   bool result = saveOctomap(path);
00606     
00607   if (result) ROS_INFO("Octomap saved to %s", path.c_str());
00608   else ROS_ERROR("Octomap saving failed");
00609     
00610   return result;
00611 }
00612 
00613 bool KeyframeMapper::addManualKeyframeSrvCallback(
00614   AddManualKeyframe::Request& request,
00615   AddManualKeyframe::Response& response)
00616 {
00617   manual_add_ = true;
00618 
00619   return true;
00620 }
00621 
00622 bool KeyframeMapper::generateGraphSrvCallback(
00623   GenerateGraph::Request& request,
00624   GenerateGraph::Response& response)
00625 {
00626   associations_.clear();
00627   graph_detector_.generateKeyframeAssociations(keyframes_, associations_);
00628 
00629   ROS_INFO("%d associations detected", (int)associations_.size());
00630   publishKeyframePoses();
00631   publishKeyframeAssociations();
00632 
00633   return true;
00634 }
00635 
00636 bool KeyframeMapper::solveGraphSrvCallback(
00637   SolveGraph::Request& request,
00638   SolveGraph::Response& response)
00639 {
00640   ros::WallTime start = ros::WallTime::now();
00641   
00642   // Graph solving: keyframe positions only, path is interpolated
00643 //  graph_solver_.solve(keyframes_, associations_);
00644   solver_.solve(keyframes_, associations_);
00645 //  updatePathFromKeyframePoses();
00646 //  max_map_z_ = getmaxheight(path_msg_)+0.2; //cut the ceiling
00647 
00648   // Graph solving: keyframe positions and VO path
00649   /*
00650   AffineTransformVector path;
00651   pathROSToEigenAffine(path_msg_, path);
00652   graph_solver_.solve(keyframes_, associations_, path);
00653   pathEigenAffineToROS(path, path_msg_);
00654   */
00655   
00656   double dur = getMsDuration(start);
00657   
00658   ROS_INFO("Solving took %.1f ms", dur);
00659     
00660 //  publishPath();
00661   publishKeyframePoses();
00662   publishKeyframeAssociations();
00663 
00664   return true;
00665 }
00666 
00667 
00671 void KeyframeMapper::updatePathFromKeyframePoses()
00672 {   
00673   int kf_size = keyframes_.size();
00674   int f_size = path_msg_.poses.size();
00675   
00676   // temporary store the new path
00677   AffineTransformVector path_new;
00678   path_new.resize(f_size);
00679   
00680   if (kf_size < 2) return; 
00681   
00682   for (int kf_idx = 0; kf_idx < kf_size - 1; ++kf_idx)
00683   {
00684     // the indices of the current and next keyframes (a and b)   
00685     const rgbdtools::RGBDKeyframe& keyframe_a = keyframes_[kf_idx];
00686     const rgbdtools::RGBDKeyframe& keyframe_b = keyframes_[kf_idx + 1];
00687     
00688     // the corresponding frame indices
00689     int f_idx_a = keyframe_a.index;
00690     int f_idx_b = keyframe_b.index;
00691          
00692     // the new poses of keyframes a and b (after graph solving)
00693     tf::Transform kf_pose_a = tfFromEigenAffine(keyframe_a.pose);
00694     tf::Transform kf_pose_b = tfFromEigenAffine(keyframe_b.pose);
00695     
00696     // the previous pose of keyframe a and b (before graph solving)
00697     tf::Transform kf_pose_a_prev, kf_pose_b_prev;
00698     tf::poseMsgToTF(path_msg_.poses[f_idx_a].pose, kf_pose_a_prev);
00699     tf::poseMsgToTF(path_msg_.poses[f_idx_b].pose, kf_pose_b_prev);
00700     
00701     // the motion, in the camera frame (after and before graph solving)
00702     tf::Transform kf_motion      = kf_pose_a.inverse() * kf_pose_b;
00703     tf::Transform kf_motion_prev = kf_pose_a_prev.inverse() * kf_pose_b_prev;
00704     
00705     // the correction from the graph solving
00706     tf::Transform correction = kf_motion_prev.inverse() * kf_motion;
00707     
00708     // update the poses in-between keyframes
00709     for (int f_idx = f_idx_a; f_idx < f_idx_b; ++f_idx)
00710     {
00711       // calculate interpolation scale
00712       double interp_scale = (double)(f_idx - f_idx_a) / (double)(f_idx_b - f_idx_a);
00713       
00714       // create interpolated correction translation and rotation
00715       tf::Vector3 v_interp = correction.getOrigin() * interp_scale;
00716       tf::Quaternion q_interp = tf::Quaternion::getIdentity();
00717       q_interp.slerp(correction.getRotation(), interp_scale);
00718       
00719       // create interpolated correction
00720       tf::Transform interpolated_correction;
00721       interpolated_correction.setOrigin(v_interp);
00722       interpolated_correction.setRotation(q_interp);
00723       
00724       // the previous frame pose
00725       tf::Transform frame_pose_prev;
00726       tf::poseMsgToTF(path_msg_.poses[f_idx].pose, frame_pose_prev);
00727       
00728       // the pevious frame motion
00729       tf::Transform frame_motion_prev = kf_pose_a_prev.inverse() * frame_pose_prev;
00730       
00731       // the interpolated motion
00732       tf::Transform interpolated_motion = frame_motion_prev * interpolated_correction;
00733       
00734       // calculate the interpolated pose
00735       path_new[f_idx] = keyframe_a.pose * eigenAffineFromTf(interpolated_motion);
00736     }  
00737   }
00738 
00739   // update the last pose
00740   const rgbdtools::RGBDKeyframe& last_kf = keyframes_[kf_size - 1];
00741 
00742   tf::Transform last_kf_pose_prev;
00743   tf::poseMsgToTF(path_msg_.poses[last_kf.index].pose, last_kf_pose_prev);
00744 
00745   // update the poses in-between last keyframe and end of vo path
00746   for (int f_idx = last_kf.index; f_idx < f_size; ++f_idx)
00747   {
00748     // the previous frame pose
00749     tf::Transform frame_pose_prev;
00750     tf::poseMsgToTF(path_msg_.poses[f_idx].pose, frame_pose_prev);
00751 
00752     // the pevious frame motion
00753     tf::Transform frame_motion_prev = last_kf_pose_prev.inverse() * frame_pose_prev;
00754 
00755     // calculate the new pose
00756     path_new[f_idx] = last_kf.pose * eigenAffineFromTf(frame_motion_prev);
00757   }
00758 
00759   // copy over the interpolated path
00760   pathEigenAffineToROS(path_new, path_msg_);
00761 }
00762 
00763 
00764 bool KeyframeMapper::savePcdMap(const std::string& path)
00765 {
00766   PointCloudT pcd_map;
00767   buildPcdMap(pcd_map);
00768   
00769   // write out
00770   pcl::PCDWriter writer;
00771   int result_pcd = writer.writeBinary<PointT>(path, pcd_map);  
00772 
00773   if (result_pcd < 0) return false;
00774   else return true;
00775 }
00776 
00777 void KeyframeMapper::buildPcdMap(PointCloudT& map_cloud)
00778 {
00779   PointCloudT::Ptr aggregate_cloud(new PointCloudT());
00780   aggregate_cloud->header.frame_id = fixed_frame_;
00781 
00782   // aggregate all frames into single cloud
00783   for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00784   {
00785     const rgbdtools::RGBDKeyframe& keyframe = keyframes_[kf_idx];
00786 
00787     PointCloudT cloud;
00788     keyframe.constructDensePointCloud(cloud, max_range_, max_stdev_);
00789 
00790     PointCloudT cloud_tf;
00791     pcl::transformPointCloud(cloud, cloud_tf, keyframe.pose);
00792     cloud_tf.header.frame_id = fixed_frame_;
00793 
00794     *aggregate_cloud += cloud_tf;
00795   }
00796 
00797   // filter cloud using voxel grid, and for max z
00798   pcl::VoxelGrid<PointT> vgf;
00799   vgf.setInputCloud(aggregate_cloud);
00800   vgf.setLeafSize(pcd_map_res_, pcd_map_res_, pcd_map_res_);
00801   vgf.setFilterFieldName("z");
00802   vgf.setFilterLimits (-std::numeric_limits<double>::infinity(), max_map_z_);
00803 
00804   vgf.filter(map_cloud);
00805 }
00806 void KeyframeMapper::buildFullCloud(PointCloudT& map_cloud)
00807 {
00808   PointCloudT::Ptr aggregate_cloud(new PointCloudT());
00809   aggregate_cloud->header.frame_id = fixed_frame_;
00810 
00811   // aggregate all frames into single cloud
00812   for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00813   {
00814     const rgbdtools::RGBDKeyframe& keyframe = keyframes_[kf_idx];
00815 
00816     PointCloudT cloud;
00817     keyframe.constructDensePointCloud(cloud, max_range_, max_stdev_);
00818 
00819     PointCloudT cloud_tf;
00820     pcl::transformPointCloud(cloud, cloud_tf, keyframe.pose);
00821     cloud_tf.header.frame_id = fixed_frame_;
00822 
00823     *aggregate_cloud += cloud_tf;
00824   }
00825   map_cloud = *aggregate_cloud;
00826 }
00827 bool KeyframeMapper::saveOctomap(const std::string& path)
00828 {
00829   bool result;
00830 
00831   if (octomap_with_color_)
00832   {
00833     octomap::ColorOcTree tree(octomap_res_);   
00834     buildColorOctomap(tree);
00835     result = tree.write(path);
00836   }
00837   else
00838   {
00839     octomap::OcTree tree(octomap_res_);   
00840     buildOctomap(tree);
00841     result = tree.write(path);
00842   }
00843   
00844   return result;
00845 }
00846 
00847 void KeyframeMapper::buildOctomap(octomap::OcTree& tree)
00848 {
00849   ROS_INFO("Building Octomap...");
00850   
00851   octomap::point3d sensor_origin(0.0, 0.0, 0.0);
00852 
00853   for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00854   {
00855 //    ROS_INFO("Processing keyframe %u", kf_idx);
00856 //    const rgbdtools::RGBDKeyframe& keyframe = keyframes_[kf_idx];
00857     
00858 //    PointCloudT cloud;
00859 //    keyframe.constructDensePointCloud(cloud, max_range_, max_stdev_);
00860            
00861 //    octomap::pose6d frame_origin = poseTfToOctomap(tfFromEigenAffine(keyframe.pose));
00862 
00863 //    // build octomap cloud from pcl cloud
00864 //    octomap::Pointcloud octomap_cloud;
00865 //    for (unsigned int pt_idx = 0; pt_idx < cloud.points.size(); ++pt_idx)
00866 //    {
00867 //      const PointT& p = cloud.points[pt_idx];
00868 //      if (!std::isnan(p.z))
00869 //        octomap_cloud.push_back(p.x, p.y, p.z);
00870 //    }
00871   PointCloudT cloud;
00872   buildFullCloud(cloud);
00873   octomap::Pointcloud octomap_cloud;
00874   for (unsigned int pt_idx = 0; pt_idx < cloud.points.size(); ++pt_idx)
00875   {
00876     const PointT& p = cloud.points[pt_idx];
00877     if (!std::isnan(p.z) && p.z < max_map_z_)
00878       octomap_cloud.push_back(p.x, p.y, p.z);
00879   }
00880   tree.insertScan(octomap_cloud,sensor_origin);
00881   }
00882 }
00883 
00884 void KeyframeMapper::buildColorOctomap(octomap::ColorOcTree& tree)
00885 {
00886   ROS_INFO("Building Octomap with color...");
00887 
00888   octomap::point3d sensor_origin(0.0, 0.0, 0.0);
00889 
00890   for (unsigned int kf_idx = 0; kf_idx < keyframes_.size(); ++kf_idx)
00891   {
00892     ROS_INFO("Processing keyframe %u", kf_idx);
00893     const rgbdtools::RGBDKeyframe& keyframe = keyframes_[kf_idx];
00894 
00895     // construct the cloud
00896     PointCloudT::Ptr cloud_unf(new PointCloudT());
00897     keyframe.constructDensePointCloud(*cloud_unf, max_range_, max_stdev_);
00898 
00899     // perform filtering for max z
00900     pcl::transformPointCloud(*cloud_unf, *cloud_unf, keyframe.pose);
00901     PointCloudT cloud;
00902     pcl::PassThrough<PointT> pass;
00903     pass.setInputCloud (cloud_unf);
00904     pass.setFilterFieldName ("z");
00905     pass.setFilterLimits (-std::numeric_limits<double>::infinity(), max_map_z_);
00906     pass.filter(cloud);
00907     pcl::transformPointCloud(cloud, cloud, keyframe.pose.inverse());
00908 
00909     octomap::pose6d frame_origin = poseTfToOctomap(tfFromEigenAffine(keyframe.pose));
00910 
00911     // build octomap cloud from pcl cloud
00912     octomap::Pointcloud octomap_cloud;
00913     for (unsigned int pt_idx = 0; pt_idx < cloud.points.size(); ++pt_idx)
00914     {
00915       const PointT& p = cloud.points[pt_idx];
00916       if (!std::isnan(p.z))
00917         octomap_cloud.push_back(p.x, p.y, p.z);
00918     }
00919 
00920     // insert scan (only xyz considered, no colors)
00921     tree.insertScan(octomap_cloud, sensor_origin, frame_origin);
00922 
00923     // insert colors
00924     PointCloudT cloud_tf;
00925     pcl::transformPointCloud(cloud, cloud_tf, keyframe.pose);
00926     for (unsigned int pt_idx = 0; pt_idx < cloud_tf.points.size(); ++pt_idx)
00927     {
00928       const PointT& p = cloud_tf.points[pt_idx];
00929       if (!std::isnan(p.z))
00930       {
00931         octomap::point3d endpoint(p.x, p.y, p.z);
00932         octomap::ColorOcTreeNode* n = tree.search(endpoint);
00933         if (n) n->setColor(p.r, p.g, p.b);
00934       }
00935     }
00936 
00937     tree.updateInnerOccupancy();
00938   }
00939 }
00940 
00941 void KeyframeMapper::publishPath()
00942 {
00943   path_msg_.header.frame_id = fixed_frame_; 
00944   path_pub_.publish(path_msg_);
00945 }
00946 
00947 bool KeyframeMapper::savePath(const std::string& filepath)
00948 {
00949   // open file
00950   std::string filename = filepath + "/path.txt";
00951   std::ofstream file(filename.c_str());
00952   if (!file.is_open()) return false;
00953 
00954   file << "# index seq stamp.sec stamp.nsec x y z qx qy qz qw" << std::endl;
00955 
00956   for (unsigned int idx = 0; idx < path_msg_.poses.size(); ++idx)
00957   {
00958     const geometry_msgs::PoseStamped& pose = path_msg_.poses[idx];
00959     
00960     file << idx << " "
00961          << pose.header.seq << " "
00962          << pose.header.stamp.sec << " "
00963          << pose.header.stamp.nsec << " "
00964          << pose.pose.position.x << " "
00965          << pose.pose.position.y << " "
00966          << pose.pose.position.z << " "
00967          << pose.pose.orientation.x << " "
00968          << pose.pose.orientation.y << " "
00969          << pose.pose.orientation.z << " " 
00970          << pose.pose.orientation.w << std::endl;
00971   }
00972 
00973   file.close();
00974   
00975   return true;
00976 }
00977 
00978 bool KeyframeMapper::savePathTUMFormat(const std::string& filepath)
00979 {
00980   // open file
00981   std::string filename = filepath + "/path.tum.txt";
00982   std::ofstream file(filename.c_str());
00983   if (!file.is_open()) return false;
00984 
00985   file << "# stamp x y z qx qy qz qw" << std::endl;
00986 
00987   for (unsigned int idx = 0; idx < path_msg_.poses.size(); ++idx)
00988   {
00989     const geometry_msgs::PoseStamped& pose = path_msg_.poses[idx];
00990     
00991     file << pose.header.stamp.sec << "."
00992          << pose.header.stamp.nsec << " "
00993          << pose.pose.position.x << " "
00994          << pose.pose.position.y << " "
00995          << pose.pose.position.z << " "
00996          << pose.pose.orientation.x << " "
00997          << pose.pose.orientation.y << " "
00998          << pose.pose.orientation.z << " " 
00999          << pose.pose.orientation.w << std::endl;
01000   }
01001 
01002   file.close();
01003     
01004   return true;
01005 }
01006 
01007 bool KeyframeMapper::loadPath(const std::string& filepath)
01008 {
01009   path_msg_.poses.clear();
01010 
01011   // open file
01012   std::string filename = filepath + "/path.txt";
01013   std::ifstream file(filename.c_str());
01014   if (!file.is_open()) return false;
01015   
01016   std::string line;
01017 
01018   // get header
01019   getline(file, line);
01020 
01021   // read each line
01022   while(std::getline(file, line))
01023   {
01024     std::istringstream is(line);
01025     
01026     // fill out pose information  
01027     geometry_msgs::PoseStamped pose;
01028     pose.header.frame_id = fixed_frame_;
01029     int idx;
01030        
01031     is >> idx
01032        >> pose.header.seq 
01033        >> pose.header.stamp.sec 
01034        >> pose.header.stamp.nsec 
01035        >> pose.pose.position.x 
01036        >> pose.pose.position.y 
01037        >> pose.pose.position.z 
01038        >> pose.pose.orientation.x 
01039        >> pose.pose.orientation.y 
01040        >> pose.pose.orientation.z 
01041        >> pose.pose.orientation.w;
01042                  
01043     // add to poses vector  
01044     path_msg_.poses.push_back(pose);
01045   }
01046     
01047   file.close();
01048   return true;
01049 }
01050 
01051 } // namespace ccny_rgbd
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends


ccny_rgbd
Author(s): Ivan Dryanovski
autogenerated on Tue Aug 27 2013 10:34:02