Skip to main content

3dsem

Classify point clouds with pretrained 3D semantic segmentation models, on your own machine, from one command.

pip install 3dsem

sem install dales-utonia
sem infer dales-utonia tile.las

The classified .laz appears next to your input file, with per-point classification, confidence, and every original dimension carried over.

What you need

  • An NVIDIA GPU with a current driver (Windows 527.41+, Linux 525.60.13+)
  • Python 3.9 or newer
  • About 10 GB of disk per model

sem install shows the download size, the license, and a GPU check, then asks once before any bytes move. It is safe to interrupt and resumes where it stopped. After install, inference runs fully offline.

Models

dales-utonia is trained on DALES aerial LiDAR and predicts 7 classes: ground, vegetation, vehicle, powerline, fence, pole, building. Its license is CC-BY-NC 4.0 (non-commercial) and is shown before install.

dales-hag-utonia predicts the same 7 classes from the same data, with height above ground added as an input. It scores higher on held-out DALES scenes (0.86 mIoU against 0.98 overall accuracy) and is the one to reach for first.

sem models lists what is available and installed. Bare sem opens an interactive picker.

How do I make it more accurate?

Use a preset. Each one turns on more of the same three ideas: predict the scene from several augmented views and vote (test-time augmentation), tile the scene a second time at a half offset so no point sits on a tile edge (overlapped voting), and clean up the labels afterwards (smoothing, island removal, geometry rules).

  • default: one pass with light smoothing
  • --med: 4 voting views, overlapped tiling, island removal. Roughly 4x the time.
  • --high: 6 views including flips and rotations, stronger smoothing, geometry rules for ground/vegetation/building confusions, per-class probability fields. Roughly 6x.
  • --ultra: 9 views and the strongest smoothing. Roughly 9x.

An explicit flag always wins over a preset, so --ultra --no-sieve means ultra without island removal.

How do I make it faster?

--low is a single pass with no cleanup, the fastest option. If a preset is mostly what you want, --no-overlap drops its second tiling pass, which is about half its extra cost.

Big buildings come out patchy or cut through. Why?

The scene is processed in square tiles, typically 50 m on a side. An object bigger than one tile is predicted in pieces, and the pieces can disagree. Two fixes that combine well:

  • --chunk-xy 100 makes the tiles bigger, so a large building fits in one. Costs GPU memory.
  • --overlap (on automatically with --med and up) predicts a second pass at a half offset and votes, which removes most seam artifacts.

It ran out of GPU memory

Lower --chunk-xy, try 35 and then 25. Smaller tiles need less VRAM, and the extra seams they create are what --overlap is for.

Poles or powerlines are disappearing

Presets from --med up turn on island removal, which absorbs clusters smaller than 10 points into their surroundings. Thin objects are exactly small clusters. Keep the filter but make it gentler with --sieve-min-pts 5, or turn it off with --no-sieve.

Can I hide the model's low-confidence guesses?

--unclass 0.6 exports every point below 60% confidence as unclassified instead of its best guess. Bare --unclass uses 0.5. To see where the model is unsure, --entropy adds a 0..1 uncertainty field, --margin adds the gap between the top two classes, and --prob-dims adds one probability field per class (grows the file).

It confidently labels things it has never seen

A crane or a boat has no class to land in, so the model puts it in the nearest one it knows, often with high confidence. Confidence alone will not catch that, because the model is confident and wrong. Two other scores will.

--unclass-gmm compares each point against how the training classes actually looked to the model and unclassifies anything too far from all of them. Bare, it uses the threshold the model was shipped with; give it a number to override. --unclass-maxlogit 4.0 catches the opposite case, points where no class drew much evidence at all. They find different mistakes, so using both is normal.

To choose your own numbers, run once with --ood-dims, which writes the raw scores into the output file so you can see where your data sits, then set the thresholds and re-export. Re-exporting never re-runs the model.

Every model in one folder ran, but the gates did nothing

--unclass-gmm needs a model that shipped with those statistics. If a model predates them, that flag stops with an error naming what is missing rather than silently exporting ungated results. --unclass and --unclass-maxlogit work on any model.

I want individual objects, not just classes

--panoptic vehicle:5x2.5 splits a class into instances using a typical footprint in meters (length x width) and writes an instance_id per point. Several classes at once: --panoptic vehicle:5x2.5,pole:1x1. Based on ALPINE, no extra training involved.

Can I combine models?

sem infer dales-utonia+dales-hag-utonia tile.las runs every model in the chain and merges their predictions with a vote: each model's per-class probabilities are averaged, and the strongest combined evidence wins. Where the models agree, the label sticks; exact ties go to the model you listed first, so lead with your strongest. The result carries an agreement field (what fraction of models agreed on each point) and an ens_member field (which model drove each label). The models must share the same class list. Each member also keeps its own tile_<model>_predictions folder, so you can compare them individually.

My file has no coordinate system

It still runs. sem uses the coordinates exactly as they stand, reprojects nothing, and warns that it is taking their unit on trust: everything below (tile size, voxel grid, neighbourhoods) is a length in metres, so a file already in metres is correct and a file in feet is off by that factor. Most aerial LiDAR is already metre-projected, which is why this usually just works.

