2 minute read

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
voxel.gif

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
aleatorio.gif