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.
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.
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")
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]