--epsg 26917 declares the projection when you know it (use your own zone's code), which silences the warning and makes the exported cloud georeferenced.

The one case that stops is lon/lat-shaped coordinates, where the whole scene spans a fraction of a degree. A 50 m tile there would cover everything at once, so that is not a slightly worse answer, it is no answer; declare a projected CRS with --epsg and it proceeds.

Reprojection only ever happens to get your data into metres, from degrees or from feet. A model is not tied to any particular CRS, only to the scale it was trained at, so a cloud already in a metre projection is never transformed.

My file is not a LAS. How does sem know what its columns mean?

It does not, and it will not guess. LAS and LAZ name their dimensions in the format spec, so intensity, return number and classification are read straight off a LAS with no help from you. Every other format (.txt, .csv, .xyz, .pts, .npy, .npz, .ply, .pcd) leaves the meaning of a field entirely up to whoever wrote it, so sem asks you:

sem infer dales-utonia scan.txt \
    --xyz-fields 1,2,3 --intensity-field 5
  • --xyz-fields A,B,C names the three coordinate fields, by name or by 0-based column number.
  • --intensity-field NAME and --return-number-field NAME name those channels. A model that wants a channel you did not name stops and lists the fields your file actually has.
  • --rgb-fields R,G,B names the colour fields.
  • --hag-field NAME uses a height-above-ground column your file already carries, instead of computing one.

Nothing is inferred from a column's position or from a name that looks familiar, because a file with id,x,y,z in that order and a file with x,y,z,id are indistinguishable to anything except you.

My colours come out black, or sem asks for --rgb-max

Point clouds store colour as 8, 10, 12 or 16 bit, and no format records which. Guessing it from the brightest point in the scene turns a 12-bit cloud nearly black and a dark 16-bit cloud into a blown-out one, so --rgb-max states the full-scale value: 255, 1023, 4095, 65535, or 1 for float 0 to 1 colour. It is only needed when the model actually consumes colour; a model that runs on intensity ignores the colour in your file and never asks.

Height above ground

Models trained with a HAG channel compute one at staging, using a ground raster whose cell size comes from the linear unit your file's CRS declares: 2 metres, or whatever length equals 2 metres in your file's own unit. A cloud in US survey feet gets a 6.56 foot cell, which is the same ground resolution. Nothing is assumed about your units; they are read from the CRS.

--hag-cell overrides that when you want a different resolution. The height error it costs is roughly the cell size times the local slope, so a smaller cell buys accuracy on steep ground and costs memory. A cloud that declares no projected CRS has no unit to read, so it stops until you either declare one with --epsg or state the cell with --hag-cell.

--ground-method picks where the ground comes from (smrf, csf, zmin, or labels when your file already marks ground). --csf-rigidness (1 steep, 2 moderate, 3 flat/urban), --smrf-window and --smrf-cut tune the ground filters. If your file marks ground with a class code, name both halves: --ground-field classification --ground-class 2; naming one without the other stops, because the code alone does not say which field holds it.

The cleanup rules are wrong for my data

The geometry rules only run when you ask for them and tell them what your classes mean: --rules --roles veg=vegetation,building=building. sem no longer decides that a class is vegetation because its name contains "tree". Their thresholds are lengths in your scene's vertical unit and unitless ratios, all settable: --rule-ground-hag (0.1), --rule-lowveg-hag (0.35), --rule-high-hag (2.0), --rule-planar-min (0.55), --rule-scatter-min (0.4).

Controlling the exported class codes

By default the export carries the model's own class indices. --asprs-map ground=2,building=6 assigns an output code per class by name. Codes are never assigned by matching class names against a keyword list, so a class you do not map keeps its model index. --unclassified-code sets the code gated points receive, and export stops rather than letting that code collide with a real class. --las-scale sets the coordinate quantum of the exported cloud in the source CRS's own unit.

I don't have a GPU

sem classifies on your own machine and needs an NVIDIA GPU. There is no cloud option here. Conversion and export are CPU work, but the model itself is not.

Can I rerun with different settings without reconverting?

Yes. The output folder is a self-contained job, named after your file and the model (tile_dales-utonia_predictions/). Quality options (presets, TTA, cleanup, export) never reconvert. Conversion options (--epsg, --ground-method, --hag, ...) and changes to the input file itself reconvert automatically; identical settings reuse the staged files. Every model keeps its own job folder, so switching models never mixes results.

A whole folder of tiles?

Pass the folder. Every .las/.laz/.ply/.pcd inside becomes one job, and results land in <model>_predictions/ inside it.

Where does everything live?

Downloads go to ~/.trainer (set TRAINER_HOME to move them). Your data and results never go there: each job is a folder next to your input, or under a default you set with sem output <dir> and undo with sem output off. sem clean dales-utonia removes one model; sem clean --all removes everything sem ever downloaded.

Can I look at the intermediate files?

sem tolas job/tile_input.npz writes tile_input.las beside it. The xyz becomes the cloud, rgb the color, and every other per-point channel a named field you can shade by in CloudCompare. That works on the staged input as well as on predictions, so it is how you see the features a model actually received, not just what it predicted.

Every option

sem infer --help documents all of it. Add --pick to browse and edit every option with arrow keys before running.

Licensing

The sem tool is MIT licensed. Each model ships a NOTICE.md stating its architecture credits and license terms; some models carry a non-commercial restriction inherited from their pretrained components, shown before you install.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

3dsem-0.1.13-py3-none-any.whl (121.8 kB view details)

Uploaded Python 3

File details

Details for the file 3dsem-0.1.13-py3-none-any.whl.

File metadata

  • Download URL: 3dsem-0.1.13-py3-none-any.whl
  • Upload date:
  • Size: 121.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.12

File hashes

Hashes for 3dsem-0.1.13-py3-none-any.whl
Algorithm Hash digest
SHA256 1a8434e0a14c44692d0f29db64329b1fb591fd81504db58af8609fcdac688233
MD5 1581739786b5df408b6af0276dd9a7ae
BLAKE2b-256 39c82ed7b6ce4aabd635288f26c2a0a6c6a3a465a9406f928129861fe2d3f24f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page