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.

Getting PCL up and running

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.

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.

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).

brew install pcl

Making a PCL project

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

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

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

#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

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.

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.

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:

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.

./myPCL test.pcd

Our output should look like

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 here. 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.

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.

#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:

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.

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

The same is done in our print out line.

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

To visualize the cloud, we need a PCLVisualizer.

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:

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:

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.

 

Leave a Reply