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
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
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
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
00082 ProcConfigServer::CallbackType f = boost::bind(&RGBDImageProc::reconfigCallback, this, _1, _2);
00083 config_server_.setCallback(f);
00084
00085
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_);
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
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
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
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
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
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
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
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
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
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
00232 double dur_unwarp, dur_rectify, dur_reproject, dur_cloud, dur_allocate;
00233
00234
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
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
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
00262
00263
00264
00265
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
00273
00274
00275
00276
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
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
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
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
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
00318 rgb_rect_info_msg_.header = rgb_info_msg->header;
00319
00320 dur_allocate = getMsDuration(start_allocate);
00321
00322
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
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);
00356 ROS_INFO("Resampling scale set to %.2f", scale_);
00357 }
00358
00359 }