# 列车点云测量系统 基于配置驱动的点云测量系统,支持多种测量任务类型。通过YAML配置文件定义测量任务,自动完成ROI提取、平面拟合、距离计算,并生成Excel报告和可视化点云文件。 ## 项目结构 ``` train_measurement_system/ ├── config/ │ └── measurements.yaml # 测量任务配置文件 ├── src/ │ ├── __init__.py # 包初始化文件 │ ├── measurements/ │ │ ├── __init__.py # 子包初始化文件 │ │ ├── base.py # 测量任务基类 │ │ ├── plane_distance.py # 平面到平面距离测量 │ │ ├── point_to_plane.py # 点到平面距离测量 │ │ └── point_to_point.py # 点到点距离测量 │ ├── config_loader.py # 配置加载器 │ ├── task_manager.py # 任务管理器 │ ├── roi_extractor.py # ROI提取 │ ├── plane_fitter.py # 平面拟合(RANSAC) │ ├── pointcloud_loader.py # 点云加载 │ ├── visualizer.py # 可视化工具 │ └── excel_exporter.py # Excel导出 ├── results/ # 测量结果输出目录(Excel文件) ├── visualizations/ # 可视化点云输出目录(PLY文件) ├── main.py # 主程序入口 ├── pyproject.toml # 项目配置文件(PEP 621) ├── setup.py # 安装脚本(向后兼容) ├── requirements.txt # 依赖清单 ├── USAGE.md # 使用说明 └── README.md # 本文件 ``` ## 功能特性 - **配置驱动**: 通过YAML配置文件定义测量任务,无需修改代码 - **多任务类型**: 支持平面到平面、点到平面、点到点三种测量类型 - **批量处理**: 一次运行可执行多个测量任务 - **自动可视化**: 自动保存每个任务的ROI点云(PLY格式) - **结果导出**: 自动生成格式化的Excel报告,包含详细统计信息 - **鲁棒性强**: RANSAC平面拟合,自动处理离群点和噪声 - **错误处理**: 单个任务失败不影响其他任务执行 - **可扩展**: 易于添加新的测量类型 ## 环境要求 - Python 3.9+ - 推荐使用 conda 环境管理 ## 快速开始 ### 1. 创建并激活环境 ```bash # 创建 conda 环境 conda create -n pcc-experiment python=3.9 conda activate pcc-experiment ``` ### 2. 安装依赖 **方式一:使用 requirements.txt** ```bash pip install -r requirements.txt ``` **方式二:安装项目** ```bash # 正常安装 pip install . # 或开发模式安装(代码修改立即生效) pip install -e . ``` 安装项目会自动安装所有依赖包,并将项目注册到 Python 环境中。 ### 2. 准备点云文件 确保你有完整的列车点云文件(PLY格式),例如: ``` D:\lab\PCC\PCC\head_train_pointcloud\train_2_100M.ply ``` ### 3. 配置测量任务 编辑 `config/measurements.yaml`,设置点云文件路径和测量任务。 **支持相对路径(相对于配置文件)或绝对路径:** ```yaml # 相对路径(推荐) pointcloud_file: "../../../head_train_pointcloud/train_2_100M.ply" # 或绝对路径 pointcloud_file: "D:\\lab\\PCC\\PCC\\head_train_pointcloud\\train_2_100M.ply" tasks: - name: "任务21_侧门高度" type: "plane_to_plane" enabled: true description: "测量侧门顶部到底部的距离" visualization_dir: "visualizations" source_roi: bbox_min: [-2500, 3358, -1545] bbox_max: [-1500, 3362, -1525] target_roi: bbox_min: [-2500, 1180, -1621] bbox_max: [-1500, 1180, -1500] params: sample_points: 100 ransac_threshold: 2.0 ransac_max_iterations: 1000 min_inlier_ratio: 0.6 ``` ### 4. 运行测量 ```bash # 使用默认配置文件 python main.py # 指定配置文件 python main.py -c config/custom.yaml # 指定点云文件(覆盖配置文件中的路径) python main.py -p data/train.ply # 指定输出目录 python main.py -o results/ # 组合使用 python main.py -c config/custom.yaml -p data/train.ply -o results/ ``` **命令行参数:** - `-c, --config`: 配置文件路径(默认: config/measurements.yaml) - `-p, --pointcloud`: 点云文件路径(覆盖配置文件) - `-o, --output`: 结果输出目录(默认: results/) ### 5. 查看结果 **Excel报告:** 保存在 `results/` 目录下 - 文件名格式:`measurement_results_YYYYMMDD_HHMMSS.xlsx` - 包含每个任务的详细统计信息: - 任务名称、类型、描述 - 点位参数(ROI 范围、目标点坐标等) - 测量数据(平均距离、标准差、最小/最大距离) - 采样点数、ROI 点数、内点率 - 错误信息(如果失败) **可视化点云:** 保存在 `visualizations/` 目录下 - 文件格式:PLY - 可使用CloudCompare或Open3D查看 - 用于验证ROI提取和测量点位置是否正确 ## 测量类型详解 ### 1. plane_to_plane(平面到平面距离) 从源平面采样点,计算到目标平面的距离。适用于测量车门高度、车体长度、窗口高度等。 **工作流程:** 1. 从source_roi包围盒提取点云 2. 使用RANSAC拟合源平面 3. 从拟合的内点中随机采样指定数量的点 4. 从target_roi包围盒提取点云 5. 使用RANSAC拟合目标平面 6. 计算采样点到目标平面的有向距离 7. 统计平均值、标准差、最小/最大距离 **配置参数:** ```yaml type: "plane_to_plane" source_roi: bbox_min: [x_min, y_min, z_min] bbox_max: [x_max, y_max, z_max] target_roi: bbox_min: [x_min, y_min, z_min] bbox_max: [x_max, y_max, z_max] params: sample_points: 100 # 采样点数 ransac_threshold: 2.0 # RANSAC距离阈值(mm) ransac_max_iterations: 1000 # RANSAC最大迭代次数 min_inlier_ratio: 0.6 # 最小内点比例 ``` **输出结果:** - 平均距离(mm) - 标准差(mm) - 最小/最大距离(mm) - 采样点数 - Source ROI点数 - Target ROI点数 - 平面拟合内点率 **可视化文件:** - `{任务名}_source_roi.ply`:源平面ROI点云 - `{任务名}_target_roi.ply`:目标平面ROI点云 --- ### 2. point_to_plane(点到平面距离) 测量指定点到参考平面的距离。支持两种模式:精确坐标查找和包围盒筛选。 **工作流程:** 1. 根据模式获取测量点: - `exact_points`模式:在点云中查找最近点 - `bbox_filtered`模式:从包围盒提取点云并筛选 2. 从target_roi提取点云并拟合参考平面(目前的实现中,直接用z=0平面,不做拟合) 3. 计算每个点到平面的距离 4. 统计平均值、标准差等 **配置参数(exact_points模式):** ```yaml type: "point_to_plane" mode: "exact_points" points: - [-753.5, 1052.5, 1445] - [3446.5, 1053, 1445] - [-753.5, 1052.5, -1445] target_roi: bbox_min: [x_min, y_min, z_min] bbox_max: [x_max, y_max, z_max] params: search_radius: 50.0 # 查找最近点的搜索半径(mm) ransac_threshold: 2.0 ransac_max_iterations: 1000 min_inlier_ratio: 0.6 use_absolute_distance: true # 是否使用绝对距离 ``` **配置参数(bbox_filtered模式):** ```yaml type: "point_to_plane" mode: "bbox_filtered" source_rois: - bbox_min: [x1_min, y1_min, z1_min] bbox_max: [x1_max, y1_max, z1_max] - bbox_min: [x2_min, y2_min, z2_min] bbox_max: [x2_max, y2_max, z2_max] filter: type: "max_abs_coordinate" # 筛选类型 axis: "z" # 筛选坐标轴 top_n: 10 # 每个ROI选择前N个点 target_roi: bbox_min: [x_min, y_min, z_min] bbox_max: [x_max, y_max, z_max] params: ransac_threshold: 2.0 ransac_max_iterations: 1000 min_inlier_ratio: 0.6 use_absolute_distance: true ``` **输出结果:** - 平均距离(mm) - 标准差(mm) - 最小/最大距离(mm) - 测量点数 - Target ROI点数 - 平面拟合内点率 **可视化文件:** - `{任务名}_found_points.ply`:测量点点云 --- ### 3. point_to_point(点到点距离) 测量点对之间的欧氏距离。支持对称点自动配对(例如测量关于z=0对称的点对)。 **工作流程:** 1. 获取测量点:在点云中查找最近点 2. 根据z坐标符号自动配对(z>0和z<0的点配对) 3. 计算每对点之间的欧氏距离 4. 统计平均值、标准差等 **配置参数:** ``` yaml type: "point_to_point" # 点对配置(使用任务3的6个点,配对测量) point_pairs: - name: "前端点对" point1: [-753.5, 1052.5, -1445] point2: [-753.5, 1052.5, 1445] - name: "中间点对" point1: [3446.5, 1053, -1445] point2: [3446.5, 1053, 1445] - name: "后端点对" point1: [8146.5, 1053, -1445] point2: [8146.5, 1053, 1445] # 最近点搜索半径(mm) search_radius: 10.0 ``` **输出结果:** - 平均距离(mm) - 标准差(mm) - 最小/最大距离(mm) - 点对数量 **可视化文件:** - `{任务名}_found_points.ply`:包含测量点的点云 --- ## 配置文件说明 ### 基本结构 ```yaml # 点云文件路径(必填) pointcloud_file: "D:\\path\\to\\pointcloud.ply" # 测量任务列表 tasks: - name: "任务名称" type: "测量类型" enabled: true/false description: "任务描述" visualization_dir: "visualizations" # ... 其他参数 ``` ### 通用参数 - `name`:任务名称(必填),用于标识任务和命名输出文件 - `type`:测量类型(必填),可选值:`plane_to_plane`、`point_to_plane`、`point_to_point` - `enabled`:是否启用任务(必填),设为`false`可跳过该任务 - `description`:任务描述(可选),用于文档说明 - `visualization_dir`:可视化输出目录(可选),设置后会保存ROI点云文件 ### 包围盒格式 所有包围盒使用以下格式,坐标单位为毫米(mm): ```yaml bbox_min: [x_min, y_min, z_min] bbox_max: [x_max, y_max, z_max] ``` **坐标系说明:** - X轴:列车横向(车头到车尾) - Y轴:列车高度(底部到顶部) - Z轴:列车纵向(左侧到右侧) ### RANSAC参数调优 RANSAC用于平面拟合,以下参数影响拟合质量: - `ransac_threshold`:内点距离阈值(mm) - 较小值(1.0-2.0):严格拟合,适合高质量点云 - 较大值(3.0-5.0):宽松拟合,适合噪声较多的点云 - `ransac_max_iterations`:最大迭代次数 - 默认1000次,通常足够 - 如果内点率很低,可增加到2000-5000 - `min_inlier_ratio`:最小内点比例 - 默认0.6(60%),表示至少60%的点在平面上 - 如果点云包含多个平面或噪声多,可降低到0.4-0.5 **调优建议:** 1. 先运行一次,查看内点率 2. 如果内点率低于min_inlier_ratio,任务会失败 3. 根据实际内点率调整参数: - 内点率50%-60%:降低min_inlier_ratio或增大ransac_threshold - 内点率>90%:可以提高要求,减小ransac_threshold --- ## 添加新任务 ### 步骤1:确定测量类型 根据测量需求选择合适的类型: - **平面到平面距离**:车门高度、车体长度、窗口高度等 - **点到平面距离**:特定点到参考平面的高度 - **点到点距离**:对称点对之间的距离 ### 步骤2:确定ROI包围盒 **方法1:使用点云浏览器工具** **方法2:使用CloudCompare或Open3D或Freecad手动查看** - 打开点云文件 - 使用测量工具确定目标区域的坐标范围 - 记录包围盒的最小和最大坐标 ### 步骤3:编辑配置文件 在 `config/measurements.yaml` 中添加新任务: ```yaml - name: "新任务名称" type: "plane_to_plane" # 或其他类型 enabled: true description: "任务描述" visualization_dir: "visualizations" source_roi: bbox_min: [x_min, y_min, z_min] bbox_max: [x_max, y_max, z_max] target_roi: bbox_min: [x_min, y_min, z_min] bbox_max: [x_max, y_max, z_max] params: sample_points: 100 ransac_threshold: 2.0 ransac_max_iterations: 1000 min_inlier_ratio: 0.6 ``` ### 步骤4:运行测试 ```bash python main.py ``` ### 步骤5:验证结果 1. **查看Excel报告**:检查测量结果是否合理 2. **查看可视化点云**:使用CloudCompare或Open3D打开PLY文件 - 确认ROI提取的位置正确 - 确认平面拟合质量(内点率) 3. **调整参数**:如果结果不理想,调整包围盒或RANSAC参数 --- ## 技术细节 ### 平面拟合算法 系统使用Open3D的RANSAC算法进行平面拟合: 1. **随机采样**:从点云中随机选择3个点 2. **拟合平面**:计算平面方程 ax + by + cz + d = 0 3. **统计内点**:计算所有点到平面的距离,距离小于阈值的为内点 4. **迭代优化**:重复上述步骤,选择内点最多的平面 5. **最终拟合**:使用所有内点进行最小二乘拟合(SVD),得到最优平面 **平面方程:** ax + by + cz + d = 0 - (a, b, c):平面法向量(单位向量) - d:平面到原点的有向距离 ### 距离计算 **点到平面距离:** ``` distance = |ax + by + cz + d| / sqrt(a² + b² + c²) ``` 由于法向量已归一化(sqrt(a² + b² + c²) = 1),简化为: ``` distance = |ax + by + cz + d| ``` **有向距离:** - 正值:点在法向量指向的一侧 - 负值:点在法向量相反的一侧 - 绝对距离:取绝对值,不考虑方向 **点到点距离(欧氏距离):** ``` distance = sqrt((x2-x1)² + (y2-y1)² + (z2-z1)²) ``` ### 性能优化 - **点云缓存**:点云文件只加载一次,所有任务共享 - **自动降采样**:ROI超过10000点时自动降采样到10000点进行SVD拟合 - **并行处理**:多个任务顺序执行,单个任务失败不影响其他任务