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 <ros/ros.h>
00035 #include <nodelet/nodelet.h>
00036 #include <image_transport/image_transport.h>
00037 #include <sensor_msgs/image_encodings.h>
00038 #include <image_geometry/pinhole_camera_model.h>
00039 #include <boost/thread.hpp>
00040 #include <depth_image_proc/depth_traits.h>
00041
00042 #include <sensor_msgs/point_cloud2_iterator.h>
00043
00044 namespace depth_image_proc {
00045
00046 namespace enc = sensor_msgs::image_encodings;
00047
00048 class PointCloudXyzRadialNodelet : public nodelet::Nodelet
00049 {
00050
00051 boost::shared_ptr<image_transport::ImageTransport> it_;
00052 image_transport::CameraSubscriber sub_depth_;
00053 int queue_size_;
00054
00055
00056 boost::mutex connect_mutex_;
00057 typedef sensor_msgs::PointCloud2 PointCloud;
00058 ros::Publisher pub_point_cloud_;
00059
00060
00061 std::vector<double> D_;
00062 boost::array<double, 9> K_;
00063
00064 int width_;
00065 int height_;
00066
00067 cv::Mat binned;
00068
00069 virtual void onInit();
00070
00071 void connectCb();
00072
00073 void depthCb(const sensor_msgs::ImageConstPtr& depth_msg,
00074 const sensor_msgs::CameraInfoConstPtr& info_msg);
00075
00076
00077 template<typename T>
00078 void convert(const sensor_msgs::ImageConstPtr& depth_msg, PointCloud::Ptr& cloud_msg);
00079 };
00080
00081 cv::Mat initMatrix(cv::Mat cameraMatrix, cv::Mat distCoeffs, int width, int height, bool radial)
00082 {
00083 int i,j;
00084 int totalsize = width*height;
00085 cv::Mat pixelVectors(1,totalsize,CV_32FC3);
00086 cv::Mat dst(1,totalsize,CV_32FC3);
00087
00088 cv::Mat sensorPoints(cv::Size(height,width), CV_32FC2);
00089 cv::Mat undistortedSensorPoints(1,totalsize, CV_32FC2);
00090
00091 std::vector<cv::Mat> ch;
00092 for(j = 0; j < height; j++)
00093 {
00094 for(i = 0; i < width; i++)
00095 {
00096 cv::Vec2f &p = sensorPoints.at<cv::Vec2f>(i,j);
00097 p[0] = i;
00098 p[1] = j;
00099 }
00100 }
00101
00102 sensorPoints = sensorPoints.reshape(2,1);
00103
00104 cv::undistortPoints(sensorPoints, undistortedSensorPoints, cameraMatrix, distCoeffs);
00105
00106 ch.push_back(undistortedSensorPoints);
00107 ch.push_back(cv::Mat::ones(1,totalsize,CV_32FC1));
00108 cv::merge(ch,pixelVectors);
00109
00110 if(radial)
00111 {
00112 for(i = 0; i < totalsize; i++)
00113 {
00114 normalize(pixelVectors.at<cv::Vec3f>(i),
00115 dst.at<cv::Vec3f>(i));
00116 }
00117 pixelVectors = dst;
00118 }
00119 return pixelVectors.reshape(3,width);
00120 }
00121
00122
00123 void PointCloudXyzRadialNodelet::onInit()
00124 {
00125 ros::NodeHandle& nh = getNodeHandle();
00126 ros::NodeHandle& private_nh = getPrivateNodeHandle();
00127 it_.reset(new image_transport::ImageTransport(nh));
00128
00129
00130 private_nh.param("queue_size", queue_size_, 5);
00131
00132
00133 ros::SubscriberStatusCallback connect_cb =
00134 boost::bind(&PointCloudXyzRadialNodelet::connectCb, this);
00135
00136 boost::lock_guard<boost::mutex> lock(connect_mutex_);
00137 pub_point_cloud_ = nh.advertise<PointCloud>("points", 1, connect_cb, connect_cb);
00138 }
00139
00140
00141 void PointCloudXyzRadialNodelet::connectCb()
00142 {
00143 boost::lock_guard<boost::mutex> lock(connect_mutex_);
00144 if (pub_point_cloud_.getNumSubscribers() == 0)
00145 {
00146 sub_depth_.shutdown();
00147 }
00148 else if (!sub_depth_)
00149 {
00150 image_transport::TransportHints hints("raw", ros::TransportHints(), getPrivateNodeHandle());
00151 sub_depth_ = it_->subscribeCamera("image_raw",
00152 queue_size_,
00153 &PointCloudXyzRadialNodelet::depthCb,
00154 this, hints);
00155 }
00156 }
00157
00158 void PointCloudXyzRadialNodelet::depthCb(const sensor_msgs::ImageConstPtr& depth_msg,
00159 const sensor_msgs::CameraInfoConstPtr& info_msg)
00160 {
00161 PointCloud::Ptr cloud_msg(new PointCloud);
00162 cloud_msg->header = depth_msg->header;
00163 cloud_msg->height = depth_msg->height;
00164 cloud_msg->width = depth_msg->width;
00165 cloud_msg->is_dense = false;
00166 cloud_msg->is_bigendian = false;
00167
00168 sensor_msgs::PointCloud2Modifier pcd_modifier(*cloud_msg);
00169 pcd_modifier.setPointCloud2FieldsByString(1, "xyz");
00170
00171 if(info_msg->D != D_ || info_msg->K != K_ || width_ != info_msg->width ||
00172 height_ != info_msg->height)
00173 {
00174 D_ = info_msg->D;
00175 K_ = info_msg->K;
00176 width_ = info_msg->width;
00177 height_ = info_msg->height;
00178 binned = initMatrix(cv::Mat_<double>(3, 3, &K_[0]),cv::Mat(D_),width_,height_,true);
00179 }
00180
00181 if (depth_msg->encoding == enc::TYPE_16UC1)
00182 {
00183 convert<uint16_t>(depth_msg, cloud_msg);
00184 }
00185 else if (depth_msg->encoding == enc::TYPE_32FC1)
00186 {
00187 convert<float>(depth_msg, cloud_msg);
00188 }
00189 else
00190 {
00191 NODELET_ERROR_THROTTLE(5, "Depth image has unsupported encoding [%s]", depth_msg->encoding.c_str());
00192 return;
00193 }
00194
00195 pub_point_cloud_.publish (cloud_msg);
00196 }
00197
00198 template<typename T>
00199 void PointCloudXyzRadialNodelet::convert(const sensor_msgs::ImageConstPtr& depth_msg, PointCloud::Ptr& cloud_msg)
00200 {
00201
00202 double unit_scaling = DepthTraits<T>::toMeters( T(1) );
00203 float bad_point = std::numeric_limits<float>::quiet_NaN();
00204
00205 sensor_msgs::PointCloud2Iterator<float> iter_x(*cloud_msg, "x");
00206 sensor_msgs::PointCloud2Iterator<float> iter_y(*cloud_msg, "y");
00207 sensor_msgs::PointCloud2Iterator<float> iter_z(*cloud_msg, "z");
00208 const T* depth_row = reinterpret_cast<const T*>(&depth_msg->data[0]);
00209 int row_step = depth_msg->step / sizeof(T);
00210 for (int v = 0; v < (int)cloud_msg->height; ++v, depth_row += row_step)
00211 {
00212 for (int u = 0; u < (int)cloud_msg->width; ++u, ++iter_x, ++iter_y, ++iter_z)
00213 {
00214 T depth = depth_row[u];
00215
00216
00217 if (!DepthTraits<T>::valid(depth))
00218 {
00219 *iter_x = *iter_y = *iter_z = bad_point;
00220 continue;
00221 }
00222 const cv::Vec3f &cvPoint = binned.at<cv::Vec3f>(u,v) * DepthTraits<T>::toMeters(depth);
00223
00224 *iter_x = cvPoint(0);
00225 *iter_y = cvPoint(1);
00226 *iter_z = cvPoint(2);
00227 }
00228 }
00229 }
00230
00231 }
00232
00233
00234 #include <pluginlib/class_list_macros.h>
00235 PLUGINLIB_EXPORT_CLASS(depth_image_proc::PointCloudXyzRadialNodelet,nodelet::Nodelet);