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
00035
00036 #include <jsk_topic_tools/log_utils.h>
00037 #include "jsk_pcl_ros/pointcloud_screenpoint.h"
00038 #include <pcl_conversions/pcl_conversions.h>
00039
00040
00041
00042
00043 void jsk_pcl_ros::PointcloudScreenpoint::onInit()
00044 {
00045 PCLNodelet::onInit();
00046
00047 queue_size_ = 1;
00048 crop_size_ = 10;
00049 k_ = 16;
00050
00051 pnh_->param ("queue_size", queue_size_, 1);
00052 pnh_->param ("crop_size", crop_size_, 10);
00053 pnh_->param ("search_size", k_, 16);
00054
00055 pnh_->param ("use_rect", use_rect_, false);
00056 pnh_->param ("use_point", use_point_, false);
00057 pnh_->param ("use_sync", use_sync_, false);
00058 pnh_->param ("use_point_array", use_point_array_, false);
00059 pnh_->param ("use_poly", use_poly_, false);
00060 pnh_->param("publish_points", publish_points_, false);
00061 pnh_->param("publish_point", publish_point_, false);
00062
00063 srv_ = pnh_->advertiseService("screen_to_point", &PointcloudScreenpoint::screenpoint_cb, this);
00064
00065 if (publish_point_) {
00066 pub_point_ = pnh_->advertise< geometry_msgs::PointStamped > ("output_point", 1);
00067 }
00068
00069 if (publish_points_) {
00070 pub_points_ = pnh_->advertise< sensor_msgs::PointCloud2 > ("output", 1);
00071 }
00072
00073 pub_polygon_ = pnh_->advertise<geometry_msgs::PolygonStamped>("output_polygon", 1);
00074
00075 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 5 )
00076 normals_tree_ = boost::make_shared< pcl::search::KdTree<pcl::PointXYZ> > ();
00077 #else
00078 normals_tree_ = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
00079 #endif
00080 n3d_.setKSearch (k_);
00081 n3d_.setSearchMethod (normals_tree_);
00082
00083 points_sub_.subscribe (*pnh_, "points", queue_size_);
00084
00085 if (use_rect_) {
00086 rect_sub_.subscribe (*pnh_, "rect", queue_size_);
00087 if (use_sync_) {
00088 sync_a_rect_ = boost::make_shared < message_filters::Synchronizer< PolygonApproxSyncPolicy > > (queue_size_);
00089 sync_a_rect_->connectInput (points_sub_, rect_sub_);
00090 sync_a_rect_->registerCallback (boost::bind (&PointcloudScreenpoint::callback_rect, this, _1, _2));
00091 } else {
00092 rect_sub_.registerCallback (boost::bind (&PointcloudScreenpoint::rect_cb, this, _1));
00093 }
00094 }
00095
00096 if (use_poly_) {
00097 poly_sub_.subscribe (*pnh_, "poly", queue_size_);
00098 if (use_sync_) {
00099 sync_a_poly_ = boost::make_shared < message_filters::Synchronizer< PolygonApproxSyncPolicy > > (queue_size_);
00100 sync_a_poly_->connectInput (points_sub_, rect_sub_);
00101 sync_a_poly_->registerCallback (boost::bind (&PointcloudScreenpoint::callback_poly, this, _1, _2));
00102 } else {
00103 poly_sub_.registerCallback (boost::bind (&PointcloudScreenpoint::poly_cb, this, _1));
00104 }
00105 }
00106
00107 if (use_point_) {
00108 point_sub_.subscribe (*pnh_, "point", queue_size_);
00109 if (use_sync_) {
00110 sync_a_point_ = boost::make_shared < message_filters::Synchronizer< PointApproxSyncPolicy > > (queue_size_);
00111 sync_a_point_->connectInput (points_sub_, point_sub_);
00112 sync_a_point_->registerCallback (boost::bind (&PointcloudScreenpoint::callback_point, this, _1, _2));
00113 } else {
00114 point_sub_.registerCallback (boost::bind (&PointcloudScreenpoint::point_cb, this, _1));
00115 }
00116 }
00117
00118 if (use_point_array_) {
00119 point_array_sub_.subscribe(*pnh_, "point_array", queue_size_);
00120 if (use_sync_) {
00121 sync_a_point_array_ = boost::make_shared < message_filters::Synchronizer< PointCloudApproxSyncPolicy > > (queue_size_);
00122 sync_a_point_array_->connectInput (points_sub_, point_array_sub_);
00123 sync_a_point_array_->registerCallback (boost::bind (&PointcloudScreenpoint::callback_point_array, this, _1, _2));
00124 } else {
00125 point_array_sub_.registerCallback (boost::bind (&PointcloudScreenpoint::point_array_cb, this, _1));
00126 }
00127 }
00128
00129 points_sub_.registerCallback (boost::bind (&PointcloudScreenpoint::points_cb, this, _1));
00130 }
00131
00132
00133 bool jsk_pcl_ros::PointcloudScreenpoint::checkpoint (pcl::PointCloud< pcl::PointXYZ > &in_pts, int x, int y,
00134 float &resx, float &resy, float &resz) {
00135 if ((x < 0) || (y < 0) || (x >= in_pts.width) || (y >= in_pts.height)) return false;
00136 pcl::PointXYZ p = in_pts.points[in_pts.width * y + x];
00137
00138 JSK_ROS_INFO_STREAM("Request: screenpoint ("<<x<<","<<y<<")="<<"(" << p.x << ", " <<p.y << ", " <<p.z <<")");
00139
00140
00141 if ( !isnan (p.x) && ((p.x != 0.0) || (p.y != 0.0) || (p.z == 0.0)) ) {
00142 resx = p.x; resy = p.y; resz = p.z;
00143 return true;
00144 }
00145 return false;
00146 }
00147
00148 bool jsk_pcl_ros::PointcloudScreenpoint::extract_point (pcl::PointCloud< pcl::PointXYZ > &in_pts, int reqx, int reqy,
00149 float &resx, float &resy, float &resz) {
00150 int x, y;
00151
00152 x = reqx < 0.0 ? ceil(reqx - 0.5) : floor(reqx + 0.5);
00153 y = reqy < 0.0 ? ceil(reqy - 0.5) : floor(reqy + 0.5);
00154 JSK_ROS_WARN("Request : %d %d", x, y);
00155
00156 if (checkpoint (in_pts, x, y, resx, resy, resz)) {
00157 return true;
00158 } else {
00159 for (int n = 1; n < crop_size_; n++) {
00160 for (int y2 = 0; y2 <= n; y2++) {
00161 int x2 = n - y2;
00162 if (checkpoint (in_pts, x + x2, y + y2, resx, resy, resz)) {
00163 return true;
00164 }
00165 if (x2 != 0 && y2 != 0) {
00166 if (checkpoint (in_pts, x - x2, y - y2, resx, resy, resz)) {
00167 return true;
00168 }
00169 }
00170 if (x2 != 0) {
00171 if (checkpoint (in_pts, x - x2, y + y2, resx, resy, resz)) {
00172 return true;
00173 }
00174 }
00175 if (y2 != 0) {
00176 if (checkpoint (in_pts, x + x2, y - y2, resx, resy, resz)) {
00177 return true;
00178 }
00179 }
00180 }
00181 }
00182 }
00183 return false;
00184 }
00185
00186 bool jsk_pcl_ros::PointcloudScreenpoint::screenpoint_cb (jsk_pcl_ros::TransformScreenpoint::Request &req,
00187 jsk_pcl_ros::TransformScreenpoint::Response &res)
00188 {
00189 JSK_ROS_DEBUG("PointcloudScreenpoint::screenpoint_cb");
00190 boost::mutex::scoped_lock lock(this->mutex_callback_);
00191 if ( pts_.points.size() == 0 ) {
00192 JSK_ROS_ERROR("no point cloud was received");
00193 return false;
00194 }
00195
00196 res.header = header_;
00197
00198 bool ret;
00199 float rx, ry, rz;
00200 ret = extract_point (pts_, req.x, req.y, rx, ry, rz);
00201 res.point.x = rx; res.point.y = ry; res.point.z = rz;
00202
00203 if (!ret) {
00204 return false;
00205 }
00206
00207
00208 n3d_.setSearchSurface(boost::make_shared<pcl::PointCloud<pcl::PointXYZ > > (pts_));
00209
00210 pcl::PointCloud<pcl::PointXYZ> cloud_;
00211 pcl::PointXYZ pt;
00212 pt.x = res.point.x;
00213 pt.y = res.point.y;
00214 pt.z = res.point.z;
00215 cloud_.points.resize(0);
00216 cloud_.points.push_back(pt);
00217
00218 n3d_.setInputCloud (boost::make_shared<pcl::PointCloud<pcl::PointXYZ > > (cloud_));
00219 pcl::PointCloud<pcl::Normal> cloud_normals;
00220 n3d_.compute (cloud_normals);
00221
00222 res.vector.x = cloud_normals.points[0].normal_x;
00223 res.vector.y = cloud_normals.points[0].normal_y;
00224 res.vector.z = cloud_normals.points[0].normal_z;
00225
00226 if((res.point.x * res.vector.x + res.point.y * res.vector.y + res.point.z * res.vector.z) < 0) {
00227 res.vector.x *= -1;
00228 res.vector.y *= -1;
00229 res.vector.z *= -1;
00230 }
00231
00232 if (publish_point_) {
00233 geometry_msgs::PointStamped ps;
00234 ps.header = header_;
00235 ps.point.x = res.point.x;
00236 ps.point.y = res.point.y;
00237 ps.point.z = res.point.z;
00238 pub_point_.publish(ps);
00239 }
00240
00241 return true;
00242 }
00243
00244 void jsk_pcl_ros::PointcloudScreenpoint::points_cb(const sensor_msgs::PointCloud2ConstPtr &msg) {
00245
00246
00247 header_ = msg->header;
00248 pcl::fromROSMsg (*msg, pts_);
00249 }
00250
00251 void jsk_pcl_ros::PointcloudScreenpoint::extract_rect (const sensor_msgs::PointCloud2ConstPtr& points_ptr,
00252 int st_x, int st_y, int ed_x, int ed_y) {
00253 if ( st_x < 0 ) st_x = 0;
00254 if ( st_y < 0 ) st_y = 0;
00255 if ( ed_x >= points_ptr->width ) ed_x = points_ptr->width -1;
00256 if ( ed_y >= points_ptr->height ) ed_y = points_ptr->height -1;
00257
00258 int wd = points_ptr->width;
00259 int ht = points_ptr->height;
00260 int rstep = points_ptr->row_step;
00261 int pstep = points_ptr->point_step;
00262
00263 sensor_msgs::PointCloud2 pt;
00264 pt.header = points_ptr->header;
00265 pt.width = ed_x - st_x + 1;
00266 pt.height = ed_y - st_y + 1;
00267 pt.row_step = pt.width * pstep;
00268 pt.point_step = pstep;
00269 pt.is_bigendian = false;
00270 pt.fields = points_ptr->fields;
00271 pt.is_dense = false;
00272 pt.data.resize(pt.row_step * pt.height);
00273
00274 unsigned char * dst_ptr = &(pt.data[0]);
00275
00276 for (size_t idx_y = st_y; idx_y <= ed_y; idx_y++) {
00277 for (size_t idx_x = st_x; idx_x <= ed_x; idx_x++) {
00278 const unsigned char * src_ptr = &(points_ptr->data[idx_y * rstep + idx_x * pstep]);
00279 memcpy(dst_ptr, src_ptr, pstep);
00280 dst_ptr += pstep;
00281 }
00282 }
00283
00284 pub_points_.publish (pt);
00285 }
00286
00287 void jsk_pcl_ros::PointcloudScreenpoint::point_cb (const geometry_msgs::PointStampedConstPtr& pt_ptr) {
00288 if (publish_point_) {
00289 geometry_msgs::PointStamped ps;
00290 bool ret; float rx, ry, rz;
00291 ret = extract_point (pts_, pt_ptr->point.x, pt_ptr->point.y, rx, ry, rz);
00292
00293 if (ret) {
00294 ps.point.x = rx; ps.point.y = ry; ps.point.z = rz;
00295 ps.header = header_;
00296 pub_point_.publish (ps);
00297 }
00298 }
00299 }
00300
00301 void jsk_pcl_ros::PointcloudScreenpoint::callback_point (const sensor_msgs::PointCloud2ConstPtr& points_ptr,
00302 const geometry_msgs::PointStampedConstPtr& pt_ptr) {
00303 point_cb (pt_ptr);
00304
00305 if (publish_points_) {
00306 int st_x = pt_ptr->point.x - crop_size_;
00307 int st_y = pt_ptr->point.y - crop_size_;
00308 int ed_x = pt_ptr->point.x + crop_size_;
00309 int ed_y = pt_ptr->point.y + crop_size_;
00310
00311 extract_rect (points_ptr, st_x, st_y, ed_x, ed_y);
00312 }
00313 }
00314
00315 void jsk_pcl_ros::PointcloudScreenpoint::point_array_cb (const sensor_msgs::PointCloud2ConstPtr& pt_arr_ptr) {
00316 if (publish_points_) {
00317 pcl::PointCloud<pcl::PointXY>::Ptr point_array_cloud(new pcl::PointCloud<pcl::PointXY>);
00318 pcl::fromROSMsg(*pt_arr_ptr, *point_array_cloud);
00319 pcl::PointCloud<pcl::PointXYZ>::Ptr result_cloud(new pcl::PointCloud<pcl::PointXYZ>);
00320 result_cloud->header = pcl_conversions::toPCL(header_);
00321 for (size_t i = 0; i < point_array_cloud->points.size(); i++) {
00322 pcl::PointXY point = point_array_cloud->points[i];
00323 geometry_msgs::PointStamped ps;
00324 bool ret; float rx, ry, rz;
00325 ret = extract_point (pts_, point.x, point.y, rx, ry, rz);
00326 if (ret) {
00327 pcl::PointXYZ point_on_screen;
00328 point_on_screen.x = rx;
00329 point_on_screen.y = ry;
00330 point_on_screen.z = rz;
00331 result_cloud->points.push_back(point_on_screen);
00332 }
00333 }
00334 sensor_msgs::PointCloud2::Ptr ros_cloud(new sensor_msgs::PointCloud2);
00335 pcl::toROSMsg(*result_cloud, *ros_cloud);
00336 ros_cloud->header = header_;
00337 pub_points_.publish(ros_cloud);
00338 }
00339 }
00340 void jsk_pcl_ros::PointcloudScreenpoint::callback_point_array (const sensor_msgs::PointCloud2ConstPtr& points_ptr,
00341 const sensor_msgs::PointCloud2ConstPtr& pt_arr_ptr) {
00342 point_array_cb(pt_arr_ptr);
00343 }
00344
00345 void jsk_pcl_ros::PointcloudScreenpoint::rect_cb (const geometry_msgs::PolygonStampedConstPtr& array_ptr) {
00346 if (array_ptr->polygon.points.size() > 1) {
00347 int st_x = array_ptr->polygon.points[0].x;
00348 int st_y = array_ptr->polygon.points[0].y;
00349 int ed_x = array_ptr->polygon.points[1].x;
00350 int ed_y = array_ptr->polygon.points[1].y;
00351 if (publish_point_) {
00352 geometry_msgs::PointStamped ps;
00353 bool ret; float rx, ry, rz;
00354 ret = extract_point (pts_, (st_x + ed_x) / 2, (st_y + ed_y) / 2, rx, ry, rz);
00355
00356 if (ret) {
00357 ps.point.x = rx; ps.point.y = ry; ps.point.z = rz;
00358 ps.header = header_;
00359 pub_point_.publish (ps);
00360 }
00361 }
00362 }
00363 }
00364
00365 void jsk_pcl_ros::PointcloudScreenpoint::poly_cb(const geometry_msgs::PolygonStampedConstPtr& array_ptr) {
00366
00367 geometry_msgs::PolygonStamped result_polygon;
00368 result_polygon.header = header_;
00369 for (size_t i = 0; i < array_ptr->polygon.points.size(); i++) {
00370 geometry_msgs::Point32 p = array_ptr->polygon.points[i];
00371 float rx, ry, rz;
00372 bool ret = extract_point (pts_, p.x, p.y, rx, ry, rz);
00373 if (!ret) {
00374 JSK_NODELET_ERROR("Failed to project point");
00375 return;
00376 }
00377 geometry_msgs::Point32 p_projected;
00378 p_projected.x = rx;
00379 p_projected.y = ry;
00380 p_projected.z = rz;
00381 result_polygon.polygon.points.push_back(p_projected);
00382 }
00383 pub_polygon_.publish(result_polygon);
00384 }
00385
00386 void jsk_pcl_ros::PointcloudScreenpoint::callback_poly(const sensor_msgs::PointCloud2ConstPtr& points_ptr,
00387 const geometry_msgs::PolygonStampedConstPtr& array_ptr) {
00388 poly_cb(array_ptr);
00389 }
00390
00391
00392
00393 void jsk_pcl_ros::PointcloudScreenpoint::callback_rect(const sensor_msgs::PointCloud2ConstPtr& points_ptr,
00394 const geometry_msgs::PolygonStampedConstPtr& array_ptr) {
00395 if (array_ptr->polygon.points.size() > 1) {
00396 int st_x = array_ptr->polygon.points[0].x;
00397 int st_y = array_ptr->polygon.points[0].y;
00398 int ed_x = array_ptr->polygon.points[1].x;
00399 int ed_y = array_ptr->polygon.points[1].y;
00400
00401 rect_cb (array_ptr);
00402
00403 if (publish_points_) {
00404 extract_rect (points_ptr, st_x, st_y, ed_x, ed_y);
00405 }
00406 }
00407 }
00408
00409 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::PointcloudScreenpoint, nodelet::Nodelet);