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