PrimitiveExtractionWidgetController.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 VisionX::gui-plugins::PrimitiveExtractionWidgetController
17  * \author Peter Kaiser ( peter dot kaiser at kit dot edu )
18  * \date 2016
19  * \copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
24 
25 #include <filesystem>
26 #include <memory>
27 #include <string>
28 
29 #include <QCheckBox>
30 #include <QComboBox>
31 #include <QDoubleSpinBox>
32 
33 #include <pcl/common/transforms.h>
34 #include <pcl/io/pcd_io.h>
35 #include <pcl/point_types.h>
36 
39 
40 #include <VisionX/interface/core/PointCloudProviderInterface.h>
42 
43 #include <AffordanceKit/primitives/Plane.h>
44 
45 #define PI 3.141592654
46 
47 namespace armarx
48 {
50  {
51  widget.setupUi(getWidget());
52  }
53 
55  {
56  }
57 
58  void
60  {
61  pointCloudProviderName =
62  settings->value("pointCloudProviderName", "").toString().toStdString();
63  pointCloudSegmenterName =
64  settings->value("pointCloudSegmenterName", "").toString().toStdString();
65  primitiveExtractorName =
66  settings->value("primitiveExtractorName", "").toString().toStdString();
67  pipelineVisualizationName =
68  settings->value("pipelineVisualizationName", "").toString().toStdString();
69  workingMemoryName = settings->value("workingMemoryName", "").toString().toStdString();
70  }
71 
72  void
74  {
75  settings->setValue("pointCloudProviderName",
76  QString::fromStdString(pointCloudProviderName));
77  settings->setValue("pointCloudSegmenterName",
78  QString::fromStdString(pointCloudSegmenterName));
79  settings->setValue("primitiveExtractorName",
80  QString::fromStdString(primitiveExtractorName));
81  settings->setValue("pipelineVisualizationName",
82  QString::fromStdString(pipelineVisualizationName));
83  settings->setValue("workingMemoryName", QString::fromStdString(workingMemoryName));
84  }
85 
86  QPointer<QDialog>
88  {
89  if (!configDialog)
90  {
91  configDialog = new PrimitiveExtractionConfigDialog(parent);
92  }
93 
94  return qobject_cast<PrimitiveExtractionConfigDialog*>(configDialog);
95  }
96 
97  void
99  {
100  pointCloudProviderName =
101  configDialog->pointCloudProviderProxyFinder->getSelectedProxyName().toStdString();
102  pointCloudSegmenterName =
103  configDialog->pointCloudSegmenterProxyFinder->getSelectedProxyName().toStdString();
104  primitiveExtractorName =
105  configDialog->primitiveExtractorProxyFinder->getSelectedProxyName().toStdString();
106  pipelineVisualizationName =
107  configDialog->pipelineVisualizationProxyFinder->getSelectedProxyName().toStdString();
108  workingMemoryName =
109  configDialog->pipelineVisualizationProxyFinder->getSelectedProxyName().toStdString();
110  }
111 
112  void
114  {
115  }
116 
117  void
119  {
120  pointCloudProvider =
121  getProxy<visionx::PointCloudProviderInterfacePrx>(pointCloudProviderName);
122  if (!pointCloudProvider)
123  {
124  ARMARX_ERROR << "Could not obtain point cloud provider proxy";
125  return;
126  }
127 
128  visionx::FakePointCloudProviderInterfacePrx _fakePointCloudProvider =
129  visionx::FakePointCloudProviderInterfacePrx::checkedCast(pointCloudProvider);
130  if (_fakePointCloudProvider)
131  {
132  widget.pushButtonLoadPointCloud->setEnabled(true);
133  }
134  else
135  {
136  widget.pushButtonLoadPointCloud->setEnabled(false);
137  }
138 
139  // The segmenter is optional (it does not exist when processing ground truth segmentations)
140  if (pointCloudSegmenterName != "")
141  {
142  try
143  {
144  pointCloudSegmenter =
145  getProxy<visionx::PointCloudSegmenterInterfacePrx>(pointCloudSegmenterName);
146  }
147  catch (const armarx::UserException& e)
148  {
149  ARMARX_INFO << "No segmenter found, assuming ground truth segmentation";
150  }
151  }
152 
153  primitiveExtractor = getProxy<visionx::PrimitiveMapperInterfacePrx>(primitiveExtractorName);
154  if (!primitiveExtractor)
155  {
156  ARMARX_ERROR << "Could not obtain primitive extractor proxy";
157  return;
158  }
159 
160  pipelineVisualization =
161  getProxy<AffordancePipelineVisualizationInterfacePrx>(pipelineVisualizationName);
162  if (!pipelineVisualization)
163  {
164  ARMARX_ERROR << "Could not obtain affordance pipeline visualization proxy";
165  return;
166  }
167 
168  workingMemory = getProxy<memoryx::WorkingMemoryInterfacePrx>(workingMemoryName);
169  if (!workingMemory)
170  {
171  ARMARX_ERROR << "Could not obtain point working memory proxy";
172  return;
173  }
174 
175  debugDrawer = getTopic<DebugDrawerInterfacePrx>("DebugDrawerUpdates");
176  if (!debugDrawer)
177  {
178  ARMARX_ERROR << "Failed to obtain debug drawer proxy";
179  return;
180  }
181 
182  connect(widget.pushButtonLoadPointCloud, SIGNAL(clicked()), this, SLOT(loadPointCloud()));
183  connect(widget.pushButtonRun, SIGNAL(clicked()), this, SLOT(run()));
184  connect(widget.pushButtonSetParam, SIGNAL(clicked()), this, SLOT(setParameters()));
185  connect(widget.pushButtonApplyTransformation,
186  SIGNAL(clicked()),
187  this,
189  connect(
190  widget.pushButtonApplyAutoRotate, SIGNAL(clicked()), this, SLOT(applyAutoRotation()));
191  connect(widget.checkBoxShowPrimitives,
192  SIGNAL(toggled(bool)),
193  this,
195  connect(widget.checkBoxShowRootPose,
196  SIGNAL(toggled(bool)),
197  this,
199  connect(widget.pushButtonImportConfig, SIGNAL(clicked()), this, SLOT(importConfig()));
200  connect(widget.pushButtonExportConfig, SIGNAL(clicked()), this, SLOT(exportConfig()));
201 
202  if (pointCloudSegmenter)
203  {
204  visionx::LccpParameters lccpParameters = pointCloudSegmenter->getLccpParameters();
205  widget.doubleSpinBoxLccpMinSegmentSize->setValue(lccpParameters.minSegmentSize);
206  widget.doubleSpinBoxLccpVoxelResolution->setValue(lccpParameters.voxelResolution);
207  widget.doubleSpinBoxLccpSeedResolution->setValue(lccpParameters.seedResolution);
208  widget.doubleSpinBoxLccpColorImportance->setValue(lccpParameters.colorImportance);
209  widget.doubleSpinBoxLccpSpatialImportance->setValue(lccpParameters.spatialImportance);
210  widget.doubleSpinBoxLccpNormalImportance->setValue(lccpParameters.normalImportance);
211  widget.doubleSpinBoxLccpConcavityThreshold->setValue(lccpParameters.concavityThreshold);
212  widget.doubleSpinBoxLccpSmoothnessThreshold->setValue(
213  lccpParameters.smoothnessThreshold);
214  }
215  else
216  {
217  widget.doubleSpinBoxLccpMinSegmentSize->setEnabled(false);
218  widget.doubleSpinBoxLccpVoxelResolution->setEnabled(false);
219  widget.doubleSpinBoxLccpSeedResolution->setEnabled(false);
220  widget.doubleSpinBoxLccpColorImportance->setEnabled(false);
221  widget.doubleSpinBoxLccpSpatialImportance->setEnabled(false);
222  widget.doubleSpinBoxLccpNormalImportance->setEnabled(false);
223  widget.doubleSpinBoxLccpConcavityThreshold->setEnabled(false);
224  widget.doubleSpinBoxLccpSmoothnessThreshold->setEnabled(false);
225  }
226 
227  visionx::PrimitiveExtractorParameters primtiveParameters =
228  primitiveExtractor->getParameters();
229  ARMARX_LOG << "parameters " << primtiveParameters.minSegmentSize;
230  widget.doubleSpinBoxMinPrimitiveSize->setValue(primtiveParameters.minSegmentSize);
231  widget.doubleSpinBoxMaxPrimitiveSize->setValue(primtiveParameters.maxSegmentSize);
232  widget.doubleSpinBoxEuclideanClusteringTolerance->setValue(
233  primtiveParameters.euclideanClusteringTolerance);
234  widget.doubleSpinBoxOutlierDistanceThreshold->setValue(primtiveParameters.outlierThreshold);
235 
236  widget.doubleSpinBoxPlaneMaxIterations->setValue(primtiveParameters.planeMaxIterations);
237  widget.doubleSpinBoxPlaneDistanceThreshold->setValue(
238  primtiveParameters.planeDistanceThreshold);
239  widget.doubleSpinBoxPlaneNormalDistance->setValue(primtiveParameters.planeNormalDistance);
240  widget.doubleSpinBoxPlaneCircularDistanceThreshold->setValue(
241  primtiveParameters.circularDistanceThreshold);
242 
243  widget.doubleSpinBoxCylinderMaxIterations->setValue(
244  primtiveParameters.cylinderMaxIterations);
245  widget.doubleSpinBoxCylinderDistanceThreshold->setValue(
246  primtiveParameters.cylinderDistanceThreshold);
247  widget.doubleSpinBoxCylinderRadiusLimit->setValue(primtiveParameters.cylinderRadiusLimit);
248 
249  widget.doubleSpinBoxSphereMaxIterations->setValue(primtiveParameters.sphereMaxIterations);
250  widget.doubleSpinBoxSphereDistanceThreshold->setValue(
251  primtiveParameters.sphereDistanceThreshold);
252  widget.doubleSpinBoxSphereNormalDistance->setValue(primtiveParameters.sphereNormalDistance);
253  }
254 
255  void
257  {
258  QObject::disconnect(this, SLOT(loadPointCloud()));
259  QObject::disconnect(this, SLOT(run()));
260  QObject::disconnect(this, SLOT(setParameters()));
261  QObject::disconnect(this, SLOT(visualizationOptionsChanged()));
262  QObject::disconnect(this, SLOT(importConfig()));
263  QObject::disconnect(this, SLOT(exportConfig()));
264  }
265 
266  void
268  {
269  QString filename =
270  QFileDialog::getOpenFileName(NULL, "Open Point Cloud", "", "Point Cloud Files (*.pcd)");
271  if (filename != "")
272  {
273  widget.lineEditPointCloud->setText(filename);
274  }
275  }
276 
277  void
279  {
280  visionx::FakePointCloudProviderInterfacePrx _fakePointCloudProvider =
281  visionx::FakePointCloudProviderInterfacePrx::checkedCast(pointCloudProvider);
282  if (_fakePointCloudProvider)
283  {
284  std::string path = widget.lineEditPointCloud->text().toStdString();
285  _fakePointCloudProvider->setPointCloudFilename(path);
286  }
287 
288  if (pointCloudSegmenter)
289  {
290  visionx::LccpParameters segmenterPrm;
291  segmenterPrm.minSegmentSize = widget.doubleSpinBoxLccpMinSegmentSize->value();
292  segmenterPrm.voxelResolution = widget.doubleSpinBoxLccpVoxelResolution->value();
293  segmenterPrm.seedResolution = widget.doubleSpinBoxLccpSeedResolution->value();
294  segmenterPrm.colorImportance = widget.doubleSpinBoxLccpColorImportance->value();
295  segmenterPrm.spatialImportance = widget.doubleSpinBoxLccpSpatialImportance->value();
296  segmenterPrm.normalImportance = widget.doubleSpinBoxLccpNormalImportance->value();
297  segmenterPrm.concavityThreshold = widget.doubleSpinBoxLccpConcavityThreshold->value();
298  segmenterPrm.smoothnessThreshold = widget.doubleSpinBoxLccpSmoothnessThreshold->value();
299  pointCloudSegmenter->setLccpParameters(segmenterPrm);
300  }
301 
302  visionx::PrimitiveExtractorParameters primitiveExtractionPrm;
303  primitiveExtractionPrm.minSegmentSize = widget.doubleSpinBoxMinPrimitiveSize->value();
304  primitiveExtractionPrm.maxSegmentSize = widget.doubleSpinBoxMaxPrimitiveSize->value();
305  primitiveExtractionPrm.planeMaxIterations = widget.doubleSpinBoxPlaneMaxIterations->value();
306  primitiveExtractionPrm.planeDistanceThreshold =
307  widget.doubleSpinBoxPlaneDistanceThreshold->value();
308  primitiveExtractionPrm.planeNormalDistance =
309  widget.doubleSpinBoxPlaneNormalDistance->value();
310  primitiveExtractionPrm.cylinderMaxIterations =
311  widget.doubleSpinBoxCylinderMaxIterations->value();
312  primitiveExtractionPrm.cylinderDistanceThreshold =
313  widget.doubleSpinBoxCylinderDistanceThreshold->value();
314  primitiveExtractionPrm.cylinderRadiusLimit =
315  widget.doubleSpinBoxCylinderRadiusLimit->value();
316  primitiveExtractionPrm.sphereMaxIterations =
317  widget.doubleSpinBoxSphereMaxIterations->value();
318  primitiveExtractionPrm.sphereDistanceThreshold =
319  widget.doubleSpinBoxSphereDistanceThreshold->value();
320  primitiveExtractionPrm.sphereNormalDistance =
321  widget.doubleSpinBoxSphereNormalDistance->value();
322  primitiveExtractionPrm.euclideanClusteringTolerance =
323  widget.doubleSpinBoxEuclideanClusteringTolerance->value();
324  primitiveExtractionPrm.outlierThreshold =
325  widget.doubleSpinBoxOutlierDistanceThreshold->value();
326  primitiveExtractionPrm.circularDistanceThreshold =
327  widget.doubleSpinBoxPlaneCircularDistanceThreshold->value();
328  primitiveExtractor->setParameters(primitiveExtractionPrm);
329  }
330 
331  void
333  {
334  setParameters();
335 
336  visionx::CapturingPointCloudProviderInterfacePrx cx =
337  visionx::CapturingPointCloudProviderInterfacePrx::checkedCast(pointCloudProvider);
338  if (cx)
339  {
340  cx->begin_startCaptureForNumFrames(1);
341  }
342  }
343 
344  void
346  {
347  pipelineVisualization->begin_enableVisualization(
348  widget.checkBoxShowPrimitives->isChecked(), false, false);
349 
350  if (widget.checkBoxShowRootPose->isChecked())
351  {
352  debugDrawer->setPoseVisu(
353  "PrimitiveExtractorGuiLayer", "RootPose", new Pose(Eigen::Matrix4f::Identity()));
354  }
355  else
356  {
357  debugDrawer->removePoseVisu("PrimitiveExtractorGuiLayer", "RootPose");
358  }
359  }
360 
361  void
363  {
364  std::string filename = widget.lineEditPointCloud->text().toStdString();
365 
366  if (!boost::algorithm::ends_with(filename, ".pcd") ||
367  !std::filesystem::is_regular_file(filename))
368  {
369  ARMARX_WARNING << "Unable to load point cloud " << filename;
370  return;
371  }
372 
373  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr pc(new pcl::PointCloud<pcl::PointXYZRGBA>());
374  if (pcl::io::loadPCDFile<pcl::PointXYZRGBA>(filename.c_str(), *pc) == -1)
375  {
376  ARMARX_WARNING << "Unable to load point cloud " << filename;
377  return;
378  }
379 
380  ARMARX_INFO << "Transforming point cloud: " << filename;
381  Eigen::Affine3f scaling(Eigen::Scaling((float)widget.doubleSpinBoxScaling->value()));
382  pcl::transformPointCloud(*pc, *pc, scaling);
383 
384  std::string out_filename =
385  QFileDialog::getSaveFileName(
386  NULL, "Save transformed PCD", filename.c_str(), "Point Cloud Files (*.pcd)")
387  .toStdString();
388  if (filename != "")
389  {
390  pcl::io::savePCDFileASCII(out_filename, *pc);
391  ARMARX_INFO << "Point cloud saved";
392  }
393  }
394 
395  void
397  {
398  QString filename = QFileDialog::getOpenFileName(
399  NULL, "Open Pipeline Configuration file", "", "Config file (*.cfg)");
400  if (filename == "")
401  {
402  return;
403  }
404 
405  QSettings config(filename, QSettings::IniFormat);
406 
407  config.beginGroup("LCCP");
408  widget.doubleSpinBoxLccpMinSegmentSize->setValue(
409  config.value("MinSegmentSize", widget.doubleSpinBoxLccpMinSegmentSize->value())
410  .toDouble());
411  widget.doubleSpinBoxLccpVoxelResolution->setValue(
412  config.value("VoxelResolution", widget.doubleSpinBoxLccpVoxelResolution->value())
413  .toDouble());
414  widget.doubleSpinBoxLccpSeedResolution->setValue(
415  config.value("SeedResolution", widget.doubleSpinBoxLccpSeedResolution->value())
416  .toDouble());
417  widget.doubleSpinBoxLccpColorImportance->setValue(
418  config.value("ColorImportance", widget.doubleSpinBoxLccpColorImportance->value())
419  .toDouble());
420  widget.doubleSpinBoxLccpSpatialImportance->setValue(
421  config.value("SpatialImportance", widget.doubleSpinBoxLccpSpatialImportance->value())
422  .toDouble());
423  widget.doubleSpinBoxLccpNormalImportance->setValue(
424  config.value("NormalImportance", widget.doubleSpinBoxLccpNormalImportance->value())
425  .toDouble());
426  widget.doubleSpinBoxLccpConcavityThreshold->setValue(
427  config.value("ConcavityThreshold", widget.doubleSpinBoxLccpConcavityThreshold->value())
428  .toDouble());
429  widget.doubleSpinBoxLccpSmoothnessThreshold->setValue(
430  config
431  .value("SmoothnessThreshold", widget.doubleSpinBoxLccpSmoothnessThreshold->value())
432  .toDouble());
433  config.endGroup();
434 
435  config.beginGroup("PrimitiveExtraction");
436  widget.doubleSpinBoxMinPrimitiveSize->setValue(
437  config.value("MinPrimitiveSize", widget.doubleSpinBoxMinPrimitiveSize->value())
438  .toDouble());
439  widget.doubleSpinBoxMaxPrimitiveSize->setValue(
440  config.value("MaxPrimitiveSize", widget.doubleSpinBoxMaxPrimitiveSize->value())
441  .toDouble());
442  widget.doubleSpinBoxPlaneMaxIterations->setValue(
443  config.value("PlaneMaxIterations", widget.doubleSpinBoxPlaneMaxIterations->value())
444  .toDouble());
445  widget.doubleSpinBoxPlaneDistanceThreshold->setValue(
446  config
447  .value("PlaneDistanceThreshold",
448  widget.doubleSpinBoxPlaneDistanceThreshold->value())
449  .toDouble());
450  widget.doubleSpinBoxPlaneNormalDistance->setValue(
451  config.value("PlaneNormalDistance", widget.doubleSpinBoxPlaneNormalDistance->value())
452  .toDouble());
453  widget.doubleSpinBoxPlaneCircularDistanceThreshold->setValue(
454  config
455  .value("PlaneCircularDistanceThreshold",
456  widget.doubleSpinBoxPlaneCircularDistanceThreshold->value())
457  .toDouble());
458  widget.doubleSpinBoxCylinderMaxIterations->setValue(
459  config
460  .value("CylinderMaxIterations", widget.doubleSpinBoxCylinderMaxIterations->value())
461  .toDouble());
462  widget.doubleSpinBoxCylinderDistanceThreshold->setValue(
463  config
464  .value("CylinderDistanceThreshold",
465  widget.doubleSpinBoxCylinderDistanceThreshold->value())
466  .toDouble());
467  widget.doubleSpinBoxCylinderRadiusLimit->setValue(
468  config.value("CylinderRadiusLimit", widget.doubleSpinBoxSphereMaxIterations->value())
469  .toDouble());
470  widget.doubleSpinBoxSphereMaxIterations->setValue(
471  config.value("SphereMaxIterations", widget.doubleSpinBoxSphereMaxIterations->value())
472  .toDouble());
473  widget.doubleSpinBoxSphereDistanceThreshold->setValue(
474  config
475  .value("SphereDistanceThreshold",
476  widget.doubleSpinBoxSphereDistanceThreshold->value())
477  .toDouble());
478  widget.doubleSpinBoxSphereNormalDistance->setValue(
479  config.value("SphereNormalDistance", widget.doubleSpinBoxSphereNormalDistance->value())
480  .toDouble());
481  widget.doubleSpinBoxEuclideanClusteringTolerance->setValue(
482  config
483  .value("EuclideanClusteringTolerance",
484  widget.doubleSpinBoxEuclideanClusteringTolerance->value())
485  .toDouble());
486  widget.doubleSpinBoxOutlierDistanceThreshold->setValue(
487  config
488  .value("OutlierDistanceThreshold",
489  widget.doubleSpinBoxOutlierDistanceThreshold->value())
490  .toDouble());
491  config.endGroup();
492 
493  ARMARX_INFO << "Current settings read from '" << filename << "'";
494  }
495 
496  void
498  {
499  QString filename = QFileDialog::getSaveFileName(
500  NULL, "Save Pipeline Configuration file", "", "Config file (*.cfg)");
501  if (filename == "")
502  {
503  return;
504  }
505 
506  QSettings config(filename, QSettings::IniFormat);
507 
508  config.beginGroup("LCCP");
509  config.setValue("MinSegmentSize", widget.doubleSpinBoxLccpMinSegmentSize->value());
510  config.setValue("VoxelResolution", widget.doubleSpinBoxLccpVoxelResolution->value());
511  config.setValue("SeedResolution", widget.doubleSpinBoxLccpSeedResolution->value());
512  config.setValue("ColorImportance", widget.doubleSpinBoxLccpColorImportance->value());
513  config.setValue("SpatialImportance", widget.doubleSpinBoxLccpSpatialImportance->value());
514  config.setValue("NormalImportance", widget.doubleSpinBoxLccpNormalImportance->value());
515  config.setValue("ConcavityThreshold", widget.doubleSpinBoxLccpConcavityThreshold->value());
516  config.setValue("SmoothnessThreshold",
517  widget.doubleSpinBoxLccpSmoothnessThreshold->value());
518  config.endGroup();
519 
520  config.beginGroup("PrimitiveExtraction");
521  config.setValue("MinPrimitiveSize", widget.doubleSpinBoxMinPrimitiveSize->value());
522  config.setValue("MaxPrimitiveSize", widget.doubleSpinBoxMaxPrimitiveSize->value());
523  config.setValue("PlaneMaxIterations", widget.doubleSpinBoxPlaneMaxIterations->value());
524  config.setValue("PlaneDistanceThreshold",
525  widget.doubleSpinBoxPlaneDistanceThreshold->value());
526  config.setValue("PlaneNormalDistance", widget.doubleSpinBoxPlaneNormalDistance->value());
527  config.setValue("PlaneCircularDistanceThreshold",
528  widget.doubleSpinBoxPlaneCircularDistanceThreshold->value());
529  config.setValue("CylinderMaxIterations",
530  widget.doubleSpinBoxCylinderMaxIterations->value());
531  config.setValue("CylinderDistanceThreshold",
532  widget.doubleSpinBoxCylinderDistanceThreshold->value());
533  config.setValue("CylinderRadiusLimit", widget.doubleSpinBoxSphereMaxIterations->value());
534  config.setValue("SphereMaxIterations", widget.doubleSpinBoxSphereMaxIterations->value());
535  config.setValue("SphereDistanceThreshold",
536  widget.doubleSpinBoxSphereDistanceThreshold->value());
537  config.setValue("SphereNormalDistance", widget.doubleSpinBoxSphereNormalDistance->value());
538  config.setValue("EuclideanClusteringTolerance",
539  widget.doubleSpinBoxEuclideanClusteringTolerance->value());
540  config.setValue("OutlierDistanceThreshold",
541  widget.doubleSpinBoxOutlierDistanceThreshold->value());
542  config.endGroup();
543 
544  config.sync();
545 
546  ARMARX_INFO << "Current settings saved to '" << filename << "'";
547  }
548 
549  // Apply a rotation to the pointCloud corresponding to the inverse of the rotational component of the biggest plane primitive.
550  // The should result in a point cloud in which the ground is fitted exactly into the x/y-plane.
551  void
553  {
555  primitives.reset(new AffordanceKitArmarX::PrimitiveSetArmarX(
556  workingMemory->getEnvironmentalPrimitiveSegment()));
557 
558  bool found = false;
559  unsigned int indexOfBiggestPrimitive;
560  unsigned int maxSampleSize = 0;
561 
562  using boost::dynamic_pointer_cast;
563  using std::dynamic_pointer_cast;
564 
565  // Find biggest plane primitive.
566  for (unsigned int i = 0; i < primitives->size(); i++)
567  {
568  AffordanceKit::PrimitivePtr primitive = primitives->at(i);
569  if (!dynamic_pointer_cast<AffordanceKit::Plane>(primitive))
570  {
571  continue;
572  }
573  AffordanceKit::PlanePtr plane = dynamic_pointer_cast<AffordanceKit::Plane>(primitive);
574  plane->sample(20, 1);
575  unsigned int curPlaneSize = plane->getSamplingSize();
576  if (curPlaneSize > maxSampleSize)
577  {
578  found = true;
579  maxSampleSize = curPlaneSize;
580  indexOfBiggestPrimitive = i;
581  }
582  }
583 
584  if (!found)
585  {
586  ARMARX_WARNING << "Did not find any plane-shaped primitives to rotate upon!";
587  return;
588  }
589 
590  // If found: get rotation of biggest plane primitive.
591  AffordanceKit::PrimitivePtr primitive = primitives->at(indexOfBiggestPrimitive);
592  if (!dynamic_pointer_cast<AffordanceKit::Plane>(primitive))
593  {
594  ARMARX_ERROR << "Could not convert to planar primitive";
595  return;
596  }
597  AffordanceKit::PlanePtr plane = dynamic_pointer_cast<AffordanceKit::Plane>(primitive);
598  Eigen::Matrix4f gp = plane->getPose();
599 
600  debugDrawer->setPoseVisu(
601  "PrimitiveExtractorGuiLayer", "BiggestPlaneRotation", new Pose(gp));
602 
603  Eigen::Matrix4f gpi = gp.inverse();
604 
605  // Rotate the point cloud around the inverse of the ground's rotation matrix.
606  std::string filename = widget.lineEditPointCloud->text().toStdString();
607  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr pc(new pcl::PointCloud<pcl::PointXYZRGBA>());
608  if (pcl::io::loadPCDFile<pcl::PointXYZRGBA>(filename.c_str(), *pc) == -1)
609  {
610  ARMARX_WARNING << "Unable to load point cloud " << filename << " for auto-rotation.";
611  return;
612  }
613 
614  // Apply transformation
615  pcl::transformPointCloud(*pc, *pc, gpi);
616 
617  // Use a simple heuristic to check if z points in the right direction (upwards)
618  int balance = 0;
619  for (unsigned int i = 0; i < pc->points.size(); i++)
620  {
621  balance += (pc->points[i].z >= 0) ? 1 : -1;
622  }
623 
624  ARMARX_INFO << "Z-axis balance after transformation: " << balance;
625  if (balance < 0)
626  {
627  // z seems to point in the wrong direction (most point have negative z-value)
628  Eigen::Affine3f rotation(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitX()));
629  pcl::transformPointCloud(*pc, *pc, rotation);
630 
631  ARMARX_INFO << "Flipping Z axis";
632 
633  // Update visualization
634  Eigen::Matrix4f T = rotation.matrix();
635  debugDrawer->setPoseVisu(
636  "PrimitiveExtractorGuiLayer", "BiggestPlaneRotation", new Pose(T * gp));
637  }
638 
639  std::string out_filename =
640  QFileDialog::getSaveFileName(
641  NULL, "Save transformed PCD", filename.c_str(), "Point Cloud Files (*.pcd)")
642  .toStdString();
643  if (filename != "")
644  {
645  pcl::io::savePCDFileASCII(out_filename, *pc);
646  ARMARX_INFO << "Point cloud saved";
647  }
648  }
649 } // namespace armarx
RemoteRobot.h
armarx::PrimitiveExtractionWidgetController::onConnectComponent
void onConnectComponent() override
Definition: PrimitiveExtractionWidgetController.cpp:118
armarx::PrimitiveExtractionWidgetController::getConfigDialog
QPointer< QDialog > getConfigDialog(QWidget *parent=0) override
getConfigDialog returns a pointer to the a configuration widget of this controller.
Definition: PrimitiveExtractionWidgetController.cpp:87
armarx::PrimitiveExtractionWidgetController::visualizationOptionsChanged
void visualizationOptionsChanged()
Definition: PrimitiveExtractionWidgetController.cpp:345
armarx::PrimitiveExtractionConfigDialog
Definition: PrimitiveExtractionConfigDialog.h:41
armarx::navigation::core::Pose
Eigen::Isometry3f Pose
Definition: basic_types.h:31
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:650
PrimitiveExtractionWidgetController.h
armarx::PrimitiveExtractionWidgetController::configured
void configured() override
This function must be implemented by the user, if he supplies a config dialog.
Definition: PrimitiveExtractionWidgetController.cpp:98
armarx::PrimitiveExtractionWidgetController::setParameters
void setParameters()
Definition: PrimitiveExtractionWidgetController.cpp:278
armarx::PrimitiveExtractionWidgetController::run
void run()
Definition: PrimitiveExtractionWidgetController.cpp:332
armarx::PrimitiveExtractionWidgetController::onInitComponent
void onInitComponent() override
Definition: PrimitiveExtractionWidgetController.cpp:113
armarx::PrimitiveExtractionWidgetController::applyAutoRotation
void applyAutoRotation()
Definition: PrimitiveExtractionWidgetController.cpp:552
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
armarx::PrimitiveExtractionWidgetController::importConfig
void importConfig()
Definition: PrimitiveExtractionWidgetController.cpp:396
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:855
M_PI
#define M_PI
Definition: MathTools.h:17
FramedPose.h
AffordanceKitArmarX::PrimitiveSetArmarX
Definition: PrimitiveSetArmarX.h:31
filename
std::string filename
Definition: VisualizationRobot.cpp:86
armarx::PrimitiveExtractionWidgetController::PrimitiveExtractionWidgetController
PrimitiveExtractionWidgetController()
Controller Constructor.
Definition: PrimitiveExtractionWidgetController.cpp:49
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
ARMARX_LOG
#define ARMARX_LOG
Definition: Logging.h:165
armarx::PrimitiveExtractionWidgetController::saveSettings
void saveSettings(QSettings *settings) override
Definition: PrimitiveExtractionWidgetController.cpp:73
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
armarx::PrimitiveExtractionWidgetController::loadPointCloud
void loadPointCloud()
Definition: PrimitiveExtractionWidgetController.cpp:267
armarx::PrimitiveExtractionWidgetController::exportConfig
void exportConfig()
Definition: PrimitiveExtractionWidgetController.cpp:497
armarx::ends_with
bool ends_with(const std::string &haystack, const std::string &needle)
Definition: StringHelpers.cpp:53
armarx::ArmarXWidgetController::getWidget
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
Definition: ArmarXWidgetController.cpp:54
pc
Introduction Thank you for taking interest in our work and downloading this software This library implements the algorithm described in the paper R R R Klein Efficient RANSAC for Point Cloud Shape in Computer Graphics Blackwell June If you use this software you should cite the aforementioned paper in any resulting publication Please send comments or bug reports to Ruwen Roland BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY OR CONSEQUENTIAL WHETHER IN STRICT OR EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE Example usage This section shows how to use the library to detect the shapes in a point cloud PointCloud pc
Definition: ReadMe.txt:68
armarx::PrimitiveExtractionWidgetController::onDisconnectComponent
void onDisconnectComponent() override
Hook for subclass.
Definition: PrimitiveExtractionWidgetController.cpp:256
PrimitiveSetArmarX.h
T
float T
Definition: UnscentedKalmanFilterTest.cpp:38
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::PrimitiveExtractionWidgetController::~PrimitiveExtractionWidgetController
virtual ~PrimitiveExtractionWidgetController()
Controller destructor.
Definition: PrimitiveExtractionWidgetController.cpp:54
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::PrimitiveExtractionWidgetController::loadSettings
void loadSettings(QSettings *settings) override
Definition: PrimitiveExtractionWidgetController.cpp:59
armarx::PrimitiveExtractionWidgetController::applyPointCloudTransformation
void applyPointCloudTransformation()
Definition: PrimitiveExtractionWidgetController.cpp:362
AffordanceKitArmarX::PrimitiveSetArmarXPtr
std::shared_ptr< PrimitiveSetArmarX > PrimitiveSetArmarXPtr
Definition: PrimitiveSetArmarX.h:42