stereo_vslam_node.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <image_transport/image_transport.h>
00003 #include <image_transport/subscriber_filter.h>
00004 #include <message_filters/subscriber.h>
00005 #include <message_filters/time_synchronizer.h>
00006 #include <dynamic_reconfigure/server.h>
00007 
00008 #include <cv_bridge/CvBridge.h>
00009 #include <image_geometry/stereo_camera_model.h>
00010 
00011 #include <vslam_system/vslam.h>
00012 #include <sba/visualization.h>
00013 #include <vslam_system/any_detector.h>
00014 #include <vslam_system/StereoVslamNodeConfig.h>
00015 
00016 #include <tf/transform_broadcaster.h>
00017 #include <tf/transform_listener.h>
00018 #include <nav_msgs/Odometry.h>
00019 #include <geometry_msgs/PoseStamped.h>
00020 
00021 #include <opencv2/legacy/legacy.hpp>
00022 
00023 #include <pcl/point_types.h>
00024 #include <pcl/point_cloud.h>
00025 
00026 void publishRegisteredPointclouds(sba::SysSBA& sba, 
00027     std::vector<frame_common::Frame, Eigen::aligned_allocator<frame_common::Frame> >& frames, 
00028     ros::Publisher& pub);
00029 
00030 class StereoVslamNode
00031 {
00032 private:
00033   ros::NodeHandle nh_;
00034   image_transport::ImageTransport it_;
00035 
00036   // Subscriptions
00037   image_transport::SubscriberFilter l_image_sub_, r_image_sub_;
00038   message_filters::Subscriber<sensor_msgs::CameraInfo> l_info_sub_, r_info_sub_;
00039   message_filters::TimeSynchronizer<sensor_msgs::Image, sensor_msgs::CameraInfo,
00040                                     sensor_msgs::Image, sensor_msgs::CameraInfo> sync_;
00041 
00042   // Publications
00043   ros::Publisher cam_marker_pub_;
00044   ros::Publisher point_marker_pub_;
00045   image_transport::CameraPublisher vo_tracks_pub_;
00046   cv::Mat vo_display_;
00047   ros::Publisher odom_pub_;
00048   tf::TransformBroadcaster tf_broadcast_;
00049   tf::TransformListener tf_listener_;
00050   tf::Transform tf_transform_;
00051   ros::Publisher pointcloud_pub_;
00052 
00053   // Processing state
00054   sensor_msgs::CvBridge l_bridge_, r_bridge_;
00055   image_geometry::StereoCameraModel cam_model_;
00056   vslam::VslamSystem vslam_system_;
00057   cv::Ptr<cv::FeatureDetector> detector_;
00058 
00059   typedef dynamic_reconfigure::Server<vslam_system::StereoVslamNodeConfig> ReconfigureServer;
00060   ReconfigureServer reconfigure_server_;
00061 
00062 public:
00063 
00064   StereoVslamNode(const std::string& vocab_tree_file, const std::string& vocab_weights_file,
00065                   const std::string& calonder_trees_file)
00066     : it_(nh_), sync_(3),
00067       vslam_system_(vocab_tree_file, vocab_weights_file),
00068       detector_(new vslam_system::AnyDetector)
00069   {
00070     // Use calonder descriptor
00071     typedef cv::CalonderDescriptorExtractor<float> Calonder;
00072     vslam_system_.frame_processor_.setFrameDescriptor(new Calonder(calonder_trees_file));
00073     
00074     // Advertise outputs
00075     cam_marker_pub_ = nh_.advertise<visualization_msgs::Marker>("/vslam/cameras", 1);
00076     point_marker_pub_ = nh_.advertise<visualization_msgs::Marker>("/vslam/points", 1);
00077     vo_tracks_pub_ = it_.advertiseCamera("/vslam/vo_tracks/image", 1);
00078     odom_pub_ = nh_.advertise<nav_msgs::Odometry>("/vo", 1);
00079     pointcloud_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("/vslam/pointcloud", 1);
00080 
00081     // Synchronize inputs
00082     l_image_sub_.subscribe(it_, "left/image_rect", 1);
00083     l_info_sub_ .subscribe(nh_, "left/camera_info", 1);
00084     r_image_sub_.subscribe(it_, "right/image_rect", 1);
00085     r_info_sub_ .subscribe(nh_, "right/camera_info", 1);
00086     sync_.connectInput(l_image_sub_, l_info_sub_, r_image_sub_, r_info_sub_);
00087     sync_.registerCallback( boost::bind(&StereoVslamNode::imageCb, this, _1, _2, _3, _4) );
00088 
00089     // Dynamic reconfigure for parameters
00090     ReconfigureServer::CallbackType f = boost::bind(&StereoVslamNode::configCb, this, _1, _2);
00091     reconfigure_server_.setCallback(f);
00092 
00093   }
00094 
00095   void configCb(vslam_system::StereoVslamNodeConfig& config, uint32_t level)
00096   {
00097     dynamic_cast<vslam_system::AnyDetector*>((cv::FeatureDetector*)detector_)->update(config);
00098     vslam_system_.frame_processor_.detector = detector_;
00099 
00100     vslam_system_.setPRRansacIt(config.pr_ransac_iterations);
00101     vslam_system_.setPRPolish(config.pr_polish);
00102     vslam_system_.setVORansacIt(config.vo_ransac_iterations);
00103     vslam_system_.setVOPolish(config.vo_polish);
00104   }
00105 
00106 
00107   void imageCb(const sensor_msgs::ImageConstPtr& l_image,
00108                const sensor_msgs::CameraInfoConstPtr& l_cam_info,
00109                const sensor_msgs::ImageConstPtr& r_image,
00110                const sensor_msgs::CameraInfoConstPtr& r_cam_info)
00111   {
00112     ROS_INFO("In callback, seq = %u", l_cam_info->header.seq);
00113     
00114     // Convert ROS messages for use with OpenCV
00115     cv::Mat left, right;
00116     try {
00117       left  = l_bridge_.imgMsgToCv(l_image, "mono8");
00118       right = r_bridge_.imgMsgToCv(r_image, "mono8");
00119     }
00120     catch (sensor_msgs::CvBridgeException& e) {
00121       ROS_ERROR("Conversion error: %s", e.what());
00122       return;
00123     }
00124     cam_model_.fromCameraInfo(l_cam_info, r_cam_info);
00125 
00126     frame_common::CamParams cam_params;
00127     cam_params.fx = cam_model_.left().fx();
00128     cam_params.fy = cam_model_.left().fy();
00129     cam_params.cx = cam_model_.left().cx();
00130     cam_params.cy = cam_model_.left().cy();
00131     cam_params.tx = cam_model_.baseline();
00132 
00133     if (vslam_system_.addFrame(cam_params, left, right)) {
00135       int size = vslam_system_.sba_.nodes.size();
00136       if (size % 2 == 0) {
00137         // publish markers
00138         sba::drawGraph(vslam_system_.sba_, cam_marker_pub_, point_marker_pub_);
00139       }
00140 
00141       // Publish VO tracks
00142       if (vo_tracks_pub_.getNumSubscribers() > 0) {
00143         frame_common::drawVOtracks(left, vslam_system_.vo_.frames, vo_display_);
00144         IplImage ipl = vo_display_;
00145         sensor_msgs::ImagePtr msg = sensor_msgs::CvBridge::cvToImgMsg(&ipl);
00146         msg->header = l_cam_info->header;
00147         vo_tracks_pub_.publish(msg, l_cam_info);
00148       }
00149       
00150       // Refine large-scale SBA.
00151       const int LARGE_SBA_INTERVAL = 10;
00152       if (size > 4 && size % LARGE_SBA_INTERVAL == 0) {
00153         ROS_INFO("Running large SBA on %d nodes", size);
00154         vslam_system_.refine();
00155       }
00156       
00157       if (pointcloud_pub_.getNumSubscribers() > 0 && size % 2 == 0)
00158         publishRegisteredPointclouds(vslam_system_.sba_, vslam_system_.frames_, pointcloud_pub_);
00159       
00160       // Publish odometry data to tf.
00161       if (0) // TODO: Change this to parameter.
00162       {
00163         ros::Time stamp = l_cam_info->header.stamp;
00164         std::string image_frame = l_cam_info->header.frame_id;
00165         Eigen::Vector4d trans = -vslam_system_.sba_.nodes.back().trans;
00166         Eigen::Quaterniond rot = vslam_system_.sba_.nodes.back().qrot.conjugate();
00167         
00168         trans.head<3>() = rot.toRotationMatrix()*trans.head<3>(); 
00169         
00170         tf_transform_.setOrigin(tf::Vector3(trans(0), trans(1), trans(2)));
00171         tf_transform_.setRotation(tf::Quaternion(rot.x(), rot.y(), rot.z(), rot.w()) );
00172         
00173         tf::Transform simple_transform;
00174         simple_transform.setOrigin(tf::Vector3(0, 0, 0));
00175         simple_transform.setRotation(tf::Quaternion(.5, -.5, .5, .5));
00176         
00177         tf_broadcast_.sendTransform(tf::StampedTransform(tf_transform_, stamp, image_frame, "visual_odom"));
00178         tf_broadcast_.sendTransform(tf::StampedTransform(simple_transform, stamp, "visual_odom", "pgraph"));
00179       
00180       
00181         // Publish odometry data on topic.
00182         if (odom_pub_.getNumSubscribers() > 0)
00183         {
00184           tf::StampedTransform base_to_image;
00185           tf::Transform base_to_visodom;
00186          
00187           try
00188           {
00189             tf_listener_.lookupTransform(image_frame, "/base_footprint",
00190                                  stamp, base_to_image);
00191           }
00192           catch (tf::TransformException ex)
00193           {
00194               ROS_WARN("%s",ex.what());
00195               return;
00196           }
00197                                  
00198           base_to_visodom = tf_transform_.inverse() * base_to_image;
00199           
00200           geometry_msgs::PoseStamped pose;
00201           nav_msgs::Odometry odom;
00202           pose.header.frame_id = "/visual_odom";
00203           pose.pose.position.x = base_to_visodom.getOrigin().x();
00204           pose.pose.position.y = base_to_visodom.getOrigin().y();
00205           pose.pose.position.z = base_to_visodom.getOrigin().z();
00206           pose.pose.orientation.x = base_to_visodom.getRotation().x();
00207           pose.pose.orientation.y = base_to_visodom.getRotation().y();
00208           pose.pose.orientation.z = base_to_visodom.getRotation().z();
00209           pose.pose.orientation.w = base_to_visodom.getRotation().w();
00210           
00211           odom.header.stamp = stamp;
00212           odom.header.frame_id = "/visual_odom";
00213           odom.child_frame_id = "/base_footprint";
00214           odom.pose.pose = pose.pose;
00215           /* odom.pose.covariance[0] = 1;
00216           odom.pose.covariance[7] = 1;
00217           odom.pose.covariance[14] = 1;
00218           odom.pose.covariance[21] = 1;
00219           odom.pose.covariance[28] = 1;
00220           odom.pose.covariance[35] = 1; */
00221           odom_pub_.publish(odom);
00222         }
00223       }
00224     }
00225   }
00226 };
00227 
00228 void publishRegisteredPointclouds(sba::SysSBA& sba, 
00229     std::vector<frame_common::Frame, Eigen::aligned_allocator<frame_common::Frame> >& frames, 
00230     ros::Publisher& pub)
00231 {
00232   pcl::PointCloud<pcl::PointXYZRGB> cloud;
00233   
00234   // Count the number of points in the system:
00235   unsigned int totalpoints = 0;
00236   for (size_t i = 0; i < frames.size(); i++)
00237   {
00238     totalpoints += frames[i].pts.size();
00239   }
00240   
00241   cloud.points.resize(totalpoints);
00242   unsigned int k = 0;
00243 
00244   for(size_t i=0; i < frames.size(); i++)
00245   {
00246     if (sba.nodes.size() < i)
00247       break;
00248     Eigen::Matrix3d rotmat = sba.nodes[i].qrot.toRotationMatrix();
00249     Eigen::Vector3d trans = sba.nodes[i].trans.head<3>();
00250     
00251     for (size_t j=0; j < frames[i].pts.size(); j++)
00252     {
00253       // If too close or too far away, just ignore.
00254       if (frames[i].pts[j].z() > 30.0 || frames[i].pts[j].z() < 0.1)
00255         continue;
00256       Eigen::Vector3d point(frames[i].pts[j].x(), frames[i].pts[j].y(), frames[i].pts[j].z());
00257       point = rotmat*point + trans;
00258       
00259       cloud.points[k].x = point(2);
00260       cloud.points[k].y = -point(0);
00261       cloud.points[k].z = -point(1);
00262     
00263       unsigned char r(255), g(255), b(255);
00264       
00265       int32_t rgb_packed = (r << 16) | (g << 8) | b;
00266       memcpy (&cloud.points[k].rgb, &rgb_packed, sizeof (int32_t));
00267       k++;
00268     }
00269   }
00270   
00271   sensor_msgs::PointCloud2 cloud_out;
00272   pcl::toROSMsg (cloud, cloud_out);
00273   cloud_out.header.frame_id = "/pgraph";
00274   pub.publish (cloud_out);
00275 }
00276 
00277 int main(int argc, char** argv) {
00278   ros::init(argc, argv, "stereo_vslam");
00279   if (argc < 4) {
00280     printf("Usage: %s <vocab tree file> <vocab weights file> <calonder trees file>\n", argv[0]);
00281     return 1;
00282   }
00283   
00284   StereoVslamNode vslam(argv[1], argv[2], argv[3]);
00285   ros::spin();
00286 }


vslam_system
Author(s): Kurt Konolige, Patrick Mihelich, Helen Oleynikova
autogenerated on Thu Jan 2 2014 12:12:31