Semana 20. Implementación de la reducción de la densidad utilizando diferentes algoritmos
MUESTREO BASADO EN VOXELIZACIÓN
El primer algoritmo de reducción de la densidad que he implementado es el basado en la voxelización. Para ello se ha utilizado la funcionvoxel_down_sample
de la librería open3d
. Este método permite reducir la densidad de una nube de puntos agrupando los puntos en voxeles (volumenes cúbicos) y seleccionando un punto representativo por voxel. Esto no solo reduce la densidad de la nube de puntos, si no que tambien mantiene la estructura original de la nube de puntos.
def reduce_point_cloud_by_voxel(points: np.ndarray, remissions: np.ndarray, voxel_size: float) -> tuple[np.ndarray, np.ndarray]:
"""
Reduce la densidad de la nube de puntos utilizando voxelización.
:param points: Nube de puntos original (N, 3)
:param remissions: Intensidades de los puntos originales (N,)
:param voxel_size: Tamaño del voxel (en las mismas unidades que las coordenadas de los puntos)
:return: Puntos reducidos y sus intensidades
"""
# Crear una nube de puntos en Open3D
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)
# Aplicar filtrado por voxelización
downsampled_pcd = pcd.voxel_down_sample(voxel_size)
# Obtener los puntos reducidos
reduced_points = np.asarray(downsampled_pcd.points)
# Si hay intensidades, asignarlas a los puntos reducidos
if len(remissions) > 0:
# Encontrar los índices de los puntos originales más cercanos a los puntos reducidos
nn = NearestNeighbors(n_neighbors=1)
nn.fit(points)
_, indices = nn.kneighbors(reduced_points)
reduced_remissions = remissions[indices.flatten()]
else:
reduced_remissions = np.zeros(len(reduced_points))
return reduced_points, reduced_remissions

MUESTREO ALEATORIO
Además del método de voxelización, he implementado un método de muestreo aleatorio. Este método selecciona aleatoriamente un subconjunto de puntos de la nube de puntos original. Este método reduce el numero de puntos de la nube en función de un indice de densidad, muestreando aleatoriamente un numero de puntos de la nube de puntos original y manteniendo los valores de intensidad de los puntos originales.
El algoritmo utiliza un índice de densidad (un valor entre 0 y 1) para determinar la proporción de puntos que se conservarán. Por ejemplo, un índice de densidad de 0.5 reducirá la nube de puntos a la mitad de su tamaño original.
def reduce_point_cloud_by_density(points: np.ndarray, remissions: np.ndarray, density_index: float) -> tuple[np.ndarray, np.ndarray]:
"""
Reduce la densidad de la nube de puntos utilizando un índice de densidad.
Los valores de intensidad (remisiones) de los puntos muestreados son los mismos que los de los puntos originales.
:param points: Nube de puntos original (N, 3)
:param remissions: Intensidades de los puntos originales (N,)
:param density_index: Índice de densidad (0 < density_index <= 1)
:return: Puntos reducidos y sus intensidades
"""
if density_index <= 0 or density_index > 1:
raise ValueError("El índice de densidad debe estar entre 0 y 1.")
# Calcular el número de puntos a muestrear
num_points = len(points)
num_samples = int(num_points * density_index)
# Muestrear aleatoriamente los puntos junto con sus intensidades
indices = np.random.choice(num_points, num_samples, replace=False)
reduced_points = points[indices]
reduced_remissions = remissions[indices]
return reduced_points, reduced_remissions
