Files
massive-cloud/docs/点云测距算法性能分析报告.md
lipan 29f1d45d66 feat: 算法升级、整车配准集成与性能分析文档
算法更新: delivery v1.2.1、平整度v1.5、测距v2.2、整车配准v1.3
适配器: vehicle-registration 新增、各算法 manifest 和 adapter 更新
后端: taskCadFiles/source 字段迁移、derivedPointClouds 注册、取消任务联动
前端: ElapsedTime 时长显示、两步算法流程、canRun 逻辑修复
文档: 新增5份算法性能分析报告
2026-06-25 08:22:20 +00:00

141 lines
5.9 KiB
Markdown
Raw Permalink 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.
# 点云测距算法性能分析报告
> 分析时间:2026-06-25
> 算法版本:`train_measurement_system_v2.2`
> 入口类:`TaskManager`(`src/task_manager.py`)
> 测试环境:INTEL SSDSC2KB01(SATA SSD,~394 MB/s);CPU 128 核
> 配置文件:`config/measurements_0618.yaml`(20 个测量任务)
---
## 执行流程总览
```
train_measurement_run.py (adapter)
├─ tm.pointcloud_path_override = pc_path
├─ tm.load_config() # 读 YAML,解析 20 个任务
├─ tm.load_point_cloud() # 一次性加载整车点云到内存 ← 瓶颈1
└─ tm.run_all_tasks()
├─ 任务1: plane_to_plane
│ ├─ ROIExtractor.extract_bbox_points() # numpy 布尔索引,O(N)
│ ├─ PlaneFitter.fit() × 2 # RANSAC,O(k×M)
│ └─ distance calculation
├─ 任务2: plane_to_plane ... (× 10 个)
├─ 任务n: point_to_point ... (× 3 个)
├─ 任务n: point_to_plane ... (× 3 个)
├─ 任务n: plane_to_plane + 4_hole_center ... (× 2 个)
└─ 任务n: point_to_point + hole_center ... (× 2 个)
```
---
## 各步骤详细说明与时间估算
### 第一阶段:I/O — 加载点云
| # | 步骤 | 代码位置 | 说明 | 估算时间 |
|---|---|---|---|---|
| 1 | `PointCloudLoader.load_ply` | `pointcloud_loader.py:11` | 逐点 `struct.unpack` for loop,**O(N) 次 Python 调用** ← 瓶颈 | **~3 min(10亿点)** |
**关键问题**:当前 `_read_binary_ply` 使用 `struct.unpack` 逐点循环,实测 ~5 M 点/s。对比 `np.frombuffer`(~30 M 点/s)慢 6×,10 亿点需要约 3 分钟仅用于读取。
```python
# 当前实现:每个点一次 Python 函数调用
for _ in range(vertex_count): # ← N次循环
data = struct.unpack(fmt, f.read(struct_size)) # ← N次 struct.unpack
points.append(data[:3])
# 理想实现:一次性内存操作
data = f.read(vertex_count * struct_size)
arr = np.frombuffer(data, dtype=record_dtype) # ← 1次调用,~6× 更快
```
---
### 第二阶段:每个测量任务的执行(共 20 个)
每个任务共享同一份全量点云 `self.point_cloud`(已加载到内存),按序独立执行。
#### 子步骤 A:ROI 裁剪
| # | 步骤 | 代码位置 | 说明 | 估算时间(单任务) |
|---|---|---|---|---|
| 2 | `ROIExtractor.extract_bbox_points` | `roi_extractor.py:10` | numpy 全量布尔掩码,O(N) | **~2–5 s(10亿点)** |
> **重要**:每个任务都调用一次 `extract_bbox_points`,对 10 亿点全量 numpy 数组做 3 列比较。20 个任务 × 2–5 s = **~40–100 s 只用于 ROI 掩码**,而 ROI 内实际只有 100–10 万个点。
各任务 ROI 尺寸与预期点数(10 亿点密度下):
| 任务 | 类型 | source ROI 尺寸 (mm) | source 预期点数 |
|---|---|---|---|
| 任务21_侧门高度 | plane_to_plane | `[1000, 4, 20]` | ~221 pts |
| 任务2_车体长度 | plane_to_plane | `[4, 400, 1600]` | ~7,091 pts |
| 任务43_窗口下沿高度 | plane_to_plane | `[1210, 2, 5]` | ~33 pts |
| 任务44_车顶高度 | plane_to_plane | `[10449, 2, 474]` | ~27,439 pts |
#### 子步骤 B:平面拟合(plane_to_plane / point_to_plane 任务)
| # | 步骤 | 代码位置 | 默认参数 | 说明 | 估算时间(单任务) |
|---|---|---|---|---|---|
| 3 | `PlaneFitter.fit`(RANSAC) | `plane_fitter.py:44` | `max_iter=1000, threshold=0.1, sample_pts=100` | RANSAC:1000 次随机抽 3 点 + 全 ROI 距离计算 | **< 0.1 s(ROI内千点级)** |
| 4 | SVD 精确平面拟合 | `plane_fitter.py:137` | `max_svd_pts=10000` | 收敛后 SVD 精确拟合;>1 万点自动降采样 | **< 0.1 s** |
| 5 | 计算平面间距离 | `plane_distance.py` | — | 点到平面距离 + 统计 | **< 0.01 s** |
#### 子步骤 C:孔心检测(含 `_hole_center` 的任务)
| # | 步骤 | 代码位置 | 说明 | 估算时间(单任务) |
|---|---|---|---|---|
| 6 | `HoleDetector.detect` | `hole_detect/hole_detector.py` | 圆心检测 + RANSAC 圆拟合 | **~2–5 s** |
---
### 第三阶段:结果输出
| # | 步骤 | 代码位置 | 说明 | 估算时间 |
|---|---|---|---|---|
| 7 | `ExcelExporter.export` | `excel_exporter.py` | openpyxl 生成 xlsx | **~5 s** |
| 8 | `MeasurementLogger.save` | `measurement_logger.py` | JSON 结果落盘 | **< 1 s** |
---
## 总时间汇总(10 亿点输入)
| 阶段 | 估算耗时 | 说明 |
|---|---|---|
| **struct loop 读取 12 GB 点云** | **~3 min** | 10 亿次 Python 调用 |
| **20 次全量 ROI 布尔索引** | **~40–100 s** | 每次 O(N),共 20 次 |
| 20 个任务实际测量计算 | **~20 s** | ROI 内点数少,RANSAC 极快 |
| 孔心检测(共 6 次) | **~20 s** | — |
| 输出(Excel + JSON) | **~5 s** | — |
| **估算总计** | **~5–6 min** | 远超算法方测试的 ROI 后场景 |
> 算法方基准(~2 min)是直接在 ROI 后的小点云上跑的结果,没有计入全量加载和 20 次全量 ROI 索引的开销。
---
## 主要瓶颈与优化建议
### 瓶颈 1:`struct.unpack` 逐点读取(改算法方可根治)
```
当前:struct.unpack × 10亿次 → ~3 min
优化:np.frombuffer 一次性读 → ~35 s
速度提升:~5×,改动:pointcloud_loader.py _read_binary_ply 约 3 行
```
### 瓶颈 2:20 次全量 numpy 布尔索引(适配器层可缓解)
```
当前:每个任务都对 10亿点数组做 3 列 boolean 比较,共 20 次
优化方案 A:adapter 预处理——用 Open3D 先按整车大 bbox 粗裁剪到 ~1亿点,
再传给 TaskManager,ROI 索引代价降 10×
优化方案 B:修改 TaskManager,第一次裁剪后缓存点云,
下一个任务的 ROI 在上次结果上继续裁(层次裁剪)
```
---
## GPU 使用情况
**不使用 GPU。** 所有计算为 CPU + numpy + scipy,无 torch/CUDA 依赖。