pythonpython-3.xdata-conversionfloating-accuracypoint-clouds

Conversion accuracy issues of E57 to LAS in Python using pye57 and laspy


I am attempting to convert an .e57 pointcloud into a .las pointcloud but I am running into issues which seem to be caused by accuracy. The following images illustrate the original .e57 in CloudCompare, compared to the converted .las file also in CloudCompare. The point size is bumped up significantly to compare the differences.

Original E57 enter image description here

Converted LAS enter image description here

As you can see the points are positioned in some kind of grid pattern in the LAS file. Inspecting the LAS file in Potree exposes the issue at a significant level. See the image below. enter image description here

My code for converting the E57 to the LAS is posted below. If anyone has any insights as to why this is happening and why the points seem to be grid-aligned then I'd be happy to hear more.

import numpy as np
import pye57
import laspy

e57 = pye57.E57("in.e57")

# read scan at index 0
data = e57.read_scan(index=0, ignore_missing_fields=True, colors=True, intensity=True)

# 'data' is a dictionary with the point types as keys
assert isinstance(data["cartesianX"], np.ndarray)
assert isinstance(data["cartesianY"], np.ndarray)
assert isinstance(data["cartesianZ"], np.ndarray)

# other attributes can be read using:
# data = e57.read_scan(0, intensity=True, colors=True, row_column=True)
assert isinstance(data["cartesianX"], np.ndarray)
assert isinstance(data["cartesianY"], np.ndarray)
assert isinstance(data["cartesianZ"], np.ndarray)
assert isinstance(data["intensity"], np.ndarray)
assert isinstance(data["colorRed"], np.ndarray)
assert isinstance(data["colorGreen"], np.ndarray)
assert isinstance(data["colorBlue"], np.ndarray)

# the ScanHeader object wraps most of the scan information:
header = e57.get_header(0)
print(header.point_count)
print(header.rotation_matrix)
print(header.translation)

# all the header information can be printed using:
for line in header.pretty_print():
    print(line)

# Create a new LAS file
las_out = laspy.create(point_format=3, file_version='1.2')

# Populate the LAS file with point cloud data
print(data["cartesianX"])
las_out.x = data["cartesianX"]
las_out.y = data["cartesianY"]
las_out.z = data["cartesianZ"]
las_out.intensity = data["intensity"]
las_out.red = data["colorRed"]
las_out.green = data["colorGreen"]
las_out.blue = data["colorBlue"]

# Close the LAS file
las_out.write("output/out.las")


Solution

  • It appears that my scaling in the LAS header was completely off. The floating points get rounded to integers as per the LAS standard and the scale determines the precision.

    I fixed the issue by adding the scale and offset headers as follows

    xmin = np.floor(np.min(data["cartesianX"]))
    ymin = np.floor(np.min(data["cartesianY"]))
    zmin = np.floor(np.min(data["cartesianZ"]))
    
    las_out.header.offset = [xmin, ymin, zmin]
    las_out.header.scale = [0.001, 0.001, 0.001]