Playing with the Point Cloud Library

Point Cloud Library, often abbreviated PCL, is an open source library for converting point clouds into meshes. I’ve been working with this library for the past six months in order to reconstruct structures based on drone footage.

It hasn’t been the easiest thing to setup PCL on my MacBook but when I got it working it has been fantastic. Here is a small introduction to installing PCL and making your first program.

> More examples will be uploaded to my github page.

To use PCL in projects, we need to compile it from the source. PCL has a good descriptions of how to do this on their website.

This is first done by downloading the source from github. Then move it to a working directory and extract it.

1
tar xvfj pcl-pcl-1.7.2.tar.gz

> If you are using a Windows computer download 7-zip or another program to etract the tar file.

This will leave a directory names `pcl-pcl-1.7.2` which we need to go to. Also in that folder we need to make a new directory for our build. This can all be done by running a single line in the terminal.

1
cd pcl-pcl-1.7.2 && mkdir build && cd build

> On Windows make sure you have `cmake`, `make` and `boost` installed. This can be problematic, it should be easier to get all of them to work if you have Visual Studio as your C++ compiler compared to just MinGW. But I haven’t made it work on Windows yet.

Now we need to run `cmake ..` to setup the build and then compile it using `make`. After the compiling is done (this can take a long time), run `make install` to finish the installation.

If a Mac is used to, it is also possible to install PCL using Homebrew (this is the way I did it).

1
brew install pcl

To incorporate PCL into ones own project we need to make a working directory and place two files in it.

1
2
mkdir myPCL && cd myPCL
touch myPCL.cpp && touch CMakeLists.txt

In the `myPCL.cpp` file we have our code, this can look something like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

int main(int argc, char const *argv[]) {

  pcl::PointCloud<pcl::PointXYZ> cloud;
  pcl::io::loadPCDFile(argv[1],cloud);

  std::cerr << "Read cloud: " << std::endl;
  std::cerr << cloud << std::endl;

  return 0;
}

`cerr` and `cout` is basically the same, just two different output places, so logging data from `cerr` will not get logged together with data from `cout`.

This program should load a PLY file and output the information. This can later be used for eg. conversion into pcd or something else. For now, we just want to see if the file can be loaded.

The second file needed is CMakeLists which is used when compiling the program.

The CMakeLists should look something like:

1
2
3
4
5
6
7
8
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
project(MY_PCL_PROJECT)
find_package(PCL 1.3 REQUIRED COMPONENTS common io)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable(myPCL myPCL.cpp)
target_link_libraries(myPCL ${PCL_COMMON_LIBRARIES} ${PCL_IO_LIBRARIES})

With both files creates we are ready to start compiling the program. Let’s make a build directory and work from that.

1
mkdir build && cd build

In the build folder we can run `cmake ..` to compile using the above folder (not build, but myPCL). This shouldn’t take long and afterwards we run `make` to finish the compiling.

After compiling is done we can run the program. This program requires us to use a pdc file for reading, so let’s make on of those.

1
touch test.pcd

> On windows just make a new file in your text editor, if you don’t have touch installed.

Open the file and add:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
VERSION .5
FIELDS x y z
SIZE 4 4 4
TYPE F F F
COUNT 1 1 1
WIDTH 9
HEIGHT 1
POINTS 9
DATA ascii
0.0054216 0.11349 0.040749
-0.0017447 0.11425 0.041273
-0.010661 0.11338 0.040916
0.026422 0.11499 0.032623
0.024545 0.12284 0.024255
0.034137 0.11316 0.02507
0.02886 0.11773 0.027037
0.02675 0.12234 0.017605
0.03575 0.1123 0.019109

Save the file and now we are ready to run our program.

1
./myPCL test.pcd

Our output should look like:

1
2
3
4
5
6
Read cloud:
points[]: 9
width: 9
height: 1
is_dense: 1
sensor origin (xyz): [0, 0, 0] / orientation (xyzw): [0, 0, 0, 1]

Now we have a `PointCloud` called `cloud` that we can work on further in the program.

Now let’s try and see how the cloud cloud looks. The file we have been using so far is pretty boring, so let’s download a better file. A pcd version of the Stanford Bunny can be found online. Place the bunny.pcd file in the build folder.

We need to change a few things in the `CMakeLists` file. With the previous file we were only using `common` and `io` but we also want to use a few other libraries, so let’s remove the restrictions and just use all the libraries.

1
2
3
4
5
6
7
8
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(MY_PCL_PROJECT)
find_package(PCL 1.7 REQUIRED COMPONENTS)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable(myPCL myPCL.cpp)
target_link_libraries(myPCL ${PCL_LIBRARIES})

I’ve also updated it to require PCL 1.7, so we don’t get any compatability errors with 1.6.

In our `myPCL.cpp` file we need to include two more libraries.

1
2
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>

Boost is used to create extra threads to run the applicaiton. Previously we just had `cloud` as a variable of type `pcl::PointCloud<pcl::PointXYZ>` but to visualize the point cloud we need to use a pointer of the cloud. This is done by writing:

1
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

That also means in the `loadPCDFile` we need to add an asterisk in frot of the cloud variable.

1
pcl::io::loadPCDFile(argv[1],*cloud);

The same is done in our print out line.

1
std::cerr << *cloud << std::endl;

To visualize the cloud, we need a PCLVisualizer.

1
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("Viewer"));

There are a few different properties in the viewer, which are setup like this:

1
2
3
4
viewer->setBackgroundColor (0, 0, 0);
viewer->addPointCloud<pcl::PointXYZ> (cloud, "sample cloud");
viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->initCameraParameters ();

To make sure the viewer doesn’t quit on us, we need:

1
2
3
4
while(!viewer->wasStopped()) {
  viewer->spinOnce(100);
  boost::this_thread::sleep (boost::posix_time::microseconds (100000));
}

We can now compile and run the program and see the point cloud in the viewer.