当前位置:首页>python>Python 点云处理:点云读取与邻域点云提取

Python 点云处理:点云读取与邻域点云提取

  • 2026-09-19 21:27:18
Python 点云处理:点云读取与邻域点云提取
点云处理是自动驾驶、三维视觉和测绘建模等领域的核心基础,而点云读取和指定坐标的邻域点云提取,是进行点云分析的基础。本文将基于 Python 的 laspy 和 pointcloud 库,介绍从点云文件读取到邻域点云精准提取的全流程,代码简洁可直接复用。
一、前置准备:laspy、pointcloud、scipy和 库
laspy库主要用于 LAS/LAZ 格式点云文件的高效读写,pointcloud 专注点云处理。scipy 是数据分析 / 三维处理的常用库,核心通过构建 KD 树空间索引,实现半径邻域和K 近邻两种主流提取方式。Pandas库用于实现邻域点云的结构化存储。
二、点云读取
点云读取在函数read_las中实现。
import laspyfrom pyntcloud import PyntClouddef read_las(filepath):    las = laspy.read(filepath)    # 2. 将所有字段转为Pandas DataFrame(保留全量信息)    las_data = {        "x": las.x,        "y": las.y,        "z": las.z,        "intensity": las.intensity,  # 强度        "classification": las.classification,  # 分类        "return_number": las.return_number  # 回波次数    }    # 补充所有扩展字段(按需添加)    for dim in las.point_format.dimension_names:        if dim not in las_data:            las_data[dim] = getattr(las, dim)    # 3. 转为PyntCloud对象(全量数据无损失)    cloud = PyntCloud(pd.DataFrame(las_data))    return cloud
三、点云邻域提取
邻域点云提取是点云分析的基础操作,核心需求是:给定一个目标二维/三维坐标,提取以该坐标为中心、指定范围内的所有点云。本次用 pointcloud 库实现半径邻域提取(最常用),步骤为 “构建点云索引→给定参数→提取邻域点云”,代码如下:
def pyntcloud_batch_neighbors(        cloud: PyntCloud,        centers: list,        search_type: str = "radius",        radius: float = None,        k: int = None,        use_2d: bool = True) -> list[PyntCloud]:    """    批量查询多个中心的邻域点云(复用KDTree,避免重复构建)    :param centers: 中心坐标列表,如 [(x1,y1), (x2,y2), ...]    :radius:邻域范围    :return: 邻域点云列表,与centers一一对应    """    # 1. 仅构建1次KDTree(批量查询的核心优化)    if use_2d:        coords = cloud.points[["x", "y"]].values    else:        coords = cloud.points[["x", "y", "z"]].values    kdtree = KDTree(coords)    for idx, center in enumerate(centers):        center = center[0:2]        center_arr = np.array(center).reshape(1, 2 if use_2d else 3)        if search_type == "radius":            neighbor_idx = kdtree.query_ball_point(center_arr, radius)[0]        else:            _, neighbor_idx = kdtree.query(center_arr, k=k)            neighbor_idx = neighbor_idx[0]            # 筛选邻域点云        if len(neighbor_idx) == 0:            empty_df = pd.DataFrame(columns=cloud.points.columns)            # neighbor_clouds.append(PyntCloud(empty_df))            print(f"警告:中心{idx + 1}({center}) 邻域内无点云")        else:            neighbor_points = cloud.points.iloc[neighbor_idx].reset_index(drop=True)            Neighbor_P = PyntCloud(neighbor_points)            # Neighbor_P.to_file("Processed_SHP/" + "A_" + str(idx) + '.ply')            pyntcloud2las(Neighbor_P,"Processed_SHP/" + "A_" + str(idx) + '.las')    print(f"✅ 批量查询完成:共处理 {len(centers)} 个中心")

关键说明

  1. KDTree建立索引,会大幅提升邻域检索速度;
  2. pyntcloud2las为本文存储邻域点云的函数,实现代码如下:

def pyntcloud2las(        pynt_cloud: PyntCloud,        las_save_path: str,        xyz_precision: int = 6,  # 坐标保留小数位数(避免科学计数法)        add_intensity: bool = True,  # 是否添加默认强度字段        overwrite: bool = True) -> bool:    """    直接将PyntCloud格式点云保存为LAS格式(无中间文件)    :param pynt_cloud: 输入的PyntCloud点云对象    :param las_save_path: LAS文件保存路径(如"output/neighbor.las")    :param xyz_precision: 坐标保留小数位数(默认6位)    :param add_intensity: 是否添加强度字段(LAS常用,默认填充0)    :param overwrite: 是否覆盖已存在的LAS文件    :return: 保存成功返回True,失败返回False    """    # 1. 校验输入点云是否为空    if len(pynt_cloud.points) == 0:        print("错误:PyntCloud点云为空,无法保存为LAS!")        return False    # 2. 校验输出路径    if os.path.exists(las_save_path) and not overwrite:        print(f"警告:LAS文件已存在,跳过 → {las_save_path}")        return False    os.makedirs(os.path.dirname(las_save_path), exist_ok=True)  # 创建目录    try:        # 3. 提取点云数据并预处理(适配LAS格式要求)        points_df = pynt_cloud.points.copy()        # 3.1 必选字段校验(LAS必须有x/y/z)        required_fields = ["x", "y", "z"]        if not all(f in points_df.columns for f in required_fields):            print(f"错误:点云缺少必选字段!需包含:{required_fields}")            return False        # 3.2 坐标精度处理(取消科学计数法,保留指定小数位)        points_df = points_df.round({            "x": xyz_precision,            "y": xyz_precision,            "z": xyz_precision        })        # 转为LAS要求的float64类型        x = points_df["x"].astype(np.float64).values        y = points_df["y"].astype(np.float64).values        z = points_df["z"].astype(np.float64).values        # 4. 初始化LAS文件(设置头文件,兼容主流软件)        # point_format=3 支持更多字段,version=1.4 是常用版本        las_header = laspy.LasHeader(point_format=3, version="1.4")        # 设置坐标偏移(用最小值偏移,减少文件体积,LAS优化)        las_header.offsets = (np.min(x), np.min(y), np.min(z))        # 设置缩放因子(对应小数精度,0.000001=6位小数)        las_header.scales = (10 ** -xyz_precision,) * 3        # 5. 写入LAS数据        las_file = laspy.LasData(las_header)        las_file.x = x        las_file.y = y        las_file.z = z        # 可选:添加强度字段(LAS标准字段,默认填充0)        if add_intensity:            las_file.intensity = np.zeros(len(x), dtype=np.uint16)        # 可选:添加分类字段(默认分类为0,代表未分类)        las_file.classification = np.zeros(len(x), dtype=np.uint8)        # 6. 保存LAS文件        las_file.write(las_save_path)        print(f"✅ PyntCloud点云已保存为LAS → {las_save_path}")        print(f"   点数:{len(las_file.points)} | 坐标精度:{xyz_precision}位小数")        return True    except Exception as e:        print(f"保存LAS失败:{e}")        return False
四、实现效果
下图左侧面板呈现的是未经处理的完整点云数据,涵盖了研究场景内全部点的 x、y、z 三维坐标及相关属性信息;右侧面板为依托本文编写的邻域查询代码(基于 KDTree 批量检索算法),从完整点云中提取的目标中心对应的局部邻域点云,直观反映了代码对邻域点云的精准提取效果。

最新文章

随机文章