You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Open3D将点云下采样至指定点数适配PointNet模型?

Open3D实现点云固定点数下采样的实用方案

针对你需要将不定点数的实时点云下采样到固定数量(如4096点)的需求,这里提供两种适配Open3D的实现方法,分别满足速度和采样质量的不同要求:

方法1:随机采样(快速高效)

适合对实时性要求极高的场景,实现简单但采样点分布可能不均匀。

import open3d as o3d
import numpy as np

def random_downsample(pcd, target_num):
    points = np.asarray(pcd.points)
    # 若原点数少于目标数,直接返回原云
    if len(points) <= target_num:
        return pcd
    
    # 生成无重复的随机索引
    indices = np.random.choice(len(points), target_num, replace=False)
    # 构建采样后的点云
    sampled_pcd = o3d.geometry.PointCloud()
    sampled_pcd.points = o3d.utility.Vector3dVector(points[indices])
    
    # 保留原云的颜色、法向量等属性
    if pcd.has_colors():
        sampled_pcd.colors = o3d.utility.Vector3dVector(np.asarray(pcd.colors)[indices])
    if pcd.has_normals():
        sampled_pcd.normals = o3d.utility.Vector3dVector(np.asarray(pcd.normals)[indices])
    
    return sampled_pcd

# 使用示例
raw_pcd = o3d.io.read_point_cloud("real_time_point_cloud.pcd")
target_points = 4096
sampled_pcd = random_downsample(raw_pcd, target_points)

方法2:最远点采样(FPS,分布均匀)

适合PointNet模型的特征提取需求,采样点分布更均匀,能更好保留点云全局特征,计算量略大于随机采样但仍适配实时场景。

import open3d as o3d
import numpy as np

def farthest_point_sample(pcd, target_num):
    points = np.asarray(pcd.points)
    num_points = len(points)
    
    if num_points <= target_num:
        return pcd
    
    # 初始化采样索引(随机选第一个点)
    sampled_indices = [np.random.randint(num_points)]
    # 记录所有点到最近采样点的距离
    distances = np.linalg.norm(points - points[sampled_indices[0]], axis=1)
    
    for _ in range(target_num - 1):
        # 选择当前距离最远的点
        farthest_idx = np.argmax(distances)
        sampled_indices.append(farthest_idx)
        # 更新所有点到最近采样点的距离
        new_distances = np.linalg.norm(points - points[farthest_idx], axis=1)
        distances = np.minimum(distances, new_distances)
    
    # 生成采样点云
    sampled_pcd = o3d.geometry.PointCloud()
    sampled_pcd.points = o3d.utility.Vector3dVector(points[sampled_indices])
    
    # 保留原属性
    if pcd.has_colors():
        sampled_pcd.colors = o3d.utility.Vector3dVector(np.asarray(pcd.colors)[sampled_indices])
    if pcd.has_normals():
        sampled_pcd.normals = o3d.utility.Vector3dVector(np.asarray(pcd.normals)[sampled_indices])
    
    return sampled_pcd

# 使用示例
raw_pcd = o3d.io.read_point_cloud("real_time_point_cloud.pcd")
target_points = 4096
sampled_pcd = farthest_point_sample(raw_pcd, target_points)

优化版FPS(KDTree加速)

针对大点数云(100k-200k),用Open3D的KDTree优化距离计算,进一步提升速度:

def fps_with_kdtree(pcd, target_num):
    points = np.asarray(pcd.points)
    num_points = len(points)
    
    if num_points <= target_num:
        return pcd
    
    kdtree = o3d.geometry.KDTreeFlann(pcd)
    sampled_indices = [np.random.randint(num_points)]
    distances = np.full(num_points, np.inf)
    
    # 初始化第一个点的距离
    _, idx, dist = kdtree.search_radius_vector_3d(points[sampled_indices[0]], np.inf)
    distances[idx] = dist
    
    for _ in range(target_num - 1):
        farthest_idx = np.argmax(distances)
        sampled_indices.append(farthest_idx)
        # 用KDTree批量计算距离
        _, idx, dist = kdtree.search_radius_vector_3d(points[farthest_idx], np.inf)
        distances[idx] = np.minimum(distances[idx], dist)
    
    sampled_pcd = o3d.geometry.PointCloud()
    sampled_pcd.points = o3d.utility.Vector3dVector(points[sampled_indices])
    
    if pcd.has_colors():
        sampled_pcd.colors = o3d.utility.Vector3dVector(np.asarray(pcd.colors)[sampled_indices])
    if pcd.has_normals():
        sampled_pcd.normals = o3d.utility.Vector3dVector(np.asarray(pcd.normals)[sampled_indices])
    
    return sampled_pcd

选型建议

  • 实时性优先:用随机采样,100k点云的采样耗时在毫秒级;
  • 模型精度优先:用FPS或优化版FPS,采样点分布均匀,更贴合PointNet的输入要求;
  • 训练阶段建议统一用FPS采样,提升模型泛化能力。

内容的提问来源于stack exchange,提问作者Atta Ur Rahman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 20:55:16