organized_statistical_outlier_removal_nodelet.cpp
Go to the documentation of this file.
1 // -*- mode: c++ -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2021, 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/or 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 
37 #include <jsk_topic_tools/diagnostic_utils.h>
38 #include <pcl/pcl_base.h>
39 #include <pcl/filters/statistical_outlier_removal.h>
42 
43 namespace jsk_pcl_ros
44 {
46  DiagnosticNodelet("OrganizedStatisticalOutlierRemoval")
47  {
48 
49  }
50 
52  {
53  DiagnosticNodelet::onInit();
54  pub_ = advertise<sensor_msgs::PointCloud2>(*pnh_, "output", 1);
55  pnh_->param("use_cluster_point_indices", use_cpi_, false);
56  pnh_->param("approximate_sync", use_async_, false);
57  pnh_->param("queue_size", queue_size_, 100);
58 
59  srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
60  dynamic_reconfigure::Server<Config>::CallbackType f =
61  boost::bind (
63  srv_->setCallback (f);
64  onInitPostProcess();
65  }
66 
68  {
69  if (use_cpi_)
70  {
71  sub_cloud_.subscribe(*pnh_, "input", 1);
72  sub_cpi_.subscribe(*pnh_, "input/cluster_indices", 1);
73  if (use_async_)
74  {
75  async_ = boost::make_shared<message_filters::Synchronizer<ApproximateSyncPolicy> >(queue_size_);
76  async_->connectInput(sub_cloud_, sub_cpi_);
77  async_->registerCallback(
78  boost::bind(
80  }
81  else
82  {
83  sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(queue_size_);
84  sync_->connectInput(sub_cloud_, sub_cpi_);
85  sync_->registerCallback(
86  boost::bind(
88  }
89  }
90  else
91  {
92  sub_ = pnh_->subscribe("input", 1, &OrganizedStatisticalOutlierRemoval::filterCloud, this);
93  }
94  }
95 
97  {
98  if (use_cpi_)
99  {
102  }
103  else
104  {
105  sub_.shutdown();
106  }
107  }
108 
109  void OrganizedStatisticalOutlierRemoval::configCallback(Config &config, uint32_t level)
110  {
111  boost::mutex::scoped_lock lock(mutex_);
112  keep_organized_ = config.keep_organized;
113  negative_ = config.negative;
114  mean_k_ = config.mean_k;
115  std_mul_ = config.stddev;
116  }
117 
118  // pcl removed the method by 1.13, no harm in defining it ourselves to use below
119 #if __cplusplus >= 201103L
120 #define pcl_isfinite(x) std::isfinite(x)
121 #endif
122 
124  const pcl::PCLPointCloud2::Ptr pcl_cloud,
125  pcl::PointIndices::Ptr pcl_indices_filtered)
126  {
127  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
128  pcl::fromPCLPointCloud2(*pcl_cloud, *cloud);
129  pcl_indices_filtered->indices = OrganizedStatisticalOutlierRemoval::getFilteredIndices(cloud);
130  }
131 
133  const pcl::PCLPointCloud2::Ptr pcl_cloud,
134  const pcl::PointIndices::Ptr pcl_indices,
135  pcl::PointIndices::Ptr pcl_indices_filtered)
136  {
137  pcl::PCLPointCloud2::Ptr pcl_cloud_ex (new pcl::PCLPointCloud2);
138  pcl::ExtractIndices<pcl::PCLPointCloud2> ex;
139  ex.setInputCloud(pcl_cloud);
140  ex.setKeepOrganized(false);
141  ex.setNegative(false);
142  ex.setIndices(pcl_indices);
143  ex.filter(*pcl_cloud_ex);
144  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ex(new pcl::PointCloud<pcl::PointXYZ>);
145  pcl::fromPCLPointCloud2(*pcl_cloud_ex, *cloud_ex);
146 
147  const std::vector<int> indices_ex_filtered = OrganizedStatisticalOutlierRemoval::getFilteredIndices(cloud_ex);
148  std::vector<int> indices_filtered;
149  indices_filtered.resize(indices_ex_filtered.size());
150  for (size_t i = 0; i < indices_ex_filtered.size(); i++)
151  {
152  indices_filtered[i] = pcl_indices->indices[indices_ex_filtered[i]];
153  }
154  pcl_indices_filtered->indices = indices_filtered;
155  }
156 
158  const pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
159  {
160  std::vector<int> indices_filtered;
161  indices_filtered.resize(cloud->size());
162 #if PCL_VERSION_COMPARE (<, 1, 9, 0)
163  // Initialize the spatial locator
164  pcl::search::Search<pcl::PointXYZ>::Ptr tree;
165  tree.reset (new pcl::search::OrganizedNeighbor<pcl::PointXYZ> ());
166  tree->setInputCloud (cloud);
167 
168  // Allocate enough space to hold the results
169  std::vector<int> indices (cloud->size());
170  std::vector<int> nn_indices (mean_k_);
171  std::vector<float> nn_dists (mean_k_);
172  std::vector<float> distances (indices.size ());
173  int valid_distances = 0;
174 
175  for (size_t i = 0; i < indices.size (); ++i) indices[i] = i;
176 
177  // Go over all the points and calculate the mean or smallest distance
178  for (size_t cp = 0; cp < indices.size (); ++cp)
179  {
180  if (!pcl_isfinite (cloud->points[indices[cp]].x) ||
181  !pcl_isfinite (cloud->points[indices[cp]].y) ||
182  !pcl_isfinite (cloud->points[indices[cp]].z))
183  {
184  distances[cp] = 0;
185  continue;
186  }
187  if (tree->nearestKSearch (indices[cp], mean_k_, nn_indices, nn_dists) == 0)
188  {
189  distances[cp] = 0;
190  continue;
191  }
192  // Minimum distance (if mean_k_ == 2) or mean distance
193  double dist_sum = 0;
194  for (int j = 1; j < mean_k_; ++j)
195  dist_sum += sqrt (nn_dists[j]);
196  distances[cp] = static_cast<float> (dist_sum / (mean_k_ - 1));
197  valid_distances++;
198  }
199 
200  // Estimate the mean and the standard deviation of the distance vector
201  double sum = 0, sq_sum = 0;
202  for (size_t i = 0; i < distances.size (); ++i)
203  {
204  sum += distances[i];
205  sq_sum += distances[i] * distances[i];
206  }
207  double mean = sum / static_cast<double>(valid_distances);
208  double variance = (sq_sum - sum * sum / static_cast<double>(valid_distances)) / (static_cast<double>(valid_distances) - 1);
209  double stddev = sqrt (variance);
210  //getMeanStd (distances, mean, stddev);
211 
212  double distance_threshold = mean + std_mul_ * stddev; // a distance that is bigger than this signals an outlier
213 
214  // Build a new cloud by neglecting outliers
215  for (int cp = 0; cp < static_cast<int> (indices.size ()); ++cp)
216  {
217  bool remove_point = false;
218  if (negative_)
219  {
220  remove_point = (distances[cp] <= distance_threshold);
221  }
222  else
223  {
224  remove_point = (distances[cp] > distance_threshold);
225  }
226  if (!remove_point)
227  {
228  indices_filtered.push_back(indices[cp]);
229  }
230  }
231 #else
232  pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
233  sor.setInputCloud(cloud);
234  sor.setMeanK(mean_k_);
235  sor.setStddevMulThresh(std_mul_);
236  sor.setNegative(negative_);
237  sor.setKeepOrganized (true);
238  sor.filter(indices_filtered);
239 #endif
240  return indices_filtered;
241  }
242 
243  void OrganizedStatisticalOutlierRemoval::filterCloud(const sensor_msgs::PointCloud2::ConstPtr& msg)
244  {
245  boost::mutex::scoped_lock lock(mutex_);
246  vital_checker_->poke();
247  sensor_msgs::PointCloud2 output;
248 
249  if (keep_organized_&& msg->is_dense) {
250  NODELET_ERROR("keep_organized parameter is true, but input pointcloud is not organized.");
251  }
252  bool keep_organized = keep_organized_ && !msg->is_dense;
253  pcl::PCLPointCloud2::Ptr pcl_cloud (new pcl::PCLPointCloud2);
254  pcl_conversions::toPCL(*msg, *pcl_cloud);
255 
256  // filter
257  pcl::PointIndices::Ptr pcl_indices_filtered (new pcl::PointIndices());
258  OrganizedStatisticalOutlierRemoval::filter(pcl_cloud, pcl_indices_filtered);
259  pcl::PCLPointCloud2::Ptr pcl_cloud_filtered (new pcl::PCLPointCloud2);
260  pcl::ExtractIndices<pcl::PCLPointCloud2> ex;
261  ex.setInputCloud(pcl_cloud);
262  ex.setKeepOrganized(keep_organized);
263  ex.setNegative(false);
264  ex.setIndices(pcl_indices_filtered);
265  ex.filter(*pcl_cloud_filtered);
266  pcl_conversions::fromPCL(*pcl_cloud_filtered, output);
267 #if PCL_VERSION_COMPARE (<, 1, 9, 0)
268  if (keep_organized) {
269  // Copy the common fields
270  output.is_bigendian = msg->is_bigendian;
271  output.fields = msg->fields;
272  output.point_step = msg->point_step;
273  output.data.resize(msg->data.size());
274  output.width = msg->width;
275  output.height = msg->height;
276  }
277 #endif
278  output.header = msg->header;
279  output.row_step = output.point_step * output.width;
280  output.is_dense = !keep_organized;
281  pub_.publish(output);
282  diagnostic_updater_->update();
283  }
284 
286  const sensor_msgs::PointCloud2::ConstPtr& msg,
287  const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& cpi_msg)
288  {
289  boost::mutex::scoped_lock lock(mutex_);
290  vital_checker_->poke();
291  sensor_msgs::PointCloud2 output;
292 
293  if (keep_organized_ && msg->is_dense) {
294  NODELET_ERROR("keep_organized parameter is true, but input pointcloud is not organized.");
295  }
296  bool keep_organized = keep_organized_ && !msg->is_dense;
297  pcl::PCLPointCloud2::Ptr pcl_cloud (new pcl::PCLPointCloud2);
298  pcl::PCLPointCloud2::Ptr pcl_cloud_filtered (new pcl::PCLPointCloud2);
299  pcl::PointIndices::Ptr pcl_indices_filtered (new pcl::PointIndices());
300  pcl_conversions::toPCL(*msg, *pcl_cloud);
301 
302  for (size_t i = 0; i < cpi_msg->cluster_indices.size(); i++)
303  {
304  pcl::PointIndices::Ptr pcl_cluster_indices (new pcl::PointIndices());
305  pcl_conversions::toPCL(cpi_msg->cluster_indices[i], *pcl_cluster_indices);
306 
307  pcl::PointIndices::Ptr pcl_cluster_indices_filtered (new pcl::PointIndices());
309  pcl_cluster_indices,
310  pcl_cluster_indices_filtered);
311  pcl_indices_filtered->indices.insert(pcl_indices_filtered->indices.end(),
312  pcl_cluster_indices_filtered->indices.begin(),
313  pcl_cluster_indices_filtered->indices.end());
314  }
315  pcl::ExtractIndices<pcl::PCLPointCloud2> ex;
316  ex.setInputCloud(pcl_cloud);
317  ex.setKeepOrganized(keep_organized);
318  ex.setNegative(false);
319  ex.setIndices(pcl_indices_filtered);
320  ex.filter(*pcl_cloud_filtered);
321  pcl_conversions::fromPCL(*pcl_cloud_filtered, output);
322 #if PCL_VERSION_COMPARE (<, 1, 9, 0)
323  if (keep_organized) {
324  // Copy the common fields
325  output.is_bigendian = msg->is_bigendian;
326  output.fields = msg->fields;
327  output.point_step = msg->point_step;
328  output.data.resize(msg->data.size());
329  output.width = msg->width;
330  output.height = msg->height;
331  }
332 #endif
333  output.header = msg->header;
334  output.row_step = output.point_step * output.width;
335  output.is_dense = !keep_organized;
336  pub_.publish(output);
337  diagnostic_updater_->update();
338  }
339 
342  {
343  if (vital_checker_->isAlive()) {
344  stat.summary(diagnostic_msgs::DiagnosticStatus::OK,
345  name_ + " running");
346  jsk_topic_tools::addDiagnosticBooleanStat("keep organized",
348  stat);
349  jsk_topic_tools::addDiagnosticBooleanStat("negative",
350  negative_,
351  stat);
352  stat.add("mean k", mean_k_);
353  stat.add("stddev", std_mul_);
354  }
355  DiagnosticNodelet::updateDiagnostic(stat);
356  }
357 }
358 
extract_top_polygon_likelihood.ex
ex
Definition: extract_top_polygon_likelihood.py:51
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::mutex_
boost::mutex mutex_
Definition: organized_statistical_outlier_removal.h:168
NODELET_ERROR
#define NODELET_ERROR(...)
sum
T sum(T *pf, int length)
depth_error_calibration.lock
lock
Definition: depth_error_calibration.py:32
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::queue_size_
int queue_size_
Definition: organized_statistical_outlier_removal.h:179
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::filterCloudWithClusterPointIndices
void filterCloudWithClusterPointIndices(const sensor_msgs::PointCloud2::ConstPtr &msg, const jsk_recognition_msgs::ClusterPointIndices::ConstPtr &cpi_msg)
Definition: organized_statistical_outlier_removal_nodelet.cpp:317
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::unsubscribe
virtual void unsubscribe()
Definition: organized_statistical_outlier_removal_nodelet.cpp:128
i
int i
diagnostic_updater::DiagnosticStatusWrapper::add
void add(const std::string &key, const bool &b)
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::subscribe
virtual void subscribe()
Definition: organized_statistical_outlier_removal_nodelet.cpp:99
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::onInit
virtual void onInit()
Definition: organized_statistical_outlier_removal_nodelet.cpp:83
jsk_pcl_ros::variance
double variance(const OneDataStat &d)
wrapper function for variance method for boost::function
Definition: one_data_stat.h:153
pcl_conversions::toPCL
void toPCL(const pcl_msgs::ModelCoefficients &mc, pcl::ModelCoefficients &pcl_mc)
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::use_cpi_
bool use_cpi_
Definition: organized_statistical_outlier_removal.h:177
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::sub_cpi_
message_filters::Subscriber< jsk_recognition_msgs::ClusterPointIndices > sub_cpi_
Definition: organized_statistical_outlier_removal.h:162
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::keep_organized_
bool keep_organized_
Definition: organized_statistical_outlier_removal.h:180
ros::Subscriber::shutdown
void shutdown()
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::pub_
ros::Publisher pub_
Definition: organized_statistical_outlier_removal.h:166
organized_statistical_outlier_removal.h
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::mean_k_
int mean_k_
Definition: organized_statistical_outlier_removal.h:183
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
message_filters::Subscriber::unsubscribe
void unsubscribe()
cloud
cloud
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::std_mul_
double std_mul_
Definition: organized_statistical_outlier_removal.h:182
class_list_macros.h
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::updateDiagnostic
void updateDiagnostic(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: organized_statistical_outlier_removal_nodelet.cpp:372
tree
tree
diagnostic_updater::DiagnosticStatusWrapper::summary
void summary(const diagnostic_msgs::DiagnosticStatus &src)
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::configCallback
virtual void configCallback(Config &config, uint32_t level)
Definition: organized_statistical_outlier_removal_nodelet.cpp:141
pcl_conversions::fromPCL
void fromPCL(const pcl::ModelCoefficients &pcl_mc, pcl_msgs::ModelCoefficients &mc)
jsk_pcl_ros
Definition: add_color_from_image.h:51
jsk_pcl_ros::stddev
double stddev(const OneDataStat &d)
wrapper function for stddev method for boost::function
Definition: one_data_stat.h:162
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::sync_
boost::shared_ptr< message_filters::Synchronizer< SyncPolicy > > sync_
Definition: organized_statistical_outlier_removal.h:163
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::filterCloud
void filterCloud(const sensor_msgs::PointCloud2::ConstPtr &msg)
Definition: organized_statistical_outlier_removal_nodelet.cpp:275
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::sub_
ros::Subscriber sub_
Definition: organized_statistical_outlier_removal.h:160
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval
Definition: organized_statistical_outlier_removal.h:88
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::use_async_
bool use_async_
Definition: organized_statistical_outlier_removal.h:178
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::srv_
boost::shared_ptr< dynamic_reconfigure::Server< Config > > srv_
Definition: organized_statistical_outlier_removal.h:167
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::filter
void filter(const pcl::PCLPointCloud2::Ptr pcl_cloud, pcl::PointIndices::Ptr pcl_indices_filtered)
Definition: organized_statistical_outlier_removal_nodelet.cpp:155
message_filters::Subscriber::subscribe
void subscribe()
nodelet::Nodelet
sqrt
double sqrt()
pcl_util.h
dump_depth_error.f
f
Definition: dump_depth_error.py:39
diagnostic_updater::DiagnosticStatusWrapper
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::sub_cloud_
message_filters::Subscriber< sensor_msgs::PointCloud2 > sub_cloud_
Definition: organized_statistical_outlier_removal.h:161
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::negative_
bool negative_
Definition: organized_statistical_outlier_removal.h:181
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::async_
boost::shared_ptr< message_filters::Synchronizer< ApproximateSyncPolicy > > async_
Definition: organized_statistical_outlier_removal.h:164
config
config
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::getFilteredIndices
std::vector< int > getFilteredIndices(const pcl::PointCloud< pcl::PointXYZ >::Ptr cloud)
Definition: organized_statistical_outlier_removal_nodelet.cpp:189
pose_with_covariance_sample.msg
msg
Definition: pose_with_covariance_sample.py:22
jsk_pcl_ros::OrganizedStatisticalOutlierRemoval::OrganizedStatisticalOutlierRemoval
OrganizedStatisticalOutlierRemoval()
Definition: organized_statistical_outlier_removal_nodelet.cpp:77
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::OrganizedStatisticalOutlierRemoval, nodelet::Nodelet)
jsk_pcl_ros::mean
double mean(const OneDataStat &d)
wrapper function for mean method for boost::function
Definition: one_data_stat.h:117
pcl_conversions.h


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Fri May 16 2025 03:12:12