00001 #include <ros/ros.h>
00002 #include <sensor_msgs/PointCloud2.h>
00003
00004 #include <pcl/pcl_base.h>
00005 #include <pcl/point_types.h>
00006 #include <pcl/ros/conversions.h>
00007 #include <pcl/filters/extract_indices.h>
00008
00009 #include <pcl_ros/pcl_nodelet.h>
00010 #include <pluginlib/class_list_macros.h>
00011
00012 #include <message_filters/subscriber.h>
00013 #include <message_filters/time_synchronizer.h>
00014 #include <message_filters/synchronizer.h>
00015
00016 #include "jsk_recognition_utils/pcl_conversion_util.h"
00017 #include <jsk_topic_tools/connection_based_nodelet.h>
00018
00019 #include <dynamic_reconfigure/server.h>
00020 #include <jsk_pcl_ros/ResizePointsPublisherConfig.h>
00021
00022 #include <cv_bridge/cv_bridge.h>
00023 #include <sensor_msgs/image_encodings.h>
00024
00025 namespace jsk_pcl_ros
00026 {
00027 class ResizePointsPublisher : public jsk_topic_tools::ConnectionBasedNodelet
00028 {
00029 typedef message_filters::sync_policies::ExactTime<sensor_msgs::PointCloud2,
00030 PCLIndicesMsg> SyncPolicy;
00031 typedef jsk_pcl_ros::ResizePointsPublisherConfig Config;
00032
00033 private:
00034 int step_x_, step_y_;
00035 message_filters::Subscriber<sensor_msgs::PointCloud2> sub_input_;
00036 message_filters::Subscriber<PCLIndicesMsg> sub_indices_;
00037 boost::shared_ptr <dynamic_reconfigure::Server<Config> > srv_;
00038 ros::Subscriber sub_;
00039 ros::Subscriber resizedmask_sub_;
00040 boost::shared_ptr<message_filters::Synchronizer<SyncPolicy> >sync_;
00041 ros::Publisher pub_;
00042 bool not_use_rgb_;
00043 boost::mutex mutex_;
00044 bool use_indices_;
00045 void onInit () {
00046 ConnectionBasedNodelet::onInit();
00047 pnh_->param("use_indices", use_indices_, false);
00048 pnh_->param("not_use_rgb", not_use_rgb_, false);
00049 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00050 dynamic_reconfigure::Server<Config>::CallbackType f =
00051 boost::bind (
00052 &ResizePointsPublisher::configCallback, this, _1, _2);
00053 srv_->setCallback (f);
00054 pub_ = advertise<sensor_msgs::PointCloud2>(*pnh_, "output", 1);
00055 resizedmask_sub_ = pnh_->subscribe("input/mask", 1, &ResizePointsPublisher::resizedmaskCallback, this);
00056 onInitPostProcess();
00057 }
00058
00059 void configCallback(Config &config, uint32_t level) {
00060 boost::mutex::scoped_lock lock(mutex_);
00061 step_x_ = config.step_x;
00062 step_y_ = config.step_y;
00063 }
00064
00065 void resizedmaskCallback (const sensor_msgs::Image::ConstPtr& msg) {
00066 boost::mutex::scoped_lock lock(mutex_);
00067 cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy
00068 (msg, sensor_msgs::image_encodings::MONO8);
00069 cv::Mat mask = cv_ptr->image;
00070 int maskwidth = mask.cols;
00071 int maskheight = mask.rows;
00072 int cnt = 0;
00073 for (size_t j = 0; j < maskheight; j++){
00074 for (size_t i = 0; i < maskwidth; i++){
00075 if (mask.at<uchar>(j, i) != 0){
00076 cnt++;
00077 }
00078 }
00079 }
00080 int surface_per = ((double) cnt) / (maskwidth * maskheight) * 100;
00081
00082 step_x_ = sqrt(surface_per);
00083 if (step_x_ < 1) {
00084 step_x_ = 1;
00085 }
00086 step_y_ = step_x_;
00087 }
00088
00089 void subscribe()
00090 {
00091
00092 if (use_indices_) {
00093 sub_input_.subscribe(*pnh_, "input", 1);
00094 sub_indices_.subscribe(*pnh_, "indices", 1);
00095 sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(10);
00096 sync_->connectInput(sub_input_, sub_indices_);
00097 if (!not_use_rgb_) {
00098 sync_->registerCallback(boost::bind(&ResizePointsPublisher::filter<pcl::PointXYZRGB>, this, _1, _2));
00099 }
00100 else {
00101 sync_->registerCallback(boost::bind(&ResizePointsPublisher::filter<pcl::PointXYZ>, this, _1, _2));
00102 }
00103 }
00104 else {
00105 if (!not_use_rgb_) {
00106 sub_ = pnh_->subscribe(
00107 "input", 1,
00108 &ResizePointsPublisher::filter<pcl::PointXYZRGB>, this);
00109 }
00110 else {
00111 sub_ = pnh_->subscribe(
00112 "input", 1,
00113 &ResizePointsPublisher::filter<pcl::PointXYZ>, this);
00114 }
00115 }
00116 }
00117
00118 void unsubscribe()
00119 {
00120 if (use_indices_) {
00121 sub_input_.unsubscribe();
00122 sub_indices_.unsubscribe();
00123 }
00124 else {
00125 sub_.shutdown();
00126 }
00127 }
00128
00129 ~ResizePointsPublisher() { }
00130
00131 template<class T> void filter (const sensor_msgs::PointCloud2::ConstPtr &input) {
00132 filter<T>(input, PCLIndicesMsg::ConstPtr());
00133 }
00134
00135 template<class T> void filter (const sensor_msgs::PointCloud2::ConstPtr &input,
00136 const PCLIndicesMsg::ConstPtr &indices) {
00137 pcl::PointCloud<T> pcl_input_cloud, output;
00138 fromROSMsg(*input, pcl_input_cloud);
00139 boost::mutex::scoped_lock lock (mutex_);
00140 std::vector<int> ex_indices;
00141 ex_indices.resize(0);
00142
00143 int width = input->width;
00144 int height = input->height;
00145 int ox, oy, sx, sy;
00146
00147 sx = step_x_;
00148 ox = sx/2;
00149 if(height == 1) {
00150 sy = 1;
00151 oy = 0;
00152 } else {
00153 sy = step_y_;
00154 oy = sy/2;
00155 }
00156
00157 if (indices) {
00158 std::vector<int> flags;
00159 flags.resize(width*height);
00160
00161
00162
00163
00164 for(unsigned int i = 0; i < indices->indices.size(); i++) {
00165 flags[indices->indices.at(i)] = 1;
00166 }
00167 for(int y = oy; y < height; y += sy) {
00168 for(int x = ox; x < width; x += sx) {
00169 if (flags[y*width + x] == 1) {
00170 ex_indices.push_back(y*width + x);
00171 }
00172 }
00173 }
00174 } else {
00175 for(int y = oy; y < height; y += sy) {
00176 for(int x = ox; x < width; x += sx) {
00177 ex_indices.push_back(y*width + x);
00178 }
00179 }
00180 }
00181 pcl::ExtractIndices<T> extract;
00182 extract.setInputCloud (pcl_input_cloud.makeShared());
00183 extract.setIndices (boost::make_shared <std::vector<int> > (ex_indices));
00184 extract.setNegative (false);
00185 extract.filter (output);
00186
00187 if (output.points.size() > 0) {
00188 sensor_msgs::PointCloud2 ros_out;
00189 toROSMsg(output, ros_out);
00190 ros_out.header = input->header;
00191 ros_out.width = (width - ox)/sx;
00192 if((width - ox)%sx) ros_out.width += 1;
00193 ros_out.height = (height - oy)/sy;
00194 if((height - oy)%sy) ros_out.height += 1;
00195 ros_out.row_step = ros_out.point_step * ros_out.width;
00196 ros_out.is_dense = input->is_dense;
00197 #if DEBUG
00198 NODELET_INFO("%dx%d (%d %d)(%d %d) -> %dx%d %d", width,height, ox, oy, sx, sy,
00199 ros_out.width, ros_out.height, ex_indices.size());
00200 #endif
00201 pub_.publish(ros_out);
00202 NODELET_DEBUG("%s:: input header stamp is [%f]", getName().c_str(),
00203 input->header.stamp.toSec());
00204 NODELET_DEBUG("%s:: output header stamp is [%f]", getName().c_str(),
00205 ros_out.header.stamp.toSec());
00206 }
00207
00208 }
00209
00210 };
00211 }
00212
00213 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::ResizePointsPublisher, nodelet::Nodelet);