25 #include <boost/graph/adjacency_list.hpp>
26 #include <boost/graph/subgraph.hpp>
27 #include <boost/graph/graph_concepts.hpp>
37 #include <boost/smart_ptr/make_shared.hpp>
39 #include <pcl/filters/filter.h>
41 #include <pcl/filters/voxel_grid.h>
42 #include <pcl/filters/approximate_voxel_grid.h>
63 std::unique_lock lock(write_mutex_);
64 config_.commitWrite();
65 usingPointCloudProvider(getProperty<std::string>(
"ProviderName").getValue());
76 enableResultPointClouds<PointT>(
"CRFSegmentationResult");
77 enableResultPointClouds<pcl::PointXYZI>(
"CRFSegmentationConfidence");
78 if (config_.getUpToDateReadBuffer().out.provide_graph_pclouds)
81 enableResultPointClouds<PointT>(
"Graph0");
82 enableResultPointClouds<PointT>(
"Graph1");
83 enableResultPointClouds<PointT>(
"Graph2");
84 enableResultPointClouds<PointT>(
"Graph3");
85 enableResultPointClouds<PointT>(
"Graph4");
88 if (config_.getUpToDateReadBuffer().out.provide_confidence_pclouds)
90 if (config_.getUpToDateReadBuffer().out.colorize_confidence_pclouds)
93 enableResultPointClouds<PointT>(
"Confidence0");
94 enableResultPointClouds<PointT>(
"Confidence1");
95 enableResultPointClouds<PointT>(
"Confidence2");
96 enableResultPointClouds<PointT>(
"Confidence3");
97 enableResultPointClouds<PointT>(
"Confidence4");
101 enableResultPointClouds<pcl::PointXYZI>(
"Confidence0");
102 enableResultPointClouds<pcl::PointXYZI>(
"Confidence1");
103 enableResultPointClouds<pcl::PointXYZI>(
"Confidence2");
104 enableResultPointClouds<pcl::PointXYZI>(
"Confidence3");
105 enableResultPointClouds<pcl::PointXYZI>(
"Confidence4");
114 std::unique_lock lock(write_mutex_);
115 prx.getValue(config_.getWriteBuffer(),
"Config");
116 config_.commitWrite();
133 pcl::PointCloud<PointT>::Ptr input_cloud_ptr(
new pcl::PointCloud<PointT>());
134 pcl::PointCloud<PointT>::Ptr output_cloud_ptr(
new pcl::PointCloud<PointT>());
136 if (!waitForPointClouds())
138 ARMARX_INFO <<
"Timeout or error while waiting for point cloud data";
142 getPointClouds(input_cloud_ptr);
147 input_cloud_ptr->is_dense =
false;
148 pcl::removeNaNFromPointCloud(*input_cloud_ptr, *input_cloud_ptr,
indices);
149 relabelPointCloud(input_cloud_ptr);
150 ARMARX_DEBUG <<
"Point Cloud has " << input_cloud_ptr->size() <<
" Points before Downsampling";
151 auto config = config_.getUpToDateReadBuffer();
152 if (config.general.use_vertex_only_graph)
155 computeVertexOnlyGraph(input_cloud_ptr);
159 computeGraphUsingVoxelGrid(input_cloud_ptr);
165 updatePersistentGraph();
168 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
170 config = config_.getUpToDateReadBuffer();
173 if (config.edge.use_xyz && !config.edge.use_combined)
177 std::vector<float> xyz_infl(3);
178 std::fill(xyz_infl.begin(), xyz_infl.end(), config.edge.xyz_influence);
182 if (config.edge.use_normals && !config.edge.use_combined)
187 std::vector<float> normals_infl(3);
188 std::fill(normals_infl.begin(), normals_infl.end(), config.edge.normals_influence);
192 if (config.edge.use_curvature && !config.edge.use_combined)
196 std::vector<float> curv_infl(1);
197 std::fill(curv_infl.begin(), curv_infl.end(), config.edge.curvature_influence);
201 if (config.edge.use_rgb && !config.edge.use_combined)
205 std::vector<float> rgb_infl(3);
206 std::fill(rgb_infl.begin(), rgb_infl.end(), config.edge.rgb_influence);
210 if (config.edge.use_time && !config.edge.use_combined)
214 std::vector<float> time_infl(1);
215 std::fill(time_infl.begin(), time_infl.end(), config.edge.time_influence);
219 if (config.edge.use_combined)
224 num_feat += config.edge.use_rgb ? 3 : 0;
225 num_feat += config.edge.use_normals ? 3 : 0;
226 num_feat += config.edge.use_xyz ? 3 : 0;
227 num_feat += config.edge.use_time ? 1 : 0;
228 num_feat += config.edge.use_curvature ? 1 : 0;
229 std::vector<float> comb_infl(num_feat);
231 for (
int i = 0; i < 3; i++)
234 if (config.edge.use_rgb)
236 comb_infl[i + j] = config.edge.rgb_influence;
239 if (config.edge.use_normals)
241 comb_infl[i + j] = config.edge.normals_influence;
244 if (config.edge.use_xyz)
246 comb_infl[i + j] = config.edge.xyz_influence;
251 if (config.edge.use_curvature)
253 comb_infl[j] = config.edge.curvature_influence;
256 if (config.edge.use_time)
258 comb_infl[j] = config.edge.time_influence;
261 config.edge.use_curvature, config.edge.use_time,
262 new PottsCompatibility(config.edge.potts_compatibilty));
272 if (config.out.provide_graph_pclouds)
276 if (config.out.provide_confidence_pclouds)
278 provideAllConfidences();
280 output_cloud_ptr->points.clear();
287 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
289 outputGraph = retrieveGraphFromPersistentGraph(timestamp_queue_.back());
292 pcl::PointCloud<pcl::PointXYZI>::Ptr confidence_cloud_ptr(
new pcl::PointCloud<pcl::PointXYZI>());
293 pcl::copyPointCloud(*temp_cloud_ptr, *confidence_cloud_ptr);
294 for (
long unsigned int i = 0; i < confidence_cloud_ptr->points.size(); i++)
311 confidence_cloud_ptr->points[i].intensity = conf;
314 output_cloud_ptr->header = input_cloud_ptr->header;
315 provideResultPointClouds<decltype(output_cloud_ptr)>(output_cloud_ptr,
"CRFSegmentationResult");
316 provideResultPointClouds<decltype(confidence_cloud_ptr)>(confidence_cloud_ptr,
"CRFSegmentationConfidence");
321 void DenseCRFSegmentationProcessor::computeGraphUsingVoxelGrid(
const PointCloudT::Ptr inputCloudPtr)
324 double r = config.general.voxel_resolution;
326 graph_builder.setInputCloud(inputCloudPtr);
328 graph_builder.compute(*current_graph_ptr_);
330 ARMARX_DEBUG <<
"Graph has " <<
static_cast<int>(boost::num_vertices(*current_graph_ptr_)) <<
" Vertices and "
331 <<
static_cast<int>(boost::num_edges(*current_graph_ptr_)) <<
" Edges";
332 if (config.edge.use_curvature || config.edge.use_normals)
344 Eigen::MatrixXf DenseCRFSegmentationProcessor::computeRandomUnaryEnergy(
int num_points)
347 Eigen::MatrixXf energy(config.general.num_classes, num_points);
348 const double u_energy = -log(1.0 / config.general.num_classes);
349 const double n_energy = -log((1.0 - config.general.ground_truth_prob) / (config.general.num_classes - 1));
350 const double p_energy = -log(config.general.ground_truth_prob);
351 energy.fill(u_energy);
352 std::random_device dev;
353 std::mt19937 rng(dev());
354 std::uniform_int_distribution<std::mt19937::result_type> dist(0, config.general.num_classes - 1);
355 for (
int k = 0; k < num_points; k++)
361 energy.col(k).fill(n_energy);
362 energy(r, k) = p_energy;
368 void DenseCRFSegmentationProcessor::generateRandomClassLabels()
372 std::random_device dev;
373 std::mt19937 rng(dev());
374 std::uniform_int_distribution<std::mt19937::result_type> dist(0,
377 for (boost::tie(vi, v_end) = boost::vertices(*current_graph_ptr_); vi != v_end; ++vi)
380 (*current_graph_ptr_)[*vi].label = r;
405 pcl::PointCloud<pcl::PointXYZL>::ConstPtr DenseCRFSegmentationProcessor::selectRandomSeeds()
409 std::vector<Graph::vertex_descriptor> v_out;
410 boost::tie(vi, v_end) = boost::vertices(*current_graph_ptr_);
412 std::sample(vi, v_end, std::back_inserter(v_out), num_classes - 1, std::mt19937{std::random_device{}()});
416 for (
auto i = v_out.begin(); i != v_out.end(); i++, j++)
418 tempCloudPtr->points[j] = (*current_graph_ptr_)[*i];
420 tempCloudPtr->points[j].label = j;
423 pcl::PointCloud<pcl::PointXYZL>::Ptr outCloudPtr(
new pcl::PointCloud<pcl::PointXYZL>());
424 pcl::copyPointCloud(*tempCloudPtr, *outCloudPtr);
462 void DenseCRFSegmentationProcessor::updatePersistentGraph()
467 static_cast<double>(current_graph_ptr_->m_graph.m_point_cloud->header.stamp / 1000.0) - initial_time_;
468 timestamp_queue_.push_back(current_ts);
470 if (timestamp_queue_.size() > 5)
473 double tsToRemove = timestamp_queue_.front();
474 timestamp_queue_.pop_front();
475 removeTimestampFromPersistentGraph(tsToRemove);
477 addCurrentGraphToPersistentGraph();
478 ARMARX_DEBUG <<
"Root Graph consisting of " << timestamp_queue_.size() <<
" Subgraphs has "
479 <<
static_cast<int>(boost::num_vertices(*persistent_graph_ptr_)) <<
" Vertices";
483 void DenseCRFSegmentationProcessor::addGraphToPersistentGraph(
Graph& graph)
488 double current_ts =
static_cast<double>(graph.m_graph.m_point_cloud->header.stamp / 1000.0) - initial_time_;
489 for (boost::tie(vi, v_end) = boost::vertices(graph); vi != v_end; ++vi)
491 VertexWTsId new_vertex = boost::add_vertex(*persistent_graph_ptr_);
492 boost::put(tsm, new_vertex, current_ts);
494 boost::put(cm, new_vertex, -1.0);
496 (*persistent_graph_ptr_)[new_vertex] = point;
500 void DenseCRFSegmentationProcessor::addCurrentGraphToPersistentGraph()
503 addGraphToPersistentGraph(*current_graph_ptr_);
506 void DenseCRFSegmentationProcessor::removeGraphFromPersistentGraph(
Graph& graph)
509 double graph_ts =
static_cast<double>(graph.m_graph.m_point_cloud->header.stamp / 1000.0) - initial_time_;
510 removeTimestampFromPersistentGraph(graph_ts);
513 void DenseCRFSegmentationProcessor::removeCurrentGraphFromPersistentGraph()
516 removeGraphFromPersistentGraph(*current_graph_ptr_);
519 void DenseCRFSegmentationProcessor::removeTimestampFromPersistentGraph(
double ts)
523 typedef vertex_timestamp_unequal_filter <TimestampMap> FilterT;
524 FilterT filter(tsm, ts);
525 GraphWithTimestamp filtered_graph = filterAndCopyPersistentGraph<FilterT>(tsm, filter);
527 persistent_graph_ptr_.swap(temp_graph_ptr);
530 GraphWithTimestamp DenseCRFSegmentationProcessor::retrieveGraphFromPersistentGraph(
double ts)
534 typedef vertex_timestamp_equal_filter <TimestampMap> FilterT;
535 FilterT filter(tsm, ts);
536 GraphWithTimestamp filtered_graph = filterAndCopyPersistentGraph<FilterT>(tsm, filter);
537 return filtered_graph;
540 GraphWithTimestamp DenseCRFSegmentationProcessor::retrieveCurrentGraphFromPersistentGraph()
544 static_cast<double>(current_graph_ptr_->m_graph.m_point_cloud->header.stamp / 1000.0) - initial_time_;
545 return retrieveGraphFromPersistentGraph(current_ts);
548 void DenseCRFSegmentationProcessor::provideAllGraphs()
551 for (
unsigned int i = 0; i < timestamp_queue_.size(); i++)
553 double ts = timestamp_queue_.at(i);
555 PointCloudT::Ptr output_cloud_ptr(
new PointCloudT());
561 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
566 void DenseCRFSegmentationProcessor::computeVertexOnlyGraph(PointCloudT::Ptr input_cloud_ptr)
571 pcl::PointCloud<PointT>::Ptr temp_cloud_ptr(
new pcl::PointCloud<PointT>());
572 ARMARX_DEBUG << input_cloud_ptr->size() <<
"before downsampling";
574 if (config.general.use_approximate_voxels)
577 pcl::ApproximateVoxelGrid<PointT> vg;
578 vg.setInputCloud(input_cloud_ptr);
579 vg.setLeafSize(config.general.voxel_resolution * 100, config.general.voxel_resolution * 100,
580 config.general.voxel_resolution * 100);
581 vg.filter(*temp_cloud_ptr);
582 temp_cloud_ptr.swap(input_cloud_ptr);
586 pcl::VoxelGrid<PointT> vg;
587 vg.setInputCloud(input_cloud_ptr);
588 vg.setLeafSize(config.general.voxel_resolution * 100, config.general.voxel_resolution * 100,
589 config.general.voxel_resolution * 100);
590 vg.filter(*temp_cloud_ptr);
591 temp_cloud_ptr.swap(input_cloud_ptr);
594 ARMARX_DEBUG << input_cloud_ptr->size() <<
"after downsampling";
597 pcl::NormalEstimation<PointT, PointWithNormalT> ne;
598 ne.setInputCloud(input_cloud_ptr);
599 pcl::search::KdTree<PointT>::Ptr tree(
new pcl::search::KdTree<PointT>());
600 ne.setSearchMethod(tree);
603 copyRGBLToRGBLNormal(*input_cloud_ptr, *cloud_normals);
605 ne.setRadiusSearch(100 * 5 * config.general.voxel_resolution);
608 ne.compute(*cloud_normals);
610 GraphPtr temp_graph_ptr = boost::make_shared<Graph>(
Graph(cloud_normals));
611 current_graph_ptr_.swap(temp_graph_ptr);
612 ARMARX_DEBUG <<
"Graph has " <<
static_cast<int>(boost::num_vertices(*current_graph_ptr_)) <<
" Vertices and "
613 <<
static_cast<int>(boost::num_edges(*current_graph_ptr_)) <<
" Edges";
619 output_cloud.header = input_cloud.header;
620 output_cloud.width = input_cloud.width;
621 output_cloud.height = input_cloud.height;
622 output_cloud.is_dense = input_cloud.is_dense;
623 output_cloud.sensor_orientation_ = input_cloud.sensor_orientation_;
624 output_cloud.sensor_origin_ = input_cloud.sensor_origin_;
625 output_cloud.points.resize(input_cloud.points.size());
627 if (input_cloud.points.size() == 0)
633 for (
size_t i = 0; i < output_cloud.size(); i++)
635 output_cloud.points[i].x = input_cloud.points[i].x;
636 output_cloud.points[i].y = input_cloud.points[i].y;
637 output_cloud.points[i].z = input_cloud.points[i].z;
638 output_cloud.points[i].r = input_cloud.points[i].r;
639 output_cloud.points[i].g = input_cloud.points[i].g;
640 output_cloud.points[i].b = input_cloud.points[i].b;
641 output_cloud.points[i].a = uint8_t(255);
642 output_cloud.points[i].label = input_cloud.points[i].label;
643 output_cloud.points[i].normal_x = 0;
644 output_cloud.points[i].normal_y = 0;
645 output_cloud.points[i].normal_z = 0;
646 output_cloud.points[i].curvature = 0;
653 output_cloud.header = input_cloud.header;
654 output_cloud.width = input_cloud.width;
655 output_cloud.height = input_cloud.height;
656 output_cloud.is_dense = input_cloud.is_dense;
657 output_cloud.sensor_orientation_ = input_cloud.sensor_orientation_;
658 output_cloud.sensor_origin_ = input_cloud.sensor_origin_;
659 output_cloud.points.resize(input_cloud.points.size());
661 if (input_cloud.points.size() == 0)
666 for (
size_t i = 0; i < output_cloud.size(); i++)
668 output_cloud.points[i].x = input_cloud.points[i].x;
669 output_cloud.points[i].y = input_cloud.points[i].y;
670 output_cloud.points[i].z = input_cloud.points[i].z;
671 output_cloud.points[i].r = input_cloud.points[i].r;
672 output_cloud.points[i].g = input_cloud.points[i].g;
673 output_cloud.points[i].b = input_cloud.points[i].b;
674 output_cloud.points[i].a = uint8_t(255);
675 output_cloud.points[i].label = input_cloud.points[i].label;
680 void DenseCRFSegmentationProcessor::relabelPointCloud(pcl::PointCloud<PointT>::Ptr input_cloud_ptr)
683 std::map<uint32_t, uint32_t> labelmap;
684 uint32_t highest_new_label = 1;
685 for (
auto& point: input_cloud_ptr->points)
687 if (labelmap.find(point.label) != labelmap.end())
689 point.label = labelmap.at(point.label);
692 labelmap.insert(std::make_pair(point.label, highest_new_label));
693 point.label = highest_new_label;
700 void DenseCRFSegmentationProcessor::provideAllConfidences()
705 for (
unsigned int i = 0; i < timestamp_queue_.size(); i++)
707 double ts = timestamp_queue_.at(i);
717 PointCloudT::Ptr output_cloud_ptr(
new PointCloudT());
718 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
719 for (
long unsigned int j = 0; j < output_cloud_ptr->points.size(); j++)
723 output_cloud_ptr->points[j].
r =
c.r * 255.0;
724 output_cloud_ptr->points[j].g =
c.g * 255.0;
725 output_cloud_ptr->points[j].b =
c.b * 255.0;
727 provideResultPointClouds<decltype(output_cloud_ptr)>(output_cloud_ptr,
"Confidence" +
std::to_string(i));
730 pcl::PointCloud<pcl::PointXYZI>::Ptr confidence_cloud_ptr(
new pcl::PointCloud<pcl::PointXYZI>());
731 pcl::copyPointCloud(*temp_cloud_ptr, *confidence_cloud_ptr);
732 for (
long unsigned int j = 0; j < confidence_cloud_ptr->points.size(); j++)
735 confidence_cloud_ptr->points[j].intensity = conf;
737 provideResultPointClouds<decltype(confidence_cloud_ptr)>(confidence_cloud_ptr,
"Confidence" +
std::to_string(i));
745 Vector5f vec{config.xyz_influence, config.rgb_influence, config.normals_influence,
746 config.curvature_influence, config.time_influence};
753 std::unique_lock lock(write_mutex_);
755 config.xyz_influence = xyz;
756 config.rgb_influence = rgb;
757 config.normals_influence = normals;
758 config.curvature_influence = curvature;
759 config.time_influence = time;