I have a point cloud and the trajectory of it. I want to cut it to smaller chunks so I will be able to process it more easily.
The problem of my code is that creates gaps and overlaps between the chunks. The methodology i followed is: first step is to split the trajectory and return a list of points along to it. Secondly, I used these points as boundaries for my chunks and i generated cylindrical regions of interest (ROIs) (I provided also the radius of the cylinder). The result I get is point cloud chunks that have gaps and overlaps between them. Here is my code:
def split(trajectory, chunks, is_distance=True, endpoints=True):
"""
Return a list of evenly spaced points along a trajectory.
Parameters
----------
trajectory : numpy.ndarray
Trajectory represented through a 2D NumPy array. Rows
represent trajectory points and the columns are the
spatial coordinates X, Y and Z (in this order).
chunks : int or float
Distance between consecutive points or number of points.
is_distance : boolean, optional (default `True`)
If True, then `chunks` is the separation distance between two
consecutive points Expressed in meters). Otherwise `chunks`
is the number of parts into which the input line is partitioned
(must be a whole number).
endpoints : boolean, optional (default `True`)
If True, then the returned points are the edges of the parts
into which the line is divided. Otherwise the returned points
are the midpoints of the trajectory chunks.
Returns
-------
points : numpy.ndarray
Sequence of equally spaced points sampled from the
interpolated input trajectory. The points are bundled
in a 2D NumPy array: one row per point and three spatial
coordinates X, Y and Z (in this order) as columns.
Notes
-----
The equally spaced points are obtained through the `interpolate`
method, which returns points at specified distances along the
line, as described in [1]_.
"""
line = LineString(trajectory)
if is_distance:
n_parts = round(line.length/chunks)
else:
n_parts = chunks
if endpoints:
distances = np.arange(0, n_parts + 1)
else:
distances = (0.5 + np.arange(0, n_parts))
distances = distances / n_parts
seq = [line.interpolate(dist, normalized=True) for dist in distances]
points = np.array(LineString(seq).coords)
return points
traj_N = np.loadtxt('my_trajectory.poly')
limits = split(traj_N, 20, is_distance=True)
np.savetxt('My_limits.txt', limits)
def cylindrical_roi(cloud, start, end, radius):
"""Return the points of a point cloud inside a cylinder.
Parameters
----------
cloud : pandas.DataFrame
Point cloud data. Columns must include 'X', 'Y', 'Z'.
start : Array-like[three floats]
X, Y and Z coordinates (in this order) of the start point
the of axis of the cylinder.
end : Array-like[three floats]
X, Y and Z coordinates (in this order) of the end point of
the axis of the cylinder.
radius : float
Radius of the cylinder.
Returns
-------
pandas.DataFrame
Points inside the cylinder of given radius and axis from
start to end.
"""
axis = end - start
length = np.linalg.norm(axis)
unit = axis / length
from_start = cloud[['X', 'Y', 'Z']] - start
proj_on_axis = np.dot(from_start, unit)
parallel = np.outer(proj_on_axis, unit)
orthogonal = from_start - parallel
dist_to_axis = np.linalg.norm(orthogonal, axis=1)
masks = (0 <= proj_on_axis,
proj_on_axis <= length,
dist_to_axis <= radius)
inside = np.logical_and.reduce(masks)
return cloud[inside]
rois = []
for start, end in zip(limits[:-1], limits[1:]):
rois.append(cylindrical_roi(road_N, start, end, 10))
# Assuming `rois` is a list of DataFrames
for i, df in enumerate(rois):
file_name = path.join(output_path, f'road_L_roi_{i}.txt') # Name for the text file
df.to_csv(file_name, sep=' ', index=False) # Save DataFrame to text file with tab-separated values