Skip to the lesson
FixTheRobot Explore Robotics / Perception / P5 3D Perception and Point Clouds / P5-T1

Perception · Theory · P5

P5-T1 — 3D Point-Cloud Representations

A point cloud is a list of points. Everything useful about it is in how you organise that list.

  • Lesson 1 of 6
  • Module 5: 3D Perception and Point Clouds
  • Theory
  • About 10 minutes to read

A LiDAR or depth camera produces a long list of 3D points. The list has no order that matches the geometry, no sense of what is free space, and no memory of which points are neighbours. To find the ground, separate objects or measure them, a program first organises the points into a structure where such questions are cheap. This lesson compares the common ones (raw points, range images, voxel grids, height maps, meshes), shows how to convert between them and what each conversion costs, and ties them to the point-cloud labs in the Sensors track, which this module builds on.

Learning objectives

After this lesson, you should be able to:

  • Describe raw points, range images, voxel grids, height maps and meshes and what each makes easy.
  • Compute the voxel index of a point, the effect of voxel downsampling and its quantisation error.
  • Explain how a k-d tree speeds up neighbour search and when a range image avoids the need for one.
  • Estimate the memory and data rate of a LiDAR and of a dense grid, and choose a representation for a task.

The idea: structure turns a pile of points into answers

Handed a bag of one hundred thousand 3D points, questions like “what is near this point?”, “is the space ahead free?” or “where is the ground?” all require a search through the whole bag. Organising the points avoids that. The right organisation depends on the question.

Four representations of the same pointsFour square panels. First: raw points scattered in a plane. Second: a regular grid of pixels, a range image, where each cell holds a distance. Third: a voxel grid where the cells that contain points are filled. Fourth: a height map where each ground cell holds a column height.raw points range image27538642 voxel grid height map (top view)12313123231231231212313123 Each form keeps something and discards something else.
The same measurements in four forms. A raw point list is complete but unordered; a range image keeps the sensor’s own grid; a voxel grid trades detail for fixed memory and quick lookup; a height map drops the vertical dimension to make ground reasoning simple.
Representations of 3D data, what they make easy and what they hide
RepresentationWhat it isEasyHard or lost
Raw pointsN × 3 list (plus intensity, ring, time)Exact positions; any geometry; no information lossNeighbour search (needs a structure); free space; ordering
Range image (organised cloud)A grid of ranges indexed by ring and azimuth (like a depth image)Neighbours are neighbouring pixels; image methods apply; fast ground and edge testsOnly what one sensor sees; moving sensor distortion; merging several sensors
Voxel gridA 3D grid of cells that are occupied, free or unknownFixed memory, constant-time lookup, downsampling, free-space queriesDetail below the voxel size; large memory if dense; resolution trade-off
Height map / bird’s-eye view (BEV)A 2D grid with a height (or statistics) per cellGround and obstacle reasoning for wheeled robots; image-like networksOverhangs, multiple levels, the vertical structure
Mesh / surfels / signed distanceSurfaces fitted to the pointsSmooth surfaces, rendering, contact reasoningCost; assumes continuous surfaces; fails on thin or noisy data

Choose the representation for the question, and keep the raw points while you can: every other form is derived from them and cannot be turned back.

How this relates to the Sensors labs

The Sensors track already has three labs on point clouds: understanding and visualising a point cloud, cleaning, filtering, transforming and downsampling it and detecting obstacles and deciding to stop. This module does not repeat them. It adds local geometry (normals, planarity), robust ground estimation on slopes and range-aware clustering with oriented boxes, and the reasons behind each.

The mathematics: voxels, neighbours and size

Voxel index and downsampling

A voxel grid of side s assigns a point p = (x, y, z) to the cell

voxel index
(i, j, k)=(⌊xs⌋, ⌊ys⌋, ⌊zs⌋)(i,\,j,\,k)=(\frac{\lfloor x}{s\rfloor },\,\frac{\lfloor y}{s\rfloor },\,\frac{\lfloor z}{s\rfloor })

Downsampling replaces all points in a cell by one, usually their centroid. The representative is then at most about s√3/2 ≈ 0.87 s from any original point (the half-diagonal of the cell), and for points spread uniformly in the cell the root-mean-square position error per axis is

