kopia lustrzana https://github.com/OpenDroneMap/ODM
102 wiersze
4.3 KiB
Python
Executable File
102 wiersze
4.3 KiB
Python
Executable File
import numpy as np
|
|
from numpy.lib.recfunctions import append_fields
|
|
|
|
class PointCloud:
|
|
"""Representation of a 3D point cloud"""
|
|
def __init__(self, xy, z, classification, rgb, indices, extra_dimensions, extra_dimensions_metadata):
|
|
self.xy = xy
|
|
self.z = z
|
|
self.classification = classification
|
|
self.rgb = rgb
|
|
self.indices = indices
|
|
self.extra_dimensions = extra_dimensions
|
|
self.extra_dimensions_metadata = extra_dimensions_metadata
|
|
|
|
@staticmethod
|
|
def with_dimensions(x, y, z, classification, red, green, blue, indices=None):
|
|
xy = np.column_stack((x, y))
|
|
rgb = np.column_stack((red, green, blue))
|
|
indices = indices if indices is not None else np.arange(0, len(x))
|
|
return PointCloud(xy, z, classification, rgb, indices, { }, { })
|
|
|
|
@staticmethod
|
|
def with_xy(xy):
|
|
[x, y] = np.hsplit(xy, 2)
|
|
empty = np.empty(xy.shape[0])
|
|
return PointCloud.with_dimensions(x.ravel(), y.ravel(), empty, np.empty(xy.shape[0], dtype=np.uint8), empty, empty, empty)
|
|
|
|
def __getitem__(self, mask):
|
|
masked_dimensions = { name: values[mask] for name, values in self.extra_dimensions.items() }
|
|
return PointCloud(self.xy[mask], self.z[mask], self.classification[mask], self.rgb[mask], self.indices[mask], masked_dimensions, self.extra_dimensions_metadata)
|
|
|
|
def concatenate(self, other_cloud):
|
|
for name, dimension in self.extra_dimensions_metadata.items():
|
|
if name not in other_cloud.extra_dimensions:
|
|
dimension.assign_default(other_cloud)
|
|
for name, dimension in other_cloud.extra_dimensions_metadata.items():
|
|
if name not in self.extra_dimensions:
|
|
dimension.assign_default(self)
|
|
new_indices = np.arange(len(self.indices), len(self.indices) + len(other_cloud.indices))
|
|
self.xy = np.concatenate((self.xy, other_cloud.xy))
|
|
self.z = np.concatenate((self.z, other_cloud.z))
|
|
self.classification = np.concatenate((self.classification, other_cloud.classification))
|
|
self.rgb = np.concatenate((self.rgb, other_cloud.rgb))
|
|
self.indices = np.concatenate((self.indices, new_indices))
|
|
self.extra_dimensions = { name: np.concatenate((values, other_cloud.extra_dimensions[name])) for name, values in self.extra_dimensions.items() }
|
|
|
|
def update(self, other_cloud):
|
|
for name, dimension in self.extra_dimensions_metadata.items():
|
|
if name not in other_cloud.extra_dimensions:
|
|
dimension.assign_default(other_cloud)
|
|
for name, dimension in other_cloud.extra_dimensions_metadata.items():
|
|
if name not in self.extra_dimensions:
|
|
dimension.assign_default(self)
|
|
self.xy[other_cloud.indices] = other_cloud.xy
|
|
self.z[other_cloud.indices] = other_cloud.z
|
|
self.classification[other_cloud.indices] = other_cloud.classification
|
|
self.rgb[other_cloud.indices] = other_cloud.rgb
|
|
for name, values in self.extra_dimensions.items():
|
|
values[other_cloud.indices] = other_cloud.extra_dimensions[name]
|
|
|
|
def add_dimension(self, dimension, values):
|
|
self.extra_dimensions[dimension.get_name()] = values
|
|
self.extra_dimensions_metadata[dimension.get_name()] = dimension
|
|
|
|
def get_xy(self):
|
|
return self.xy
|
|
|
|
def get_z(self):
|
|
return self.z
|
|
|
|
def len(self):
|
|
return len(self.z)
|
|
|
|
def get_extra_dimension_values(self, name):
|
|
return self.extra_dimensions[name]
|
|
|
|
def get_bounding_box(self):
|
|
[x_min, y_min] = np.amin(self.xy, axis=0)
|
|
[x_max, y_max] = np.amax(self.xy, axis=0)
|
|
z_min = min(self.z)
|
|
z_max = max(self.z)
|
|
return BoundingBox3D(x_min, x_max, y_min, y_max, z_min, z_max)
|
|
|
|
|
|
class BoundingBox3D:
|
|
def __init__(self, x_min, x_max, y_min, y_max, z_min, z_max):
|
|
self.x_min = x_min
|
|
self.x_max = x_max
|
|
self.y_min = y_min
|
|
self.y_max = y_max
|
|
self.z_min = z_min
|
|
self.z_max = z_max
|
|
|
|
def keep_points_inside(self, point_cloud):
|
|
min = np.array([self.x_min, self.y_min, self.z_min])
|
|
max = np.array([self.x_max, self.y_max, self.z_max])
|
|
|
|
arr = np.column_stack((point_cloud.get_xy(), point_cloud.get_z()))
|
|
mask = np.all(np.logical_and(min <= arr, arr <= max), axis=1)
|
|
|
|
return point_cloud[mask]
|