ATTPCROOT  0.3.0-alpha
A ROOT-based framework for analyzing data from active target detectors
main.cpp
Go to the documentation of this file.
1 #pragma warning(push, 0)
2 //#define TIME // Uncomment this for time mesurement (output to stderr)
3 //#include <pcl/filters/statistical_outlier_removal.h>
4 #include <pcl/common/common.h>
5 #include <pcl/filters/extract_indices.h>
6 #include <pcl/io/pcd_io.h>
7 #include <pcl/visualization/pcl_visualizer.h>
8 
9 #ifdef TIME
10 #include <time.h>
11 #endif
12 #include <fstream>
13 #include <iostream>
14 #include <sstream>
15 #include <vector>
16 #pragma warning(pop)
17 
18 #include "hc.h"
19 #include "msd.h"
20 #include "mst.h"
21 #include "smoothenCloud.h"
22 
23 // usage message
24 const char *usage =
25  "Usage:\n"
26  "\tcloud_viewer [options] <infile>\n"
27  "Options (defaults in brackets):\n"
28  "\t-gnuplot print result as a gnuplot command\n"
29  "\t-r <radius> radius for point smoothing [7.0]\n"
30  "\t (when negative, it is set to dNN)\n"
31  "\t-k <n> number of nearest neighbours used for creating triplets\n"
32  "\t [19]\n"
33  "\t-n <n> number of the best triplets to use [3]\n"
34  "\t-a <alpha> maximum angle between the lines in a triplet [0.015]\n"
35  "\t-s <scale> scalingfactor for clustering [1.0]\n"
36  "\t-t <dist> best cluster distance [5.0]\n"
37  "\t-m <n> minimum number of triplets for a cluster [5]\n"
38  "\t-o <outfile> write results to <outfile>\n"
39  "\t-x11 show interactive window with clustering\n"
40  "\t-v <n> be verbose and save debug trace to file. n is the\n"
41  "\t verbose depth\n"
42  "Version:\n"
43  "\t1.0 from 2018-03-27";
44 /*
45  "\t-dx <dx> step width in x'y'-plane [0]\n"
46  "\t when <dx>=0, it is set to 1/64 of total width\n"
47  "\t-nlines <nl> maximum number of lines returned [0]\n"
48  "\t when <nl>=0, all lines are returned\n"
49  "\t-minvotes <nv> only lines with at least <nv> points are returned [0]\n"
50  "\t-raw print plot data in easily machine-parsable format\n"
51  "\t-vv be even more verbose\n";
52 */
53 
54 struct hc_params {
59  float smoothRadius;
62  float _padding;
63 };
64 
65 typedef struct {
66  uint8_t r;
67  uint8_t g;
68  uint8_t b;
69 } rgb_t;
70 
71 struct Point {
72  float x;
73  float y;
74  float z;
75  std::vector<int> clIds;
76 
77  Point(pcl::PointXYZ point) {
78  x = point.x;
79  y = point.y;
80  z = point.z;
81  }
82 
83  bool operator==(const Point &p) const {
84  return (x == p.x && y == p.y && z == p.z);
85  }
86 };
87 
88 void visualizeTriplets(pcl::visualization::PCLVisualizer &viewer,
89  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
90  std::vector<hc::triplet> const &triplets) {
91  size_t lineId = 0;
92 
93  for (size_t tripletIndex = 0; tripletIndex < triplets.size();
94  ++tripletIndex) {
95  hc::triplet const &tripletEl = triplets[tripletIndex];
96  double const r = (double)((tripletIndex * 23) % 19) / 18.0;
97  double const g = (double)((tripletIndex * 23) % 7) / 6.0;
98  double const b = (double)((tripletIndex * 23) % 3) / 2.0;
99 
100  {
101  pcl::PointXYZI const &pointA = (*cloud)[tripletEl.pointIndexA];
102  pcl::PointXYZI const &pointB = (*cloud)[tripletEl.pointIndexB];
103 
104  std::ostringstream oss;
105  oss << "line" << lineId;
106  viewer.addLine<pcl::PointXYZI>(pointA, pointB, r, g, b, oss.str());
107  ++lineId;
108  }
109 
110  {
111  pcl::PointXYZI const &pointA = (*cloud)[tripletEl.pointIndexB];
112  pcl::PointXYZI const &pointB = (*cloud)[tripletEl.pointIndexC];
113 
114  std::ostringstream oss;
115  oss << "line" << lineId;
116  viewer.addLine<pcl::PointXYZI>(pointA, pointB, r, g, b, oss.str());
117  ++lineId;
118  }
119 
120  ++tripletIndex;
121  }
122 }
123 
124 void visualizeClusterAsMst(pcl::visualization::PCLVisualizer &viewer,
125  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
126  Cluster const &cluster) {
127  size_t lineId = 0;
128  std::vector<pcl::PointIndicesPtr> clusters = cluster.getClusters();
129 
130  for (size_t clusterIndex = 0; clusterIndex < clusters.size();
131  ++clusterIndex) {
132  pcl::PointIndicesPtr const &pointIndices = clusters[clusterIndex];
133  pcl::PointCloud<pcl::PointXYZI>::Ptr clusterCloud(
134  new pcl::PointCloud<pcl::PointXYZI>());
135  pcl::ExtractIndices<pcl::PointXYZI> extract;
136  extract.setInputCloud(cloud);
137  extract.setIndices(pointIndices);
138  extract.setNegative(false);
139  extract.filter(*clusterCloud);
140 
141  std::vector<mst::state> mstResult =
142  mst::calculateMinimumSpanningTree(clusterCloud);
143 
144  if (mstResult.size() < 1) continue;
145 
146  double const r = (double)((clusterIndex * 23) % 19) / 18.0;
147  double const g = (double)((clusterIndex * 23) % 7) / 6.0;
148  double const b = (double)((clusterIndex * 23) % 3) / 2.0;
149 
150  mst::state const &lastMstResult = mstResult[mstResult.size() - 1];
151  std::vector<mst::edge> const &edges = lastMstResult.edges;
152  for (size_t i = 0; i < edges.size(); ++i) {
153  mst::edge const &edge = edges[i];
154  pcl::PointXYZI const &pointA = (*clusterCloud)[edge.voxelIndexA];
155  pcl::PointXYZI const &pointB = (*clusterCloud)[edge.voxelIndexB];
156 
157  std::ostringstream oss;
158  oss << "line" << lineId;
159  viewer.addLine<pcl::PointXYZI>(pointA, pointB, r, g, b, oss.str());
160  ++lineId;
161  }
162  }
163 }
164 
165 /*
166 Cluster useHc(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
167  std::vector<hc::triplet> triplets, float scale,
168  float bestClusterDistanceDelta, size_t cleanupMinTriplets,
169  int opt_verbose = 0) {
170  hc::ScaleTripletMetric scaleTripletMetric(scale);
171  hc::cluster_history result =
172  hc::calculateHc(cloud, triplets, scaleTripletMetric,
173  hc::singleLinkClusterMetric, opt_verbose);
174  hc::cluster_group const &clusterGroup =
175  hc::getBestClusterGroup(result, bestClusterDistanceDelta);
176  hc::cluster_group const &cleanedUpClusterGroup =
177  hc::cleanupClusterGroup(clusterGroup, cleanupMinTriplets);
178 
179  return hc::toCluster(triplets, cleanedUpClusterGroup, cloud->size());
180 }
181 */
182 
183 /*
184 @brief cluster pointcloud.
185 
186 This function clusters the pointcloud and returns the clusters.
187 
188 @param cloud the point cloud
189 @param triplets the triplets
190 @param scale the scale for the triplet metric
191 @param cdist the max distance for merging clusters
192 @param cleanup_min_triplets the minimum count of triplets for a cluster
193 @param opt_verbose verbosity
194 @return the clusters
195 */
196 Cluster use_hc(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
197  std::vector<hc::triplet> triplets, float scale, float cdist,
198  size_t cleanup_min_triplets, int opt_verbose = 0) {
199  hc::ScaleTripletMetric scale_triplet_metric(scale);
200  hc::cluster_group result =
201  hc::compute_hc(cloud, triplets, scale_triplet_metric, cdist, opt_verbose);
202  hc::cluster_group const &cleaned_up_cluster_group =
203  hc::cleanupClusterGroup(result, cleanup_min_triplets);
204 
205  return hc::toCluster(triplets, cleaned_up_cluster_group, cloud->size());
206 }
207 
208 void colorByIndex(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud,
209  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_rgb) {
210  cloud_rgb->clear();
211  pcl::copyPointCloud(*cloud, *cloud_rgb);
212 
213  size_t index = 0;
214  for (pcl::PointCloud<pcl::PointXYZRGB>::iterator it = cloud_rgb->begin();
215  it != cloud_rgb->end(); ++it) {
216  it->r = (uint8_t)(256 * (index % 8) / 8);
217  it->g = it->r / 2;
218  it->b = it->r;
219  ++index;
220  }
221 }
222 
223 void colorByIntensity(pcl::PointCloud<pcl::PointXYZI>::ConstPtr cloud,
224  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_rgb,
225  float minIntensity = 0.0f, float maxIntensity = 4000.0f) {
226  cloud_rgb->clear();
227  pcl::copyPointCloud(*cloud, *cloud_rgb);
228 
229  float size = maxIntensity - minIntensity;
230 
231  for (size_t i = 0; i < cloud->size(); ++i) {
232  pcl::PointXYZRGB &point = (*cloud_rgb)[i];
233 
234  point.r = (uint8_t)(256 * (((*cloud)[i].intensity - minIntensity) / size));
235  point.g = point.r / 2;
236  point.b = point.r;
237  }
238 }
239 
240 void colorByCluster(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud,
241  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_rgb,
242  Cluster const cluster,
243  std::vector<rgb_t> const cluster_rgb) {
244  cloud_rgb->clear();
245  pcl::copyPointCloud(*cloud, *cloud_rgb);
246 
247  // default color: red
248  for (size_t i = 0; i < cloud->size(); ++i) {
249  pcl::PointXYZRGB &point = (*cloud_rgb)[i];
250 
251  point.r = 255;
252  point.g = 0;
253  point.b = 0;
254  }
255 
256  std::vector<pcl::PointIndicesPtr> clusters = cluster.getClusters();
257  for (size_t i = 0; i < clusters.size(); ++i) {
258  pcl::PointIndicesPtr const &pointIndices = clusters[i];
259  rgb_t rgb = cluster_rgb[i];
260  std::vector<int> indices = pointIndices->indices;
261  for (size_t i = 0; i < indices.size(); ++i) {
262  int index = indices[i];
263  pcl::PointXYZRGB &point = (*cloud_rgb)[index];
264 
265  point.r = rgb.r;
266  point.g = rgb.g;
267  point.b = rgb.b;
268  }
269  }
270 }
271 
272 std::vector<rgb_t> createClusterColour(
273  pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud, Cluster const cluster) {
274  std::vector<rgb_t> cluster_rgb;
275  std::vector<pcl::PointIndicesPtr> clusters = cluster.getClusters();
276  for (size_t clusterIndex = 0; clusterIndex < clusters.size();
277  ++clusterIndex) {
278  pcl::PointIndicesPtr const &pointIndices = clusters[clusterIndex];
279  double const r = (double)((clusterIndex * 23) % 19) / 18.0;
280  double const g = (double)((clusterIndex * 23) % 7) / 6.0;
281  double const b = (double)((clusterIndex * 23) % 3) / 2.0;
282  rgb_t rgb;
283  rgb.r = (uint8_t)(r * 255);
284  rgb.g = (uint8_t)(g * 255);
285  rgb.b = (uint8_t)(b * 255);
286 
287  cluster_rgb.push_back(rgb);
288  }
289  return cluster_rgb;
290 }
291 
292 /*
293 @brief prints gnuplot output.
294 
295 This function prints a cloud with clustering as gnuplot script to stdout.
296 
297 @param cloud the point cloud
298 @param cluster the clusters
299 @return vector of mean squared distances of every point in the cloud
300 */
301 void clustersToGnuplot(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
302  Cluster const cluster, std::vector<rgb_t> cluster_rgb) {
303  // gnuplot with RGB as Hex. The colour represents the point's cluster
304  std::ostringstream oss, header;
305  pcl::PointXYZ min, max;
306  header << "set mouse\n";
307  pcl::getMinMax3D(*cloud, min, max);
308  header << "set xrange [" << min.x << ":" << max.x << "]\n";
309  header << "set yrange [" << min.y << ":" << max.y << "]\n";
310  header << "set zrange [" << min.z << ":" << max.z << "]\nsplot ";
311 
312  std::vector<pcl::PointXYZ, Eigen::aligned_allocator<pcl::PointXYZ> > points =
313  cloud->points;
314  std::vector<pcl::PointIndicesPtr> clusters = cluster.getClusters();
315  for (size_t clusterIndex = 0; clusterIndex < clusters.size();
316  ++clusterIndex) {
317  pcl::PointIndicesPtr const &pointIndices = clusters[clusterIndex];
318  // get color colour
319  rgb_t rgb = cluster_rgb[clusterIndex];
320  unsigned long rgb_hex = (rgb.r << 16) | (rgb.g << 8) | rgb.b;
321 
322  header << " '-' with points lc '#" << std::hex << rgb_hex
323  << "' title 'track " << clusterIndex << "',";
324  for (size_t i = 0; i < pointIndices->indices.size(); ++i) {
325  int index = pointIndices->indices[i];
326  pcl::PointXYZ point = cloud->points[index];
327 
328  // remove clustered points from point-vector
329  for (std::vector<pcl::PointXYZ,
330  Eigen::aligned_allocator<pcl::PointXYZ> >::iterator it =
331  points.end();
332  it != points.begin(); --it) {
333  if (it->x == point.x && it->y == point.y && it->z == point.z) {
334  points.erase(it);
335  break;
336  }
337  }
338  oss << point.x << " " << point.y << " " << point.z << std::endl;
339  }
340  oss << "e" << std::endl;
341  }
342 
343  // plot all unclustered points red
344  header << "'-' with points lc 'red' title 'noise'\n";
345  for (std::vector<pcl::PointXYZ,
346  Eigen::aligned_allocator<pcl::PointXYZ> >::iterator it =
347  points.begin();
348  it != points.end(); ++it) {
349  oss << it->x << " " << it->y << " " << it->z << std::endl;
350  }
351  oss << "e\n";
352 
353  oss << "pause mouse keypress\n";
354  std::cout << header.str() << oss.str();
355 }
356 
357 /*
358 @brief prints gnuplot output.
359 
360 This function prints a coloured cloud as gnuplot script to stdout.
361 
362 @param cloud the point cloud
363 @return vector of mean squared distances of every point in the cloud
364 */
365 void clustersToGnuplot(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud) {
366  // Method for gnuplot 4.6 with RGB vale from RGB Pointcloud
367  std::ostringstream oss;
368  oss << "set mouse\nrgb(r,g,b) = 65536 * int(r) + 256 * int(g) + int(b)\n";
369  oss << "splot '-' using 1:2:3:(rgb($4,$5,$6)) with points lc rgb variable\n";
370  for (pcl::PointCloud<pcl::PointXYZRGB>::iterator it = cloud->begin();
371  it != cloud->end(); ++it) {
372  oss << it->x << " " << it->y << " " << it->z << " ";
373  oss << (int)it->r << " " << (int)it->g << " " << (int)it->b << "\n";
374  }
375  oss << "e\n";
376  oss << "pause mouse keypress\n";
377  std::cout << oss.str();
378 }
379 
380 /*
381 @brief saves the smoothen cloud as gnuplot-file
382 
383 @param cloud the point cloud
384 @param fname filename
385 @return vector of mean squared distances of every point in the cloud
386 */
387 void debugGnuplot(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_smooth,
388  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
389  const char *fname = "debug_smoothed.gnuplot") {
390  // saves cloud in gnuplot file
391  std::ofstream of(fname);
392  pcl::PointXYZI min, max;
393  if (!of.is_open()) {
394  std::cerr << "Could Not save under '" << fname << std::endl;
395  ;
396  exit(1);
397  }
398  pcl::getMinMax3D(*cloud, min, max);
399  of << "set mouse\n";
400  of << "set xrange [" << min.x << ":" << max.x << "]\n";
401  of << "set yrange [" << min.y << ":" << max.y << "]\n";
402  of << "set zrange [" << min.z << ":" << max.z << "]\n";
403 
404  of << "splot '-' with points lc 'black' title 'original', '-' with points lc "
405  "'red' title 'smoothed'\n";
406  for (size_t i = 0; i < cloud->points.size(); ++i) {
407  pcl::PointXYZI point = cloud->points[i];
408  of << point.x << " " << point.y << " " << point.z << std::endl;
409  }
410  of << "e\n";
411 
412  for (size_t i = 0; i < cloud_smooth->points.size(); ++i) {
413  pcl::PointXYZI point = cloud_smooth->points[i];
414  of << point.x << " " << point.y << " " << point.z << std::endl;
415  }
416  of << "e\npause mouse keypress\n";
417 
418  of.close();
419 }
420 
421 /*
422 @brief Saves point cloud with clusters as csv
423 
424 This function saves a point cloud with clusterinformation in the following
425 format:
426  x,y,z,cluster
427 
428 @param cloud the point cloud
429 @param cluster the clusters
430 @param fname filename
431 @return vector of mean squared distances of every point in the cloud
432 */
433 void clustersToCSV(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
434  Cluster const cluster) {
435  std::vector<Point> points;
436 
437  for (size_t i = 0; i < cloud->points.size(); ++i) {
438  pcl::PointXYZ point = cloud->points[i];
439  points.push_back(Point(point));
440  }
441 
442  std::vector<pcl::PointIndicesPtr> clusters = cluster.getClusters();
443  for (size_t clusterIndex = 0; clusterIndex < clusters.size();
444  ++clusterIndex) {
445  pcl::PointIndicesPtr const &pointIndices = clusters[clusterIndex];
446  for (size_t i = 0; i < pointIndices->indices.size(); ++i) {
447  int index = pointIndices->indices[i];
448  points[index].clIds.push_back(clusterIndex);
449  }
450  }
451 
452  std::cout << "# Comment: a trackID of -1 represents noise\n# x, y, z, trackID\n";
453 
454  for (std::vector<Point>::iterator it = points.begin(); it != points.end();
455  ++it) {
456  std::cout << it->x << "," << it->y << "," << it->z << ",";
457  if (it->clIds.empty()) {
458  // Noise
459  std::cout << "-1\n";
460  } else {
461  for (size_t i = 0; i < it->clIds.size(); ++i) {
462  if (i > 0) {
463  std::cout << ";";
464  }
465  std::cout << it->clIds[i];
466  }
467  std::cout << std::endl;
468  }
469  }
470 }
471 
472 /*
473 @brief saves a point cloud as csv
474 
475 @param cloud the point cloud
476 @param fname filename
477 @return vector of mean squared distances of every point in the cloud
478 */
479 void cloudToCSV(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
480  const char *fname = "debug_smoothed.csv") {
481  // converts pointcloud to csv
482  std::ofstream of(fname);
483  if (!of.is_open()) {
484  std::cerr << "Could Not save under '" << fname << std::endl;
485  exit(1);
486  }
487  of << "# x,y,z" << std::endl;
488  for (size_t i = 0; i < cloud->points.size(); ++i) {
489  pcl::PointXYZI point = cloud->points[i];
490  of << point.x << "," << point.y << "," << point.z << std::endl;
491  }
492  of.close();
493 }
494 
495 int main(int argc, char **argv) {
496 #ifdef TIME
497  double time1 = 0.0, tstart;
498 #endif
499  // default values for command line options
500  char *infile_name = NULL, *outfile_name = NULL;
501  int opt_verbose = 0;
502  bool gnuplot = false, x11 = false;
503  hc_params opt_params;
504 
505  hc_params bestParams;
506  // AtTPC
507  // Skalierungsfaktor für das clustering
508  bestParams.cloudScaleModifier = 1.0;
509  // Radius zum glätten der Punkte
510  bestParams.smoothRadius = 7.0f;
511  // Anzal nächste Nachbarn um Triplets zu erzeugen
512  bestParams.genTripletsNnKandidates = 19;
513  // Anzahl bester Triplets, die aus der Kandidatenmenge übernommen werden
514  bestParams.genTripletsNBest = 3;
515  // Vermutung: Maximaler Winkel zwichen den Geraden AB und BC im Triplet.
516  bestParams.genTripletsMaxError = 0.015;
517  // Schwellwert für den besten Cluster Abstand.
518  // Darüber werden die Cluster nicht mehr vereinigt
519  bestParams.bestClusterDistanceDelta = 5.0; // Aymans: 2.0
520  // Schwellwert zum Entfernen aller Cluster,
521  // welche weniger Tripletten besitzen als angegeben.
522  bestParams.cleanupMinTriplets = 5;
523  opt_params = bestParams;
524 
525  // parse command line
526  for (int i = 1; i < argc; i++) {
527  if (0 == strcmp(argv[i], "-v")) {
528  ++i;
529  if (i < argc) {
530  opt_verbose = atoi(argv[i]);
531  } else {
532  std::cerr << usage << std::endl;
533  return 1;
534  }
535  } else if (0 == strcmp(argv[i], "-gnuplot")) {
536  gnuplot = true;
537  } else if (0 == strcmp(argv[i], "-s")) {
538  ++i;
539  if (i < argc) {
540  opt_params.cloudScaleModifier = atof(argv[i]);
541  } else {
542  std::cerr << usage << std::endl;
543  return 1;
544  }
545  } else if (0 == strcmp(argv[i], "-r")) {
546  ++i;
547  if (i < argc) {
548  opt_params.smoothRadius = atof(argv[i]);
549  } else {
550  std::cerr << usage << std::endl;
551  return 1;
552  }
553  } else if (0 == strcmp(argv[i], "-k")) {
554  ++i;
555  if (i < argc) {
556  opt_params.genTripletsNnKandidates = atoi(argv[i]);
557  } else {
558  std::cerr << usage << std::endl;
559  return 1;
560  }
561  } else if (0 == strcmp(argv[i], "-n")) {
562  ++i;
563  if (i < argc) {
564  opt_params.genTripletsNBest = atoi(argv[i]);
565  } else {
566  std::cerr << usage << std::endl;
567  return 1;
568  }
569  } else if (0 == strcmp(argv[i], "-a")) {
570  ++i;
571  if (i < argc) {
572  opt_params.genTripletsMaxError = atof(argv[i]);
573  } else {
574  std::cerr << usage << std::endl;
575  return 1;
576  }
577  } else if (0 == strcmp(argv[i], "-t")) {
578  ++i;
579  if (i < argc) {
580  opt_params.bestClusterDistanceDelta = atof(argv[i]);
581  } else {
582  std::cerr << usage << std::endl;
583  return 1;
584  }
585  } else if (0 == strcmp(argv[i], "-m")) {
586  ++i;
587  if (i < argc) {
588  opt_params.cleanupMinTriplets = atoi(argv[i]);
589  } else {
590  std::cerr << usage << std::endl;
591  return 1;
592  }
593  } else if (0 == strcmp(argv[i], "-o")) {
594  if (i + 1 == argc) {
595  std::cerr << "Not enough parameters\n" << usage << std::endl;
596  return 1;
597  } else if (argv[i + 1][0] == '-') {
598  std::cerr << "Please enter outfile name\n" << usage << std::endl;
599  return 1;
600  }
601  outfile_name = argv[++i];
602  } else if (0 == strcmp(argv[i], "-x11")) {
603  x11 = true;
604  } else if (argv[i][0] == '-') {
605  std::cerr << usage << std::endl;
606  return 1;
607  } else {
608  infile_name = argv[i];
609  }
610  }
611 
612  // plausibilty checks
613  if (!infile_name) {
614  std::cerr << "Error: no infile given!\n" << usage << std::endl;
615  return 1;
616  }
617  if (0 != access(infile_name, R_OK)) {
618  std::cerr << "Error: cannot read infile '" << infile_name << "'!\n" << usage << std::endl;
619  return 1;
620  }
621 
622 // load data
623 #ifdef TIME
624  tstart = clock();
625 #endif
626  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_xyzti(
627  new pcl::PointCloud<pcl::PointXYZI>());
628  pcl::io::loadPCDFile(std::string(infile_name), *cloud_xyzti);
629  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz(
630  new pcl::PointCloud<pcl::PointXYZ>());
631  pcl::copyPointCloud(*cloud_xyzti, *cloud_xyz);
632  if (cloud_xyz->size() == 0) {
633  std::cerr << "Error: empty cloud in file '" << infile_name << "'\n";
634  return 2;
635  }
636 #ifdef TIME
637  time1 = clock() - tstart;
638  std::cerr << "file loading time: " << time1 / CLOCKS_PER_SEC << "s"
639  << std::endl;
640 #endif
641 
642  if (opt_params.smoothRadius < 0.0) {
643  float fq = msd::first_quartile(cloud_xyz);
644  opt_params.smoothRadius = fq;
645  if (opt_verbose > 0) {
646  std::cout << "Computed smoothen radius: " << fq << std::endl;
647  }
648  }
649 // pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_filtered(new
650 // pcl::PointCloud<pcl::PointXYZI>()); pcl::PointCloud<pcl::PointXYZ>::Ptr
651 // cloud_outliner(new pcl::PointCloud<pcl::PointXYZ>());
652 
653 /*
654 // outliner removal
655 pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sorfilter(true);
656 sorfilter.setInputCloud(cloud_xyz);
657 sorfilter.setMeanK(12);
658 sorfilter.setStddevMulThresh(2.0);
659 sorfilter.filter(*cloud_filtered);
660 
661 // get removed indices
662 pcl::IndicesConstPtr indices_rem = sorfilter.getRemovedIndices();
663 pcl::ExtractIndices<pcl::PointXYZ> extract;
664 extract.setInputCloud(cloud_xyz);
665 extract.setIndices(indices_rem);
666 extract.setNegative(false);
667 extract.filter(*cloud_outliner);
668 */
669 
670 // smoothen cloud
671 #ifdef TIME
672  tstart = clock();
673 #endif
674  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_xyzti_smooth(
675  new pcl::PointCloud<pcl::PointXYZI>());
676 
677  // cloud_smooth = smoothenCloud(cloud_filtered, 12); // k nearest neighbour
678  cloud_xyzti_smooth =
679  smoothenCloud(cloud_xyzti, opt_params.smoothRadius); // radius
680 
681  if (opt_verbose > 0) {
682  cloudToCSV(cloud_xyzti_smooth);
683  debugGnuplot(cloud_xyzti_smooth, cloud_xyzti);
684  }
685 #ifdef TIME
686  time1 = clock() - tstart;
687  std::cerr << "smoothen time: " << time1 / CLOCKS_PER_SEC << "s" << std::endl;
688 #endif
689 
690  // calculate cluster
692  std::vector<hc::triplet> triplets;
693 
694 #ifdef TIME
695  tstart = clock();
696 #endif
697  triplets = hc::generateTriplets(
698  cloud_xyzti_smooth, opt_params.genTripletsNnKandidates,
699  opt_params.genTripletsNBest, opt_params.genTripletsMaxError);
700 #ifdef TIME
701  time1 = clock() - tstart;
702  std::cerr << "gen triplet time: " << time1 / CLOCKS_PER_SEC << "s"
703  << std::endl;
704 #endif
705 
706 #ifdef TIME
707  tstart = clock();
708 #endif
709  /*
710  cluster = useHc(cloud_xyzti_smooth, triplets, opt_params.cloudScaleModifier,
711  opt_params.bestClusterDistanceDelta,
712  opt_params.cleanupMinTriplets, opt_verbose);
713  */
714  cluster = use_hc(cloud_xyzti_smooth, triplets, opt_params.cloudScaleModifier,
715  opt_params.bestClusterDistanceDelta,
716  opt_params.cleanupMinTriplets, opt_verbose);
717 #ifdef TIME
718  time1 = clock() - tstart;
719  std::cerr << "clustering time: " << time1 / CLOCKS_PER_SEC << "s"
720  << std::endl;
721 #endif
722 
723  // create colours by clusters
724  std::vector<rgb_t> cluster_rgb = createClusterColour(cloud_xyz, cluster);
725 
726  if (gnuplot) {
727  clustersToGnuplot(cloud_xyz, cluster, cluster_rgb);
728  } else if (outfile_name) {
729  // redirect cout to outfile
730  std::streambuf *backup = std::cout.rdbuf();
731  std::ofstream of(outfile_name);
732  std::cout.rdbuf(of.rdbuf());
733  clustersToCSV(cloud_xyz, cluster);
734  std::cout.rdbuf(backup);
735  of.close();
736  } else if (x11) {
737  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_xyzrgb(
738  new pcl::PointCloud<pcl::PointXYZRGB>());
739  colorByCluster(cloud_xyz, cloud_xyzrgb, cluster, cluster_rgb);
740  // Visualization
741  pcl::visualization::PCLVisualizer viewer("PCL Viewer");
742  viewer.setPosition(0, 0);
743  viewer.setSize(800, 600);
744  viewer.setShowFPS(true);
745  viewer.setBackgroundColor(1.0, 1.0, 1.0);
746  viewer.setCameraPosition(0.0, 0.0, 2000.0, 0.0, 1.0, 0.0);
747 
748  if (opt_verbose > 2) {
749  visualizeTriplets(viewer, cloud_xyzti_smooth, triplets);
750  } else {
751  visualizeClusterAsMst(viewer, cloud_xyzti, cluster);
752  }
753  viewer.addPointCloud(cloud_xyzrgb, "cloud");
754  viewer.setPointCloudRenderingProperties(
755  pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "cloud");
756  if (opt_verbose > 2) {
757  viewer.setPointCloudRenderingProperties(
758  pcl::visualization::PCL_VISUALIZER_OPACITY, 0.75, "cloud");
759  }
760 
761  viewer.spin();
762  } else {
763  clustersToCSV(cloud_xyz, cluster);
764  }
765  return 0;
766 }
Point::Point
Point(pcl::PointXYZ point)
Definition: main.cpp:77
hc_params::genTripletsNnKandidates
size_t genTripletsNnKandidates
Definition: main.cpp:56
hc::triplet::pointIndexC
size_t pointIndexC
Definition: hc.h:18
scale
constexpr auto scale
Definition: AtHitCluster.cxx:15
mst::state::edges
std::vector< edge > edges
Definition: mst.h:15
clustersToCSV
void clustersToCSV(pcl::PointCloud< pcl::PointXYZ >::Ptr cloud, Cluster const cluster)
Definition: main.cpp:433
use_hc
Cluster use_hc(pcl::PointCloud< pcl::PointXYZI >::Ptr cloud, std::vector< hc::triplet > triplets, float scale, float cdist, size_t cleanup_min_triplets, int opt_verbose=0)
Definition: main.cpp:196
msd.h
clustersToGnuplot
void clustersToGnuplot(pcl::PointCloud< pcl::PointXYZ >::Ptr cloud, Cluster const cluster, std::vector< rgb_t > cluster_rgb)
Definition: main.cpp:301
rgb_t::g
uint8_t g
Definition: main.cpp:67
hc::triplet::pointIndexA
size_t pointIndexA
Definition: hc.h:16
f
double(* f)(double t, const double *par)
Definition: lmcurve.cxx:21
hc_params::cloudScaleModifier
float cloudScaleModifier
Definition: main.cpp:55
main
int main(int argc, char **argv)
Definition: main.cpp:495
hc_params::bestClusterDistanceDelta
float bestClusterDistanceDelta
Definition: main.cpp:61
usage
const char * usage
Definition: main.cpp:24
colorByIntensity
void colorByIntensity(pcl::PointCloud< pcl::PointXYZI >::ConstPtr cloud, pcl::PointCloud< pcl::PointXYZRGB >::Ptr cloud_rgb, float minIntensity=0.0f, float maxIntensity=4000.0f)
Definition: main.cpp:223
mst::state
Definition: mst.h:14
cloudToCSV
void cloudToCSV(pcl::PointCloud< pcl::PointXYZI >::Ptr cloud, const char *fname="debug_smoothed.csv")
Definition: main.cpp:479
Point::operator==
bool operator==(const Point &p) const
Definition: main.cpp:83
hc_params::smoothRadius
float smoothRadius
Definition: main.cpp:59
visualizeTriplets
void visualizeTriplets(pcl::visualization::PCLVisualizer &viewer, pcl::PointCloud< pcl::PointXYZI >::Ptr cloud, std::vector< hc::triplet > const &triplets)
Definition: main.cpp:88
hc_params::genTripletsMaxError
float genTripletsMaxError
Definition: main.cpp:60
hc::generateTriplets
std::vector< triplet > generateTriplets(pcl::PointCloud< pcl::PointXYZI >::ConstPtr cloud, size_t k, size_t n, float a)
Definition: hc.cxx:22
hc::cluster
std::vector< size_t > cluster
Definition: hc.h:25
Cluster
Definition: cluster.h:9
mst::edge
Definition: mst.h:8
hc_params::genTripletsNBest
size_t genTripletsNBest
Definition: main.cpp:57
hc::cleanupClusterGroup
cluster_group cleanupClusterGroup(cluster_group const &clusterGroup, size_t m)
Definition: hc.cxx:203
msd::first_quartile
float first_quartile(pcl::PointCloud< pcl::PointXYZ >::Ptr cloud)
Definition: msd.cxx:65
Point::x
float x
Definition: main.cpp:72
rgb_t
Definition: main.cpp:65
Point
Definition: main.cpp:71
mst::edge::voxelIndexA
size_t voxelIndexA
Definition: mst.h:9
mst::calculateMinimumSpanningTree
std::vector< state > calculateMinimumSpanningTree(pcl::PointCloud< pcl::PointXYZI >::ConstPtr cloud, MstMetric metric, MstFilter filter)
Definition: mst.cpp:38
hc_params::cleanupMinTriplets
size_t cleanupMinTriplets
Definition: main.cpp:58
Point::clIds
std::vector< int > clIds
Definition: main.cpp:75
hc_params
Definition: main.cpp:54
colorByCluster
void colorByCluster(pcl::PointCloud< pcl::PointXYZ >::ConstPtr cloud, pcl::PointCloud< pcl::PointXYZRGB >::Ptr cloud_rgb, Cluster const cluster, std::vector< rgb_t > const cluster_rgb)
Definition: main.cpp:240
hc.h
mst.h
rgb_t::b
uint8_t b
Definition: main.cpp:68
Point::y
float y
Definition: main.cpp:73
hc::compute_hc
cluster_group compute_hc(pcl::PointCloud< pcl::PointXYZI >::ConstPtr cloud, std::vector< triplet > const &triplets, ScaleTripletMetric triplet_metric, float t, int opt_verbose)
Definition: hc.cxx:139
hc_params::_padding
float _padding
Definition: main.cpp:62
mst::edge::voxelIndexB
size_t voxelIndexB
Definition: mst.h:9
rgb_t::r
uint8_t r
Definition: main.cpp:66
hc::triplet::pointIndexB
size_t pointIndexB
Definition: hc.h:17
createClusterColour
std::vector< rgb_t > createClusterColour(pcl::PointCloud< pcl::PointXYZ >::ConstPtr cloud, Cluster const cluster)
Definition: main.cpp:272
hc::toCluster
Cluster toCluster(std::vector< hc::triplet > const &triplets, hc::cluster_group const &clusterGroup, size_t pointIndexCount)
Definition: hc.cxx:216
colorByIndex
void colorByIndex(pcl::PointCloud< pcl::PointXYZ >::ConstPtr cloud, pcl::PointCloud< pcl::PointXYZRGB >::Ptr cloud_rgb)
Definition: main.cpp:208
visualizeClusterAsMst
void visualizeClusterAsMst(pcl::visualization::PCLVisualizer &viewer, pcl::PointCloud< pcl::PointXYZI >::Ptr cloud, Cluster const &cluster)
Definition: main.cpp:124
debugGnuplot
void debugGnuplot(pcl::PointCloud< pcl::PointXYZI >::Ptr cloud_smooth, pcl::PointCloud< pcl::PointXYZI >::Ptr cloud, const char *fname="debug_smoothed.gnuplot")
Definition: main.cpp:387
hc::triplet
Definition: hc.h:15
smoothenCloud
pcl::PointCloud< pcl::PointXYZI >::Ptr smoothenCloud(pcl::PointCloud< pcl::PointXYZI >::Ptr cloud, double r, bool useMedian)
Definition: smoothenCloud.cxx:15
hc::cluster_group
Definition: hc.h:27
smoothenCloud.h
Point::z
float z
Definition: main.cpp:74
hc::ScaleTripletMetric
Definition: hc.h:37