Shapes as point clouds
Read these first if they are new to you
- Vectors: arrows made of numbers Basic
- Arrays in NumPy Intermediate
The idea in one paragraph
A point cloud describes a shape by a list of points on it or inside it. Each point is three numbers, its x, y and z coordinates. The list has no special order: shuffle it and you still have the same shape. The number of points is a choice. More points show more detail and cost more memory. A point cloud stores only where the shape is, so it stays small even for a long, thin object in a big space.
A point cloud is a table of points, one row per point
Picture a donut dusted with flour. Each grain of flour sits at one spot on the surface. If you write down where every grain sits, you can draw the donut again from that list alone. That list is a point cloud: a set of points that together show a shape.
Each point is a position in space, written as three numbers (see vectors).
So a point cloud with N points is a table with N rows and 3 columns. In Python this table
is an array of shape (N, 3) (see arrays in NumPy).
Before you use the viewer below, guess: how many points do you need before you can tell that the shape is a donut?
With a few hundred points the hole becomes clear. With a few thousand the surface looks smooth. The shape did not change. Only the number of samples did.
The order of the rows does not matter
The table lists the points in some order, but the order carries no meaning. Swap two rows and the shape stays the same. So a point cloud is really a set: a collection where only membership counts, not position in a list.
This fact shapes every program that reads point clouds. A program should give the same answer for both numberings above. A function with that property is called permutation invariant; the unit order doesn't matter explains how a model can have it.
A point cloud stores only where the shape is
Another way to store a shape is a 3D grid of tiny boxes that are each full or empty (see voxels). A grid spends memory on every box, including all the empty space around the shape. A point cloud spends memory only on the shape itself.
A program stores each coordinate as a 32-bit decimal number, which takes 4 bytes.
- A point cloud of 2,048 points has 2,048 × 3 = 6,144 numbers.
- That takes 6,144 × 4 = 24,576 bytes, about 25 kilobytes.
- A grid of 256 × 256 × 256 boxes, at 1 byte per box, takes 16,777,216 bytes, about 17 megabytes.
- The grid is 16,777,216 ÷ 24,576 ≈ 683 times larger.
The gap grows for thin shapes, such as a long wire, because most of the grid is then empty.
The price is that a point cloud has a fixed level of detail. Between two points, it says nothing. If a part of the shape is thinner than the gap between points, that part can vanish. Programs often choose a fixed number of points per shape, spread evenly; farthest-point sampling is one way to choose them.
Here each point holds only a position. Real point clouds often carry more numbers per row, such as a color, a brightness, or the direction the surface faces at that point (its normal). Also, some point clouds sample only the surface of a shape, while others fill its inside. Which one you have depends on how the points were made.
In NumPy, a point cloud is an array with three columns
This snippet builds the eight corners of a cube as a point cloud, shuffles the rows, and checks that the shape is unchanged.
point_clouds.py
import numpy as np
# The 8 corners of a cube with side 2, centered at the origin.
# Each corner takes x, y and z from (-1, 1); dtype=float stores them as decimals.
cloud = np.array([[x, y, z] for x in (-1, 1) for y in (-1, 1) for z in (-1, 1)], dtype=float)
print(cloud.shape)
rng = np.random.default_rng(0)
shuffled = cloud[rng.permutation(len(cloud))] # the same points, rows in a new order
print(cloud[0], shuffled[0]) # the first rows differ
print(cloud.mean(axis=0), shuffled.mean(axis=0)) # the center does not
# np.array_equal: do the two sorted lists of rows match?
print(np.array_equal(np.unique(cloud, axis=0), np.unique(shuffled, axis=0)))
(8, 3)
[-1. -1. -1.] [-1. 1. -1.]
[0. 0. 0.] [0. 0. 0.]
True
The center, the mean of all the points, does not depend on the order. Neither does the sorted list of rows
that np.unique returns. Both are examples of permutation-invariant summaries.
Check yourself
-
A point cloud has 4,096 points with only x, y, z per point. What is the shape of its NumPy array, and how many bytes does it take at 4 bytes per number?
Answer
The shape is
(4096, 3). It holds 4,096 × 3 = 12,288 numbers, so it takes 12,288 × 4 = 49,152 bytes. -
A program reads a point cloud and reports the coordinates of its first row as "the tip of the shape." What is wrong with that?
Answer
The first row is not special. Shuffling the rows gives the same shape but a different first row, so the program would report a different "tip." A useful answer must not depend on the order of the rows.
-
You sample a thin wire, 1 unit long, with points spaced about 0.1 units apart. The wire has a gap of 0.02 units in the middle. Will the point cloud show the gap?
Answer
Probably not. The gap is much smaller than the spacing between points, so the two sides look continuous. To see the gap, you need points spaced closer than 0.02 units near it.
Go further
Optional background. This unit covers what you need here.
-
Load a real point cloud in Python, view it, and thin it out; the later sections show normals and cropping.
-
How a machine-learning library loads shapes as point clouds and samples a fixed number of points from each.
-
PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation Qi, Su, Mo and Guibas, 2017 Paper Advanced
The paper that made "a point cloud is an unordered set" the starting point for neural networks on points.
Where this shows up
Units that build on this one
- Farthest-point sampling Intermediate
- Connectomics: mapping neurons from images Intermediate
- Data augmentation: new views of an example Intermediate
- Shape completion: generating the missing part Intermediate
- Order doesn't matter: permutation invariance Intermediate