37 #include <jsk_topic_tools/diagnostic_utils.h>
38 #include <pcl/pcl_base.h>
39 #include <pcl/filters/statistical_outlier_removal.h>
46 DiagnosticNodelet(
"OrganizedStatisticalOutlierRemoval")
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);
59 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
60 dynamic_reconfigure::Server<Config>::CallbackType
f =
63 srv_->setCallback (
f);
75 async_ = boost::make_shared<message_filters::Synchronizer<ApproximateSyncPolicy> >(
queue_size_);
85 sync_->registerCallback(
119 #if __cplusplus >= 201103L
120 #define pcl_isfinite(x) std::isfinite(x)
124 const pcl::PCLPointCloud2::Ptr pcl_cloud,
125 pcl::PointIndices::Ptr pcl_indices_filtered)
127 pcl::PointCloud<pcl::PointXYZ>::Ptr
cloud(
new pcl::PointCloud<pcl::PointXYZ>);
128 pcl::fromPCLPointCloud2(*pcl_cloud, *cloud);
133 const pcl::PCLPointCloud2::Ptr pcl_cloud,
134 const pcl::PointIndices::Ptr pcl_indices,
135 pcl::PointIndices::Ptr pcl_indices_filtered)
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);
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++)
152 indices_filtered[
i] = pcl_indices->indices[indices_ex_filtered[
i]];
154 pcl_indices_filtered->indices = indices_filtered;
158 const pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
160 std::vector<int> indices_filtered;
161 indices_filtered.resize(
cloud->size());
162 #if PCL_VERSION_COMPARE (<, 1, 9, 0)
164 pcl::search::Search<pcl::PointXYZ>::Ptr
tree;
165 tree.reset (
new pcl::search::OrganizedNeighbor<pcl::PointXYZ> ());
166 tree->setInputCloud (cloud);
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;
175 for (
size_t i = 0;
i < indices.size (); ++
i) indices[i] = i;
178 for (
size_t cp = 0; cp < indices.size (); ++cp)
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))
187 if (
tree->nearestKSearch (indices[cp],
mean_k_, nn_indices, nn_dists) == 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));
201 double sum = 0, sq_sum = 0;
202 for (
size_t i = 0;
i < distances.size (); ++
i)
205 sq_sum += distances[
i] * distances[
i];
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);
215 for (
int cp = 0; cp < static_cast<int> (indices.size ()); ++cp)
217 bool remove_point =
false;
220 remove_point = (distances[cp] <= distance_threshold);
224 remove_point = (distances[cp] > distance_threshold);
228 indices_filtered.push_back(indices[cp]);
232 pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
233 sor.setInputCloud(cloud);
237 sor.setKeepOrganized (
true);
238 sor.filter(indices_filtered);
240 return indices_filtered;
246 vital_checker_->poke();
247 sensor_msgs::PointCloud2 output;
250 NODELET_ERROR(
"keep_organized parameter is true, but input pointcloud is not organized.");
253 pcl::PCLPointCloud2::Ptr pcl_cloud (
new pcl::PCLPointCloud2);
257 pcl::PointIndices::Ptr pcl_indices_filtered (
new pcl::PointIndices());
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);
267 #if PCL_VERSION_COMPARE (<, 1, 9, 0)
268 if (keep_organized) {
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;
278 output.header =
msg->header;
279 output.row_step = output.point_step * output.width;
280 output.is_dense = !keep_organized;
282 diagnostic_updater_->update();
286 const sensor_msgs::PointCloud2::ConstPtr&
msg,
287 const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& cpi_msg)
290 vital_checker_->poke();
291 sensor_msgs::PointCloud2 output;
294 NODELET_ERROR(
"keep_organized parameter is true, but input pointcloud is not organized.");
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());
302 for (
size_t i = 0;
i < cpi_msg->cluster_indices.size();
i++)
304 pcl::PointIndices::Ptr pcl_cluster_indices (
new pcl::PointIndices());
307 pcl::PointIndices::Ptr pcl_cluster_indices_filtered (
new pcl::PointIndices());
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());
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);
322 #if PCL_VERSION_COMPARE (<, 1, 9, 0)
323 if (keep_organized) {
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;
333 output.header =
msg->header;
334 output.row_step = output.point_step * output.width;
335 output.is_dense = !keep_organized;
337 diagnostic_updater_->update();
343 if (vital_checker_->isAlive()) {
344 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
346 jsk_topic_tools::addDiagnosticBooleanStat(
"keep organized",
349 jsk_topic_tools::addDiagnosticBooleanStat(
"negative",
355 DiagnosticNodelet::updateDiagnostic(stat);