pointcloud_screenpoint_nodelet.cpp
Go to the documentation of this file.
00001 // -*- mode: c++ -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2014, JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/o2r other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the JSK Lab nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
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 // F/K/A <ray converter>
00041 // Haseru Chen, Kei Okada, Yohei Kakiuchi
00042 
00043 void jsk_pcl_ros::PointcloudScreenpoint::onInit()
00044 {
00045   PCLNodelet::onInit();
00046 
00047   queue_size_ = 1;
00048   crop_size_ = 10;
00049   k_ = 16; // todo : this value should be set from parameter.
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   // search near points
00138   JSK_ROS_INFO_STREAM("Request: screenpoint ("<<x<<","<<y<<")="<<"(" << p.x << ", " <<p.y << ", " <<p.z <<")");
00139   //return !(isnan (p.x) || ( (p.x == 0.0) && (p.y == 0.0) && (p.z == 0.0)));
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   // search normal
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   //JSK_ROS_DEBUG("PointcloudScreenpoint::points_cb");
00246   //boost::mutex::scoped_lock lock(this->mutex_callback_);
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_); // if hydro
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   // publish polygon
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);


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Wed Sep 16 2015 04:36:48