00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <boost/version.hpp>
00035 #if ((BOOST_VERSION / 100) % 1000) >= 53
00036 #include <boost/thread/lock_guard.hpp>
00037 #endif
00038
00039 #include <ros/ros.h>
00040 #include <nodelet/nodelet.h>
00041 #include <image_transport/image_transport.h>
00042 #include <image_transport/subscriber_filter.h>
00043 #include <message_filters/subscriber.h>
00044 #include <message_filters/synchronizer.h>
00045 #include <message_filters/sync_policies/exact_time.h>
00046 #include <message_filters/sync_policies/approximate_time.h>
00047
00048 #include <image_geometry/stereo_camera_model.h>
00049 #include <opencv2/calib3d/calib3d.hpp>
00050
00051 #include <sensor_msgs/image_encodings.h>
00052 #include <stereo_msgs/DisparityImage.h>
00053
00054 #include <stereo_image_proc/DisparityConfig.h>
00055 #include <dynamic_reconfigure/server.h>
00056
00057 namespace stereo_image_proc {
00058
00059 using namespace sensor_msgs;
00060 using namespace stereo_msgs;
00061 using namespace message_filters::sync_policies;
00062
00063 class DisparityNodelet : public nodelet::Nodelet
00064 {
00065 boost::shared_ptr<image_transport::ImageTransport> it_;
00066
00067
00068 image_transport::SubscriberFilter sub_l_image_, sub_r_image_;
00069 message_filters::Subscriber<CameraInfo> sub_l_info_, sub_r_info_;
00070 typedef ExactTime<Image, CameraInfo, Image, CameraInfo> ExactPolicy;
00071 typedef ApproximateTime<Image, CameraInfo, Image, CameraInfo> ApproximatePolicy;
00072 typedef message_filters::Synchronizer<ExactPolicy> ExactSync;
00073 typedef message_filters::Synchronizer<ApproximatePolicy> ApproximateSync;
00074 boost::shared_ptr<ExactSync> exact_sync_;
00075 boost::shared_ptr<ApproximateSync> approximate_sync_;
00076
00077
00078 boost::mutex connect_mutex_;
00079 ros::Publisher pub_disparity_;
00080
00081
00082 boost::recursive_mutex config_mutex_;
00083 typedef stereo_image_proc::DisparityConfig Config;
00084 typedef dynamic_reconfigure::Server<Config> ReconfigureServer;
00085 boost::shared_ptr<ReconfigureServer> reconfigure_server_;
00086
00087
00088 image_geometry::StereoCameraModel model_;
00089 cv::StereoBM block_matcher_;
00090
00091 virtual void onInit();
00092
00093 void connectCb();
00094
00095 void imageCb(const ImageConstPtr& l_image_msg, const CameraInfoConstPtr& l_info_msg,
00096 const ImageConstPtr& r_image_msg, const CameraInfoConstPtr& r_info_msg);
00097
00098 void configCb(Config &config, uint32_t level);
00099 };
00100
00101 void DisparityNodelet::onInit()
00102 {
00103 ros::NodeHandle &nh = getNodeHandle();
00104 ros::NodeHandle &private_nh = getPrivateNodeHandle();
00105
00106 it_.reset(new image_transport::ImageTransport(nh));
00107
00108
00109
00110 int queue_size;
00111 private_nh.param("queue_size", queue_size, 5);
00112 bool approx;
00113 private_nh.param("approximate_sync", approx, false);
00114 if (approx)
00115 {
00116 approximate_sync_.reset( new ApproximateSync(ApproximatePolicy(queue_size),
00117 sub_l_image_, sub_l_info_,
00118 sub_r_image_, sub_r_info_) );
00119 approximate_sync_->registerCallback(boost::bind(&DisparityNodelet::imageCb,
00120 this, _1, _2, _3, _4));
00121 }
00122 else
00123 {
00124 exact_sync_.reset( new ExactSync(ExactPolicy(queue_size),
00125 sub_l_image_, sub_l_info_,
00126 sub_r_image_, sub_r_info_) );
00127 exact_sync_->registerCallback(boost::bind(&DisparityNodelet::imageCb,
00128 this, _1, _2, _3, _4));
00129 }
00130
00131
00132 ReconfigureServer::CallbackType f = boost::bind(&DisparityNodelet::configCb,
00133 this, _1, _2);
00134 reconfigure_server_.reset(new ReconfigureServer(config_mutex_, private_nh));
00135 reconfigure_server_->setCallback(f);
00136
00137
00138 ros::SubscriberStatusCallback connect_cb = boost::bind(&DisparityNodelet::connectCb, this);
00139
00140 boost::lock_guard<boost::mutex> lock(connect_mutex_);
00141 pub_disparity_ = nh.advertise<DisparityImage>("disparity", 1, connect_cb, connect_cb);
00142 }
00143
00144
00145 void DisparityNodelet::connectCb()
00146 {
00147 boost::lock_guard<boost::mutex> lock(connect_mutex_);
00148 if (pub_disparity_.getNumSubscribers() == 0)
00149 {
00150 sub_l_image_.unsubscribe();
00151 sub_l_info_ .unsubscribe();
00152 sub_r_image_.unsubscribe();
00153 sub_r_info_ .unsubscribe();
00154 }
00155 else if (!sub_l_image_.getSubscriber())
00156 {
00157 ros::NodeHandle &nh = getNodeHandle();
00158
00160 image_transport::TransportHints hints("raw", ros::TransportHints(), getPrivateNodeHandle());
00161 sub_l_image_.subscribe(*it_, "left/image_rect", 1, hints);
00162 sub_l_info_ .subscribe(nh, "left/camera_info", 1);
00163 sub_r_image_.subscribe(*it_, "right/image_rect", 1, hints);
00164 sub_r_info_ .subscribe(nh, "right/camera_info", 1);
00165 }
00166 }
00167
00168 void DisparityNodelet::imageCb(const ImageConstPtr& l_image_msg,
00169 const CameraInfoConstPtr& l_info_msg,
00170 const ImageConstPtr& r_image_msg,
00171 const CameraInfoConstPtr& r_info_msg)
00172 {
00174 assert(l_image_msg->encoding == sensor_msgs::image_encodings::MONO8);
00175 assert(r_image_msg->encoding == sensor_msgs::image_encodings::MONO8);
00176
00177
00178 model_.fromCameraInfo(l_info_msg, r_info_msg);
00179
00180
00181 DisparityImagePtr disp_msg = boost::make_shared<DisparityImage>();
00182 disp_msg->header = l_info_msg->header;
00183 disp_msg->image.header = l_info_msg->header;
00184 disp_msg->image.height = l_image_msg->height;
00185 disp_msg->image.width = l_image_msg->width;
00186 disp_msg->image.encoding = sensor_msgs::image_encodings::TYPE_32FC1;
00187 disp_msg->image.step = disp_msg->image.width * sizeof(float);
00188 disp_msg->image.data.resize(disp_msg->image.height * disp_msg->image.step);
00189
00190
00191 disp_msg->f = model_.right().fx();
00192 disp_msg->T = model_.baseline();
00193
00194
00195 cv::Ptr<CvStereoBMState> params = block_matcher_.state;
00196 int border = params->SADWindowSize / 2;
00197 int left = params->numberOfDisparities + params->minDisparity + border - 1;
00198 int wtf = (params->minDisparity >= 0) ? border + params->minDisparity : std::max(border, -params->minDisparity);
00199 int right = disp_msg->image.width - 1 - wtf;
00200 int top = border;
00201 int bottom = disp_msg->image.height - 1 - border;
00202 disp_msg->valid_window.x_offset = left;
00203 disp_msg->valid_window.y_offset = top;
00204 disp_msg->valid_window.width = right - left;
00205 disp_msg->valid_window.height = bottom - top;
00206
00207
00208 disp_msg->min_disparity = params->minDisparity;
00209 disp_msg->max_disparity = params->minDisparity + params->numberOfDisparities - 1;
00210 disp_msg->delta_d = 1.0 / 16;
00211
00212
00213 const cv::Mat_<uint8_t> l_image(l_image_msg->height, l_image_msg->width,
00214 const_cast<uint8_t*>(&l_image_msg->data[0]),
00215 l_image_msg->step);
00216 const cv::Mat_<uint8_t> r_image(r_image_msg->height, r_image_msg->width,
00217 const_cast<uint8_t*>(&r_image_msg->data[0]),
00218 r_image_msg->step);
00219 cv::Mat_<float> disp_image(disp_msg->image.height, disp_msg->image.width,
00220 reinterpret_cast<float*>(&disp_msg->image.data[0]),
00221 disp_msg->image.step);
00222
00223
00224 block_matcher_(l_image, r_image, disp_image, CV_32F);
00225
00226
00227 double cx_l = model_.left().cx();
00228 double cx_r = model_.right().cx();
00229 if (cx_l != cx_r)
00230 cv::subtract(disp_image, cv::Scalar(cx_l - cx_r), disp_image);
00231
00232 pub_disparity_.publish(disp_msg);
00233 }
00234
00235 void DisparityNodelet::configCb(Config &config, uint32_t level)
00236 {
00237
00238 config.prefilter_size |= 0x1;
00239 config.correlation_window_size |= 0x1;
00240 config.disparity_range = (config.disparity_range / 16) * 16;
00241
00242
00243
00244 block_matcher_.state->preFilterSize = config.prefilter_size;
00245 block_matcher_.state->preFilterCap = config.prefilter_cap;
00246 block_matcher_.state->SADWindowSize = config.correlation_window_size;
00247 block_matcher_.state->minDisparity = config.min_disparity;
00248 block_matcher_.state->numberOfDisparities = config.disparity_range;
00249 block_matcher_.state->uniquenessRatio = config.uniqueness_ratio;
00250 block_matcher_.state->textureThreshold = config.texture_threshold;
00251 block_matcher_.state->speckleWindowSize = config.speckle_size;
00252 block_matcher_.state->speckleRange = config.speckle_range;
00253 }
00254
00255 }
00256
00257
00258 #include <pluginlib/class_list_macros.h>
00259 PLUGINLIB_EXPORT_CLASS(stereo_image_proc::DisparityNodelet,nodelet::Nodelet)