mask_image_to_depth_considered_mask_image_nodelet.cpp
Go to the documentation of this file.
1 // -*- mode: c++ -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2014, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/o2r other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 #define BOOST_PARAMETER_MAX_ARITY 7
38 #include <cv_bridge/cv_bridge.h>
39 #include <pcl/kdtree/kdtree_flann.h>
40 #include <pcl/filters/impl/filter.hpp>
41 
42 namespace jsk_pcl_ros_utils
43 {
45  {
46  DiagnosticNodelet::onInit();
47  pub_ = advertise<sensor_msgs::Image>(*pnh_, "output", 1);
48  applypub_ = advertise<sensor_msgs::Image>(*pnh_, "applyoutput", 1);
49  srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
50  dynamic_reconfigure::Server<Config>::CallbackType f =
51  boost::bind (
53  srv_->setCallback (f);
54  sub_ = pnh_->subscribe("input/maskregion", 1, &MaskImageToDepthConsideredMaskImage::mask_region_callback, this);
55  region_width_ = 0;
56  region_height_ = 0;
57  region_x_off_ = 0;
58  region_y_off_ = 0;
59 
61  }
62 
64  boost::mutex::scoped_lock lock(mutex_);
65  extract_num_ = config.extract_num;
66  use_mask_region_ = config.use_mask_region;
67  in_the_order_of_depth_ = config.in_the_order_of_depth;
68 
69  if (approximate_sync_ != config.approximate_sync ||
70  queue_size_ != config.queue_size) {
71  approximate_sync_ = config.approximate_sync;
72  queue_size_ = config.queue_size;
73  if (isSubscribed()) {
74  unsubscribe();
75  subscribe();
76  }
77  }
78  }
79 
80 
81  void MaskImageToDepthConsideredMaskImage::mask_region_callback(const sensor_msgs::Image::ConstPtr& msg){
82  boost::mutex::scoped_lock lock(mutex_);
85  cv::Mat mask = cv_ptr->image;
86  int tmp_width = 0;
87  int tmp_height = 0;
88  int tmp_x_off = 0;
89  int tmp_y_off = 0;
90  bool flag = true;
91  int maskwidth = mask.cols;
92  int maskheight = mask.rows;
93  int cnt = 0;
94  for (size_t j = 0; j < maskheight; j++) {
95  for (size_t i = 0; i < maskwidth; i++) {
96  if (mask.at<uchar>(j, i) != 0) {
97  cnt++;
98  if (flag == true) {
99  tmp_x_off = i;
100  tmp_y_off = j;
101  flag = false;
102  }
103  else {
104  tmp_width = i-tmp_x_off + 1;
105  tmp_height = j-tmp_y_off + 1;
106  }}}}
107  NODELET_INFO("mask_image_to_depth_considered_mask_image_nodelet : tmp width:%d height:%d x_off:%d y_off:%d", tmp_width, tmp_height, tmp_x_off, tmp_y_off);
108  region_width_ratio_ = ((double) tmp_width) / maskwidth;
109  region_height_ratio_ = ((double) tmp_height) / maskheight;
110  region_x_off_ratio_ = ((double) tmp_x_off) / maskwidth;
111  region_y_off_ratio_ = ((double) tmp_y_off) / maskheight;
112  use_region_ratio_ = true;
113  NODELET_INFO("mask_image_to_depth_considered_mask_image_nodelet : next region width_ratio:%f height_ratio:%f x_off_ratio:%f y_off_ratio:%f", region_width_ratio_, region_height_ratio_, region_x_off_ratio_, region_y_off_ratio_);
114  }
115 
116 
118  {
119  sub_input_.subscribe(*pnh_, "input", 1);
120  sub_image_.subscribe(*pnh_, "input/image", 1);
121  if (approximate_sync_) {
122  async_ = boost::make_shared<message_filters::Synchronizer<ApproximateSyncPolicy> >(queue_size_);
123  async_->connectInput(sub_input_, sub_image_);
124  async_->registerCallback(boost::bind(&MaskImageToDepthConsideredMaskImage::extractmask, this, _1, _2));
125  }
126  else {
127  sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(queue_size_);
128  sync_->connectInput(sub_input_, sub_image_);
129  sync_->registerCallback(boost::bind(&MaskImageToDepthConsideredMaskImage::extractmask,
130  this, _1, _2));
131  }
132  }
133 
135  {
138  }
139 
141  (
142  const sensor_msgs::PointCloud2::ConstPtr& point_cloud2_msg,
143  const sensor_msgs::Image::ConstPtr& image_msg)
144  {
145  boost::mutex::scoped_lock lock(mutex_);
146  if (point_cloud2_msg->width == image_msg->width && point_cloud2_msg->height == image_msg->height) {
147  if (in_the_order_of_depth_ == true) {
148  vital_checker_->poke();
149  pcl::PointCloud<pcl::PointXYZ>::Ptr
150  cloud (new pcl::PointCloud<pcl::PointXYZ>);
151  pcl::fromROSMsg(*point_cloud2_msg, *cloud);
152  pcl::PointCloud<pcl::PointXYZ>::Ptr
153  edge_cloud (new pcl::PointCloud<pcl::PointXYZ>);
154  pcl::PointCloud<pcl::PointXYZ>::Ptr
155  nan_removed_edge_cloud (new pcl::PointCloud<pcl::PointXYZ>);
156 
157  int width = image_msg->width;
158  int height = image_msg->height;
159  pcl::PointXYZ nan_point;
160  nan_point.x = NAN;
161  nan_point.y = NAN;
162  nan_point.z = NAN;
165  cv::Mat mask = cv_ptr->image;
166  edge_cloud->is_dense = false;
167  edge_cloud->points.resize(width * height);
168  edge_cloud->width = width;
169  edge_cloud->height = height;
170  if (use_region_ratio_) {
175  }
176  if (use_mask_region_ == false || region_width_ == 0 || region_height_ == 0) {
177  for (size_t j = 0; j < mask.rows; j++) {
178  for (size_t i = 0; i < mask.cols; i++) {
179  if (mask.at<uchar>(j, i) != 0) {//if white
180  edge_cloud->points[j * width + i] = cloud->points[j * width + i];
181  }
182  else {
183  edge_cloud->points[j * width + i] = nan_point;
184  }
185  }
186  }
187  }
188  else {
189  NODELET_DEBUG("directed region width:%d height:%d", region_width_, region_height_);
190  //set nan_point to all points first.
191  for (size_t j = 0; j < mask.rows; j++) {
192  for (size_t i = 0; i < mask.cols; i++) {
193  edge_cloud->points[j * width + i] = nan_point;
194  }
195  }
196  int x_end = region_x_off_+ region_width_;
197  int y_end = region_y_off_+ region_height_;
198  for (size_t j = region_y_off_; j < y_end; j++) {
199  for (size_t i = region_x_off_; i < x_end; i++) {
200  if (i < image_msg->width && j <image_msg->height) {
201  if (mask.at<uchar>(j, i) != 0) {//if white
202  edge_cloud->points[j * width + i] = cloud->points[j * width + i];
203  }
204  }
205  }
206  }
207  }
208  std::vector<int> indices;
209  pcl::removeNaNFromPointCloud (*edge_cloud, *nan_removed_edge_cloud, indices);
210  if (nan_removed_edge_cloud->points.size() != 0) {
211  cv::Mat mask_image = cv::Mat::zeros(height, width, CV_8UC1);
212  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
213  kdtree.setInputCloud(edge_cloud);
214  pcl::PointXYZ zero;
215  std::vector<int> near_indices(extract_num_);
216  std::vector<float> near_distances(extract_num_);
217  kdtree.nearestKSearch(zero, extract_num_, near_indices, near_distances);
218  NODELET_DEBUG("directed num of extract points:%d num of nearestKSearch points:%d", extract_num_, ((int) near_indices.size()));
219  int ext_num=std::min(extract_num_, ((int) near_indices.size()));
220  for (int idx = 0; idx < ext_num; idx++) {
221  int x = near_indices.at(idx) % width;
222  int y = near_indices.at(idx) / width;
223  mask_image.at<uchar>(y, x) = 255;
224  }
225  cv_bridge::CvImage mask_bridge(point_cloud2_msg->header,
227  mask_image);
228  pub_.publish(mask_bridge.toImageMsg());
229  if (use_mask_region_ == false || region_width_ == 0 | region_height_ == 0) {
230  applypub_.publish(mask_bridge.toImageMsg());
231  }
232  else {
233  int min_x = region_x_off_;
234  int min_y = region_y_off_;
235  int max_x = region_width_ + region_x_off_ -1;
236  int max_y = region_height_ + region_y_off_ -1;
237  NODELET_DEBUG("minx:%d miny:%d maxx:%d maxy:%d", min_x, min_y, max_x, max_y);
238  cv::Rect region = cv::Rect(min_x, min_y, std::max(max_x - min_x, 0), std::max(max_y - min_y, 0));
239  cv::Mat clipped_mask_image = mask_image(region);
240  cv_bridge::CvImage clipped_mask_bridge(point_cloud2_msg->header,
242  clipped_mask_image);
243  applypub_.publish(clipped_mask_bridge.toImageMsg());
244  }
245  }
246  }
247  else {
250  cv::Mat mask = cv_ptr->image;
251  cv::Mat tmp_mask = cv::Mat::zeros(image_msg->height, image_msg->width, CV_8UC1);
252  int data_len=image_msg->width * image_msg->height;
253  int cnt = 0;
254  if (use_mask_region_ ==false || region_width_ == 0 || region_height_ == 0) {
255  for (size_t j = 0; j < mask.rows; j++) {
256  for (size_t i = 0; i < mask.cols; i++) {
257  if (mask.at<uchar>(j, i) != 0) {//if white
258  cnt++;
259  if (std::min(extract_num_ , data_len) > cnt) {
260  tmp_mask.at<uchar>(j, i) = mask.at<uchar>(j, i);
261  }
262  }
263  }
264  }
265  }
266  else {
267  ROS_INFO("directed region width:%d height:%d", region_width_, region_height_);
268  int x_end = region_x_off_ + region_width_;
269  int y_end = region_y_off_ + region_height_;
270  for (size_t j = region_y_off_; j < y_end; j++) {
271  for (size_t i = region_x_off_; i < x_end; i++) {
272  if (i < image_msg->width && j <image_msg->height){
273  if (mask.at<uchar>(j, i) != 0) {//if white
274  cnt++;
275  if (std::min(extract_num_ , data_len) > cnt) {
276  tmp_mask.at<uchar>(j, i) = mask.at<uchar>(j, i);
277  }
278  }
279  }
280  }
281  }
282  }
283  cv_bridge::CvImage mask_bridge(point_cloud2_msg->header,
285  tmp_mask);
286  pub_.publish(mask_bridge.toImageMsg());
287  if (use_mask_region_ == false || region_width_ == 0 | region_height_ == 0) {
288  applypub_.publish(mask_bridge.toImageMsg());
289  }
290  else {
291  int min_x = region_x_off_;
292  int min_y = region_y_off_;
293  int max_x = region_width_ + region_x_off_ -1;
294  int max_y = region_height_ + region_y_off_ -1;
295  cv::Rect region = cv::Rect(min_x, min_y, std::max(max_x - min_x, 0), std::max(max_y - min_y, 0));
296  cv::Mat clipped_mask_image = tmp_mask (region);
297  NODELET_INFO("minx:%d miny:%d maxx:%d maxy:%d", min_x, min_y, max_x, max_y);
298  cv_bridge::CvImage clipped_mask_bridge(point_cloud2_msg->header,
300  clipped_mask_image);
301  applypub_.publish(clipped_mask_bridge.toImageMsg());
302  }
303  }
304  }
305  else {
306  ROS_ERROR ("ERROR: Different width and height. Points[width:%d height:%d] Image[width:%d height:%d]", point_cloud2_msg->width, point_cloud2_msg->height, image_msg->width, image_msg->height);
307  }
308  }
309 }
310 
f
lock
void publish(const boost::shared_ptr< M > &message) const
jsk_pcl_ros_utils::MaskImageToDepthConsideredMaskImageConfig Config
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros_utils::MaskImageToDepthConsideredMaskImage, nodelet::Nodelet)
message_filters::Subscriber< sensor_msgs::PointCloud2 > sub_input_
double y
#define ROS_INFO(...)
boost::shared_ptr< ros::NodeHandle > pnh_
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
jsk_topic_tools::VitalChecker::Ptr vital_checker_
boost::shared_ptr< message_filters::Synchronizer< SyncPolicy > > sync_
#define NODELET_INFO(...)
boost::shared_ptr< dynamic_reconfigure::Server< Config > > srv_
void subscribe(ros::NodeHandle &nh, const std::string &topic, uint32_t queue_size, const ros::TransportHints &transport_hints=ros::TransportHints(), ros::CallbackQueueInterface *callback_queue=0)
double x
#define ROS_ERROR(...)
#define NODELET_DEBUG(...)
sensor_msgs::ImagePtr toImageMsg() const
boost::shared_ptr< message_filters::Synchronizer< ApproximateSyncPolicy > > async_
virtual void extractmask(const sensor_msgs::PointCloud2::ConstPtr &point_cloud2_msg, const sensor_msgs::Image::ConstPtr &image_msg)


jsk_pcl_ros_utils
Author(s): Yohei Kakiuchi
autogenerated on Mon May 3 2021 03:03:15