quantisation error of a voxel
σquantisation=s12≈0.29 s\sigma _{\text{quantisation}}=\frac{s}{\sqrt{12}}\approx 0.29\,\mathrm{s}
per axis, for a point placed at the cell centre
s
the voxel side length in metres: the resolution of the representation.
⌊·⌋
the floor function: round down to an integer.
(i, j, k)
the integer cell coordinates; stored in a hash table so that only occupied cells use memory.
σquantisation
the error introduced by replacing points with a cell representative, small when s is smaller than the sensor noise.

Neighbour search

The k nearest neighbours or all points within radius r of a query are needed for normals, clustering and filtering. Brute force costs O(N) per query, so O(N2) for all points. A k-d tree recursively splits the points by the median along one axis, so a query visits about O(log N) nodes; building it costs O(N log N). A voxel hash gives constant-time lookup of the 27 cells around a point when the radius is about one voxel. An organised cloud (range image) needs no structure: the neighbours of pixel (u, v) are the pixels around it, though a neighbouring pixel can be far in 3D across a depth edge.

Data rate and memory

A sensor with R rings and A azimuth steps at f sweeps per second produces

LiDAR data rate
points per second=R⋅A⋅f\text{points per second}=R\cdot A\cdot f
bytes per second≈points per second×bytes per point(typically 16: x, y, z, intensity as 4−byte floats)\text{bytes per second}\approx \text{points per second}\times \text{bytes per point}(\text{typically}\,16:\,x,\,y,\,z,\,\text{intensity as}\,4-\text{byte floats})

A dense 3D grid over a volume X × Y × Z with side s has X·Y·Z/s3 cells: halving the voxel size multiplies the memory by eight. Real maps are sparse (most space is empty), which is why hash tables, octrees and sparse voxel structures are used.

A worked example: how much data, and how much does downsampling lose?

A LiDAR has 64 rings and 1024 azimuth steps per revolution at 10 Hz.

data rate of the example LiDAR
points per sweep=64×1024=65, 536\text{points per sweep}=64\times 1024=65,\,536
points per second=65, 536×10=655, 360\text{points per second}=65,\,536\times 10=655,\,360
data rate≈655, 360×16 bytes=10.5 MB/s\text{data rate}\approx 655,\,360\times 16\,\text{bytes}=10.5\,\mathrm{MB}/\mathrm{s}

655,360 points per second is more than a robot’s planner or a low-power processor can handle if every point is used, so the cloud is almost always downsampled first. A voxel filter of side 0.2 m keeps far fewer points; how many fewer depends strongly on the scene, because nearby surfaces are dense and many of their points fall into the same voxel, while distant surfaces are sparse and each point tends to fall into its own voxel.

Quantisation

With voxels of 0.2 m, the error introduced by taking the cell centre is 0.2 / √12 = 5.8 cm per axis. With voxels of 0.02 m it is 0.58 cm. The sensor’s own range noise (about 2 to 3 cm) is the natural scale: a voxel much finer than the noise stores noise, and one much coarser throws away measured detail. If the centroid of the points in the cell is used instead of the centre, the error is smaller for cells that hold many points.

Dense grid memory

A grid covering 100 m × 100 m × 10 m at 0.2 m has 12,500,000 cells; at 0.1 m it has 100,000,000 cells (eight times more). At one byte per cell the 0.1 m grid takes 100 MB, and at one bit per cell about 13 MB. A typical outdoor scan fills only a small fraction of those cells, so a sparse structure that stores only the occupied ones is the practical choice.

Choosing for the task

Matching representation to task
TaskA good representationWhy
Finding the ground and obstacles for a wheeled robotRange image or height mapNeighbours and slopes are cheap; 2.5D is enough
Clustering objectsRaw points with a k-d tree, or a BEV gridNeeds distances between points
Checking whether a path is freeOccupancy grid (with unknown)Constant-time lookup; free versus unknown
Building a map over timeVoxel hash or octreeFixed memory per area; incremental update
Measuring one objectRaw points of the objectNo quantisation; full precision

Engineering implications and limitations

Keep timestamps and ring indices. A raw LiDAR point carries its acquisition time and ring. The time lets you correct the distortion caused by the robot moving during the sweep (motion compensation); the ring and azimuth let you rebuild the range image. Dropping them early forecloses both.

Downsample once, early, with a stated resolution. Choose a voxel size from the noise and the smallest object that matters, document it, and keep the raw data in the log. Each stage that downsamples again compounds the loss.

