SegmentRansacShapeExtractor.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::ArmarXObjects::SegmentRansacShapeExtractor
17  * @author Rainer Kartmann ( rainer dot kartmann 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 <VirtualRobot/VirtualRobot.h>
26 
28 
31 
32 #include <SemanticObjectRelations/Hooks/VisualizerInterface.h>
33 #include <SemanticObjectRelations/Shapes.h>
34 
35 namespace visionx
36 {
37 
39  std::string prefix) :
41  {
42  // ICE
43 
44  defineOptionalProperty<std::string>("ice.DebugObserverName",
45  "DebugObserver",
46  "Name of the topic the DebugObserver listens to.");
47 
48  defineOptionalProperty<std::string>("ice.ShapesTopicName",
49  "ShapesTopic",
50  "Name of the topic on which shapes are reported.");
51  defineOptionalProperty<std::string>("ice.ShapesName",
52  "SegmentRansacShapes",
53  "Name to use when reporting the extracted shapes.");
54 
55 
56  // EXTRACTION
57 
58  defineOptionalProperty<bool>(
59  "mode.AsPipeline",
60  false,
61  "Extract shapes on each new point cloud and publish them to the shapes topic.");
62 
63  defineOptionalProperty<std::string>(
64  "ransac.TargetShapes",
65  "box, cylinder, sphere",
66  "Shapes to be extracted (any combination of: box, cylinder, sphere).");
67 
68  defineOptionalProperty<float>(
69  "ransac.maxModelError", 1000., "Discard a model if its error is above this threshold.")
70  .setMin(0.);
71 
72  defineOptionalProperty<int>(
73  "ransac.maxIterations", 100, "Maximal number of iterations of each RANSAC run.")
74  .setMin(0);
75 
76  defineOptionalProperty<float>(
77  "ransac.distanceThresholdBox",
78  5.,
79  "A point with a distance below this threshold is considererd an inlier. (Box)")
80  .setMin(0.);
81  defineOptionalProperty<float>(
82  "ransac.distanceThresholdPCL",
83  0.5,
84  "A point with a distance below this threshold is considererd an inlier. "
85  "(PCL, i.e. cylinder and sphere)")
86  .setMin(0.);
87  defineOptionalProperty<float>(
88  "ransac.outlierRate",
89  0.0125f,
90  "The percentage of points that may be considered as outliers and may be ignored for "
91  "fitting. "
92  "This affects box extents, cylinder height, and error computation.")
93  .setMin(0)
94  .setMax(1.);
95  defineOptionalProperty<float>(
96  "ransac.minInlierRate",
97  0.75,
98  "A model is considered a good fit, if this fraction of all points are "
99  "inliers for that model. (0.0 ... 1.0)")
100  .setMin(0.)
101  .setMax(1.0);
102  defineOptionalProperty<float>(
103  "ransac.sizePenaltyFactor",
104  0.000125f,
105  "Weight of the size penalty (relative to distance error). "
106  "Size penalty inhibits shapes with huge radius (cyl, sph) or extents (box)."
107  "Set to 0 to disable size penalty.")
108  .setMin(0);
109  defineOptionalProperty<float>(
110  "ransac.sizePenaltyExponent",
111  2.0,
112  "Exponent of the of the size penalty (as in s^x, with size measure s and exponent x). "
113  "Size penalty inhibits shapes with huge radius (cyl, sph) or extents (box).")
114  .setMin(0);
115 
116 
117  // VISUALIZATION
118 
120  *this,
122  semrel::VisuLevel::RESULT);
123  }
124 
125  void
127  {
128  offeringTopicFromProperty("ice.ShapesTopicName");
129  getProperty(this->shapesName, "ice.ShapesName");
130 
131  offeringTopicFromProperty("ice.DebugObserverName");
132  debugDrawer.offeringTopic(*this);
133 
134 
135  // Initialize shapeExtraction with parameters.
136  shapeExtraction.setMaxModelError(getProperty<float>("ransac.maxModelError"));
137  shapeExtraction.setMaxIterations(getProperty<int>("ransac.maxIterations"));
138 
139  shapeExtraction.setDistanceThresholdBox(getProperty<float>("ransac.distanceThresholdBox"));
140  shapeExtraction.setDistanceThresholdPCL(getProperty<float>("ransac.distanceThresholdPCL"));
141 
142  shapeExtraction.setOutlierRate(getProperty<float>("ransac.outlierRate"));
143 
144  shapeExtraction.setMinInlierRate(getProperty<float>("ransac.minInlierRate"));
145 
146  shapeExtraction.setSizePenaltyFactor(getProperty<float>("ransac.sizePenaltyFactor"));
147  shapeExtraction.setSizePenaltyExponent(getProperty<float>("ransac.sizePenaltyExponent"));
148 
149  // Target shapes
150  {
151  std::string targetShapes = getProperty<std::string>("ransac.TargetShapes");
152 
153  // Make targetShapes all lowercase
155  targetShapes.begin(), targetShapes.end(), targetShapes.begin(), ::tolower);
156 
157  // find != npos <=> string contained
158  shapeExtraction.setBoxExtractionEnabled(targetShapes.find("box") != std::string::npos);
159  shapeExtraction.setCylinderExtractionEnabled(targetShapes.find("cylinder") !=
160  std::string::npos);
161  shapeExtraction.setSphereExtractionEnabled(targetShapes.find("sphere") !=
162  std::string::npos);
163  }
164  }
165 
166  void
168  {
169  getTopicFromProperty(shapesTopic, "ice.ShapesTopicName");
170 
171  getTopicFromProperty(debugObserver, "ice.DebugObserverName");
172  debugDrawer.getTopic(*this);
173 
176  }
177 
178  void
180  {
181  }
182 
183  void
185  {
186  }
187 
188  void
190  {
191  // Fetch input point cloud.
192  pcl::PointCloud<PointT>::Ptr receivedPointCloud(new pcl::PointCloud<PointT>());
193  if (waitForPointClouds(10000))
194  {
195  if (!getPointClouds(receivedPointCloud))
196  {
197  ARMARX_WARNING << "Unable to get point cloud data.";
198  return;
199  }
200  }
201  else
202  {
203  ARMARX_VERBOSE << "Timeout or error while waiting for pointclouds.";
204  return;
205  }
206 
207  if (debugObserver)
208  {
209  debugObserver->setDebugChannel(
210  getName(),
211  {
212  {"Point Cloud Size",
213  new armarx::Variant(static_cast<int>(receivedPointCloud->size()))},
214  {"Point Cloud Time",
215  new armarx::Variant(static_cast<int>(receivedPointCloud->header.stamp))},
216  });
217  }
218 
219  // Store new point cloud
220  {
221  std::scoped_lock lock(inputPointCloudMutex);
222  this->inputPointCloud = receivedPointCloud;
223  }
224 
225  if (getProperty<bool>("mode.AsPipeline"))
226  {
227  armarx::semantic::data::ShapeList shapes;
228  {
229  std::scoped_lock lockInputPointCloud(inputPointCloudMutex, extractionMutex);
230 
231  ARMARX_INFO << "Running shape extraction (" << inputPointCloud->size()
232  << " points) ...";
233  const semrel::ShapeExtractionResult extractionResult =
234  shapeExtraction.extract(*inputPointCloud);
235  shapes = armarx::semantic::toIce(extractionResult.objects);
236  }
237  if (debugObserver)
238  {
239  debugObserver->setDebugChannel(
240  getName(),
241  {
242  {"Num Extracted Shapes",
243  new armarx::Variant(static_cast<int>(shapes.size()))},
244  });
245  }
246  shapesTopic->reportShapes(shapesName, shapes);
247  }
248  }
249 
250  armarx::semantic::data::ShapeList
252  {
253  if (!inputPointCloud)
254  {
255  ARMARX_WARNING << "No point cloud received. Not running shape extraction.";
256  return {};
257  }
258 
259  // Make sure input point cloud is not being read.
260  std::scoped_lock lockInputPointCloud(inputPointCloudMutex, extractionMutex);
261 
262  ARMARX_INFO << "Running shape extraction (" << inputPointCloud->size() << " points) ...";
263  semrel::ShapeExtractionResult extractionResult = shapeExtraction.extract(*inputPointCloud);
264 
265  armarx::semantic::data::ShapeList result;
266  // Store the result.
267  {
268  std::scoped_lock lock(extractedShapes.mutex);
269 
270  extractedShapes.shapes = std::move(extractionResult.objects);
271  extractedShapes.shapesIce = armarx::semantic::toIce(extractedShapes.shapes);
272 
273  ARMARX_INFO << "Extracted " << extractedShapes.shapes.size() << " shapes. \n"
274  << extractedShapes.shapes;
275 
276  result = extractedShapes.shapesIce;
277  }
278 
279  ARMARX_VERBOSE << "Publishing shapes... ";
280  debugObserver->setDebugChannel(
281  getName(),
282  {
283  {"Num Extracted Shapes", new armarx::Variant(static_cast<int>(result.size()))},
284  });
285 
286  return result;
287  }
288 
289  armarx::semantic::data::ShapeList
291  {
292  std::lock_guard<std::mutex> lock(extractedShapes.mutex);
293  return extractedShapes.shapesIce;
294  }
295 
296  std::string
298  {
299  return "SegmentRansacShapeExtractor";
300  }
301 
304  {
307  }
308 
309 } // namespace visionx
visionx::SegmentRansacShapeExtractor::onConnectPointCloudProcessor
void onConnectPointCloudProcessor() override
Definition: SegmentRansacShapeExtractor.cpp:167
shape.h
armarx::Variant
The Variant class is described here: Variants.
Definition: Variant.h:223
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
armarx::DebugDrawerTopic::offeringTopic
void offeringTopic(ManagedIceObject &component, const std::string &topicNameOverride="") const
Call offeringTopic([topicName]) on the given component.
Definition: DebugDrawerTopic.cpp:80
hooks.h
visionx::SegmentRansacShapeExtractor::getExtractedShapes
armarx::semantic::data::ShapeList getExtractedShapes(const Ice::Current &=Ice::emptyCurrent) override
Definition: SegmentRansacShapeExtractor.cpp:290
visionx
ArmarX headers.
Definition: OpenPoseStressTest.h:38
visionx::SegmentRansacShapeExtractor::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: SegmentRansacShapeExtractor.cpp:303
Pose.h
visionx::SegmentRansacShapeExtractor::onInitPointCloudProcessor
void onInitPointCloudProcessor() override
Definition: SegmentRansacShapeExtractor.cpp:126
visionx::SegmentRansacShapeExtractor::onDisconnectPointCloudProcessor
void onDisconnectPointCloudProcessor() override
Definition: SegmentRansacShapeExtractor.cpp:179
visionx::SegmentRansacShapeExtractorPropertyDefinitions
Property definitions of SegmentRansacShapeExtractor.
Definition: SegmentRansacShapeExtractor.h:46
armarx::Component::offeringTopicFromProperty
void offeringTopicFromProperty(const std::string &propertyName)
Offer a topic whose name is specified by the given property.
Definition: Component.cpp:159
armarx::semantic::setArmarXHooksAsImplementation
void setArmarXHooksAsImplementation(const DebugDrawerInterfacePrx &debugDrawer, const std::string &logTag="SemanticObjectRelations")
Definition: hooks.cpp:7
visionx::SegmentRansacShapeExtractor::onExitPointCloudProcessor
void onExitPointCloudProcessor() override
Definition: SegmentRansacShapeExtractor.cpp:184
visionx::SegmentRansacShapeExtractor::extractShapes
armarx::semantic::data::ShapeList extractShapes(const Ice::Current &=Ice::emptyCurrent) override
Definition: SegmentRansacShapeExtractor.cpp:251
armarx::semantic::toIce
data::Graph toIce(const semrel::AttributedGraph &input)
Definition: graph.cpp:15
armarx::Component::getTopicFromProperty
TopicProxyType getTopicFromProperty(const std::string &propertyName)
Get a topic proxy whose name is specified by the given property.
Definition: Component.h:221
armarx::semantic::properties::defineVisualizationLevel
void defineVisualizationLevel(armarx::ComponentPropertyDefinitions &defs, const std::string &propertyName=defaults::visualizationLevelName, semrel::VisuLevel defaultLevel=semrel::VisuLevel::RESULT, const std::string &description=defaults::visualizationLevelDescription)
Definition: ArmarXVisualizer.cpp:217
visionx::PointCloudProcessor::waitForPointClouds
bool waitForPointClouds(int milliseconds=1000)
Wait for new PointClouds.
Definition: PointCloudProcessor.cpp:458
SegmentRansacShapeExtractor.h
visionx::PointCloudProcessorPropertyDefinitions
Properties of PointCloudProcessor.
Definition: PointCloudProcessor.h:166
visionx::PointCloudProcessor::getPointClouds
int getPointClouds(const PointCloudPtrT &pointCloudPtr)
Poll PointClouds from provider.
Definition: PointCloudProcessor.h:380
armarx::transform
auto transform(const Container< InputT, Alloc > &in, OutputT(*func)(InputT const &)) -> Container< OutputT, typename std::allocator_traits< Alloc >::template rebind_alloc< OutputT >>
Convenience function (with less typing) to transform a container of type InputT into the same contain...
Definition: algorithm.h:351
armarx::Component::getConfigIdentifier
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition: Component.cpp:79
visionx::SegmentRansacShapeExtractor::process
void process() override
Definition: SegmentRansacShapeExtractor.cpp:189
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
armarx::semantic::properties::defaults::visualizationLevelName
const std::string visualizationLevelName
Definition: ArmarXVisualizer.cpp:211
armarx::PropertyUser::getProperty
Property< PropertyType > getProperty(const std::string &name)
Property creation and retrieval.
Definition: PropertyUser.h:180
IceUtil::Handle< class PropertyDefinitionContainer >
visionx::SegmentRansacShapeExtractor::getDefaultName
std::string getDefaultName() const override
Definition: SegmentRansacShapeExtractor.cpp:297
armarx::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:108
armarx::DebugDrawerTopic::getTopic
DebugDrawerInterfacePrx getTopic() const
Get the topic.
Definition: DebugDrawerTopic.cpp:62
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:35
visionx::SegmentRansacShapeExtractorPropertyDefinitions::SegmentRansacShapeExtractorPropertyDefinitions
SegmentRansacShapeExtractorPropertyDefinitions(std::string prefix)
Definition: SegmentRansacShapeExtractor.cpp:38
shapes
MiscLib::Vector< std::pair< MiscLib::RefCountPtr< PrimitiveShape >, size_t > > shapes
Definition: ReadMe.txt:92
armarx::semantic::properties::setMinimumVisuLevel
void setMinimumVisuLevel(armarx::PropertyUser &defs, const std::string &propertyName=defaults::visualizationLevelName)
Definition: ArmarXVisualizer.cpp:237