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
25#include <pcl/octree/octree.h>
26
28
29using namespace armarx;
30
31void
33{
34 primitivesProviderName = getProperty<std::string>("PrimitivesProviderName").getValue();
36
37 usingProxy(getProperty<std::string>("PointCloudProviderName").getValue());
38 usingProxy(getProperty<std::string>("PointCloudSegmenterName").getValue());
39 usingProxy(getProperty<std::string>("PrimitiveExtractorName").getValue());
40
41 sourcePointCloudFilename = getProperty<std::string>("SourcePointCloud").getValue();
42 referencePointCloudFilename = getProperty<std::string>("GroundTruthPointCloud").getValue();
43 exportDirectory = getProperty<std::string>("ExportDirectory").getValue();
44
45 // Load reference point cloud
50 {
51 ARMARX_ERROR << "Could not find point cloud files in ArmarXDataPath";
52 return;
53 }
54
55 referencePointCloud.reset(new pcl::PointCloud<pcl::PointXYZRGBL>());
56 if (pcl::io::loadPCDFile(referencePointCloudFilename.c_str(), *referencePointCloud) == -1)
57 {
58 ARMARX_WARNING << "Unable to load point cloud from file "
59 << getProperty<std::string>("GroundTruthPointCloud").getValue();
60 return;
61 }
62
63 // Initialize default parameters
64 extractionPrm.minSegmentSize = 100;
65 extractionPrm.maxSegmentSize = 250000000;
66 extractionPrm.euclideanClusteringTolerance = 30;
67 extractionPrm.outlierThreshold = 20;
68
69 extractionPrm.planeMaxIterations = 100;
70 extractionPrm.planeDistanceThreshold = 40;
71 extractionPrm.planeNormalDistance = 10;
72
73 extractionPrm.cylinderMaxIterations = 100;
74 extractionPrm.cylinderDistanceThreshold = 10;
75 extractionPrm.cylinderRadiusLimit = 10;
76
77 extractionPrm.sphereMaxIterations = 100;
78 extractionPrm.sphereDistanceThreshold = 90;
79 extractionPrm.sphereNormalDistance = 10;
80 extractionPrm.circularDistanceThreshold = 10;
81
82 segmentationPrm.minSegmentSize = 5;
83 segmentationPrm.voxelResolution = 20;
84 segmentationPrm.seedResolution = 70;
85 segmentationPrm.colorImportance = 0;
86 segmentationPrm.spatialImportance = 1;
87 segmentationPrm.normalImportance = 4;
88 segmentationPrm.concavityThreshold = 10;
89 segmentationPrm.smoothnessThreshold = 0.1;
90
91 bestFitness = -std::numeric_limits<float>::infinity();
92
93 // Initialize bounds
94 bounds_segmentation_minSegmentSize = Eigen::Vector2f(100, 1000);
95 bounds_segmentation_maxSegmentSize = Eigen::Vector2f(250000000, 250000000);
97 bounds_segmentation_outlierThreshold = Eigen::Vector2f(1, 100);
98 bounds_segmentation_planeMaxIterations = Eigen::Vector2f(100, 100);
99 bounds_segmentation_planeDistanceThreshold = Eigen::Vector2f(1e-6, 100);
100 bounds_segmentation_planeNormalDistance = Eigen::Vector2f(1e-6, 100);
101 bounds_segmentation_cylinderMaxIterations = Eigen::Vector2f(100, 100);
102 bounds_segmentation_cylinderDistanceThreshold = Eigen::Vector2f(1e-6, 100);
103 bounds_segmentation_cylinderRadiusLimit = Eigen::Vector2f(1e-6, 100);
104 bounds_segmentation_sphereMaxIterations = Eigen::Vector2f(100, 100);
105 bounds_segmentation_sphereDistanceThreshold = Eigen::Vector2f(1e-6, 100);
106 bounds_segmentation_sphereNormalDistance = Eigen::Vector2f(1e-6, 100);
107 bounds_segmentation_circularDistanceThreshold = Eigen::Vector2f(1, 100);
108 bounds_primitives_minSegmentSize = Eigen::Vector2f(1, 100);
109 bounds_primitives_voxelResolution = Eigen::Vector2f(1, 100);
110 bounds_primitives_seedResolution = Eigen::Vector2f(1, 100);
111 bounds_primitives_colorImportance = Eigen::Vector2f(0, 0);
112 bounds_primitives_spatialImportance = Eigen::Vector2f(1e-6, 100);
113 bounds_primitives_normalImportance = Eigen::Vector2f(1e-6, 100);
114 bounds_primitives_concavityThreshold = Eigen::Vector2f(1e-6, 100);
115 bounds_primitives_smoothnessThreshold = Eigen::Vector2f(1e-6, 100);
116}
117
118void
120{
122 getProperty<std::string>("PointCloudProviderName").getValue());
124 {
125 ARMARX_ERROR << "Could not obtain point cloud provider proxy";
126 return;
127 }
128
130 getProperty<std::string>("PointCloudSegmenterName").getValue());
132 {
133 ARMARX_ERROR << "Could not obtain point cloud segmenter proxy";
134 return;
135 }
136
138 getProperty<std::string>("PrimitiveExtractorName").getValue());
140 {
141 ARMARX_ERROR << "Could not obtain primitive extractor";
142 return;
143 }
144
145 iteration = 1;
146
147 primitiveExtractor->setParameters(extractionPrm);
148 pointCloudSegmenter->setLccpParameters(segmentationPrm);
149
150 pointCloudProvider->setPointCloudFilename(sourcePointCloudFilename);
151 pointCloudProvider->begin_startCaptureForNumFrames(1);
152}
153
154void
158
159void
163
164void
166{
168 {
169 return;
170 }
171
172 pcl::PointCloud<pcl::PointXYZL>::Ptr primitives(new pcl::PointCloud<pcl::PointXYZL>());
173 if (!getPointClouds(primitivesProviderName, primitives))
174 {
175 ARMARX_WARNING << "Unable to get point cloud data.";
176 return;
177 }
178
179 float fitness = compareLabeledPointClouds(primitives, referencePointCloud);
180 ARMARX_INFO << "Processed point cloud #" << iteration << " received (fitness = " << fitness
181 << ")";
182
183 if (fitness > bestFitness)
184 {
185 ARMARX_INFO << "New best parameter set found";
188 bestFitness = fitness;
189
191 }
192 else
193 {
194 ARMARX_INFO << "Current parameter set not better";
195 }
196
197 iteration++;
199
200 primitiveExtractor->setParameters(extractionPrm);
201 pointCloudSegmenter->setLccpParameters(segmentationPrm);
202 pointCloudProvider->begin_startCaptureForNumFrames(1);
203}
204
211
212float
214 const pcl::PointCloud<pcl::PointXYZL>::Ptr& labeled,
215 const pcl::PointCloud<pcl::PointXYZRGBL>::Ptr& reference)
216{
217 ARMARX_INFO << labeled->size() << " points in segmentation point cloud";
218 ARMARX_INFO << reference->size() << " points in ground truth point cloud";
219
220 pcl::octree::OctreePointCloudSearch<pcl::PointXYZL> octree(50);
221 octree.setInputCloud(labeled);
222 octree.addPointsFromInputCloud();
223
224 std::map<unsigned int, unsigned int> labelMap;
225
226 unsigned int num_covered = 0;
227 for (auto& p : reference->points)
228 {
229 std::vector<int> indices;
230 std::vector<float> squaredDistances;
231
232 pcl::PointXYZL q;
233 q.x = p.x;
234 q.y = p.y;
235 q.z = p.z;
236
237 if (octree.nearestKSearch(q, 1, indices, squaredDistances) > 0 && squaredDistances[0] < 50)
238 {
239 if (labelMap.find(p.label) == labelMap.end())
240 {
241 labelMap[p.label] = labeled->points[indices[0]].label;
242 }
243 if (labelMap[p.label] == labeled->points[indices[0]].label)
244 {
245 num_covered++;
246 }
247 }
248 }
249
250 return ((float)num_covered) / reference->size();
251}
252
253void
255{
256 // Randomly sample within a hyperplane around the current parameter set
257 extractionPrm.minSegmentSize =
259 extractionPrm.maxSegmentSize =
261 extractionPrm.euclideanClusteringTolerance =
262 sample(bestExtractionPrm.euclideanClusteringTolerance,
264 extractionPrm.outlierThreshold =
266 extractionPrm.planeMaxIterations =
268 extractionPrm.planeDistanceThreshold = sample(bestExtractionPrm.planeDistanceThreshold,
270 extractionPrm.planeNormalDistance =
272 extractionPrm.cylinderMaxIterations =
274 extractionPrm.cylinderDistanceThreshold = sample(bestExtractionPrm.cylinderDistanceThreshold,
276 extractionPrm.cylinderRadiusLimit =
278 extractionPrm.sphereMaxIterations =
280 extractionPrm.sphereDistanceThreshold = sample(bestExtractionPrm.sphereDistanceThreshold,
282 extractionPrm.sphereNormalDistance =
284 extractionPrm.circularDistanceThreshold = sample(bestExtractionPrm.circularDistanceThreshold,
286
287 segmentationPrm.minSegmentSize =
289 segmentationPrm.voxelResolution =
291 segmentationPrm.seedResolution =
293 segmentationPrm.colorImportance =
295 segmentationPrm.spatialImportance =
297 segmentationPrm.normalImportance =
299 segmentationPrm.concavityThreshold =
301 segmentationPrm.smoothnessThreshold =
303
304 std::stringstream s;
305 s << "Randomly determined parameter set: {" << std::endl
306 << " extractionPrm.minSegmentSize: " << extractionPrm.minSegmentSize << "," << std::endl
307 << " extractionPrm.maxSegmentSize: " << extractionPrm.maxSegmentSize << "," << std::endl
308 << " extractionPrm.euclideanClusteringTolerance: "
309 << extractionPrm.euclideanClusteringTolerance << "," << std::endl
310 << " extractionPrm.outlierThreshold: " << extractionPrm.outlierThreshold << ","
311 << std::endl
312 << " extractionPrm.planeMaxIterations: " << extractionPrm.planeMaxIterations << ","
313 << std::endl
314 << " extractionPrm.planeDistanceThreshold: " << extractionPrm.planeDistanceThreshold << ","
315 << std::endl
316 << " extractionPrm.planeNormalDistance: " << extractionPrm.planeNormalDistance << ","
317 << std::endl
318 << " extractionPrm.cylinderMaxIterations: " << extractionPrm.cylinderMaxIterations << ","
319 << std::endl
320 << " extractionPrm.cylinderDistanceThreshold: " << extractionPrm.cylinderDistanceThreshold
321 << "," << std::endl
322 << " extractionPrm.cylinderRadiusLimit: " << extractionPrm.cylinderRadiusLimit << ","
323 << std::endl
324 << " extractionPrm.sphereMaxIterations: " << extractionPrm.sphereMaxIterations << ","
325 << std::endl
326 << " extractionPrm.sphereDistanceThreshold: " << extractionPrm.sphereDistanceThreshold
327 << "," << std::endl
328 << " extractionPrm.sphereNormalDistance: " << extractionPrm.sphereNormalDistance << ","
329 << std::endl
330 << " extractionPrm.circularDistanceThreshold: " << extractionPrm.circularDistanceThreshold
331 << "," << std::endl
332 << " segmentationPrm.minSegmentSize: " << segmentationPrm.minSegmentSize << ","
333 << std::endl
334 << " segmentationPrm.voxelResolution: " << segmentationPrm.voxelResolution << ","
335 << std::endl
336 << " segmentationPrm.seedResolution: " << segmentationPrm.seedResolution << ","
337 << std::endl
338 << " segmentationPrm.colorImportance: " << segmentationPrm.colorImportance << ","
339 << std::endl
340 << " segmentationPrm.spatialImportance: " << segmentationPrm.spatialImportance << ","
341 << std::endl
342 << " segmentationPrm.normalImportance: " << segmentationPrm.normalImportance << ","
343 << std::endl
344 << " segmentationPrm.concavityThreshold: " << segmentationPrm.concavityThreshold << ","
345 << std::endl
346 << " segmentationPrm.smoothnessThreshold: " << segmentationPrm.smoothnessThreshold << ","
347 << std::endl
348 << "}";
349 ARMARX_INFO << s.str();
350}
351
352float
353PrimitiveExtractionParameterTuning::sample(float current, const Eigen::Vector2f& bounds)
354{
355 float radius_percent = 0.05;
356
357 if (iteration % 5 == 0)
358 {
359 radius_percent = 0.3;
360 }
361
362 // Random value in [-1, 1]
363 float r = ((float)(rand() % 2000 - 1000)) / 1000.0f;
364
365 // Scale to admitted radius
366 current += r * (bounds(1) - bounds(0)) * radius_percent;
367
368 // Crop to boundaries
369 current = std::max(current, bounds(0));
370 current = std::min(current, bounds(1));
371
372 return current;
373}
374
375void
377 const std::string& directory,
378 const pcl::PointCloud<pcl::PointXYZL>::Ptr& pointCloud,
379 const visionx::LccpParameters& lccp_prm,
380 const visionx::PrimitiveExtractorParameters& pe_prm)
381{
382 std::stringstream path_pcd;
383 path_pcd << directory << "/point_cloud_" << iteration << ".pcd";
384
385 std::stringstream path_prm;
386 path_prm << directory << "/parameters_" << iteration << ".cfg";
387
388 ARMARX_INFO << "Exporting labeled point cloud to: " << path_pcd.str();
389 pcl::io::savePCDFile<pcl::PointXYZL>(path_pcd.str(), *pointCloud);
390
391 ARMARX_INFO << "Exporting parameters to: " << path_prm.str();
392 std::ofstream f;
393 f.open(path_prm.str());
394
395 f << "Randomly determined parameter set: {" << std::endl
396 << " extractionPrm.minSegmentSize: " << pe_prm.minSegmentSize << "," << std::endl
397 << " extractionPrm.maxSegmentSize: " << pe_prm.maxSegmentSize << "," << std::endl
398 << " extractionPrm.euclideanClusteringTolerance: " << pe_prm.euclideanClusteringTolerance
399 << "," << std::endl
400 << " extractionPrm.outlierThreshold: " << pe_prm.outlierThreshold << "," << std::endl
401 << " extractionPrm.planeMaxIterations: " << pe_prm.planeMaxIterations << "," << std::endl
402 << " extractionPrm.planeDistanceThreshold: " << pe_prm.planeDistanceThreshold << ","
403 << std::endl
404 << " extractionPrm.planeNormalDistance: " << pe_prm.planeNormalDistance << "," << std::endl
405 << " extractionPrm.cylinderMaxIterations: " << pe_prm.cylinderMaxIterations << ","
406 << std::endl
407 << " extractionPrm.cylinderDistanceThreshold: " << pe_prm.cylinderDistanceThreshold << ","
408 << std::endl
409 << " extractionPrm.cylinderRadiusLimit: " << pe_prm.cylinderRadiusLimit << "," << std::endl
410 << " extractionPrm.sphereMaxIterations: " << pe_prm.sphereMaxIterations << "," << std::endl
411 << " extractionPrm.sphereDistanceThreshold: " << pe_prm.sphereDistanceThreshold << ","
412 << std::endl
413 << " extractionPrm.sphereNormalDistance: " << pe_prm.sphereNormalDistance << ","
414 << std::endl
415 << " extractionPrm.circularDistanceThreshold: " << pe_prm.circularDistanceThreshold << ","
416 << std::endl
417 << " segmentationPrm.minSegmentSize: " << lccp_prm.minSegmentSize << "," << std::endl
418 << " segmentationPrm.voxelResolution: " << lccp_prm.voxelResolution << "," << std::endl
419 << " segmentationPrm.seedResolution: " << lccp_prm.seedResolution << "," << std::endl
420 << " segmentationPrm.colorImportance: " << lccp_prm.colorImportance << "," << std::endl
421 << " segmentationPrm.spatialImportance: " << lccp_prm.spatialImportance << "," << std::endl
422 << " segmentationPrm.normalImportance: " << lccp_prm.normalImportance << "," << std::endl
423 << " segmentationPrm.concavityThreshold: " << lccp_prm.concavityThreshold << ","
424 << std::endl
425 << " segmentationPrm.smoothnessThreshold: " << lccp_prm.smoothnessThreshold << ","
426 << std::endl
427 << "}" << std::endl
428 << std::endl
429 << "fitness: " << bestFitness << std::endl;
430
431 f.close();
432}
#define float
Definition 16_Level.h:22
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)
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
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.