3D visionGuide

Point cloud filtering before surface reconstruction: the pipeline

An ordered cleaning pass for raw 3D sensor point clouds: fit a plane, threshold z, cluster by distance, keep clusters by size, estimate normals, then mesh.

LumaSpec Vision10 min read Share on LinkedIn

On this page 9 sections
  1. 01The order that works
  2. 02Step 1: fit a reference plane, then set the z band
  3. 03Step 2: cluster by 3D distance, sized from point spacing
  4. 04Step 3: keep clusters by point count and extent
  5. 05Step 4: estimate normals on the points that survive
  6. 06Mesh last, then check the mesh against the points
  7. 07When the usual pipeline is the wrong tool
  8. 08Threshold checklist
  9. 09Questions

A point cloud straight from a 3D sensor is rarely meshable: fixture edges, background returns and sparse reflection ghosts ride along with the part, and greedy triangulation turns each of them into spikes, bridges or a second shell welded to the first. The fix is an ordered cleaning pass whose thresholds all derive from one measurement — the sensor's point spacing. This guide gives the order, the formulas and a complete worked example: a machined aluminium bracket scanned by a laser profiler at 0.1 mm along the scan line and 0.5 mm between lines, cleaned and meshed end to end.

The order that works

Run five steps, in this order:

  1. Fit a reference plane, then threshold every point into a z band above it.
  2. Cluster the survivors into connected regions by nearest-neighbour distance.
  3. Keep the regions with the point count and extent to be the part.
  4. Estimate normals on the surviving points, oriented toward the sensor.
  5. Triangulate last.

The order is not stylistic. The z band deletes most of the cloud for free, so clustering runs on a fraction of the points and cannot chain the part to the fixture through below-plane returns. Clustering precedes the size filter because a region has no size until it exists. Normals come after every deletion because a normal is an average over neighbours: remove a point afterwards and the normals around it are stale without warning. Triangulation runs last because it consumes normals and trusts that the input contains only surface.

Every threshold below comes from the spacing you measure on your own cloud, not from a default. Set them once from that measurement and the pass transfers between parts unchanged.

Step 1: fit a reference plane, then set the z band

Thresholding raw sensor z trims a tilted scene unevenly. A fixture 0.5° out of level moves the same surface by 200 mm × tan 0.5° = 1.75 mm across a 200 mm field — taller than many feature heights, so one fixed band cuts into the part at one end and leaves background at the other. Fit a least-squares plane to the fixture instead, using points sampled in a part-free frame, and write the band as heights above that plane.

For the worked bracket, the pad sits 0.2 mm above the fixture, the tallest boss reaches 12.4 mm and fixture noise runs ±0.1 mm. The band [0.2 mm, 13.0 mm] keeps every feature, drops the fixture body and the conveyor behind it, and still catches ghost returns floating above the boss.

The plane-fit mechanics are the same ones used to measure a height difference from a 3D point cloud. Removing a ground plane outdoors is the same operation at metre scale — see ground removal for obstacle detection.

Step 2: cluster by 3D distance, sized from point spacing

Join every pair of points closer than a distance d and follow the chains; each connected group becomes one region. The only parameter is d, and it comes from the cloud's own spacing.

For the bracket scene the profiler samples 0.1 mm along each line with 0.5 mm pitch, so the closest diagonal neighbour sits at √(0.1² + 0.5²) mm ≈ 0.51 mm. Set d = 1.0 mm: twice the diagonal joins real neighbours with margin and stays far below the 3 mm gap to a fixture sliver, which therefore survives as its own region for step 3 to reject.

Two failures bracket the useful range. A d below the diagonal spacing splits surfaces into strips along the scan lines; a d above the smallest part-to-part gap merges two parts into one region, and no later filter can separate them.

Starting values by cloud source — plug in your own field width and pixel count, and the division gives the spacing:

Cloud source Spacing comes from Example spacing Starting d
Laser profiler line pitch across, sampling step along the line 0.1 mm × 0.5 mm 1.0 mm
Structured light field width ÷ camera pixels 500 mm ÷ 1280 px ≈ 0.39 mm 1.0 mm
Depth / ToF field width ÷ depth-map columns 600 mm ÷ 320 px ≈ 1.9 mm 5 mm

Profilers add a wrinkle: the across-line spacing is the line pitch, while the along-line step follows the conveyor encoder, so spacing drifts with speed — scan spacing control keeps it honest. The two profilers below bracket the range; their data-sheet rows show exactly which values set the pitch and the step:

