Concatenate the points of two Point Clouds
In this tutorial we will learn how to concatenate the points of two different point clouds. The constraint imposed here is that the type and number of fields in the two datasets have to be equal. We will also learn how to concatenate the fields (e.g., dimensions) of two different point clouds. The constraint imposed here is that the number of points in the two datasets has to be equal.
The code
First, create a file, let’s say, concatenate_clouds.cpp
in your favorite
editor, and place the following code inside it:
1#include <iostream>
2#include <pcl/point_types.h>
3#include <pcl/common/io.h> // for concatenateFields
4
5int
6 main (int argc, char** argv)
7{
8 if (argc != 2)
9 {
10 std::cerr << "please specify command line arg '-f' or '-p'" << std::endl;
11 exit(0);
12 }
13 pcl::PointCloud<pcl::PointXYZ> cloud_a, cloud_b, cloud_c;
14 pcl::PointCloud<pcl::Normal> n_cloud_b;
15 pcl::PointCloud<pcl::PointNormal> p_n_cloud_c;
16
17 // Fill in the cloud data
18 cloud_a.width = 5;
19 cloud_a.height = cloud_b.height = n_cloud_b.height = 1;
20 cloud_a.resize (cloud_a.width * cloud_a.height);
21 if (strcmp(argv[1], "-p") == 0)
22 {
23 cloud_b.width = 3;
24 cloud_b.resize (cloud_b.width * cloud_b.height);
25 }
26 else{
27 n_cloud_b.width = 5;
28 n_cloud_b.resize (n_cloud_b.width * n_cloud_b.height);
29 }
30
31 for (std::size_t i = 0; i < cloud_a.size (); ++i)
32 {
33 cloud_a[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
34 cloud_a[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
35 cloud_a[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
36 }
37 if (strcmp(argv[1], "-p") == 0)
38 for (std::size_t i = 0; i < cloud_b.size (); ++i)
39 {
40 cloud_b[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
41 cloud_b[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
42 cloud_b[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
43 }
44 else
45 for (std::size_t i = 0; i < n_cloud_b.size (); ++i)
46 {
47 n_cloud_b[i].normal[0] = 1024 * rand () / (RAND_MAX + 1.0f);
48 n_cloud_b[i].normal[1] = 1024 * rand () / (RAND_MAX + 1.0f);
49 n_cloud_b[i].normal[2] = 1024 * rand () / (RAND_MAX + 1.0f);
50 }
51 std::cerr << "Cloud A: " << std::endl;
52 for (std::size_t i = 0; i < cloud_a.size (); ++i)
53 std::cerr << " " << cloud_a[i].x << " " << cloud_a[i].y << " " << cloud_a[i].z << std::endl;
54
55 std::cerr << "Cloud B: " << std::endl;
56 if (strcmp(argv[1], "-p") == 0)
57 for (std::size_t i = 0; i < cloud_b.size (); ++i)
58 std::cerr << " " << cloud_b[i].x << " " << cloud_b[i].y << " " << cloud_b[i].z << std::endl;
59 else
60 for (std::size_t i = 0; i < n_cloud_b.size (); ++i)
61 std::cerr << " " << n_cloud_b[i].normal[0] << " " << n_cloud_b[i].normal[1] << " " << n_cloud_b[i].normal[2] << std::endl;
62
63 // Copy the point cloud data
64 if (strcmp(argv[1], "-p") == 0)
65 {
66 cloud_c = cloud_a;
67 cloud_c += cloud_b;
68 std::cerr << "Cloud C: " << std::endl;
69 for (std::size_t i = 0; i < cloud_c.size (); ++i)
70 std::cerr << " " << cloud_c[i].x << " " << cloud_c[i].y << " " << cloud_c[i].z << " " << std::endl;
71 }
72 else
73 {
74 pcl::concatenateFields (cloud_a, n_cloud_b, p_n_cloud_c);
75 std::cerr << "Cloud C: " << std::endl;
76 for (std::size_t i = 0; i < p_n_cloud_c.size (); ++i)
77 std::cerr << " " <<
78 p_n_cloud_c[i].x << " " << p_n_cloud_c[i].y << " " << p_n_cloud_c[i].z << " " <<
79 p_n_cloud_c[i].normal[0] << " " << p_n_cloud_c[i].normal[1] << " " << p_n_cloud_c[i].normal[2] << std::endl;
80 }
81 return (0);
82}
The explanation
Now, let’s break down the code piece by piece.
In lines:
pcl::PointCloud<pcl::PointXYZ> cloud_a, cloud_b, cloud_c;
pcl::PointCloud<pcl::Normal> n_cloud_b;
pcl::PointCloud<pcl::PointNormal> p_n_cloud_c;
// Fill in the cloud data
cloud_a.width = 5;
cloud_a.height = cloud_b.height = n_cloud_b.height = 1;
cloud_a.resize (cloud_a.width * cloud_a.height);
if (strcmp(argv[1], "-p") == 0)
{
cloud_b.width = 3;
cloud_b.resize (cloud_b.width * cloud_b.height);
}
else{
n_cloud_b.width = 5;
n_cloud_b.resize (n_cloud_b.width * n_cloud_b.height);
}
for (std::size_t i = 0; i < cloud_a.size (); ++i)
{
cloud_a[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_a[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_a[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
if (strcmp(argv[1], "-p") == 0)
for (std::size_t i = 0; i < cloud_b.size (); ++i)
{
cloud_b[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_b[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_b[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
else
for (std::size_t i = 0; i < n_cloud_b.size (); ++i)
{
n_cloud_b[i].normal[0] = 1024 * rand () / (RAND_MAX + 1.0f);
n_cloud_b[i].normal[1] = 1024 * rand () / (RAND_MAX + 1.0f);
n_cloud_b[i].normal[2] = 1024 * rand () / (RAND_MAX + 1.0f);
}
we define the five Point Clouds for use in concatenating clouds: three inputs (cloud_a, cloud_b and n_cloud_b), two outputs (cloud_c and p_n_cloud_c). Then we fill in the data for the two input point clouds we are using (for points cloud_a and cloud_b, for fields cloud_a and n_cloud_b).
Then, lines:
std::cerr << "Cloud A: " << std::endl;
for (std::size_t i = 0; i < cloud_a.size (); ++i)
std::cerr << " " << cloud_a[i].x << " " << cloud_a[i].y << " " << cloud_a[i].z << std::endl;
std::cerr << "Cloud B: " << std::endl;
if (strcmp(argv[1], "-p") == 0)
for (std::size_t i = 0; i < cloud_b.size (); ++i)
std::cerr << " " << cloud_b[i].x << " " << cloud_b[i].y << " " << cloud_b[i].z << std::endl;
else
for (std::size_t i = 0; i < n_cloud_b.size (); ++i)
std::cerr << " " << n_cloud_b[i].normal[0] << " " << n_cloud_b[i].normal[1] << " " << n_cloud_b[i].normal[2] << std::endl;
display the content of cloud_a and either cloud_b or n_cloud_b (depending on the command line argument) to screen.
If we are trying to concatenate points then the code below:
cloud_c = cloud_a;
cloud_c += cloud_b;
creates cloud_c by concatenating the points of cloud_a and cloud_b together.
Otherwise if we are attempting to concatenate fields then the code below:
pcl::concatenateFields (cloud_a, n_cloud_b, p_n_cloud_c);
creates p_n_cloud_c by concatenating the fields of cloud_a and cloud_b together.
Finally either:
std::cerr << "Cloud C: " << std::endl;
for (std::size_t i = 0; i < cloud_c.size (); ++i)
std::cerr << " " << cloud_c[i].x << " " << cloud_c[i].y << " " << cloud_c[i].z << " " << std::endl;
or
std::cerr << "Cloud C: " << std::endl;
for (std::size_t i = 0; i < p_n_cloud_c.size (); ++i)
std::cerr << " " <<
p_n_cloud_c[i].x << " " << p_n_cloud_c[i].y << " " << p_n_cloud_c[i].z << " " <<
p_n_cloud_c[i].normal[0] << " " << p_n_cloud_c[i].normal[1] << " " << p_n_cloud_c[i].normal[2] << std::endl;
is used to show the content of cloud_c or p_n_cloud_c to the screen depending on if we concatenated the points or fields of the PointClouds.
Compiling and running the program
Add the following lines to your CMakeLists.txt file:
1cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
2
3project(concatenate_clouds)
4
5find_package(PCL 1.2 REQUIRED)
6
7include_directories(${PCL_INCLUDE_DIRS})
8link_directories(${PCL_LIBRARY_DIRS})
9add_definitions(${PCL_DEFINITIONS})
10
11add_executable (concatenate_clouds concatenate_clouds.cpp)
12target_link_libraries (concatenate_clouds ${PCL_LIBRARIES})
After you have made the executable, you can run it. Simply do:
$ ./concatenate_clouds -p
to concatenate points or do:
$ ./concatenate_clouds -f
to concatenate fields.
You will see something similar to if concatenating points:
Cloud A:
0.352222 -0.151883 -0.106395
-0.397406 -0.473106 0.292602
-0.731898 0.667105 0.441304
-0.734766 0.854581 -0.0361733
-0.4607 -0.277468 -0.916762
Cloud B:
0.183749 0.968809 0.512055
-0.998983 -0.463871 0.691785
0.716053 0.525135 -0.523004
Cloud C:
0.352222 -0.151883 -0.106395
-0.397406 -0.473106 0.292602
-0.731898 0.667105 0.441304
-0.734766 0.854581 -0.0361733
-0.4607 -0.277468 -0.916762
0.183749 0.968809 0.512055
-0.998983 -0.463871 0.691785
0.716053 0.525135 -0.523004
and similar to this if concatenating fields:
Cloud A:
0.352222 -0.151883 -0.106395
-0.397406 -0.473106 0.292602
-0.731898 0.667105 0.441304
-0.734766 0.854581 -0.0361733
-0.4607 -0.277468 -0.916762
Cloud B:
0.183749 0.968809 0.512055
-0.998983 -0.463871 0.691785
0.716053 0.525135 -0.523004
0.439387 0.56706 0.905417
-0.579787 0.898706 -0.504929
Cloud C:
0.352222 -0.151883 -0.106395 0.183749 0.968809 0.512055
-0.397406 -0.473106 0.292602 -0.998983 -0.463871 0.691785
-0.731898 0.667105 0.441304 0.716053 0.525135 -0.523004
-0.734766 0.854581 -0.0361733 0.439387 0.56706 0.905417
-0.4607 -0.277468 -0.916762 -0.579787 0.898706 -0.504929