DenseCRFSegmentationProcessor.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package ROBDEKON::ArmarXObjects::DenseCRFSegmentationProcessor
17 * @author Christoph Pohl ( christoph dot pohl at kit dot edu )
18 * @date 2019
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
25#include <boost/graph/adjacency_list.hpp>
26#include <boost/graph/graph_concepts.hpp>
27#include <boost/graph/subgraph.hpp>
28//#include <boost/bimap.hpp>
29//#include <boost/graph/copy.hpp>
30
31//#include <Eigen/Core>
32//#include <Eigen/Geometry>
33
34#include <algorithm>
35#include <random>
36
37#include <boost/smart_ptr/make_shared.hpp>
38
39#include <pcl/filters/approximate_voxel_grid.h>
40#include <pcl/filters/filter.h>
41#include <pcl/filters/voxel_grid.h>
42
44
46
48#include "DenseGraphCRF.hpp"
50
51
52using namespace armarx;
53
62
63void
65{
67 std::unique_lock lock(write_mutex_);
68 config_.commitWrite(); // To commit the property definitions to the buffer
69 usingPointCloudProvider(getProperty<std::string>("ProviderName").getValue());
70 current_graph_ptr_ = GraphPtr(new Graph);
71 persistent_graph_ptr_ = GraphWithTimestampPtr(new GraphWithTimestamp);
72 initial_time_ = TimeUtil::GetTime().toMilliSecondsDouble();
73}
74
75void
77{
79 // enableResultPointClouds<PointT>();
80 // add a name to provide more than one result point cloud
81 enableResultPointClouds<PointT>("CRFSegmentationResult");
82 enableResultPointClouds<pcl::PointXYZI>("CRFSegmentationConfidence");
83 if (config_.getUpToDateReadBuffer().out.provide_graph_pclouds)
84 {
91 }
92
93 if (config_.getUpToDateReadBuffer().out.provide_confidence_pclouds)
94 {
95 if (config_.getUpToDateReadBuffer().out.colorize_confidence_pclouds)
96 {
100 enableResultPointClouds<PointT>("Confidence2");
101 enableResultPointClouds<PointT>("Confidence3");
102 enableResultPointClouds<PointT>("Confidence4");
103 }
104 else
105 {
112 }
113 }
114
115 {
118 RemoteGui::MakeGuiConfig("Config", config_.getUpToDateReadBuffer()),
119 [this](armarx::RemoteGui::TabProxy& prx)
120 {
121 std::unique_lock lock(write_mutex_);
122 prx.getValue(config_.getWriteBuffer(), "Config");
123 config_.commitWrite();
124 });
125 }
126}
127
128void
132
133void
137
138void
140{
142 pcl::PointCloud<PointT>::Ptr input_cloud_ptr(new pcl::PointCloud<PointT>());
143 pcl::PointCloud<PointT>::Ptr output_cloud_ptr(new pcl::PointCloud<PointT>());
144
145 if (!waitForPointClouds())
146 {
147 ARMARX_INFO << "Timeout or error while waiting for point cloud data";
148 return;
149 }
150 else
151 {
152 getPointClouds(input_cloud_ptr);
153 }
154 // TODO: there will be a local exception when the number of labels is bigger than the number of classes set
155 // which is hard to decipher
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)
163 {
165 computeVertexOnlyGraph(input_cloud_ptr);
166 }
167 else
168 {
170 computeGraphUsingVoxelGrid(input_cloud_ptr);
171 }
172 // if (not pre_segmented_)
173 // {
174 // computeRandomWalkerSegmentation();
175 // }
176 updatePersistentGraph();
177 PointCloudWithNormalT::Ptr temp_cloud_ptr = pcl::graph::point_cloud(*current_graph_ptr_);
178 // pcl::copyPointCloud(*temp_cloud_ptr, *output_cloud_ptr);
179 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
180 // generateRandomClassLabels();
181 config = config_.getUpToDateReadBuffer();
182 DenseGraphCRF<GraphWithTimestamp> crf(persistent_graph_ptr_, config.general.num_classes);
183 crf.computeUnaryEnergyFromGraph(config.general.ground_truth_prob);
184 if (config.edge.use_xyz && !config.edge.use_combined)
185 {
187 TIMING_START(AddXYZFeature);
188 std::vector<float> xyz_infl(3);
189 std::fill(xyz_infl.begin(), xyz_infl.end(), config.edge.xyz_influence);
191 new PottsCompatibility(10));
192 TIMING_END_STREAM(AddXYZFeature, ARMARX_DEBUG);
193 }
194 if (config.edge.use_normals && !config.edge.use_combined)
195 {
197 // TODO: use normals causes segfault
198 TIMING_START(AddNormalFeature);
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));
203 TIMING_END_STREAM(AddNormalFeature, ARMARX_DEBUG);
204 }
205 if (config.edge.use_curvature && !config.edge.use_combined)
206 {
208 TIMING_START(AddCurvatureFeature);
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));
213 TIMING_END_STREAM(AddCurvatureFeature, ARMARX_DEBUG);
214 }
215 if (config.edge.use_rgb && !config.edge.use_combined)
216 {
218 TIMING_START(AddRGBFeature);
219 std::vector<float> rgb_infl(3);
220 std::fill(rgb_infl.begin(), rgb_infl.end(), config.edge.rgb_influence);
222 new PottsCompatibility(10));
223 TIMING_END_STREAM(AddRGBFeature, ARMARX_DEBUG);
224 }
225 if (config.edge.use_time && !config.edge.use_combined)
226 {
228 TIMING_START(AddTimeFeature);
229 std::vector<float> time_infl(1);
230 std::fill(time_infl.begin(), time_infl.end(), config.edge.time_influence);
231 crf.addPairwiseGaussianFeature<TimeFeature>(time_infl, new PottsCompatibility(1));
232 TIMING_END_STREAM(AddTimeFeature, ARMARX_DEBUG);
233 }
234 if (config.edge.use_combined)
235 {
237 TIMING_START(AddCombinedFeature);
238 int num_feat = 0;
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);
245 int j;
246 for (int i = 0; i < 3; i++)
247 {
248 j = 0;
249 if (config.edge.use_rgb)
250 {
251 comb_infl[i + j] = config.edge.rgb_influence;
252 j += 3;
253 }
254 if (config.edge.use_normals)
255 {
256 comb_infl[i + j] = config.edge.normals_influence;
257 j += 3;
258 }
259 if (config.edge.use_xyz)
260 {
261 comb_infl[i + j] = config.edge.xyz_influence;
262 j += 3;
263 }
264 }
265 if (config.edge.use_curvature)
266 {
267 comb_infl[j] = config.edge.curvature_influence;
268 j++;
269 }
270 if (config.edge.use_time)
271 {
272 comb_infl[j] = config.edge.time_influence;
273 }
274 crf.addCombinedGaussianFeature(comb_infl,
275 config.edge.use_rgb,
276 config.edge.use_normals,
277 config.edge.use_xyz,
278 config.edge.use_curvature,
279 config.edge.use_time,
280 new PottsCompatibility(config.edge.potts_compatibilty));
281 TIMING_END_STREAM(AddCombinedFeature, ARMARX_DEBUG);
282 }
283
284
285 // VectorXs map = crf.map(map_iterations_);
287 TIMING_START(MAP);
288 Eigen::VectorXf confidence = crf.map_and_confidence(config.general.map_iterations);
290 if (config.out.provide_graph_pclouds)
291 {
292 provideAllGraphs();
293 }
294 if (config.out.provide_confidence_pclouds)
295 {
296 provideAllConfidences();
297 }
298 output_cloud_ptr->points.clear();
299 GraphWithTimestamp outputGraph = retrieveCurrentGraphFromPersistentGraph();
300 // ConfidenceMap cm = boost::get(boost::vertex_confidence_t(), outputGraph.m_graph);
301
302
303 temp_cloud_ptr = pcl::graph::point_cloud(outputGraph);
304 // pcl::copyPointCloud(*temp_cloud_ptr, *output_cloud_ptr);
305 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
306 // FIXME: providePointClouds segfaults when called with pcl::pointXYZRGB
307 outputGraph = retrieveGraphFromPersistentGraph(timestamp_queue_.back());
308 ConfidenceMap cm = boost::get(boost::vertex_confidence_t(), outputGraph.m_graph);
309 temp_cloud_ptr = pcl::graph::point_cloud(outputGraph);
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++)
314 {
315 // float angle = confidence[i] * M_PI;
316 // float red = 255.0 * sin(angle);
317 // float green = 255.0 * sin(angle + 2 * M_PI / 3.); // + 60°
318 // float blue = 255.0 * sin(angle + 4 * M_PI / 3.); // + 120°
319 float conf = cm[i];
320 // colormap::Color c = jet.getColor(conf);
321 // int rgb = int(conf*2147483647);
322 // uint8_t r = (rgb >> 16) & 0x0000ff;
323 // uint8_t g = (rgb >> 8) & 0x0000ff;
324 // uint8_t b = (rgb) & 0x0000ff;
325
326
327 // confidence_cloud_ptr->points[i].r = c.r * 255.0;
328 // confidence_cloud_ptr->points[i].g = c.g * 255.0;
329 // confidence_cloud_ptr->points[i].b = c.b * 255.0;
330 confidence_cloud_ptr->points[i].intensity = conf;
331 }
333 output_cloud_ptr->header = input_cloud_ptr->header;
334 provideResultPointClouds<decltype(output_cloud_ptr)>(output_cloud_ptr, "CRFSegmentationResult");
336 "CRFSegmentationConfidence");
337 pcl::PointXYZRGBA i;
338}
339
340void
341DenseCRFSegmentationProcessor::computeGraphUsingVoxelGrid(const PointCloudT::Ptr inputCloudPtr)
342{
343 const auto& config = config_.getUpToDateReadBuffer();
344 double r = config.general.voxel_resolution;
346 graph_builder.setInputCloud(inputCloudPtr);
347 TIMING_START(ComputeGraph);
348 graph_builder.compute(*current_graph_ptr_);
349 TIMING_END_STREAM(ComputeGraph, ARMARX_DEBUG);
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_))
352 << " Edges";
353 if (config.edge.use_curvature || config.edge.use_normals)
354 {
355 TIMING_START(ComputeNormalsAndCurvatures);
356 pcl::graph::computeNormalsAndCurvatures(*current_graph_ptr_);
357 TIMING_END_STREAM(ComputeNormalsAndCurvatures, ARMARX_DEBUG);
358 TIMING_START(ComputeSignedCurvatures);
359 pcl::graph::computeSignedCurvatures(*current_graph_ptr_);
360 TIMING_END_STREAM(ComputeSignedCurvatures, ARMARX_DEBUG);
361 }
362}
363
364Eigen::MatrixXf
365DenseCRFSegmentationProcessor::computeRandomUnaryEnergy(int num_points)
366{
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++)
379 {
380 // Set the energy
381 int r = dist(rng);
382 if (r >= 0)
383 {
384 energy.col(k).fill(n_energy);
385 energy(r, k) = p_energy;
386 }
387 }
388 return energy;
389}
390
391void
392DenseCRFSegmentationProcessor::generateRandomClassLabels()
393{
394
395 VertexIterator vi, v_end;
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)
401 {
402 int r = dist(rng);
403 (*current_graph_ptr_)[*vi].label = r;
404 }
405}
406
407//void DenseCRFSegmentationProcessor::computeRandomWalkerSegmentation()
408//{
409// computeEdgeWeights();
410// pcl::segmentation::RandomWalkerSegmentation<PointT> rws;
411// rws.setInputGraph(current_graph_ptr_);
412// rws.setSeeds(selectRandomSeeds());
413// std::vector<pcl::PointIndices> clusters;
414// rws.segment(clusters);
415// PointCloudWithNormalT::Ptr tempCloud = pcl::graph::point_cloud(*current_graph_ptr_);
416// VertexIterator vi, v_end;
417// int lbl = 0;
418// for (auto clstr_ptr = clusters.begin(); clstr_ptr != clusters.end(); clstr_ptr++, lbl++)
419// {
420// for (auto pt_ind_ptr = clstr_ptr->indices.begin(); pt_ind_ptr != clstr_ptr->indices.end(); pt_ind_ptr++)
421// {
422// (*current_graph_ptr_)[static_cast<Graph::vertex_descriptor>(*pt_ind_ptr)].label = lbl;
423// }
424// }
425//}
426
427pcl::PointCloud<pcl::PointXYZL>::ConstPtr
428DenseCRFSegmentationProcessor::selectRandomSeeds()
429{
430 auto num_classes = config_.getUpToDateReadBuffer().general.num_classes;
431 VertexIterator vi, v_end;
432 std::vector<Graph::vertex_descriptor> v_out;
433 boost::tie(vi, v_end) = boost::vertices(*current_graph_ptr_);
434 // select num_classes_ random samples from the vertices as seeds
435 std::sample(vi,
436 v_end,
437 std::back_inserter(v_out),
438 num_classes - 1,
439 std::mt19937{std::random_device{}()});
440
441 PointCloudWithNormalT::Ptr tempCloudPtr(new PointCloudWithNormalT(num_classes, 1));
442 int j = 0;
443 for (auto i = v_out.begin(); i != v_out.end(); i++, j++)
444 {
445 tempCloudPtr->points[j] = (*current_graph_ptr_)[*i];
446 // each seed gets an individiual label
447 tempCloudPtr->points[j].label = j;
448 }
449
450 pcl::PointCloud<pcl::PointXYZL>::Ptr outCloudPtr(new pcl::PointCloud<pcl::PointXYZL>());
451 pcl::copyPointCloud(*tempCloudPtr, *outCloudPtr);
452 return outCloudPtr;
453}
454
455//void DenseCRFSegmentationProcessor::computeEdgeWeights()
456//{
457// using namespace pcl::graph;
458// typedef EdgeWeightComputer<Graph> EWC;
459// EWC computer;
460// if (use_xyz_)
461// {
462// float influence = xyz_influence_;
463// float multiplier = 1.0;
464// computer.addTerm<terms::XYZ>(influence, multiplier, EWC::NORMALIZATION_LOCAL);
465// }
466// if (use_normals_)
467// {
468// float influence = normals_influence_;
469// float multiplier = 1.0;
470// computer.addTerm<terms::Normal>(influence, multiplier);
471// }
472// if (use_curvature_)
473// {
474// float influence = curvature_influence_;
475// float multiplier = 1.0;
476// computer.addTerm<terms::Curvature>(influence, multiplier);
477// }
478// if (use_rgb_)
479// {
480// float influence = rgb_influence_;
481// float multiplier = 1.0;
482// computer.addTerm<terms::RGB>(influence, multiplier, EWC::NORMALIZATION_GLOBAL);
483// }
484// computer.setSmallWeightThreshold(1e-5);
485// computer.setSmallWeightPolicy(EWC::SMALL_WEIGHT_COERCE_TO_THRESHOLD);
486// computer.compute(*current_graph_ptr_);
487//}
488
489void
490DenseCRFSegmentationProcessor::updatePersistentGraph()
491{
493 TIMING_START(UpdateRootGraph)
494 double current_ts =
495 static_cast<double>(current_graph_ptr_->m_graph.m_point_cloud->header.stamp / 1000.0) -
496 initial_time_;
497 timestamp_queue_.push_back(current_ts);
498 // graph_queue_.push_back(*current_graph_ptr_);
499 if (timestamp_queue_.size() > 5)
500 {
502 double tsToRemove = timestamp_queue_.front();
503 timestamp_queue_.pop_front();
504 removeTimestampFromPersistentGraph(tsToRemove);
505 }
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";
509 TIMING_END_STREAM(UpdateRootGraph, ARMARX_DEBUG)
510}
511
512void
513DenseCRFSegmentationProcessor::addGraphToPersistentGraph(Graph& graph)
514{
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);
517 VertexIterator vi, v_end;
518 double current_ts =
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)
521 {
522 VertexWTsId new_vertex = boost::add_vertex(*persistent_graph_ptr_);
523 boost::put(tsm, new_vertex, current_ts);
524 // value of -1.0 signals it has not been set
525 boost::put(cm, new_vertex, -1.0);
526 PointWithNormalT point = graph.m_graph.m_point_cloud->points[*vi];
527 (*persistent_graph_ptr_)[new_vertex] = point;
528 }
529}
530
531void
532DenseCRFSegmentationProcessor::addCurrentGraphToPersistentGraph()
533{
535 addGraphToPersistentGraph(*current_graph_ptr_);
536}
537
538void
539DenseCRFSegmentationProcessor::removeGraphFromPersistentGraph(Graph& graph)
540{
542 double graph_ts =
543 static_cast<double>(graph.m_graph.m_point_cloud->header.stamp / 1000.0) - initial_time_;
544 removeTimestampFromPersistentGraph(graph_ts);
545}
546
547void
548DenseCRFSegmentationProcessor::removeCurrentGraphFromPersistentGraph()
549{
551 removeGraphFromPersistentGraph(*current_graph_ptr_);
552}
553
554void
555DenseCRFSegmentationProcessor::removeTimestampFromPersistentGraph(double ts)
556{
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);
562 GraphWithTimestampPtr temp_graph_ptr = boost::make_shared<GraphWithTimestamp>(filtered_graph);
563 persistent_graph_ptr_.swap(temp_graph_ptr);
564}
565
567DenseCRFSegmentationProcessor::retrieveGraphFromPersistentGraph(double ts)
568{
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;
575}
576
578DenseCRFSegmentationProcessor::retrieveCurrentGraphFromPersistentGraph()
579{
581 double current_ts =
582 static_cast<double>(current_graph_ptr_->m_graph.m_point_cloud->header.stamp / 1000.0) -
583 initial_time_;
584 return retrieveGraphFromPersistentGraph(current_ts);
585}
586
587void
588DenseCRFSegmentationProcessor::provideAllGraphs()
589{
591 for (unsigned int i = 0; i < timestamp_queue_.size(); i++)
592 {
593 double ts = timestamp_queue_.at(i);
594 GraphWithTimestamp graph = retrieveGraphFromPersistentGraph(ts);
595 PointCloudT::Ptr output_cloud_ptr(new PointCloudT());
596 PointCloudWithNormalT::Ptr temp_cloud_ptr(new PointCloudWithNormalT());
597 temp_cloud_ptr = pcl::graph::point_cloud(graph);
598 // pcl::graph::indices (Subgraph& g)
599 // pcl::copyPointCloud(*temp_cloud_ptr, *output_cloud_ptr);
600 // FIXME: providePointClouds segfaults when called with pcl::pointXYZRGB
601 copyRGBLNormalToRGBL(*temp_cloud_ptr, *output_cloud_ptr);
602 provideResultPointClouds(output_cloud_ptr, "Graph" + std::to_string(i));
603 }
604}
605
606void
607DenseCRFSegmentationProcessor::computeVertexOnlyGraph(PointCloudT::Ptr input_cloud_ptr)
608{
610 const auto& config = config_.getUpToDateReadBuffer();
611 TIMING_START(VoxelDownsample);
612 pcl::PointCloud<PointT>::Ptr temp_cloud_ptr(new pcl::PointCloud<PointT>());
613 ARMARX_DEBUG << input_cloud_ptr->size() << "before downsampling";
614 // TODO: Voxel downsampling produces a cloud with a=0 for every point; Fix this
615 if (config.general.use_approximate_voxels)
616 {
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);
625 }
626 else
627 {
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);
636 }
638 ARMARX_DEBUG << input_cloud_ptr->size() << "after downsampling";
639 TIMING_END_STREAM(VoxelDownsample, ARMARX_DEBUG);
640 TIMING_START(NormalComputation);
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);
645 PointCloudWithNormalT::Ptr cloud_normals(new PointCloudWithNormalT());
646 // pcl::copyPointCloud(*input_cloud_ptr, *cloud_normals);
647 copyRGBLToRGBLNormal(*input_cloud_ptr, *cloud_normals);
648 // Use all neighbors in a sphere of radius 3cm
649 ne.setRadiusSearch(100 * 5 * config.general.voxel_resolution);
651 // Compute the features
652 ne.compute(*cloud_normals);
653 TIMING_END_STREAM(NormalComputation, ARMARX_DEBUG);
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_))
658 << " Edges";
659}
660
661void
662DenseCRFSegmentationProcessor::copyRGBLToRGBLNormal(PointCloudT& input_cloud,
663 PointCloudWithNormalT& output_cloud)
664{
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());
673
674 if (input_cloud.points.size() == 0)
675 {
677 return;
678 }
680 for (size_t i = 0; i < output_cloud.size(); i++)
681 {
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;
694 }
695}
696
697void
698DenseCRFSegmentationProcessor::copyRGBLNormalToRGBL(PointCloudWithNormalT& input_cloud,
699 PointCloudT& output_cloud)
700{
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());
709
710 if (input_cloud.points.size() == 0)
711 {
712 return;
713 }
715 for (size_t i = 0; i < output_cloud.size(); i++)
716 {
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;
725 }
726}
727
728void
729DenseCRFSegmentationProcessor::relabelPointCloud(pcl::PointCloud<PointT>::Ptr input_cloud_ptr)
730{
732 std::map<uint32_t, uint32_t> labelmap;
733 uint32_t highest_new_label = 1;
734 for (auto& point : input_cloud_ptr->points)
735 {
736 if (labelmap.find(point.label) != labelmap.end())
737 {
738 point.label = labelmap.at(point.label);
739 }
740 else
741 {
742 labelmap.insert(std::make_pair(point.label, highest_new_label));
743 point.label = highest_new_label;
744 highest_new_label++;
745 }
746 }
747}
748
749void
750DenseCRFSegmentationProcessor::provideAllConfidences()
751{
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++)
756 {
757 double ts = timestamp_queue_.at(i);
758 GraphWithTimestamp graph = retrieveGraphFromPersistentGraph(ts);
759 ConfidenceMap cm = boost::get(boost::vertex_confidence_t(), graph.m_graph);
760 PointCloudWithNormalT::Ptr temp_cloud_ptr(new PointCloudWithNormalT());
761 temp_cloud_ptr = pcl::graph::point_cloud(graph);
762 // pcl::graph::indices (Subgraph& g)
763 // pcl::copyPointCloud(*temp_cloud_ptr, *output_cloud_ptr);
764 // FIXME: providePointClouds segfaults when called with pcl::pointXYZRGB
765 if (colorize)
766 {
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++)
770 {
771 float conf = cm[j];
772 colormap::Color c = jet.getColor(conf);
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;
776 }
778 "Confidence" + std::to_string(i));
779 }
780 else
781 {
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++)
786 {
787 float conf = cm[j];
788 confidence_cloud_ptr->points[j].intensity = conf;
789 }
791 confidence_cloud_ptr, "Confidence" + std::to_string(i));
792 }
793 }
794}
795
796Vector5f
798{
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};
805 return vec;
806}
807
808void
810 float rgb,
811 float normals,
812 float curvature,
813 float time,
814 const Ice::Current& current)
815{
816 // TODO: use mutex
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();
825}
constexpr T c
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void setEdgeWeights(float xyz, float rgb, float normals, float curvature, float time, const Ice::Current &current) override
Vector5f getCurrentEdgeWeights(const Ice::Current &current) override
boost::graph_traits< Graph >::vertex_iterator VertexIterator
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)
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
const T & getUpToDateReadBuffer() const
Color getColor(double x) const override
Definition jet.h:29
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.
Definition Logging.h:181
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define TIMING_START(name)
Helper macro to do timing tests.
Definition TimeUtil.h:289
#define TIMING_END_STREAM(name, os)
Prints duration.
Definition TimeUtil.h:310
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
Definition Common.h:33
boost::property_map< CloudGraphWithTimestamp, boost::vertex_confidence_t >::type ConfidenceMap
Definition Common.h:77
boost::shared_ptr< GraphWithTimestamp > GraphWithTimestampPtr
Definition Common.h:64
boost::property_map< CloudGraphWithTimestamp, boost::vertex_timestamp_t >::type TimestampMap
Definition Common.h:75
pcl::PointCloud< PointT > PointCloudT
Definition Common.h:32
boost::graph_traits< GraphWithTimestamp >::vertex_descriptor VertexWTsId
Definition Common.h:69
Agraph_t * GraphPtr
Definition Layout.h:41
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
boost::subgraph< CloudGraphWithTimestamp > GraphWithTimestamp
Definition Common.h:59
boost::subgraph< CloudGraph > Graph
Definition Common.h:58
pcl::PointXYZRGBLNormal PointWithNormalT
Definition Common.h:31
void computeSignedCurvatures(Graph &graph)
Compute the type of curvature (concave/convex) for each vertex.
Definition common.hpp:111
void computeNormalsAndCurvatures(Graph &graph, bool neighborhood_1ring=false)
Compute normals and curvatures for all vertices in a graph.
Definition common.hpp:55
pcl::PointCloud< P >::Ptr point_cloud(PCG &g)
Retrieve the point cloud stored in a point cloud graph.
#define ARMARX_TRACE
Definition trace.h:77