Discover 3D Point Cloud Processing with Python
By: Florent Poux
Tags: Matplotlib, 3d, Numpy, Python, Point Cloud

5-Step Guide to set-up your python environment

We need to set-up our environment. I recommend to download Anaconda Navigator, which comes with an easy GUI.

Once downloaded and installed, create an environment (2nd tab on the left > Create button), which allows you to specify a python version (the latest is fine). You know it is selected when the green arrow is next to it.

Anaconda GUI — Manage independent projects through environments with different libraries / Python versions

Once created, you can then link wanted libraries without conflicts. Very handy! For this, just search packages in what is installed (E.g. NumPy, Matplotlib), and if it is not popping, then select Not installed, check them both and click on Apply to install them. Numpy and Matplotlib are standard libraries that will be useful for this and future projects.

Searching for libraries in the conda library package manager

You are almost set-up, now back to the Anaconda Home Tab, make sure you are in the right environment (Applications on XXX), then you can install Spyder as the IDE (Integrated Development Environment)to start your code project.

🤓 Note: Spyder is one of the best tools for any amateur who is new to python coding. Another great tool is Jupyter, which does a great job of presenting interactive code to higher management for better visualization. We will explore this as well as Google Colab on future posts.

Once the installation progress bar is done you are ready! You can now launch Spyder. While the GUI may allow several possibilities, to directly obtain results, first write your script (1), execute your script (2) and explore + interact with results in the console (3).

The 3 basic elements of the Spyder Python interface

Download your point cloud dataset

For future experiments, we will use a sampled point cloud that you can freely download from this repository. If you want to visualize it beforehand without installing anything, you can check the webGL version.

3D Point Cloud of a statue from the Glyptotek Museum in Copenhagen, reconstructed with Photogrammetry. The acquisition of the dataset extends the scope of the article and will be covered in a separate post. If you want to learn such techniques, you can visit the Geodata Academy and 3D Reconstructor.

Your first lines of code

In Sypder, let us start by using a very powerful library: NumPy. You can already write your first shortcode in the script area (left window):

1 import numpy as np

2 file_data_path=”E:\sample.xyz”

3 point_cloud= np.loadtxt(file_data_path, skiprows=1, max_rows=1000000)

This shortcode (1) import the library NumPy for further use as a short name “np”; (2) create a variable that holds the string pointing to the file that contains the points; (3) import the point cloud as a variable named point_cloud, skipping the first row (holding, for example, the number of points), and setting a maximal number of rows to run tests without memory shortages.

You can now run your script (green arrow), and save it as a .py file on your hard-drive when the pop-up appears. You can now access the first point of the entity that holds your data (point_cloud) by directly writing in the console:

In: point_cloud[0]

You will then get an array containing the content of the first point, in this case, X, Y and Z coordinates.

Out: array([0.480, 1.636, 1.085])

These were your first steps with python and point clouds. Now that you know how to load point data, let us look at some interesting processes.

Extracting desired attributes

We have a point cloud with 6 attributes: X, Y, Z, R, G, B. It is important to note that when playing with NumPy arrays, the indexes always start at 0. So, if loaded without field names, then getting the second point is done doing:

In: point_cloud[1]

Out: array([0.480, 1.636, 1.085, 25, 44, 68])

If from there we want to obtain the Red (R) attribute (the NumPy “column” index is 3), we can do:

In: point_cloud[1][3]

Out: 25

If we want to extract the Z attribute for all the points in the point cloud:

In: point_cloud[:,1]

Out: array([2.703, 2.716, 2.712, …, 2.759, 2.741, 2.767])

If we want to extract only X, Y, Z attributes for all the points:

In: point_cloud[:,:3]

Out: array([[4.933, 2.703, 2.194],

[4.908, 2.716, 2.178],

[4.92 , 2.712, 2.175],

…,

[5.203, 2.759, 0.335],

[5.211, 2.741, 0.399],

[5.191, 2.767, 0.279]])

Congratulations, you just played around with multi-dimensional indexing 👏. Note that in the example above :3] , the third column (R) is excluded from the selection. Each result can be stored in variables if they are meant to be used more than one time:

xyz=point_cloud[:,:3]

rgb=point_cloud[:,3:]

Attribute-based data analysis

Now let us look at some useful analysis. If you want to know the mean height of your point cloud, then you can easily do:

In: np.mean(point_cloud,axis=0)[2]

Out: 2.6785763

💡 Hint: here, the axis set to 0 is asking to look at each “column” independently. If ignored, then the mean run on all the values, and if set to 1, it will average per row.

If now you want to extract points which are within a buffer of 1 meter from the mean height (we assume the value is stored in mean_Z):

In: point_cloud[abs( point_cloud[:,2]-mean_Z)<1]

Out: array([…])

💡 Hint: In python, and programming in general, there is more than one way to solve a problem. The provided is a very short and efficient way, which may not be the most intuitive. Trying to solve it using a for loop is a great exercise. The aim is a good balance between clarity and efficiency, see the PEP-8 guidelines.

Now you know how to set-up your environment, use Python, Spyder GUI and NumPy for your coding endeavors. You can load point clouds and play with attributes, but you can try other scenarios such as color filtering, point proximities …