Files
massive-cloud/alg/点云测距v1.1/train_measurement_system/README.md

487 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 列车点云测量系统
基于配置驱动的点云测量系统,支持多种测量任务类型。通过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拟合
- **并行处理**:多个任务顺序执行,单个任务失败不影响其他任务