rgbd_image_proc.cpp
Go to the documentation of this file.
00001 
00024 #include "ccny_rgbd/apps/rgbd_image_proc.h"
00025 
00026 namespace ccny_rgbd {
00027 
00028 RGBDImageProc::RGBDImageProc(
00029   const ros::NodeHandle& nh, 
00030   const ros::NodeHandle& nh_private):
00031   nh_(nh), nh_private_(nh_private), 
00032   rgb_image_transport_(nh_),
00033   depth_image_transport_(nh_), 
00034   config_server_(nh_private_),
00035   size_in_(0,0)
00036 { 
00037   // parameters 
00038   if (!nh_private_.getParam ("queue_size", queue_size_))
00039     queue_size_ = 5;
00040   if (!nh_private_.getParam("scale", scale_))
00041     scale_ = 1.0;
00042   if (!nh_private_.getParam("unwarp", unwarp_))
00043     unwarp_ = true;
00044   if (!nh_private_.getParam("verbose", verbose_))
00045     verbose_ = false;
00046   if (!nh_private_.getParam("publish_cloud", publish_cloud_))
00047     publish_cloud_ = true;
00048   if (!nh_private_.getParam("calib_path", calib_path_))
00049   {
00050     std::string home_path = getenv("HOME");
00051     calib_path_ = home_path + "/.ros/rgbd_calibration";
00052   }
00053 
00054   calib_extr_filename_ = calib_path_ + "/extr.yml";
00055   calib_warp_filename_ = calib_path_ + "/warp.yml";
00056   
00057   // load calibration (extrinsics, depth unwarp params) from files
00058   loadCalibration();
00059   if (unwarp_)
00060   {
00061     bool load_result = loadUnwarpCalibration();
00062     if (!load_result)
00063     {
00064       ROS_WARN("Disbaling unwarping due to missing calibration file");
00065       unwarp_ = true;
00066     }
00067   }
00068   
00069   // publishers
00070   rgb_publisher_   = rgb_image_transport_.advertise(
00071     "rgbd/rgb", queue_size_);
00072   depth_publisher_ = depth_image_transport_.advertise(
00073     "rgbd/depth", queue_size_);
00074   info_publisher_  = nh_.advertise<CameraInfoMsg>(
00075     "rgbd/info", queue_size_);
00076 
00077   if(publish_cloud_)
00078     cloud_publisher_ = nh_.advertise<PointCloudT>(
00079           "rgbd/cloud", queue_size_);
00080 
00081   // dynamic reconfigure
00082   ProcConfigServer::CallbackType f = boost::bind(&RGBDImageProc::reconfigCallback, this, _1, _2);
00083   config_server_.setCallback(f);
00084   
00085   // subscribers
00086   sub_rgb_.subscribe  (rgb_image_transport_,   
00087     "/camera/rgb/image_color", queue_size_);
00088   sub_depth_.subscribe(depth_image_transport_, 
00089     "/camera/depth/image_raw", queue_size_); //16UC1
00090   
00091   sub_rgb_info_.subscribe  (nh_, 
00092     "/camera/rgb/camera_info", queue_size_);
00093   sub_depth_info_.subscribe(nh_, 
00094     "/camera/depth/camera_info", queue_size_);
00095   
00096   sync_.reset(new RGBDSynchronizer4(
00097                 RGBDSyncPolicy4(queue_size_), sub_rgb_, sub_depth_, 
00098                 sub_rgb_info_, sub_depth_info_));
00099   
00100   sync_->registerCallback(boost::bind(&RGBDImageProc::RGBDCallback, this, _1, _2, _3, _4)); 
00101 }
00102 
00103 RGBDImageProc::~RGBDImageProc()
00104 {
00105   ROS_INFO("Destroying RGBDImageProc"); 
00106 }
00107 
00108 bool RGBDImageProc::loadCalibration()
00109 {
00110   // check that file exist
00111   if (!boost::filesystem::exists(calib_extr_filename_))
00112   {
00113     ROS_ERROR("Could not open %s", calib_extr_filename_.c_str());
00115     return false;
00116   }
00117 
00118   // load intrinsics and distortion coefficients
00119   ROS_INFO("Reading camera calibration files...");
00120   cv::FileStorage fs_extr(calib_extr_filename_, cv::FileStorage::READ);
00121 
00122   fs_extr["ir2rgb"] >> ir2rgb_;
00123 
00124   return true;
00125 }
00126 
00127 bool RGBDImageProc::loadUnwarpCalibration()
00128 {
00129   if (!boost::filesystem::exists(calib_warp_filename_))
00130   {
00131     ROS_ERROR("Could not open %s", calib_warp_filename_.c_str());
00132     return false;
00133   }
00134   
00135   // load warp coefficients
00136   cv::FileStorage fs_warp(calib_warp_filename_, cv::FileStorage::READ);   
00137 
00138   fs_warp["c0"] >> coeff_0_;
00139   fs_warp["c1"] >> coeff_1_;
00140   fs_warp["c2"] >> coeff_2_;
00141   fs_warp["fit_mode"] >> fit_mode_;
00142   
00143   return true;
00144 }
00145 
00146 void RGBDImageProc::initMaps(
00147   const CameraInfoMsg::ConstPtr& rgb_info_msg,
00148   const CameraInfoMsg::ConstPtr& depth_info_msg)
00149 { 
00150   boost::mutex::scoped_lock(mutex_);
00151   
00152   ROS_INFO("Initializing rectification maps");
00153   
00154   // **** get OpenCV matrices from CameraInfo messages
00155   cv::Mat intr_rgb, intr_depth;
00156   cv::Mat dist_rgb, dist_depth;
00157   
00158   convertCameraInfoToMats(rgb_info_msg, intr_rgb, dist_rgb);
00159   convertCameraInfoToMats(depth_info_msg, intr_depth, dist_depth); 
00160   
00161   // **** sizes 
00162   double alpha = 0.0;
00163     
00164   if (size_in_.width  != (int)rgb_info_msg->width || 
00165       size_in_.height != (int)rgb_info_msg->height)
00166   {
00167     ROS_WARN("Image size does not match CameraInfo size. Rescaling.");
00168     double w_factor = (double)size_in_.width  / (double)rgb_info_msg->width;
00169     double h_factor = (double)size_in_.height / (double)rgb_info_msg->height;
00170     
00171     intr_rgb.at<double>(0,0) *= w_factor;
00172     intr_rgb.at<double>(1,1) *= h_factor;   
00173     intr_rgb.at<double>(0,2) *= w_factor;
00174     intr_rgb.at<double>(1,2) *= h_factor;
00175 
00176     intr_depth.at<double>(0,0) *= w_factor;
00177     intr_depth.at<double>(1,1) *= h_factor;   
00178     intr_depth.at<double>(0,2) *= w_factor;
00179     intr_depth.at<double>(1,2) *= h_factor;
00180   }
00181   
00182   cv::Size size_out;
00183   size_out.height = size_in_.height * scale_;
00184   size_out.width  = size_in_.width  * scale_;
00185    
00186   // **** get optimal camera matrices
00187   intr_rect_rgb_ = cv::getOptimalNewCameraMatrix(
00188     intr_rgb, dist_rgb, size_in_, alpha, size_out);
00189  
00190   intr_rect_depth_ = cv::getOptimalNewCameraMatrix(
00191     intr_depth, dist_depth, size_in_, alpha, size_out);
00192       
00193   // **** create undistortion maps
00194   cv::initUndistortRectifyMap(
00195     intr_rgb, dist_rgb, cv::Mat(), intr_rect_rgb_, 
00196     size_out, CV_16SC2, map_rgb_1_, map_rgb_2_);
00197   
00198   cv::initUndistortRectifyMap(
00199     intr_depth, dist_depth, cv::Mat(), intr_rect_depth_, 
00200     size_out, CV_16SC2, map_depth_1_, map_depth_2_);  
00201   
00202   // **** rectify the coefficient images
00203   if(unwarp_)
00204   {
00205     cv::remap(coeff_0_, coeff_0_rect_, map_depth_1_, map_depth_2_,  cv::INTER_NEAREST);
00206     cv::remap(coeff_1_, coeff_1_rect_, map_depth_1_, map_depth_2_,  cv::INTER_NEAREST);
00207     cv::remap(coeff_2_, coeff_2_rect_, map_depth_1_, map_depth_2_,  cv::INTER_NEAREST);
00208   }
00209 
00210   // **** save new intrinsics as camera models
00211   rgb_rect_info_msg_.header = rgb_info_msg->header;
00212   rgb_rect_info_msg_.width  = size_out.width;
00213   rgb_rect_info_msg_.height = size_out.height;  
00214 
00215   depth_rect_info_msg_.header = depth_info_msg->header;
00216   depth_rect_info_msg_.width  = size_out.width;
00217   depth_rect_info_msg_.height = size_out.height;  
00218   
00219   convertMatToCameraInfo(intr_rect_rgb_,   rgb_rect_info_msg_);
00220   convertMatToCameraInfo(intr_rect_depth_, depth_rect_info_msg_);  
00221 }
00222 
00223 void RGBDImageProc::RGBDCallback(
00224   const ImageMsg::ConstPtr& rgb_msg,
00225   const ImageMsg::ConstPtr& depth_msg,
00226   const CameraInfoMsg::ConstPtr& rgb_info_msg,
00227   const CameraInfoMsg::ConstPtr& depth_info_msg)
00228 {  
00229   boost::mutex::scoped_lock(mutex_);
00230   
00231   // for profiling
00232   double dur_unwarp, dur_rectify, dur_reproject, dur_cloud, dur_allocate; 
00233   
00234   // **** images need to be the same size
00235   if (rgb_msg->height != depth_msg->height || 
00236       rgb_msg->width  != depth_msg->width)
00237   {
00238     ROS_WARN("RGB and depth images have different sizes, skipping");
00239     return;
00240   }
00241   
00242   // **** initialize if needed
00243   if (size_in_.height != (int)rgb_msg->height ||
00244       size_in_.width  != (int)rgb_msg->width)
00245   {
00246     ROS_INFO("Initializing");
00247   
00248     size_in_.height = (int)rgb_msg->height;
00249     size_in_.width  = (int)rgb_msg->width;
00250     
00251     initMaps(rgb_info_msg, depth_info_msg);
00252   }
00253   
00254   // **** convert ros images to opencv Mat
00255   cv_bridge::CvImageConstPtr rgb_ptr   = cv_bridge::toCvShare(rgb_msg);
00256   cv_bridge::CvImageConstPtr depth_ptr = cv_bridge::toCvShare(depth_msg);
00257 
00258   const cv::Mat& rgb_img   = rgb_ptr->image;
00259   const cv::Mat& depth_img = depth_ptr->image;
00260   
00261   //cv::imshow("RGB", rgb_img);
00262   //cv::imshow("Depth", depth_img);
00263   //cv::waitKey(1);
00264   
00265   // **** rectify
00266   ros::WallTime start_rectify = ros::WallTime::now();
00267   cv::Mat rgb_img_rect, depth_img_rect;
00268   cv::remap(rgb_img, rgb_img_rect, map_rgb_1_, map_rgb_2_, cv::INTER_LINEAR);
00269   cv::remap(depth_img, depth_img_rect, map_depth_1_, map_depth_2_,  cv::INTER_NEAREST);
00270   dur_rectify = getMsDuration(start_rectify);
00271   
00272   //cv::imshow("RGB Rect", rgb_img_rect);
00273   //cv::imshow("Depth Rect", depth_img_rect);
00274   //cv::waitKey(1);
00275   
00276   // **** unwarp 
00277   if (unwarp_) 
00278   {    
00279     ros::WallTime start_unwarp = ros::WallTime::now();
00280     rgbdtools::unwarpDepthImage(
00281       depth_img_rect, coeff_0_rect_, coeff_1_rect_, coeff_2_rect_, fit_mode_);
00282     dur_unwarp = getMsDuration(start_unwarp);
00283   }
00284   else dur_unwarp = 0.0;
00285   
00286   // **** reproject
00287   ros::WallTime start_reproject = ros::WallTime::now();
00288   cv::Mat depth_img_rect_reg;
00289   rgbdtools::buildRegisteredDepthImage(
00290     intr_rect_depth_, intr_rect_rgb_, ir2rgb_, depth_img_rect, depth_img_rect_reg);
00291   dur_reproject = getMsDuration(start_reproject);
00292 
00293   // **** point cloud
00294   if (publish_cloud_)
00295   {
00296     ros::WallTime start_cloud = ros::WallTime::now();
00297     PointCloudT::Ptr cloud_ptr;
00298     cloud_ptr.reset(new PointCloudT());
00299     rgbdtools::buildPointCloud(
00300       depth_img_rect_reg, rgb_img_rect, intr_rect_rgb_, *cloud_ptr);
00301     cloud_ptr->header = rgb_info_msg->header;
00302     cloud_publisher_.publish(cloud_ptr);
00303     dur_cloud = getMsDuration(start_cloud);
00304   }
00305   else dur_cloud = 0.0;
00306   
00307   // **** allocate registered rgb image
00308   ros::WallTime start_allocate = ros::WallTime::now();
00309 
00310   cv_bridge::CvImage cv_img_rgb(rgb_msg->header, rgb_msg->encoding, rgb_img_rect);
00311   ImageMsg::Ptr rgb_out_msg = cv_img_rgb.toImageMsg();
00312 
00313   // **** allocate registered depth image
00314   cv_bridge::CvImage cv_img_depth(depth_msg->header, depth_msg->encoding, depth_img_rect_reg);
00315   ImageMsg::Ptr depth_out_msg = cv_img_depth.toImageMsg();
00316   
00317   // **** update camera info (single, since both images are in rgb frame)
00318   rgb_rect_info_msg_.header = rgb_info_msg->header;
00319   
00320   dur_allocate = getMsDuration(start_allocate); 
00321 
00322   // **** print diagnostics
00323   
00324   double dur_total = dur_rectify + dur_reproject + dur_unwarp + dur_cloud + dur_allocate;
00325   if(verbose_)
00326   {
00327     ROS_INFO("Rect %.1f Reproj %.1f Unwarp %.1f Cloud %.1f Alloc %.1f Total %.1f ms",
00328              dur_rectify, dur_reproject,  dur_unwarp, dur_cloud, dur_allocate,
00329              dur_total);
00330   }
00331   // **** publish
00332   rgb_publisher_.publish(rgb_out_msg);
00333   depth_publisher_.publish(depth_out_msg);
00334   info_publisher_.publish(rgb_rect_info_msg_);
00335 }
00336 
00337 void RGBDImageProc::reconfigCallback(ProcConfig& config, uint32_t level)
00338 {
00339   boost::mutex::scoped_lock(mutex_);
00340   bool old_publish_cloud = publish_cloud_;
00341       publish_cloud_ = config.publish_cloud;
00342   if(!old_publish_cloud && publish_cloud_)
00343   {
00344     cloud_publisher_ = nh_.advertise<PointCloudT>(
00345         "rgbd/cloud", queue_size_);
00346   }
00347   else
00348   {
00349     if(old_publish_cloud && !publish_cloud_)
00350       cloud_publisher_.shutdown();
00351   }
00352 
00353 
00354   scale_ = config.scale;
00355   size_in_ = cv::Size(0,0); // force a reinitialization on the next image callback
00356   ROS_INFO("Resampling scale set to %.2f", scale_);
00357 }
00358 
00359 } //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