Specification MIS-DP3850-01P MV-DP4180-03P
Data points/profile 3200 4080
Reference distance 126 mm 175 mm
Measurement range (Z-axis) 86 mm 100 mm
Measurement range (X-axis) 65 mm @ near end; 85 mm @ reference distance; 105 mm @ far end 75 mm @ near field of view; 100 mm @ reference distance; 125 mm @ far field of view
Resolution (Z-axis) 4.38 ~ 8.33 μm 3.72 μm to 8.40 μm
Repeatability (Z-axis) 1.68 μm @ data that sensor tests gauge block on optical platform1 1.5 μm @ data that sensor tests gauge block on optical platform
Profile data interval 20.4 ~ 35.7 μm 18.5 μm to 32.2 μm
Scan frame rate 3.4 kHz to 46.7 kHz (high frame rate mode) 2.5 kHz (within max. measurement range), max. 49 kHz (in ROI mode)
Data output Original image, profile data, depth image, brightness image Profile data, depth image, brightness image
Trigger mode Software trigger, hardware trigger (differential encoder) Software trigger, hardware trigger (differential encoder)
Laser wavelength 405 nm 650 nm
Laser safety class Class3R Class 3R
Price $12,379.00 · quoted $12,389.00 · quoted

All 2 share: Linearity Z-axis (±% of MR) 0.01; Power supply 24 VDC; Ingress protection IP67; Humidity 20% RH to 85% RH (no condensation). Values as printed in each product's data sheet; open a part for its drawing and full specifications.

Connected-component grouping in general, including the organised-grid variant, is covered step by step in 3D point cloud segmentation by connected components.

Step 3: keep clusters by point count and extent

Density comes straight from the spacing: ρ = 1 ÷ (0.1 mm × 0.5 mm) = 20 points/mm². The smallest feature the inspection must keep is an 8 mm diameter boss, so its area is π × (4 mm)² = 50.3 mm² and a complete boss carries 50.3 mm² × 20 points/mm² ≈ 1005 points.

Set the minimum at 800 points, about 80% of a complete boss, so the region survives losing its edge points to the z band. Splash chains and sparse ghosts rarely reach a few hundred points and fall out on their own.

Add an extent window to catch runaway chains: keep regions whose x-y extent falls between 5 mm and 150 mm. The bracket spans 120 mm, dust specks fall below the window and a chain that swallowed background exceeds it.

Last gate: triangulate each candidate once. A region that returns slivers or nothing is splash, not surface — drop it and log it, because a rising splash count means exposure or lighting needs attention before any threshold should move.

ρ = 1 / (sx × sy) points per mm² N_min ≈ 0.8 × A_feature × ρ

Step 4: estimate normals on the points that survive

A normal is a local plane fit: least squares over each point's neighbourhood, or a moving-least-squares pass when the surface is noisy. The radius sets the balance. At r = 2 × pitch = 1.0 mm the expected neighbourhood holds ρ × π × r² = 20 × π × 1² ≈ 63 points, comfortably above the roughly twenty a stable fit needs — a plane has three fit parameters, and about ten points per parameter is the classical floor. Below that, normals wobble with single-point noise. On curved features keep the radius at two spacings and no more: a plane stretched across a curve reports the chord, so curvature flattens exactly where it matters.

Orient every normal toward the sensor and make the set consistent. Greedy triangulation grows the surface along the normals, and a flipped patch folds the mesh on itself. Normal direction outlives this pipeline too: when the mesh feeds a robot finishing path, the same orientation problem returns as tool-path error, and the curve-normal fix for robotic surface sanding is the downstream version of this step.

If the source is a rendered or textured point map rather than measured points, recompute normals on the underlying data first; renders carry display normals, not measurement normals.

n ≈ ρ × π × r² points per neighbourhood r = 2 × max spacing

Mesh last, then check the mesh against the points

Greedy projection triangulation grows the mesh triangle by triangle, joining neighbours within a search radius. Set that radius between the pitch and the part gap: 0.75 mm here, above the 0.5 mm pitch so real neighbours connect and far below the 3 mm gap so nothing bridges. Too small leaves holes at every sparse patch; too large smooths real steps and spans small gaps the part actually has.

Then measure the mesh against the points it came from. On machined surfaces at this spacing, with profiler z noise in the hundredths of a millimetre, expect a mean point-to-mesh distance under 0.05 mm and a maximum under 0.2 mm. A maximum above one pitch — 0.5 mm here — means the mesh bridged a hole, and the usual cause is depth dropout at the edge (missing points in a 3D camera point cloud), not the triangulator.

Check the exported file, not the viewer: exports and viewer renders disagree for mundane reasons — decimation on save, unit scaling, frame flips — and the consumer of the mesh sees the file.

Finer detail than the spacing supports is a capture decision, not a cleaning one; x-y-z resolution settings are chosen before scanning.

The whole pass is host-side arithmetic. Two million points occupy 24 MB as float x-y-z coordinates and 48 MB with normals, and neighbour-search structures take the working set past a few hundred MB — comfortably inside a vision controller with 16 GB of memory. The MV-VC5525-256G70-NN, for example, pairs 32 GB of memory with PoE camera ports for the sensor link.

