Exwayz trajectories as they are output by exwayz_slam.exe, exwayz_loop_closure.exe or exwayz_georef.exe for instance are stored in a .ply binary format.

Content description

Field name Type Description
x double X component of the pose’s translation
y double Y component of the pose’s translation
z double Z component of the pose’s translation
qx double X component of the pose’s rotation quaternion
qy double Y component of the pose’s rotation quaternion
qz double Z component of the pose’s rotation quaternion
qw double Omega component of the pose’s rotation quaternion
timestamp double Hardware timestamp of the LiDAR frame corresponding to the pose
indices int Index of the frame in the dataset

Offset

A trajectory can come with an offset file (when written by exwayz_georef.exe for instance) to avoid storing too big coordinates directly in the .ply . The offset file

If the two above conditions are matched, when Exwayz executables will receive a .ply trajectory in input, they will automatically read the .offset and then get the trajectory in global coordinates

Read PLY trajectory in Python

import numpy as np
from plyfile import PlyData
from pyquaternion import Quaternion

def main():
    ply_fpath = "2_georef/traj_fusion_gps.ply"

    ply = PlyData.read(ply_fpath)
    ply_props = [p.name for p in ply['vertex'].properties]

    positions = []
    rotations = []
    timestamps = []
    indices = []

    for vertex in ply['vertex']:
        positions.append( np.array([vertex['x'], vertex['y'], vertex['z']]) )

        if 'q_w' in ply_props:
            rotations.append( Quaternion(w=vertex['q_w'], x=vertex['q_x'], y=vertex['q_y'], z=vertex['q_z']) )

        if 'timestamp' in ply_props:
            timestamps.append(vertex['timestamp'])

        if 'indices' in ply_props:
            indices.append(vertex['indices'])

    print("positions:", positions[0:10])
    print("rotations:", rotations[0:min(10, len(rotations))])
    print("timestamps:", timestamps[0:min(10, len(rotations))])
    print("indices:", indices[0:min(10, len(rotations))])

if __name__== "__main__":
    main()