color_filter_nodelet.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2014, JSK Lab
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/o2r other materials provided
16  * with the distribution.
17  * * Neither the name of the JSK Lab nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
36 
38 
39 namespace jsk_pcl_ros
40 {
41 
42  /*** RGB ***/
43 
45  {
46  r_max_ = 255;
47  r_min_ = 0;
48  g_max_ = 255;
49  g_min_ = 0;
50  b_max_ = 255;
51  b_min_ = 0;
52 
54  }
55 
57  {
58  ConditionPtr condp (new pcl::ConditionAnd<pcl::PointXYZRGB> ());
59 
60  int r_max, r_min, g_max, g_min, b_max, b_min;
61  if ( r_max_ >= r_min_ ) {
62  r_max = r_max_;
63  r_min = r_min_;
64  }
65  else {
66  r_max = r_min_;
67  r_min = r_max_;
68  }
69  if ( g_max_ >= g_min_ ) {
70  g_max = g_max_;
71  g_min = g_min_;
72  }
73  else {
74  g_max = g_min_;
75  g_min = g_max_;
76  }
77  if ( b_max_ >= b_min_ ) {
78  b_max = b_max_;
79  b_min = b_min_;
80  }
81  else {
82  b_max = b_min_;
83  b_min = b_max_;
84  }
85 
86  {
87  ConditionPtr cond (new pcl::ConditionAnd<pcl::PointXYZRGB> ());
88  ComparisonPtr le (new Comparison ("r", pcl::ComparisonOps::LE, r_max));
89  ComparisonPtr ge (new Comparison ("r", pcl::ComparisonOps::GE, r_min));
90  cond->addComparison (le);
91  cond->addComparison (ge);
92  condp->addCondition(cond);
93  }
94  {
95  ConditionPtr cond (new pcl::ConditionAnd<pcl::PointXYZRGB> ());
96  ComparisonPtr le (new Comparison ("g", pcl::ComparisonOps::LE, g_max));
97  ComparisonPtr ge (new Comparison ("g", pcl::ComparisonOps::GE, g_min));
98  cond->addComparison (le);
99  cond->addComparison (ge);
100  condp->addCondition(cond);
101  }
102  {
103  ConditionPtr cond (new pcl::ConditionAnd<pcl::PointXYZRGB> ());
104  ComparisonPtr le (new Comparison ("b", pcl::ComparisonOps::LE, b_max));
105  ComparisonPtr ge (new Comparison ("b", pcl::ComparisonOps::GE, b_min));
106  cond->addComparison (le);
107  cond->addComparison (ge);
108  condp->addCondition(cond);
109  }
110 
111  filter_instance_.setCondition (condp);
112  }
113 
114  void RGBColorFilter::configCallback(jsk_pcl_ros::RGBColorFilterConfig &config, uint32_t level)
115  {
116  boost::mutex::scoped_lock lock (mutex_);
117  r_max_ = config.r_limit_max;
118  r_min_ = config.r_limit_min;
119  g_max_ = config.g_limit_max;
120  g_min_ = config.g_limit_min;
121  b_max_ = config.b_limit_max;
122  b_min_ = config.b_limit_min;
123  updateCondition();
124  }
125 
126  void RGBColorFilter::convertToColorSpace(float &x, float &y, float &z,
127  unsigned char r, unsigned char g, unsigned char b)
128  {
129  x = r/255.0;
130  y = g/255.0;
131  z = b/255.0;
132  }
133 
134  /*** HSI ***/
136  {
137  h_max_ = 127;
138  h_min_ = -128;
139  s_max_ = 255;
140  s_min_ = 0;
141  i_max_ = 255;
142  i_min_ = 0;
143 
145  }
146 
148  {
149  ConditionPtr condp (new pcl::ConditionAnd<pcl::PointXYZRGB> ());
150 
151  int h_max, h_min, s_max, s_min, i_max, i_min;
152  if ( h_max_ >= h_min_ ) {
153  h_max = h_max_;
154  h_min = h_min_;
155  }
156  else {
157  h_max = h_min_;
158  h_min = h_max_;
159  }
160  if ( s_max_ >= s_min_ ) {
161  s_max = s_max_;
162  s_min = s_min_;
163  }
164  else {
165  s_max = s_min_;
166  s_min = s_max_;
167  }
168  if ( i_max_ >= i_min_ ) {
169  i_max = i_max_;
170  i_min = i_min_;
171  }
172  else {
173  i_max = i_min_;
174  i_min = i_max_;
175  }
176 
177  {
178  ConditionPtr cond (new pcl::ConditionAnd<pcl::PointXYZRGB> ());
179  ComparisonPtr le (new Comparison ("h", pcl::ComparisonOps::LE, h_max));
180  ComparisonPtr ge (new Comparison ("h", pcl::ComparisonOps::GE, h_min));
181  cond->addComparison (le);
182  cond->addComparison (ge);
183  condp->addCondition(cond);
184  }
185  {
186  ConditionPtr cond (new pcl::ConditionAnd<pcl::PointXYZRGB> ());
187  ComparisonPtr le (new Comparison ("s", pcl::ComparisonOps::LE, s_max));
188  ComparisonPtr ge (new Comparison ("s", pcl::ComparisonOps::GE, s_min));
189  cond->addComparison (le);
190  cond->addComparison (ge);
191  condp->addCondition(cond);
192  }
193  {
194  ConditionPtr cond (new pcl::ConditionAnd<pcl::PointXYZRGB> ());
195  ComparisonPtr le (new Comparison ("i", pcl::ComparisonOps::LE, i_max));
196  ComparisonPtr ge (new Comparison ("i", pcl::ComparisonOps::GE, i_min));
197  cond->addComparison (le);
198  cond->addComparison (ge);
199  condp->addCondition(cond);
200  }
201 
202  filter_instance_.setCondition (condp);
203  }
204 
205  void HSIColorFilter::configCallback(jsk_pcl_ros::HSIColorFilterConfig &config, uint32_t level)
206  {
207  boost::mutex::scoped_lock lock (mutex_);
208  h_max_ = config.h_limit_max;
209  h_min_ = config.h_limit_min;
210  s_max_ = config.s_limit_max;
211  s_min_ = config.s_limit_min;
212  i_max_ = config.i_limit_max;
213  i_min_ = config.i_limit_min;
214  updateCondition();
215  }
216 
217  void HSIColorFilter::convertToColorSpace(float &x, float &y, float &z,
218  unsigned char r, unsigned char g, unsigned char b)
219  {
220  // http://pointcloudlibrary.github.io/documentation/conditional__removal_8hpp_source.html
221  // definitions taken from http://en.wikipedia.org/wiki/HSL_and_HSI
222  float hx = (2.0f * r - g - b) / 4.0f; // hue x component -127 to 127
223  float hy = static_cast<float> (g - b) * 111.0f / 255.0f; // hue y component -111 to 111
224  int8_t h_ = static_cast<std::int8_t> (std::atan2(hy, hx) * 128.0f / M_PI);
225 
226  int32_t i = (r+g+b)/3; // 0 to 255
227  uint8_t i_ = static_cast<std::uint8_t> (i);
228 
229  std::int32_t m; // min(r,g,b)
230  m = (r < g) ? r : g;
231  m = (m < b) ? m : b;
232 
233  uint8_t s_ = static_cast<std::uint8_t> ((i == 0) ? 0 : 255 - (m * 255) / i); // saturation 0 to 255
234  //
235  x = (s_ * cos(h_ * M_PI / 128.0))/255.0; // h between -128 to 128
236  y = (s_ * sin(h_ * M_PI / 128.0))/255.0;
237  z = i_/255.0;
238  }
239 
240  /*** ColorFilter ***/
241  template <class PackedComparison, typename Config>
242  void ColorFilter<PackedComparison, Config>::filter(const sensor_msgs::PointCloud2ConstPtr &input,
243  const PCLIndicesMsg::ConstPtr& indices)
244  {
245 
246  boost::mutex::scoped_lock lock (mutex_);
247  pcl::PointCloud<pcl::PointXYZRGB> tmp_in, tmp_out;
248  sensor_msgs::PointCloud2 out;
249  fromROSMsg(*input, tmp_in);
250 
251  filter_instance_.setInputCloud (tmp_in.makeShared());
252  if (indices) {
253  pcl::IndicesPtr vindices;
254  vindices.reset(new std::vector<int> (indices->indices));
255  filter_instance_.setIndices(vindices);
256  }
257  filter_instance_.filter(tmp_out);
258 
259  if ( color_space_pub_.getNumSubscribers() > 0 ){
261  if ( color_space_msg_.data.size() != tmp_in.points.size()) {
262  color_space_msg_.data.resize(16*tmp_in.points.size());
263  color_space_msg_.width = tmp_in.points.size();
264  color_space_msg_.height = 1;
265  color_space_msg_.point_step = 16;
266  color_space_msg_.row_step = tmp_in.points.size();
267  }
268  for (unsigned int j=0; j<tmp_in.points.size(); j++) {
269  uint32_t rgb_data_ = *reinterpret_cast<int*> (&tmp_in.points[j].rgb);
270  unsigned char r_ = (rgb_data_>>16) & 0x0000ff;
271  unsigned char g_ = (rgb_data_>>8) & 0x0000ff;
272  unsigned char b_ = (rgb_data_) & 0x0000ff;
273 
274  float x_, y_, z_;
275  convertToColorSpace(x_, y_, z_, r_, g_, b_); // convert rgb to xyz to construct color space
276 
277  // skip (set black and move point to origin) if no depth data present
278  if ( std::isnan(tmp_in.points[j].x) && std::isnan(tmp_in.points[j].y) && std::isnan(tmp_in.points[j].z) ) {
279  x_ = y_ = z_ = 0;
280  r_ = g_ = b_ = 0;
281  }
282  memcpy((void *)(&(color_space_msg_.data[j*16+0])), (const void *)&x_, sizeof(float));
283  memcpy((void *)(&(color_space_msg_.data[j*16+4])), (const void *)&y_, sizeof(float));
284  memcpy((void *)(&(color_space_msg_.data[j*16+8])), (const void *)&z_, sizeof(float));
285  // skip (set gray) if the point is filtered
286  if ( std::isnan(tmp_out.points[j].x) && std::isnan(tmp_out.points[j].y) && std::isnan(tmp_out.points[j].z) ) {
287  unsigned char gray_ = 16 + (r_/3 + g_/3 + b_/3)*(255-16)/255;
288  r_ = g_ = b_ = gray_;
289  }
290  // set data to color_space_msg
291  unsigned char rgb_packed_[4] = {r_, g_, b_, 0};
292  memcpy((void *)(&(color_space_msg_.data[j*16+12])), (const void *)rgb_packed_, 4*sizeof(unsigned char));
293  }
295  }
296 
297  if (tmp_out.points.size() > 0) {
298  toROSMsg(tmp_out, out);
299  pub_.publish(out);
300  }
301  }
302 
303  template <class PackedComparison, typename Config>
304  void ColorFilter<PackedComparison, Config>::filter(const sensor_msgs::PointCloud2ConstPtr &input)
305  {
306  filter(input, PCLIndicesMsg::ConstPtr());
307  }
308 
309  template <class PackedComparison, typename Config>
311  {
312  ConnectionBasedNodelet::onInit();
313 
314  color_space_pub_ = pnh_->advertise<sensor_msgs::PointCloud2>("color_space", 1);
315  color_space_msg_.header.frame_id = "/map";
316  color_space_msg_.fields.resize(4);
317  color_space_msg_.fields[0].name = "x";
318  color_space_msg_.fields[0].offset = 0;
319  color_space_msg_.fields[0].datatype = sensor_msgs::PointField::FLOAT32;
320  color_space_msg_.fields[0].count = 1;
321  color_space_msg_.fields[1].name = "y";
322  color_space_msg_.fields[1].offset = 4;
323  color_space_msg_.fields[1].datatype = sensor_msgs::PointField::FLOAT32;
324  color_space_msg_.fields[1].count = 1;
325  color_space_msg_.fields[2].name = "z";
326  color_space_msg_.fields[2].offset = 8;
327  color_space_msg_.fields[2].datatype = sensor_msgs::PointField::FLOAT32;
328  color_space_msg_.fields[2].count = 1;
329  color_space_msg_.fields[3].name = "rgb";
330  color_space_msg_.fields[3].offset = 12;
331  color_space_msg_.fields[3].datatype = sensor_msgs::PointField::UINT32;
332  color_space_msg_.fields[3].count = 1;
333 
334  updateCondition();
335  bool keep_organized;
336  pnh_->param("keep_organized", keep_organized, false);
337  pnh_->param("use_indices", use_indices_, false);
338  pub_ = advertise<sensor_msgs::PointCloud2>(*pnh_, "output", 1);
339 
340  filter_instance_ = pcl::ConditionalRemoval<pcl::PointXYZRGB>(true);
341  filter_instance_.setKeepOrganized(keep_organized);
342 
343  srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
344  typename dynamic_reconfigure::Server<Config>::CallbackType f =
345  boost::bind (&ColorFilter::configCallback, this, _1, _2);
346  srv_->setCallback (f);
347 
349  }
350 
351  template <class PackedComparison, typename Config>
353  {
354  sub_input_.subscribe(*pnh_, "input", 1);
355  if (use_indices_) {
356  sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(10);
357  sub_indices_.subscribe(*pnh_, "indices", 1);
358  sync_->connectInput(sub_input_, sub_indices_);
359  sync_->registerCallback(boost::bind(&ColorFilter::filter, this, _1, _2));
360  //sub_input_ = pnh_->subscribe("input", 1, &RGBColorFilter::filter, this);
361  }
362  else {
364  }
365  }
366 
367  template <class PackedComparison, typename Config>
369  {
371  if (use_indices_) {
373  }
374  }
375 
376 }
377 
int r_max
void publish(const boost::shared_ptr< M > &message) const
double cos()
double sin()
virtual void configCallback(Config &config, uint32_t level)=0
virtual void configCallback(jsk_pcl_ros::RGBColorFilterConfig &config, uint32_t level)
virtual void configCallback(jsk_pcl_ros::HSIColorFilterConfig &config, uint32_t level)
#define M_PI
boost::shared_ptr< dynamic_reconfigure::Server< jsk_pcl_ros::RGBColorFilterConfig > > srv_
Definition: color_filter.h:77
boost::shared_ptr< ros::NodeHandle > pnh_
virtual void convertToColorSpace(float &x, float &y, float &z, unsigned char r, unsigned char g, unsigned char b)
PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::RGBColorFilter, nodelet::Nodelet)
uint32_t getNumSubscribers() const
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)
virtual void convertToColorSpace(float &x, float &y, float &z, unsigned char r, unsigned char g, unsigned char b)
virtual void filter(const sensor_msgs::PointCloud2ConstPtr &input)
Connection registerCallback(const C &callback)


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Mon May 3 2021 03:03:46