Vision controllersHikrobot MV-VC5525-256G70-NN VC5000 Vision Controller, 12th-I5, 32GB+256G SSD, Supported PCIEMV-VC5525-256G70-NN
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
PoE
PoE camera ports
Light outputs
8 built-in channels
$4,479.00 · quotedView and quoteBuild a system with it

When the usual pipeline is the wrong tool

  • Height-only checks: stop after step 1 and mask a 2D ROI. Clustering and normals add runtime and no information when the verdict is a height against the plane.
  • Downsampling: never before measuring or cleaning. Decimation moves every surviving point off its measured position and changes nearest-neighbour distances, so tuned thresholds break — see why decimation shifts points.
  • Shiny, curved parts: multipath ghosts land inside the z band, and no threshold removes them. Re-capture at a second angle and intersect the two passes, or use the sensor's multipath suppression.
  • Walls thinner than about two spacings: the band and the clustering starve them of points. Add a second station or scan closer instead of widening thresholds.
  • Transient returns such as weld spatter: test persistence across two consecutive clouds and drop clusters present in only one. Spatter never repeats; surfaces do.

For a full inspection built on cleaned clouds — pin features, presence, geometry — see the point-cloud inspection workflow.

Threshold checklist

Capture:

  • One part-free frame for the plane fit, re-fit at changeover; tilt otherwise enters every threshold.
  • Along-line step and pitch recorded in mm, re-measured after any speed change.

Band:

  • Bottom just above fixture noise: 0.2 mm in the worked scene.
  • Top at tallest feature plus 0.5 mm: 13.0 mm there.

Clustering:

  • d at two to three times diagonal spacing: 1.0 mm here.
  • Two-part test: parts 3 mm apart must stay separate regions.

Keeping:

  • Minimum points at 0.8 × feature area × density: 800 points here.
  • Extent window: 5 mm to 150 mm here.

Normals:

  • r at twice the pitch: 1.0 mm here, about 63 points per neighbourhood.

Mesh:

  • Search radius between pitch and gap: 0.75 mm here.
  • Maximum point-to-mesh distance below one pitch: 0.5 mm here.

Five numbers, one measurement: band, cluster distance, minimum points, normal radius and search radius all fall out of the point spacing, so measure the spacing first and the first mesh arrives clean. Sensors that produce clouds worth this pass:

3D sensorsHikrobot MIS-DP3850-01P 3D laser profile sensorMIS-DP3850-01P
Type
Laser profiler
$12,379.00 · quotedView and quote
3D sensorsHikrobot MV-DP4180-03P 3D Laser Profile SensorMV-DP4180-03P
Type
Laser profiler
$12,389.00 · quotedView and quote
3D sensorsHikrobot MV-DPS200P-02 Projected structured-light 3D cameraMV-DPS200P-02
Type
Stereo / structured light
$8,829.00 · quotedView and quote

Pick the sensor in the 3D sensors category or its camera finder, pair it with a vision controller, and the system configurator steps through the whole chain. Related reading lives on the 3D topic page.

Questions

What cluster distance should I start with on a laser profiler cloud?

Derive it from the two spacings and test the extremes. A profiler sampling 0.05 mm along the line with 0.4 mm pitch has a diagonal neighbour distance of √(0.05² + 0.4²) ≈ 0.40 mm, so start at 1 mm: real neighbours join, and parts separated by 3 mm stay separate. If surfaces split into strips along the scan lines the value is too small; if two parts merge, it is too large.

Why does greedy triangulation still leave spikes or holes after cleaning?

Spikes mean stray points survived: tighten the z band or raise the minimum point count until the ghost clusters drop. Holes mean the search radius sits below the local spacing, or normals are missing or inconsistently oriented, because greedy triangulation grows the surface along them. Compute normals on the final point set and set the search radius just above the largest spacing you measured.

Should I downsample a dense cloud before meshing it?

Not before measuring or cleaning. Decimation moves every surviving point off its measured position, which shifts edges and flattens curvature, and it changes nearest-neighbour distances, so a cluster distance tuned before downsampling splits the cloud afterwards. Filter, cluster and mesh at native spacing; downsample only for visualisation or training data, where geometry tolerance is loose.

Do I need normals if the inspection only measures heights?

No. Heights against a reference plane, and volume or area by comparison, work on raw x-y-z points, so the pipeline can stop after the size filter. Normals earn their runtime when a tool consumes surface orientation: curvature, draft angle, meshing, or a robot path that follows the surface. Add the step when a downstream operator needs it, not by default.

How do I set the z band when the fixture itself appears in the cloud?

Fit the plane to fixture points from a part-free frame, read the fixture's noise from that same fit, and set the band from roughly twice that noise up to just above the tallest feature. Features spanning 0.2 mm to 12.4 mm above the fixture with ±0.1 mm noise get a band of 0.2 mm to 13.0 mm: the fixture body drops out and every feature survives.