Use sparse structures. Hash tables, octrees and k-d trees keep memory and time proportional to what is occupied. Dense 3D arrays are fine for small local grids and fatal for maps.

Represent unknown space. Points record where something was hit; they say nothing about free or unknown space (Lesson P1-T5). If a decision depends on free space, build an occupancy structure that traces rays and has an unknown state.

Mind the frame. Every representation is defined in a frame: sensor, base or world. Merging clouds from several sensors or times needs the transforms of Lesson P1-T4 and accurate timestamps (Module 8).

Measure before optimising. Profile the pipeline: often the neighbour search, not the geometry, takes the time, and a coarser voxel or a range-image shortcut removes the bottleneck.

Common misconceptions

“A point cloud is a map.”

It is a set of points from one or more sweeps. It has no notion of free or unknown space and grows without bound. A map is a managed, bounded structure built from clouds.

“A finer voxel grid is always more accurate.”

Below the sensor noise it stores noise, and memory grows with the cube of the resolution. The voxel size should match the noise and the task.

“Neighbouring pixels in a range image are neighbours in space.”

Not across depth discontinuities: the pixel next to an object’s edge may be on the wall behind it, metres away in 3D.

“Downsampling does not change the geometry.”

It changes the density, which changes normals, clustering distances and thresholds that were tuned on the full-density data.

Engineering takeaways

  1. Raw points are complete and unordered; range images, voxel grids, height maps and meshes add structure at the cost of detail or coverage.
  2. Voxel index = ⌊p/s⌋; quantisation error is about s/√12 per axis; a sensible s is near the sensor noise.
  3. k-d trees reduce neighbour search from O(N) to about O(log N) per query; an organised cloud gets neighbours from the image grid.
  4. A 64 × 1024 LiDAR at 10 Hz gives about 655 000 points per second (about 10 MB/s); a dense grid costs X·Y·Z/s³ cells.
  5. Choose the representation for the question, keep timestamps and raw data, and represent unknown space explicitly.

References and further reading

Standard references; the data-rate and memory numbers were computed for this lesson.

  • Rusu, R. B. and Cousins, S. (2011). 3D is here: Point Cloud Library (PCL). ICRA: point-cloud data structures, filters and k-d trees.
  • Bentley, J. L. (1975). Multidimensional binary search trees used for associative searching. Communications of the ACM 18(9): the k-d tree.
  • Hornung, A., Wurm, K. M., Bennewitz, M., Stachniss, C. and Burgard, W. (2013). OctoMap: an efficient probabilistic 3D mapping framework based on octrees. Autonomous Robots 34(3).
  • Thrun, S., Burgard, W. and Fox, D. (2005). Probabilistic Robotics. MIT Press: occupancy grids and range-sensor models.

Knowledge check

Three conceptual questions. Write an answer, then reveal the explanation. Your answers stay in your browser.

Question 1

A point is at (1.37, −0.42, 0.88) m and the voxel side is 0.25 m. What is its voxel index, and what is the centre of that voxel?

Explanation

Index = (⌊1.37/0.25⌋, ⌊−0.42/0.25⌋, ⌊0.88/0.25⌋) = (5, −2, 3) (since −0.42/0.25 = −1.68, whose floor is −2). The cell spans 1.25 to 1.50 in x, −0.50 to −0.25 in y and 0.75 to 1.00 in z, so its centre is (1.375, −0.375, 0.875).

Question 2

A LiDAR produces 128 rings × 2048 azimuth steps at 20 Hz. How many points per second? If each point takes 16 bytes, what data rate is that?

Explanation

128 × 2048 = 262 144 points per sweep, times 20 = 5 242 880 points per second, about 5.2 million. At 16 bytes per point that is about 84 MB/s: far too much to process naively, which is why downsampling and organised-cloud methods matter.

Question 3

You compute normals from a range image using the pixels around each point as neighbours. Where does this give wrong normals, and what check helps?

Explanation

At depth discontinuities, where a neighbouring pixel belongs to a different surface much further away: the “neighbourhood” spans two surfaces. Reject neighbours whose range differs from the centre pixel’s by more than a threshold that grows with range.

What’s next

Next: what can be read from a point’s neighbourhood: normals, curvature and how plane, line and scatter differ.

Next lesson

P5-T2 — Neighborhoods and Geometric Features

Compute normals and planarity from a local neighbourhood.

Nothing below is required to finish this lesson.