25#include <boost/graph/adjacency_list.hpp>
26#include <boost/graph/graph_concepts.hpp>
27#include <boost/graph/subgraph.hpp>
37#include <boost/smart_ptr/make_shared.hpp>
39#include <pcl/filters/approximate_voxel_grid.h>
40#include <pcl/filters/filter.h>
41#include <pcl/filters/voxel_grid.h>
59 def->optional(config_.getWriteBuffer(),
"",
"");
67 std::unique_lock lock(write_mutex_);
68 config_.commitWrite();
83 if (config_.getUpToDateReadBuffer().out.provide_graph_pclouds)
93 if (config_.getUpToDateReadBuffer().out.provide_confidence_pclouds)
95 if (config_.getUpToDateReadBuffer().out.colorize_confidence_pclouds)
121 std::unique_lock lock(write_mutex_);
122 prx.getValue(config_.getWriteBuffer(),
"Config");
123 config_.commitWrite();
142 pcl::PointCloud<PointT>::Ptr input_cloud_ptr(
new pcl::PointCloud<PointT>());
143 pcl::PointCloud<PointT>::Ptr output_cloud_ptr(
new pcl::PointCloud<PointT>());
147 ARMARX_INFO <<
"Timeout or error while waiting for point cloud data";
156 std::vector<int> indices;
157 input_cloud_ptr->is_dense =
false;
158 pcl::removeNaNFromPointCloud(*input_cloud_ptr, *input_cloud_ptr, indices);
159 relabelPointCloud(input_cloud_ptr);
160 ARMARX_DEBUG <<
"Point Cloud has " << input_cloud_ptr->size() <<
" Points before Downsampling";
161 auto config = config_.getUpToDateReadBuffer();
162 if (config.general.use_vertex_only_graph)
165 computeVertexOnlyGraph(input_cloud_ptr);
170 computeGraphUsingVoxelGrid(input_cloud_ptr);
176 updatePersistentGraph();
179 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
181 config = config_.getUpToDateReadBuffer();
184 if (config.edge.use_xyz && !config.edge.use_combined)
188 std::vector<float> xyz_infl(3);
189 std::fill(xyz_infl.begin(), xyz_infl.end(), config.edge.xyz_influence);
191 new PottsCompatibility(10));
194 if (config.edge.use_normals && !config.edge.use_combined)
199 std::vector<float> normals_infl(3);
200 std::fill(normals_infl.begin(), normals_infl.end(), config.edge.normals_influence);
202 normals_infl,
new PottsCompatibility(10));
205 if (config.edge.use_curvature && !config.edge.use_combined)
209 std::vector<float> curv_infl(1);
210 std::fill(curv_infl.begin(), curv_infl.end(), config.edge.curvature_influence);
212 curv_infl,
new PottsCompatibility(10));
215 if (config.edge.use_rgb && !config.edge.use_combined)
219 std::vector<float> rgb_infl(3);
220 std::fill(rgb_infl.begin(), rgb_infl.end(), config.edge.rgb_influence);
222 new PottsCompatibility(10));
225 if (config.edge.use_time && !config.edge.use_combined)
229 std::vector<float> time_infl(1);
230 std::fill(time_infl.begin(), time_infl.end(), config.edge.time_influence);
234 if (config.edge.use_combined)
239 num_feat += config.edge.use_rgb ? 3 : 0;
240 num_feat += config.edge.use_normals ? 3 : 0;
241 num_feat += config.edge.use_xyz ? 3 : 0;
242 num_feat += config.edge.use_time ? 1 : 0;
243 num_feat += config.edge.use_curvature ? 1 : 0;
244 std::vector<float> comb_infl(num_feat);
246 for (
int i = 0; i < 3; i++)
249 if (config.edge.use_rgb)
251 comb_infl[i + j] = config.edge.rgb_influence;
254 if (config.edge.use_normals)
256 comb_infl[i + j] = config.edge.normals_influence;
259 if (config.edge.use_xyz)
261 comb_infl[i + j] = config.edge.xyz_influence;
265 if (config.edge.use_curvature)
267 comb_infl[j] = config.edge.curvature_influence;
270 if (config.edge.use_time)
272 comb_infl[j] = config.edge.time_influence;
276 config.edge.use_normals,
278 config.edge.use_curvature,
279 config.edge.use_time,
280 new PottsCompatibility(config.edge.potts_compatibilty));
290 if (config.out.provide_graph_pclouds)
294 if (config.out.provide_confidence_pclouds)
296 provideAllConfidences();
298 output_cloud_ptr->points.clear();
305 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
307 outputGraph = retrieveGraphFromPersistentGraph(timestamp_queue_.back());
310 pcl::PointCloud<pcl::PointXYZI>::Ptr confidence_cloud_ptr(
311 new pcl::PointCloud<pcl::PointXYZI>());
312 pcl::copyPointCloud(*temp_cloud_ptr, *confidence_cloud_ptr);
313 for (
long unsigned int i = 0; i < confidence_cloud_ptr->points.size(); i++)
330 confidence_cloud_ptr->points[i].intensity = conf;
333 output_cloud_ptr->header = input_cloud_ptr->header;
336 "CRFSegmentationConfidence");
341DenseCRFSegmentationProcessor::computeGraphUsingVoxelGrid(
const PointCloudT::Ptr inputCloudPtr)
344 double r = config.general.voxel_resolution;
346 graph_builder.setInputCloud(inputCloudPtr);
348 graph_builder.compute(*current_graph_ptr_);
350 ARMARX_DEBUG <<
"Graph has " <<
static_cast<int>(boost::num_vertices(*current_graph_ptr_))
351 <<
" Vertices and " <<
static_cast<int>(boost::num_edges(*current_graph_ptr_))
353 if (config.edge.use_curvature || config.edge.use_normals)
365DenseCRFSegmentationProcessor::computeRandomUnaryEnergy(
int num_points)
367 const auto& config = config_.getUpToDateReadBuffer();
368 Eigen::MatrixXf energy(config.general.num_classes, num_points);
369 const double u_energy = -log(1.0 / config.general.num_classes);
370 const double n_energy =
371 -log((1.0 - config.general.ground_truth_prob) / (config.general.num_classes - 1));
372 const double p_energy = -log(config.general.ground_truth_prob);
373 energy.fill(u_energy);
374 std::random_device dev;
375 std::mt19937 rng(dev());
376 std::uniform_int_distribution<std::mt19937::result_type> dist(0,
377 config.general.num_classes - 1);
378 for (
int k = 0; k < num_points; k++)
384 energy.col(k).fill(n_energy);
385 energy(r, k) = p_energy;
392DenseCRFSegmentationProcessor::generateRandomClassLabels()
396 std::random_device dev;
397 std::mt19937 rng(dev());
398 std::uniform_int_distribution<std::mt19937::result_type> dist(
399 0, config_.getUpToDateReadBuffer().general.num_classes - 1);
400 for (boost::tie(vi, v_end) = boost::vertices(*current_graph_ptr_); vi != v_end; ++vi)
403 (*current_graph_ptr_)[*vi].label = r;
427pcl::PointCloud<pcl::PointXYZL>::ConstPtr
428DenseCRFSegmentationProcessor::selectRandomSeeds()
430 auto num_classes = config_.getUpToDateReadBuffer().general.num_classes;
432 std::vector<Graph::vertex_descriptor> v_out;
433 boost::tie(vi, v_end) = boost::vertices(*current_graph_ptr_);
437 std::back_inserter(v_out),
439 std::mt19937{std::random_device{}()});
443 for (
auto i = v_out.begin(); i != v_out.end(); i++, j++)
445 tempCloudPtr->points[j] = (*current_graph_ptr_)[*i];
447 tempCloudPtr->points[j].label = j;
450 pcl::PointCloud<pcl::PointXYZL>::Ptr outCloudPtr(
new pcl::PointCloud<pcl::PointXYZL>());
451 pcl::copyPointCloud(*tempCloudPtr, *outCloudPtr);
490DenseCRFSegmentationProcessor::updatePersistentGraph()
495 static_cast<double>(current_graph_ptr_->m_graph.m_point_cloud->header.stamp / 1000.0) -
497 timestamp_queue_.push_back(current_ts);
499 if (timestamp_queue_.size() > 5)
502 double tsToRemove = timestamp_queue_.front();
503 timestamp_queue_.pop_front();
504 removeTimestampFromPersistentGraph(tsToRemove);
506 addCurrentGraphToPersistentGraph();
507 ARMARX_DEBUG <<
"Root Graph consisting of " << timestamp_queue_.size() <<
" Subgraphs has "
508 <<
static_cast<int>(boost::num_vertices(*persistent_graph_ptr_)) <<
" Vertices";
513DenseCRFSegmentationProcessor::addGraphToPersistentGraph(
Graph& graph)
515 TimestampMap tsm = boost::get(boost::vertex_timestamp_t(), persistent_graph_ptr_->m_graph);
516 ConfidenceMap cm = boost::get(boost::vertex_confidence_t(), persistent_graph_ptr_->m_graph);
519 static_cast<double>(graph.m_graph.m_point_cloud->header.stamp / 1000.0) - initial_time_;
520 for (boost::tie(vi, v_end) = boost::vertices(graph); vi != v_end; ++vi)
522 VertexWTsId new_vertex = boost::add_vertex(*persistent_graph_ptr_);
523 boost::put(tsm, new_vertex, current_ts);
525 boost::put(cm, new_vertex, -1.0);
527 (*persistent_graph_ptr_)[new_vertex] = point;
532DenseCRFSegmentationProcessor::addCurrentGraphToPersistentGraph()
535 addGraphToPersistentGraph(*current_graph_ptr_);
539DenseCRFSegmentationProcessor::removeGraphFromPersistentGraph(
Graph& graph)
543 static_cast<double>(graph.m_graph.m_point_cloud->header.stamp / 1000.0) - initial_time_;
544 removeTimestampFromPersistentGraph(graph_ts);
548DenseCRFSegmentationProcessor::removeCurrentGraphFromPersistentGraph()
551 removeGraphFromPersistentGraph(*current_graph_ptr_);
555DenseCRFSegmentationProcessor::removeTimestampFromPersistentGraph(
double ts)
558 TimestampMap tsm = boost::get(boost::vertex_timestamp_t(), persistent_graph_ptr_->m_graph);
559 typedef vertex_timestamp_unequal_filter<TimestampMap> FilterT;
560 FilterT filter(tsm, ts);
561 GraphWithTimestamp filtered_graph = filterAndCopyPersistentGraph<FilterT>(tsm, filter);
563 persistent_graph_ptr_.swap(temp_graph_ptr);
567DenseCRFSegmentationProcessor::retrieveGraphFromPersistentGraph(
double ts)
570 TimestampMap tsm = boost::get(boost::vertex_timestamp_t(), persistent_graph_ptr_->m_graph);
571 typedef vertex_timestamp_equal_filter<TimestampMap> FilterT;
572 FilterT filter(tsm, ts);
573 GraphWithTimestamp filtered_graph = filterAndCopyPersistentGraph<FilterT>(tsm, filter);
574 return filtered_graph;
578DenseCRFSegmentationProcessor::retrieveCurrentGraphFromPersistentGraph()
582 static_cast<double>(current_graph_ptr_->m_graph.m_point_cloud->header.stamp / 1000.0) -
584 return retrieveGraphFromPersistentGraph(current_ts);
588DenseCRFSegmentationProcessor::provideAllGraphs()
591 for (
unsigned int i = 0; i < timestamp_queue_.size(); i++)
593 double ts = timestamp_queue_.at(i);
595 PointCloudT::Ptr output_cloud_ptr(
new PointCloudT());
601 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
607DenseCRFSegmentationProcessor::computeVertexOnlyGraph(PointCloudT::Ptr input_cloud_ptr)
610 const auto& config = config_.getUpToDateReadBuffer();
612 pcl::PointCloud<PointT>::Ptr temp_cloud_ptr(
new pcl::PointCloud<PointT>());
613 ARMARX_DEBUG << input_cloud_ptr->size() <<
"before downsampling";
615 if (config.general.use_approximate_voxels)
618 pcl::ApproximateVoxelGrid<PointT> vg;
619 vg.setInputCloud(input_cloud_ptr);
620 vg.setLeafSize(config.general.voxel_resolution * 100,
621 config.general.voxel_resolution * 100,
622 config.general.voxel_resolution * 100);
623 vg.filter(*temp_cloud_ptr);
624 temp_cloud_ptr.swap(input_cloud_ptr);
629 pcl::VoxelGrid<PointT> vg;
630 vg.setInputCloud(input_cloud_ptr);
631 vg.setLeafSize(config.general.voxel_resolution * 100,
632 config.general.voxel_resolution * 100,
633 config.general.voxel_resolution * 100);
634 vg.filter(*temp_cloud_ptr);
635 temp_cloud_ptr.swap(input_cloud_ptr);
638 ARMARX_DEBUG << input_cloud_ptr->size() <<
"after downsampling";
641 pcl::NormalEstimation<PointT, PointWithNormalT> ne;
642 ne.setInputCloud(input_cloud_ptr);
643 pcl::search::KdTree<PointT>::Ptr tree(
new pcl::search::KdTree<PointT>());
644 ne.setSearchMethod(tree);
647 copyRGBLToRGBLNormal(*input_cloud_ptr, *cloud_normals);
649 ne.setRadiusSearch(100 * 5 * config.general.voxel_resolution);
652 ne.compute(*cloud_normals);
654 GraphPtr temp_graph_ptr = boost::make_shared<Graph>(
Graph(cloud_normals));
655 current_graph_ptr_.swap(temp_graph_ptr);
656 ARMARX_DEBUG <<
"Graph has " <<
static_cast<int>(boost::num_vertices(*current_graph_ptr_))
657 <<
" Vertices and " <<
static_cast<int>(boost::num_edges(*current_graph_ptr_))
662DenseCRFSegmentationProcessor::copyRGBLToRGBLNormal(
PointCloudT& input_cloud,
666 output_cloud.header = input_cloud.header;
667 output_cloud.width = input_cloud.width;
668 output_cloud.height = input_cloud.height;
669 output_cloud.is_dense = input_cloud.is_dense;
670 output_cloud.sensor_orientation_ = input_cloud.sensor_orientation_;
671 output_cloud.sensor_origin_ = input_cloud.sensor_origin_;
672 output_cloud.points.resize(input_cloud.points.size());
674 if (input_cloud.points.size() == 0)
680 for (
size_t i = 0; i < output_cloud.size(); i++)
682 output_cloud.points[i].x = input_cloud.points[i].x;
683 output_cloud.points[i].y = input_cloud.points[i].y;
684 output_cloud.points[i].z = input_cloud.points[i].z;
685 output_cloud.points[i].r = input_cloud.points[i].r;
686 output_cloud.points[i].g = input_cloud.points[i].g;
687 output_cloud.points[i].b = input_cloud.points[i].b;
688 output_cloud.points[i].a = uint8_t(255);
689 output_cloud.points[i].label = input_cloud.points[i].label;
690 output_cloud.points[i].normal_x = 0;
691 output_cloud.points[i].normal_y = 0;
692 output_cloud.points[i].normal_z = 0;
693 output_cloud.points[i].curvature = 0;
702 output_cloud.header = input_cloud.header;
703 output_cloud.width = input_cloud.width;
704 output_cloud.height = input_cloud.height;
705 output_cloud.is_dense = input_cloud.is_dense;
706 output_cloud.sensor_orientation_ = input_cloud.sensor_orientation_;
707 output_cloud.sensor_origin_ = input_cloud.sensor_origin_;
708 output_cloud.points.resize(input_cloud.points.size());
710 if (input_cloud.points.size() == 0)
715 for (
size_t i = 0; i < output_cloud.size(); i++)
717 output_cloud.points[i].x = input_cloud.points[i].x;
718 output_cloud.points[i].y = input_cloud.points[i].y;
719 output_cloud.points[i].z = input_cloud.points[i].z;
720 output_cloud.points[i].r = input_cloud.points[i].r;
721 output_cloud.points[i].g = input_cloud.points[i].g;
722 output_cloud.points[i].b = input_cloud.points[i].b;
723 output_cloud.points[i].a = uint8_t(255);
724 output_cloud.points[i].label = input_cloud.points[i].label;
729DenseCRFSegmentationProcessor::relabelPointCloud(pcl::PointCloud<PointT>::Ptr input_cloud_ptr)
732 std::map<uint32_t, uint32_t> labelmap;
733 uint32_t highest_new_label = 1;
734 for (
auto& point : input_cloud_ptr->points)
736 if (labelmap.find(point.label) != labelmap.end())
738 point.label = labelmap.at(point.label);
742 labelmap.insert(std::make_pair(point.label, highest_new_label));
743 point.label = highest_new_label;
750DenseCRFSegmentationProcessor::provideAllConfidences()
753 colormap::MATLAB::Jet jet;
754 bool colorize = config_.getUpToDateReadBuffer().out.colorize_confidence_pclouds;
755 for (
unsigned int i = 0; i < timestamp_queue_.size(); i++)
757 double ts = timestamp_queue_.at(i);
759 ConfidenceMap cm = boost::get(boost::vertex_confidence_t(), graph.m_graph);
767 PointCloudT::Ptr output_cloud_ptr(
new PointCloudT());
768 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
769 for (
long unsigned int j = 0; j < output_cloud_ptr->points.size(); j++)
773 output_cloud_ptr->points[j].
r =
c.r * 255.0;
774 output_cloud_ptr->points[j].g =
c.g * 255.0;
775 output_cloud_ptr->points[j].b =
c.b * 255.0;
778 "Confidence" + std::to_string(i));
782 pcl::PointCloud<pcl::PointXYZI>::Ptr confidence_cloud_ptr(
783 new pcl::PointCloud<pcl::PointXYZI>());
784 pcl::copyPointCloud(*temp_cloud_ptr, *confidence_cloud_ptr);
785 for (
long unsigned int j = 0; j < confidence_cloud_ptr->points.size(); j++)
788 confidence_cloud_ptr->points[j].intensity = conf;
791 confidence_cloud_ptr,
"Confidence" + std::to_string(i));
799 const auto& config = config_.getUpToDateReadBuffer().edge;
800 Vector5f vec{config.xyz_influence,
801 config.rgb_influence,
802 config.normals_influence,
803 config.curvature_influence,
804 config.time_influence};
814 const Ice::Current& current)
817 std::unique_lock lock(write_mutex_);
818 auto& config = config_.getWriteBuffer().edge;
819 config.xyz_influence = xyz;
820 config.rgb_influence = rgb;
821 config.normals_influence = normals;
822 config.curvature_influence = curvature;
823 config.time_influence = time;
824 config_.commitWrite();
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onExitPointCloudProcessor() override
void setEdgeWeights(float xyz, float rgb, float normals, float curvature, float time, const Ice::Current ¤t) override
void onConnectPointCloudProcessor() override
Vector5f getCurrentEdgeWeights(const Ice::Current ¤t) override
void onDisconnectPointCloudProcessor() override
boost::graph_traits< Graph >::vertex_iterator VertexIterator
void onInitPointCloudProcessor() override
Eigen::VectorXf map_and_confidence(int n_iterations)
void computeUnaryEnergyFromGraph(float gt_prob)
void addPairwiseGaussianFeature(std::vector< float > sigma, LabelCompatibility *function, KernelType kernel_type=DIAG_KERNEL, NormalizationType normalization_type=NORMALIZE_SYMMETRIC)
void addCombinedGaussianFeature(std::vector< float > sigma, bool use_rgb, bool use_norm, bool use_xyz, bool use_curv, bool use_time, LabelCompatibility *function, KernelType kernel_type=DIAG_KERNEL, NormalizationType normalization_type=NORMALIZE_SYMMETRIC)
void createOrUpdateRemoteGuiTab(Ts &&... ts)
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
const T & getUpToDateReadBuffer() const
Color getColor(double x) const override
This class builds a BGL graph representing an input dataset by using octree::OctreePointCloud.
void enableResultPointClouds(std::string resultProviderName="")
Enables visualization.
int getPointClouds(const PointCloudPtrT &pointCloudPtr)
Poll PointClouds from provider.
void usingPointCloudProvider(std::string providerName)
Registers a delayed topic subscription and a delayed provider proxy retrieval which will be available...
bool waitForPointClouds(int milliseconds=1000)
Wait for new PointClouds.
void provideResultPointClouds(const PointCloudPtrT &pointClouds, std::string providerName="")
sends result PointClouds for visualization
#define ARMARX_INFO
The normal logging level.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define TIMING_START(name)
Helper macro to do timing tests.
#define TIMING_END_STREAM(name, os)
Prints duration.
RemoteGui::WidgetPtr MakeGuiConfig(const std::string &name, const T &val)
This file offers overloads of toIce() and fromIce() functions for STL container types.
pcl::PointCloud< PointWithNormalT > PointCloudWithNormalT
boost::property_map< CloudGraphWithTimestamp, boost::vertex_confidence_t >::type ConfidenceMap
boost::shared_ptr< GraphWithTimestamp > GraphWithTimestampPtr
boost::property_map< CloudGraphWithTimestamp, boost::vertex_timestamp_t >::type TimestampMap
pcl::PointCloud< PointT > PointCloudT
boost::graph_traits< GraphWithTimestamp >::vertex_descriptor VertexWTsId
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
boost::subgraph< CloudGraphWithTimestamp > GraphWithTimestamp
boost::subgraph< CloudGraph > Graph
pcl::PointXYZRGBLNormal PointWithNormalT
void computeSignedCurvatures(Graph &graph)
Compute the type of curvature (concave/convex) for each vertex.
void computeNormalsAndCurvatures(Graph &graph, bool neighborhood_1ring=false)
Compute normals and curvatures for all vertices in a graph.
pcl::PointCloud< P >::Ptr point_cloud(PCG &g)
Retrieve the point cloud stored in a point cloud graph.