1. 点云数据读取与可视化

任务目标

本案例将使用 Open3D 读取 PCD/PLY 格式的点云文件,并实现基本的 3D 可视化。完成本案例后,你将能够:加载点云数据、在交互式窗口中旋转/缩放/平移视角,并通过键盘切换不同视角(前视、俯视、侧视)。

环境与依赖

  • Python 3.8+
  • Open3D:pip install open3d
  • NumPy(Open3D 自动依赖,无需单独安装)

实现代码

以下代码完整实现了点云读取、可视化与视角切换功能。代码中内置了示例数据生成逻辑,确保在没有外部文件时也能直接运行验证。

import open3d as o3d
import numpy as np
import os
import sys

# ========== 1. 数据准备:生成或加载点云 ==========
def get_point_cloud(file_path=None):
    """从文件加载点云;若文件不存在或未指定,则生成一个示例点云(彩色立方体表面)"""
    if file_path and os.path.exists(file_path):
        # 根据扩展名自动选择读取函数
        ext = os.path.splitext(file_path)[1].lower()
        if ext in ['.pcd', '.ply']:
            pcd = o3d.io.read_point_cloud(file_path)
            if pcd.is_empty():
                raise ValueError(f"文件 {file_path} 中未读取到有效点云")
            return pcd
        else:
            raise ValueError(f"不支持的文件格式: {ext},仅支持 .pcd 或 .ply")
    
    # 生成示例点云:立方体表面 + 随机噪声,便于观察三维结构
    print("未指定有效文件,生成示例点云(立方体表面)...")
    # 生成立方体8个顶点
    vertices = np.array([
        [0,0,0], [1,0,0], [1,1,0], [0,1,0],
        [0,0,1], [1,0,1], [1,1,1], [0,1,1]
    ], dtype=np.float64)
    # 对每条边进行插值,形成表面点
    edges = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),(0,4),(1,5),(2,6),(3,7)]
    points = []
    for a, b in edges:
        for t in np.linspace(0, 1, 20):
            points.append(vertices[a] + t * (vertices[b] - vertices[a]))
    points = np.array(points)
    # 添加少量噪声使点云更真实
    points += np.random.normal(0, 0.01, points.shape)
    
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(points)
    # 根据坐标生成颜色(便于视觉区分方向)
    colors = (points - points.min(axis=0)) / (points.max(axis=0) - points.min(axis=0))
    pcd.colors = o3d.utility.Vector3dVector(colors)
    return pcd

# ========== 2. 视角切换回调 ==========
view_control = None  # 全局引用,供回调使用

def switch_view(vis):
    """键盘回调:按1=前视(X轴),2=俯视(Z轴),3=侧视(Y轴)"""
    global view_control
    key = vis.get_key_code()
    ctr = vis.get_view_control()
    
    if key == ord('1'):      # 前视:沿X轴看
        ctr.set_front([1, 0, 0])
        ctr.set_up([0, 0, 1])
    elif key == ord('2'):    # 俯视:沿Z轴看
        ctr.set_front([0, 0, 1])
        ctr.set_up([0, 1, 0])
    elif key == ord('3'):    # 侧视:沿Y轴看
        ctr.set_front([0, 1, 0])
        ctr.set_up([0, 0, 1])
    else:
        return False
    return False  # 返回False表示不阻止其他事件

# ========== 3. 主程序 ==========
def main():
    # 支持命令行传入文件路径:python script.py your_file.pcd
    file_path = sys.argv[1] if len(sys.argv) > 1 else None
    
    # 加载点云
    pcd = get_point_cloud(file_path)
    print(f"点云点数: {len(pcd.points)}")
    
    # 创建可视化窗口
    vis = o3d.visualization.VisualizerWithKeyCallback()
    vis.create_window(window_name="3D点云可视化", width=800, height=600)
    
    # 添加点云到场景
    vis.add_geometry(pcd)
    
    # 注册键盘回调
    vis.register_key_callback(ord('1'), switch_view)
    vis.register_key_callback(ord('2'), switch_view)
    vis.register_key_callback(ord('3'), switch_view)
    
    # 设置初始视角(默认等轴测视角)
    ctr = vis.get_view_control()
    ctr.set_front([-0.5, -0.5, -0.5])  # 等轴测方向
    ctr.set_up([0, 0, 1])
    
    # 启动交互式窗口(阻塞直到窗口关闭)
    vis.run()
    vis.destroy_window()

if __name__ == "__main__":
    main()

运行方式

  1. 将上述代码保存为 pointcloud_viewer.py
  2. 直接运行(使用内置示例数据):python pointcloud_viewer.py
  3. 或指定点云文件运行:python pointcloud_viewer.py your_pointcloud.pcd(支持 .pcd 和 .ply)

验证方法与判定标准

运行程序后,应出现一个3D可视化窗口,其中显示彩色立方体点云(或你指定的点云文件)。通过以下操作验证功能是否正常:

  • 旋转:按住鼠标左键拖动,点云应随鼠标旋转
  • 缩放:滚动鼠标滚轮,点云应放大/缩小
  • 平移:按住 Ctrl + 鼠标左键拖动(或按住鼠标右键拖动),点云应平移
  • 视角切换:按下键盘 1 键,视角切换为前视(沿X轴方向);按 2 键切换为俯视(沿Z轴方向);按 3 键切换为侧视(沿Y轴方向)

通过条件:以上所有交互操作均能正常响应,且视角切换后点云显示方向正确(例如俯视时看到的是立方体顶面)。窗口关闭后程序正常退出,无报错。

常见问题

  • 窗口无法打开:确认已安装 Open3D 且版本 ≥ 0.13(pip install --upgrade open3d)
  • 读取文件失败:确认文件路径正确且格式为 PCD/PLY 二进制或 ASCII 格式
  • 视角切换无效:确保点击窗口使其获得键盘焦点后再按键