Skip to content

BlogHow-to

How to convert your point cloud data into .Las / .Laz

4 min readHow-to

A figure asking how to convert point cloud data into .las or .laz

Pointly takes LAS and LAZ. LAZ first, because it is the same data compressed and there is less of it to move.

Most point clouds arrive that way already. When one does not, converting it is a short job, and this is how.

Use version 1.4 where you can

LAS is the open lidar format the ASPRS maintains: the points, and a class on every point. Version 1.2 is still everywhere and carries a standard catalog without trouble. Version 1.4 is the current one, and where there is a choice it is the one to ask a supplier for.

Three things come with it.

  • A catalog can run past 32 classes. The older point formats give the class five bits, which is 32 values and no more. Point formats 6 to 10 give it a full byte, which is 256.
  • One file can hold more than 4.29 billion points. The header up to LAS 1.3 counts points in 32 bits and stops there. From 1.4 it counts in 64.
  • The coordinate reference system travels as WKT. The older versions carry it as GeoTIFF keys, and not every projection has one.

That last point is worth a moment. A file that arrives without a reference system is read as meters. A survey in feet without one has to be settled before it can be processed, which is a conversation rather than a setting, so writing the system into the file is cheaper than sending it alongside.

The short way

Most conversions need no code at all. CloudCompare opens a long list of formats and saves LAS and LAZ. PDAL and LAStools do the same from a command line, which is what you want when it is a folder rather than a file. LASzip compresses and decompresses on its own.

The Python way

Reach for Python when the format is one nothing else reads. Benchmark datasets are the usual case: Semantic3D keeps the points in one text file and the classes in another, and joining the two is part of the conversion.

laspy is the library, and it changed shape in version 2.0. The File and Header classes of the 1.x line are gone, and code written against them raises on a current install, which is worth knowing because plenty of it is still online. What follows was run on laspy 2.6.

import numpy as np
import pandas as pd
import laspy

raw = pd.read_csv(PATH_TO_DATA_FILE, sep=' ', header=None).values
labels = pd.read_csv(PATH_TO_LABEL_FILE, sep=' ', header=None).values[:, 0]

# xyz in the first three columns, intensity in the fourth, rgb in five to seven
xyz = np.ascontiguousarray(raw[:, 0:3], dtype='float64')
rgb = np.ascontiguousarray(raw[:, 4:7], dtype='uint16') * 256
intensity = np.ascontiguousarray(raw[:, 3], dtype='uint16') * 256

header = laspy.LasHeader(version='1.4', point_format=7)
header.offsets = np.floor(xyz.min(axis=0))
header.scales = np.array([0.01, 0.01, 0.01])

las = laspy.LasData(header)
las.x, las.y, las.z = xyz[:, 0], xyz[:, 1], xyz[:, 2]
las.red, las.green, las.blue = rgb[:, 0], rgb[:, 1], rgb[:, 2]
las.intensity = intensity
las.classification = labels

las.write('out.laz')

Four lines in there are worth a sentence each.

  • point_format=7 is the LAS 1.4 record that carries color next to the class. Format 6 is the same one without color, format 8 adds near infrared.
  • min(axis=0), not axis=1. The offset is one value per axis. Along the other axis you get one value per point, and the file that comes out is wrong rather than broken, which is the worse of the two.
  • Color as uint16. LAS keeps color in 16 bits, so an 8 bit channel is multiplied up on the way in. Cast to uint8 first and the multiplication overflows before it ever reaches the file.
  • .laz straight out of write. There is no second compression step. It needs a backend, pip install laspy[lazrs], and after that the extension decides.

Writing the reference system in

Two more lines, and the projection travels with the file rather than in an email.

from pyproj import CRS

header.add_crs(CRS.from_epsg(25832))

Do this on the header, before LasData(header). It goes in as WKT and reads back out as the EPSG code it went in as.

Then upload it

A LAZ with a catalog and a reference system in it is a file the platform can take straight away, and a file anyone you send it to can open. That is what the conversion buys.

If your data is in a format none of this covers, or the classes are in a scheme that has to be mapped onto yours, tell us what you have and we will tell you what it takes.

Update. The code sample was rewritten for laspy 2.0, which removed the laspy.file.File and laspy.header.Header interfaces the original used. Every line above was run before it was published.

All articles