列车点云测量系统
基于配置驱动的点云测量系统,支持多种测量任务类型。通过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. 创建并激活环境
# 创建 conda 环境
conda create -n pcc-experiment python=3.9
conda activate pcc-experiment
2. 安装依赖
方式一:使用 requirements.txt
pip install -r requirements.txt
方式二:安装项目
# 正常安装
pip install .
# 或开发模式安装(代码修改立即生效)
pip install -e .
安装项目会自动安装所有依赖包,并将项目注册到 Python 环境中。
2. 准备点云文件
确保你有完整的列车点云文件(PLY格式),例如:
D:\lab\PCC\PCC\head_train_pointcloud\train_2_100M.ply
3. 配置测量任务
编辑 config/measurements.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. 运行测量
# 使用默认配置文件
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(平面到平面距离)
从源平面采样点,计算到目标平面的距离。适用于测量车门高度、车体长度、窗口高度等。
工作流程:
- 从source_roi包围盒提取点云
- 使用RANSAC拟合源平面
- 从拟合的内点中随机采样指定数量的点
- 从target_roi包围盒提取点云
- 使用RANSAC拟合目标平面
- 计算采样点到目标平面的有向距离
- 统计平均值、标准差、最小/最大距离
配置参数:
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(点到平面距离)
测量指定点到参考平面的距离。支持两种模式:精确坐标查找和包围盒筛选。
工作流程:
- 根据模式获取测量点:
exact_points模式:在点云中查找最近点bbox_filtered模式:从包围盒提取点云并筛选
- 从target_roi提取点云并拟合参考平面(目前的实现中,直接用z=0平面,不做拟合)
- 计算每个点到平面的距离
- 统计平均值、标准差等
配置参数(exact_points模式):
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模式):
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对称的点对)。
工作流程:
- 获取测量点:在点云中查找最近点
- 根据z坐标符号自动配对(z>0和z<0的点配对)
- 计算每对点之间的欧氏距离
- 统计平均值、标准差等
配置参数:
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:包含测量点的点云
配置文件说明
基本结构
# 点云文件路径(必填)
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_pointenabled:是否启用任务(必填),设为false可跳过该任务description:任务描述(可选),用于文档说明visualization_dir:可视化输出目录(可选),设置后会保存ROI点云文件
包围盒格式
所有包围盒使用以下格式,坐标单位为毫米(mm):
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
调优建议:
- 先运行一次,查看内点率
- 如果内点率低于min_inlier_ratio,任务会失败
- 根据实际内点率调整参数:
- 内点率50%-60%:降低min_inlier_ratio或增大ransac_threshold
- 内点率>90%:可以提高要求,减小ransac_threshold
添加新任务
步骤1:确定测量类型
根据测量需求选择合适的类型:
- 平面到平面距离:车门高度、车体长度、窗口高度等
- 点到平面距离:特定点到参考平面的高度
- 点到点距离:对称点对之间的距离
步骤2:确定ROI包围盒
方法1:使用点云浏览器工具
方法2:使用CloudCompare或Open3D或Freecad手动查看
- 打开点云文件
- 使用测量工具确定目标区域的坐标范围
- 记录包围盒的最小和最大坐标
步骤3:编辑配置文件
在 config/measurements.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:运行测试
python main.py
步骤5:验证结果
- 查看Excel报告:检查测量结果是否合理
- 查看可视化点云:使用CloudCompare或Open3D打开PLY文件
- 确认ROI提取的位置正确
- 确认平面拟合质量(内点率)
- 调整参数:如果结果不理想,调整包围盒或RANSAC参数
技术细节
平面拟合算法
系统使用Open3D的RANSAC算法进行平面拟合:
- 随机采样:从点云中随机选择3个点
- 拟合平面:计算平面方程 ax + by + cz + d = 0
- 统计内点:计算所有点到平面的距离,距离小于阈值的为内点
- 迭代优化:重复上述步骤,选择内点最多的平面
- 最终拟合:使用所有内点进行最小二乘拟合(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拟合
- 并行处理:多个任务顺序执行,单个任务失败不影响其他任务