Cleaning up poor quality laser scans with Meshlab

Friday, September 12, 2025 

Laser scanning often results in files that are massive, like 100s of megabytes, even gigabytes of data.  This is rarely useful. Metrology and digitization of most manufactured parts should be done with touch probes for accuracy and clean data, 3 points define a plane not 300,000. One is reminded of the adage “a person with one clock knows the time, a person with two is never sure.” However, laser scanners scan fast and give cool looking results without much expertise, even if they make the data clean up slow. So here we are, 68 simple steps to a clean mesh.

MeshLab is an amazingly powerful tool that implements code straight out of current mathematical papers in python efficiently and well.  It is a great tool, but unless you have time and the background to read all of the papers, it can be hard to choose which reconstruction or simplification or cleaning algorithm and what parameters will clean up a noisy mesh without turning it into a crazy starburst of near infinite polygons.  This little post is a cookbook series of steps that reduced a 17m face cluster of 172 components and 15,934 boundary edges into a 902k face single component, water-tight, two-manifold, properly normalized, 3D printable mesh in “only” 3.5 hours of processing time (or about 6 hours with user inattention).  It worked successfully 4 times on 4 different scans, so seems robust.

The basic process is to:

  1. Loop through some steps to clean up the import mesh, verifying with topological measures,
  2. Rebuild the mesh at high fidelity and resolution, making it huge but regular and consistent,
  3. Loop through the cleaning steps to make fix surviving crazies from the scan
  4. Decimate the huge mesh down to an appropriate uniform minimum feature resolution as needed to capture details, which will be too detailed in flat/simple areas,
  5. Clean up whatever crazies that process introduced,
  6. Use Quadric Edge Collapse Decimation to reach a target facet count/file size that can be ingested by downstream apps (typically <1m faces is a good target), which preserves edge detail intelligently.
  7. Clean up any crazies that algo created.
  8. Make the normals coherent
  9. Export the result.   Yay.

This sequence reduced the input from 17M faces with severe topology issues to a clean, watertight 902K face mesh suitable for CAD import that preserved geometry and sufficient detail for reverse engineering, reproduction, and fit checks.

A detail of the original file looked like this, note the insane density of verticies:

After this clean-up sequence, the data is much less cluttered but critical details remain well defined and clear.

Note the edges still have plenty of points, but the relatively flat part are now encoded in a minimal number of points, sufficient relative to the feature sizes to represent geometry and surface quality.

I uploaded an annotated logfile of the process in case the below isn’t clear and the MeshLab .mlx script file with the filter parameters as well which can be kinda copy-pasted into the script window automate the process in blocks. If I have to do more of this, I’ll automated it further as a python script that would call PyMeshLab.py and conditionally fork on the results of the topological quality measure results. It’s a good way to keep your CPU busy.


Meshlab Sequence

Import the messy file into meshlab.

Initial State

  • Starting mesh: 17,052,444 faces, 8,534,047 vertices
  • 172 connected components, 15,934 boundary edges
  • Non-manifold mesh with multiple topological issues

Phase A: Initial Cleanup and Repair

  1. Compute Topological Measures — 29.6 sec
    • Identified initial mesh problems
  2. Merge Close Vertices — 27.8 sec
    • Threshold: 0.1975 (0.01% of bounding box)
    • Merged 166,446 vertices
  3. Remove Duplicate Faces — 5.3 sec
    • Deleted 3,933 duplicate faces
  4. Remove Duplicate Vertices — 4.1 sec
    • No duplicates found
  5. Remove Isolated Pieces — 14.5 sec
    • Min diameter: 790.013 (40% of bounding box)
    • Removed 136 of 137 components, 14,193 vertices
  6. Remove T-Vertices – 28.8 sec
    • Method: Edge Collapse, Ratio: 40, Iterate: true
    • Removed 1,745 T-vertices
  7. Remove Unreferenced Vertices — 0.2 sec
    • None found
  8. Remove Zero Area Faces — 0.8 sec
    • None found
  9. Select Non-Manifold Edges — 6.3 sec total
  10. Dilate Selection — 2.4 sec total
  11. Delete selected faces AND vertices
    • Deleted 36,787 faces
  12. Repair Non-Manifold Vertices — 11.8 sec
    • Method: Split vertices
    • Split 42 non-manifold vertices
  13. Select/Delete Self-Intersecting Faces — 86.9 sec total
    • Deleted 771 faces
  14. Close Holes — 52.5 min
    • Max hole size: 300 edges, Refine: true
    • Closed 1,598 holes, added 16,658 faces

At this point the model should be clean enough for surface reconstruction which will create a new mesh shrink-wrapped over the scanned mesh.

Phase B: Surface Reconstruction

  1. Screened Poisson Reconstruction — 12.6 min
    • Depth: 14, Adaptive depth: 7
    • Scale: 1.2, Samples per node: 1.5
    • Interpolation weight: 12

This creates a new mesh layer – verify it is a good match to the old (toggle the “eye” for each layer on and off) and if it is good, close the eye of the original file, delete hidden layers, and then save as a new file name. This mesh is roughly 2x larger than the original and will be slow until it is decimated to a reasonable size.

Phase C: Clean up the new giant mesh

14-26. Repeat cleanup sequence (Phase A) — ~67 min total.

  • Similar parameters as Phase A
  • Removed 16 of 17 newly created disconnected components (floating glitches)
  • Removed 32,758 T-vertices
  • Removed 152 self-intersecting surfaces
  • Select non-manifold, dilate, delete removed 6270 faces, 1661 vertices
  • Closed 404 holes
  • Assumed close enough for CD reduction (which is robust against topological oddities)

Phase D: Clustering Decimation

  1. Clustering Decimation — 14.9 sec
    • Cell size: 0.988 (0.05% of bounding box) this means ~1 mm resolution on a part ~1.95 meters long, a parameter that is highly design dependent.
    • Reduced to 4,486,934 faces

Phase E: Third Cleanup Round

28-40. Another cleanup cycle — ~49 min total.

  • Removed 9,269 duplicate faces
  • Deleted 128,584 non-manifold faces
  • Closed 5,050 holes

Down to 4,406,986 faces, but 74 components so repeat the clean cycle:

41-52. Fourth cleanup iteration — ~48 min total.

  • Removed 73 of 74 components
  • Multiple hole closing operations

Single component, 4,405,554 faces, no holes, two manifold: OK for QECD.

Phase F: QECD Decimation

  1. Quadric Edge Collapse Decimation — 88.1 sec
    • Target: 902,777 faces (20% of current)
    • Preserve boundary: true, Planar simplification: true
    • Planar weight: 0.001 (default)

Reduced to ~900K faces: this is an acceptable size for most programs to ingest.

Phase G: Final Cleanup

54-65. Final cleanup passes — ~8.5 min total.

Three iteration of cleanup sequence.

  1. Final topology check — 2.3 sec
    • Final mesh: 451,053 vertices, 902,498 faces
    • Single connected component
    • Two-manifold, watertight (0 boundary edges)
    • Genus: 99 (99 through-holes)
  2. Re-Orient Faces Coherently — 1.9 sec
  3. Export — 0.5 sec

Saved as an STL file, binary, no texture data (or as needed for next program)

Total Processing Time

Approximately 3.5 hours (mostly hole-closing operations which took ~2.5 hours total)

Posted at 18:35:18 GMT-0700

Category: FabricationHowToTechnology