PrimitiveExtractionParameterTuning.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::PrimitiveExtractionParameterTuning
17 * @author Peter Kaiser ( peter dot kaiser at kit dot edu )
18 * @date 2017
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
26
27#include <pcl/octree/octree.h>
28
30
31using namespace armarx;
32
33void
35{
36 primitivesProviderName = getProperty<std::string>("PrimitivesProviderName").getValue();
38
39 usingProxy(getProperty<std::string>("PointCloudProviderName").getValue());
40 usingProxy(getProperty<std::string>("PointCloudSegmenterName").getValue());
41 usingProxy(getProperty<std::string>("PrimitiveExtractorName").getValue());
42
43 sourcePointCloudFilename = getProperty<std::string>("SourcePointCloud").getValue();
44 referencePointCloudFilename = getProperty<std::string>("GroundTruthPointCloud").getValue();
45 exportDirectory = getProperty<std::string>("ExportDirectory").getValue();
46
47 // Load reference point cloud
52 {
53 ARMARX_ERROR << "Could not find point cloud files in ArmarXDataPath";
54 return;
55 }
56
57 referencePointCloud.reset(new pcl::PointCloud<pcl::PointXYZRGBL>());
58 if (pcl::io::loadPCDFile(referencePointCloudFilename.c_str(), *referencePointCloud) == -1)
59 {
60 ARMARX_WARNING << "Unable to load point cloud from file "
61 << getProperty<std::string>("GroundTruthPointCloud").getValue();
62 return;
63 }
64
65 // Initialize default parameters
66 extractionPrm.minSegmentSize = 100;
67 extractionPrm.maxSegmentSize = 250000000;
68 extractionPrm.euclideanClusteringTolerance = 30;
69 extractionPrm.outlierThreshold = 20;
70
71 extractionPrm.planeMaxIterations = 100;
72 extractionPrm.planeDistanceThreshold = 40;
73 extractionPrm.planeNormalDistance = 10;
74
75 extractionPrm.cylinderMaxIterations = 100;
76 extractionPrm.cylinderDistanceThreshold = 10;
77 extractionPrm.cylinderRadiusLimit = 10;
78
79 extractionPrm.sphereMaxIterations = 100;
80 extractionPrm.sphereDistanceThreshold = 90;
81 extractionPrm.sphereNormalDistance = 10;
82 extractionPrm.circularDistanceThreshold = 10;
83
84 segmentationPrm.minSegmentSize = 5;
85 segmentationPrm.voxelResolution = 20;
86 segmentationPrm.seedResolution = 70;
87 segmentationPrm.colorImportance = 0;
88 segmentationPrm.spatialImportance = 1;
89 segmentationPrm.normalImportance = 4;
90 segmentationPrm.concavityThreshold = 10;
91 segmentationPrm.smoothnessThreshold = 0.1;
92
93 bestFitness = -std::numeric_limits<float>::infinity();
94
95 // Initialize bounds
96 bounds_segmentation_minSegmentSize = Eigen::Vector2f(100, 1000);
97 bounds_segmentation_maxSegmentSize = Eigen::Vector2f(250000000, 250000000);
99 bounds_segmentation_outlierThreshold = Eigen::Vector2f(1, 100);
100 bounds_segmentation_planeMaxIterations = Eigen::Vector2f(100, 100);
101 bounds_segmentation_planeDistanceThreshold = Eigen::Vector2f(1e-6, 100);
102 bounds_segmentation_planeNormalDistance = Eigen::Vector2f(1e-6, 100);
103 bounds_segmentation_cylinderMaxIterations = Eigen::Vector2f(100, 100);
104 bounds_segmentation_cylinderDistanceThreshold = Eigen::Vector2f(1e-6, 100);
105 bounds_segmentation_cylinderRadiusLimit = Eigen::Vector2f(1e-6, 100);
106 bounds_segmentation_sphereMaxIterations = Eigen::Vector2f(100, 100);
107 bounds_segmentation_sphereDistanceThreshold = Eigen::Vector2f(1e-6, 100);
108 bounds_segmentation_sphereNormalDistance = Eigen::Vector2f(1e-6, 100);
109 bounds_segmentation_circularDistanceThreshold = Eigen::Vector2f(1, 100);
110 bounds_primitives_minSegmentSize = Eigen::Vector2f(1, 100);
111 bounds_primitives_voxelResolution = Eigen::Vector2f(1, 100);
112 bounds_primitives_seedResolution = Eigen::Vector2f(1, 100);
113 bounds_primitives_colorImportance = Eigen::Vector2f(0, 0);
114 bounds_primitives_spatialImportance = Eigen::Vector2f(1e-6, 100);
115 bounds_primitives_normalImportance = Eigen::Vector2f(1e-6, 100);
116 bounds_primitives_concavityThreshold = Eigen::Vector2f(1e-6, 100);
117 bounds_primitives_smoothnessThreshold = Eigen::Vector2f(1e-6, 100);
118}
119
120void
122{
124 getProperty<std::string>("PointCloudProviderName").getValue());
126 {
127 ARMARX_ERROR << "Could not obtain point cloud provider proxy";
128 return;
129 }
130
132 getProperty<std::string>("PointCloudSegmenterName").getValue());
134 {
135 ARMARX_ERROR << "Could not obtain point cloud segmenter proxy";
136 return;
137 }
138
140 getProperty<std::string>("PrimitiveExtractorName").getValue());
142 {
143 ARMARX_ERROR << "Could not obtain primitive extractor";
144 return;
145 }
146
147 iteration = 1;
148
149 primitiveExtractor->setParameters(extractionPrm);
150 pointCloudSegmenter->setLccpParameters(segmentationPrm);
151
152 pointCloudProvider->setPointCloudFilename(sourcePointCloudFilename);
153 pointCloudProvider->begin_startCaptureForNumFrames(1);
154}
155
156void
160
161void
165
166void
168{
170 {
171 return;
172 }
173
174 pcl::PointCloud<pcl::PointXYZL>::Ptr primitives(new pcl::PointCloud<pcl::PointXYZL>());
175 if (!getPointClouds(primitivesProviderName, primitives))
176 {
177 ARMARX_WARNING << "Unable to get point cloud data.";
178 return;
179 }
180
181 float fitness = compareLabeledPointClouds(primitives, referencePointCloud);
182 ARMARX_INFO << "Processed point cloud #" << iteration << " received (fitness = " << fitness
183 << ")";
184
185 if (fitness > bestFitness)
186 {
187 ARMARX_INFO << "New best parameter set found";
190 bestFitness = fitness;
191
193 }
194 else
195 {
196 ARMARX_INFO << "Current parameter set not better";
197 }
198
199 iteration++;
201
202 primitiveExtractor->setParameters(extractionPrm);
203 pointCloudSegmenter->setLccpParameters(segmentationPrm);
204 pointCloudProvider->begin_startCaptureForNumFrames(1);
205}
206
213
214float
216 const pcl::PointCloud<pcl::PointXYZL>::Ptr& labeled,
217 const pcl::PointCloud<pcl::PointXYZRGBL>::Ptr& reference)
218{
219 ARMARX_INFO << labeled->size() << " points in segmentation point cloud";
220 ARMARX_INFO << reference->size() << " points in ground truth point cloud";
221
222 pcl::octree::OctreePointCloudSearch<pcl::PointXYZL> octree(50);
223 octree.setInputCloud(labeled);
224 octree.addPointsFromInputCloud();
225
226 std::map<unsigned int, unsigned int> labelMap;
227
228 unsigned int num_covered = 0;
229 for (auto& p : reference->points)
230 {
231 std::vector<int> indices;
232 std::vector<float> squaredDistances;
233
234 pcl::PointXYZL q;
235 q.x = p.x;
236 q.y = p.y;
237 q.z = p.z;
238
239 if (octree.nearestKSearch(q, 1, indices, squaredDistances) > 0 && squaredDistances[0] < 50)
240 {
241 if (labelMap.find(p.label) == labelMap.end())
242 {
243 labelMap[p.label] = labeled->points[indices[0]].label;
244 }
245 if (labelMap[p.label] == labeled->points[indices[0]].label)
246 {
247 num_covered++;
248 }
249 }
250 }
251
252 return ((float)num_covered) / reference->size();
253}
254
255void
257{
258 // Randomly sample within a hyperplane around the current parameter set
259 extractionPrm.minSegmentSize =
261 extractionPrm.maxSegmentSize =
263 extractionPrm.euclideanClusteringTolerance =
264 sample(bestExtractionPrm.euclideanClusteringTolerance,
266 extractionPrm.outlierThreshold =
268 extractionPrm.planeMaxIterations =
270 extractionPrm.planeDistanceThreshold = sample(bestExtractionPrm.planeDistanceThreshold,
272 extractionPrm.planeNormalDistance =
274 extractionPrm.cylinderMaxIterations =
276 extractionPrm.cylinderDistanceThreshold = sample(bestExtractionPrm.cylinderDistanceThreshold,
278 extractionPrm.cylinderRadiusLimit =
280 extractionPrm.sphereMaxIterations =
282 extractionPrm.sphereDistanceThreshold = sample(bestExtractionPrm.sphereDistanceThreshold,
284 extractionPrm.sphereNormalDistance =
286 extractionPrm.circularDistanceThreshold = sample(bestExtractionPrm.circularDistanceThreshold,
288
289 segmentationPrm.minSegmentSize =
291 segmentationPrm.voxelResolution =
293 segmentationPrm.seedResolution =
295 segmentationPrm.colorImportance =
297 segmentationPrm.spatialImportance =
299 segmentationPrm.normalImportance =
301 segmentationPrm.concavityThreshold =
303 segmentationPrm.smoothnessThreshold =
305
306 std::stringstream s;
307 s << "Randomly determined parameter set: {" << std::endl
308 << " extractionPrm.minSegmentSize: " << extractionPrm.minSegmentSize << "," << std::endl
309 << " extractionPrm.maxSegmentSize: " << extractionPrm.maxSegmentSize << "," << std::endl
310 << " extractionPrm.euclideanClusteringTolerance: "
311 << extractionPrm.euclideanClusteringTolerance << "," << std::endl
312 << " extractionPrm.outlierThreshold: " << extractionPrm.outlierThreshold << ","
313 << std::endl
314 << " extractionPrm.planeMaxIterations: " << extractionPrm.planeMaxIterations << ","
315 << std::endl
316 << " extractionPrm.planeDistanceThreshold: " << extractionPrm.planeDistanceThreshold << ","
317 << std::endl
318 << " extractionPrm.planeNormalDistance: " << extractionPrm.planeNormalDistance << ","
319 << std::endl
320 << " extractionPrm.cylinderMaxIterations: " << extractionPrm.cylinderMaxIterations << ","
321 << std::endl
322 << " extractionPrm.cylinderDistanceThreshold: " << extractionPrm.cylinderDistanceThreshold
323 << "," << std::endl
324 << " extractionPrm.cylinderRadiusLimit: " << extractionPrm.cylinderRadiusLimit << ","
325 << std::endl
326 << " extractionPrm.sphereMaxIterations: " << extractionPrm.sphereMaxIterations << ","
327 << std::endl
328 << " extractionPrm.sphereDistanceThreshold: " << extractionPrm.sphereDistanceThreshold
329 << "," << std::endl
330 << " extractionPrm.sphereNormalDistance: " << extractionPrm.sphereNormalDistance << ","
331 << std::endl
332 << " extractionPrm.circularDistanceThreshold: " << extractionPrm.circularDistanceThreshold
333 << "," << std::endl
334 << " segmentationPrm.minSegmentSize: " << segmentationPrm.minSegmentSize << ","
335 << std::endl
336 << " segmentationPrm.voxelResolution: " << segmentationPrm.voxelResolution << ","
337 << std::endl
338 << " segmentationPrm.seedResolution: " << segmentationPrm.seedResolution << ","
339 << std::endl
340 << " segmentationPrm.colorImportance: " << segmentationPrm.colorImportance << ","
341 << std::endl
342 << " segmentationPrm.spatialImportance: " << segmentationPrm.spatialImportance << ","
343 << std::endl
344 << " segmentationPrm.normalImportance: " << segmentationPrm.normalImportance << ","
345 << std::endl
346 << " segmentationPrm.concavityThreshold: " << segmentationPrm.concavityThreshold << ","
347 << std::endl
348 << " segmentationPrm.smoothnessThreshold: " << segmentationPrm.smoothnessThreshold << ","
349 << std::endl
350 << "}";
351 ARMARX_INFO << s.str();
352}
353
354float
355PrimitiveExtractionParameterTuning::sample(float current, const Eigen::Vector2f& bounds)
356{
357 float radius_percent = 0.05;
358
359 if (iteration % 5 == 0)
360 {
361 radius_percent = 0.3;
362 }
363
364 // Random value in [-1, 1]
365 float r = ((float)(rand() % 2000 - 1000)) / 1000.0f;
366
367 // Scale to admitted radius
368 current += r * (bounds(1) - bounds(0)) * radius_percent;
369
370 // Crop to boundaries
371 current = std::max(current, bounds(0));
372 current = std::min(current, bounds(1));
373
374 return current;
375}
376
377void
379 const std::string& directory,
380 const pcl::PointCloud<pcl::PointXYZL>::Ptr& pointCloud,
381 const visionx::LccpParameters& lccp_prm,
382 const visionx::PrimitiveExtractorParameters& pe_prm)
383{
384 std::stringstream path_pcd;
385 path_pcd << directory << "/point_cloud_" << iteration << ".pcd";
386
387 std::stringstream path_prm;
388 path_prm << directory << "/parameters_" << iteration << ".cfg";
389
390 ARMARX_INFO << "Exporting labeled point cloud to: " << path_pcd.str();
391 pcl::io::savePCDFile<pcl::PointXYZL>(path_pcd.str(), *pointCloud);
392
393 ARMARX_INFO << "Exporting parameters to: " << path_prm.str();
394 std::ofstream f;
395 f.open(path_prm.str());
396
397 f << "Randomly determined parameter set: {" << std::endl
398 << " extractionPrm.minSegmentSize: " << pe_prm.minSegmentSize << "," << std::endl
399 << " extractionPrm.maxSegmentSize: " << pe_prm.maxSegmentSize << "," << std::endl
400 << " extractionPrm.euclideanClusteringTolerance: " << pe_prm.euclideanClusteringTolerance
401 << "," << std::endl
402 << " extractionPrm.outlierThreshold: " << pe_prm.outlierThreshold << "," << std::endl
403 << " extractionPrm.planeMaxIterations: " << pe_prm.planeMaxIterations << "," << std::endl
404 << " extractionPrm.planeDistanceThreshold: " << pe_prm.planeDistanceThreshold << ","
405 << std::endl
406 << " extractionPrm.planeNormalDistance: " << pe_prm.planeNormalDistance << "," << std::endl
407 << " extractionPrm.cylinderMaxIterations: " << pe_prm.cylinderMaxIterations << ","
408 << std::endl
409 << " extractionPrm.cylinderDistanceThreshold: " << pe_prm.cylinderDistanceThreshold << ","
410 << std::endl
411 << " extractionPrm.cylinderRadiusLimit: " << pe_prm.cylinderRadiusLimit << "," << std::endl
412 << " extractionPrm.sphereMaxIterations: " << pe_prm.sphereMaxIterations << "," << std::endl
413 << " extractionPrm.sphereDistanceThreshold: " << pe_prm.sphereDistanceThreshold << ","
414 << std::endl
415 << " extractionPrm.sphereNormalDistance: " << pe_prm.sphereNormalDistance << ","
416 << std::endl
417 << " extractionPrm.circularDistanceThreshold: " << pe_prm.circularDistanceThreshold << ","
418 << std::endl
419 << " segmentationPrm.minSegmentSize: " << lccp_prm.minSegmentSize << "," << std::endl
420 << " segmentationPrm.voxelResolution: " << lccp_prm.voxelResolution << "," << std::endl
421 << " segmentationPrm.seedResolution: " << lccp_prm.seedResolution << "," << std::endl
422 << " segmentationPrm.colorImportance: " << lccp_prm.colorImportance << "," << std::endl
423 << " segmentationPrm.spatialImportance: " << lccp_prm.spatialImportance << "," << std::endl
424 << " segmentationPrm.normalImportance: " << lccp_prm.normalImportance << "," << std::endl
425 << " segmentationPrm.concavityThreshold: " << lccp_prm.concavityThreshold << ","
426 << std::endl
427 << " segmentationPrm.smoothnessThreshold: " << lccp_prm.smoothnessThreshold << ","
428 << std::endl
429 << "}" << std::endl
430 << std::endl
431 << "fitness: " << bestFitness << std::endl;
432
433 f.close();
434}
435
436std::string
438{
439 return "PrimitiveExtractionParameterTuning";
440}
441
442std::string
447
#define float
Definition 16_Level.h:22
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
Brief description of class PrimitiveExtractionParameterTuning.
float compareLabeledPointClouds(const pcl::PointCloud< pcl::PointXYZL >::Ptr &labeled, const pcl::PointCloud< pcl::PointXYZRGBL >::Ptr &reference)
visionx::FakePointCloudProviderInterfacePrx pointCloudProvider
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
float sample(float current, const Eigen::Vector2f &bounds)
visionx::PointCloudSegmenterInterfacePrx pointCloudSegmenter
void exportBestSetup(const std::string &directory, const pcl::PointCloud< pcl::PointXYZL >::Ptr &pointCloud, const visionx::LccpParameters &lccp_prm, const visionx::PrimitiveExtractorParameters &pe_prm)
pcl::PointCloud< pcl::PointXYZRGBL >::Ptr referencePointCloud
std::string getDefaultName() const override
Retrieve default name of component.
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.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define q
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.