Files
massive-cloud/alg/delivery_v1.1/underframe_deflection/USAGE.md

364 lines
12 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.
# underframe_deflection 集成调用指南 (v1.1)
> 高铁底架纵梁挠度测量算法 —— 基于点云的计算。
> 本文档面向把本算法集成进上层软件的开发者:怎么准备 **CAD 基准 + 扫描点云 + ROI JSON** 三件套输入、怎么调用、怎么读结果。
---
## 0. TL;DR
```python
from underframe_deflection import run_measurement_pipeline
report = run_measurement_pipeline(
input_cloud="scan.ply",
cad_path="reference.ply",
roi_path="roi.json",
out_dir="out/",
)
# 关心的两个核心数值
print(report["deflection"]["left"]["selected_measurement"]["signed_deflection_mm"])
print(report["deflection"]["right"]["selected_measurement"]["signed_deflection_mm"])
```
落盘后会得到:
```
out/
├── report.json # 完整结果
├── report.xlsx # 误差报表(Summary + 4 张中间表)
├── deflection_curves.csv # 沿 X 的挠度曲线
├── beam_tracks.csv # 候选梁切片诊断
├── images/ # 5 张诊断 PNG
└── ply/ # 4 个着色 PLY 叠加图
```
---
## 1. 算法的三个输入
| 输入 | 类型 | 必需 | 说明 |
| --- | --- | --- | --- |
| **扫描点云** | `.ply / .xyz / .txt / .csv` | ✅ 必须 | 现场采集得到的 (N, 3) XYZ 点云,单位 mm |
| **CAD 基准** | `.ply / .xyz / .stl / .obj` | 可选但强烈建议 | 预先 tessellate / 采样过的 CAD 几何,作为配准基准坐标系;不直接吃 STEP/IGES |
| **ROI JSON** | `.json` | 可选但强烈建议 | 描述车底测量区域的轴对齐 bbox,坐标基于 CAD 坐标系 |
> 三者**全给**时走 v1.1 完整流程:去噪 → 配准到 CAD 系 → 按 ROI JSON 截区 → 算挠度 → 出 Excel。
> 只给扫描点云时走 legacy 流程,与本算法 v1.0 行为完全一致(仅多出 bilateral 这一步可用 `--no-bilateral` 关掉)。
### 1.1 ROI JSON 文件格式
固定 6 个 float 字段,单位 mm,CAD 坐标系下:
```json
{
"x_min": -12500.0,
"x_max": 12500.0,
"y_min": 150.0,
"y_max": 4100.0,
"z_min": -1680.0,
"z_max": 200.0
}
```
约束:每个轴 `min < max`,且都是有限实数;任一字段缺失或非法 → `InvalidPointCloudError`。
`test_data/sample_roi.json` 是一个可直接使用的样例。
### 1.2 CAD 基准
- **不解析 STEP / IGES**。如果你只有 `.stp`,请用 CAD 软件或离线脚本先把它转成 `.stl` / `.ply` / `.obj`,再喂给本算法。
- 三角网格的话只读顶点位置,face 信息忽略 —— 算法内部把 CAD 当作"参考点集"用 ICP 对齐。
- `test_data/m000004802409t02_asm_100000pts.ply` 是从原始 STEP 采样得到的 10 万点 PLY,可直接当 CAD 基准。
---
## 2. 三种调用方式
### 2.1 命令行(最简单的集成方式)
```bash
underframe-measure \
--input-cloud scan.ply \
--cad reference.ply \
--roi roi.json \
--out-dir out/
```
可选开关:
| 开关 | 含义 |
| --- | --- |
| `--config CONFIG.json` | 覆盖部分内部超参数(结构同 `DEFAULT_CONFIG`) |
| `--profile {auto,M,TC,TP,custom}` | 调参档位 |
| `--skip-registration` | 给了 `--cad` 但不跑 ICP(适合调试或扫描已经预对齐) |
| `--no-bilateral` | 关闭双边滤波(v1.0 行为) |
| `--skip-excel` | 不写 `.xlsx` |
未安装本包时,等价命令:
```bash
python -m underframe_deflection.cli --input-cloud scan.ply ...
```
### 2.2 一次性 Python 函数(推荐)
```python
from underframe_deflection import run_measurement_pipeline
report = run_measurement_pipeline(
input_cloud="scan.ply",
cad_path="reference.ply", # 可选
roi_path="roi.json", # 可选
out_dir="out/",
config_path=None, # 可选 JSON 配置覆盖
profile="auto", # 可选档位
skip_registration=False,
enable_bilateral=True,
skip_excel=False,
)
```
**返回**:`report` 是一个 `dict`,结构与 `out/report.json` 完全一致。
### 2.3 纯内存计算(不读写文件)
如果你已经从其它来源拿到了点云和 ROI(例如直接从相机驱动 / 数据库取数据),可以避开文件 I/O:
```python
import numpy as np
from underframe_deflection import compute_deflection, load_point_cloud
points = load_point_cloud("scan.ply") # 或自己构造 (N, 3) ndarray
roi_aabb = { # 与 ROI JSON 同结构的 dict
"x_min": -12500, "x_max": 12500,
"y_min": 150, "y_max": 4100,
"z_min": -1680, "z_max": 200,
}
result = compute_deflection(points, roi_aabb=roi_aabb)
print(result.left.selected_signed_mm, result.right.selected_signed_mm)
```
> 注意:`compute_deflection` 本身**不做 CAD 配准**。如果你想自己控制配准过程,先调用 `register_to_cad`,把变换应用到点云后再喂给 `compute_deflection`,配合 `config["frame"]["use_input_axes"]=True`(这本来就是默认值)即可:
```python
from underframe_deflection import (
read_cad_reference, register_to_cad, compute_deflection,
)
from underframe_deflection.registration import apply_transform
scan = load_point_cloud("scan.ply")
cad = read_cad_reference("reference.ply")
# 你需要一份预解算好的 config(spacing 之类)。最简单的办法:
from underframe_deflection.config import load_config, resolve_numeric_parameters, cloud_geometry
from underframe_deflection.preprocess import estimate_spacing
cfg = load_config(None, "auto")
cfg = resolve_numeric_parameters(cfg, cloud_geometry(scan), estimate_spacing(scan))
reg = register_to_cad(scan, cad, cfg)
scan_aligned = apply_transform(scan, reg.R, reg.t)
result = compute_deflection(scan_aligned, roi_aabb=roi_aabb)
```
---
## 3. 读取输出
### 3.1 核心数值(最常用)
```python
left = report["deflection"]["left"]["selected_measurement"]
right = report["deflection"]["right"]["selected_measurement"]
if left["available"]:
x_mm = left["x_mm"]
signed = left["signed_deflection_mm"] # 带符号,向下为负
absolute = left["absolute_deflection_mm"]
type_ = left["selected_type"] # "downward" / "upward"
beam_pt = left["beam_point"] # [x, y, z]
ref_pt = left["reference_point"] # [x, y, z]
```
如果你用的是 `compute_deflection`,公开数据类更直接:
```python
result.left.selected_signed_mm
result.left.max_downward_mm
result.left.max_downward_x_mm
result.left.max_upward_mm
result.left.reference_confidence
result.curves.x_mm # ndarray
result.curves.left_deflection_mm # ndarray, NaN 表示该 X 处无效
```
### 3.2 质量警告 `quality_flags`
**非致命**问题列在这里,调用方应判断是否要重测:
| Flag | 含义 |
| --- | --- |
| `left_track_missing` / `right_track_missing` | 单侧梁追踪失败 |
| `left_representative_line_missing` / `right_...` | 单侧代表线拟合失败 |
| `left_reference_unavailable` / `right_...` | 单侧参考线不可用 |
| `left_reference_low_confidence` / `right_...` | 参考线置信度低 |
| `left_track_low_coverage` / `right_...` | 单侧追踪覆盖率 < 45% |
| `left_right_symmetry_warning` | 左右对称性偏差 > 18% |
| **`registration_not_converged`** | ICP 未收敛到容差内 |
| **`registration_poor_quality`** | ICP 最终 RMS > max(10 mm, 2×点间距) |
| **`registration_low_inlier_ratio`** | ICP 内点比例 < 50% |
| **`passthrough_empty`** | ROI passthrough 后点过少,已自动回退 |
| **`bilateral_degraded`** | bilateral k 邻域被裁剪 |
加粗的几项是 v1.1 新增。
### 3.3 配准信息
```python
reg = report["registration"]
if reg["performed"]:
reg["rms_mm"] # 最终对齐残差
reg["initial_rms_mm"] # 粗对齐后的初始残差
reg["iterations"]
reg["inlier_ratio"]
reg["converged"] # bool
reg["R"] # 3x3 list
reg["t"] # length-3 list
```
### 3.4 Excel 误差报表
`out/report.xlsx` 5 个 sheet:
| Sheet | 内容 |
| --- | --- |
| **Summary** | key/value 形式:版本、输入路径、配准统计、预处理各阶段计数、左右挠度核心数值、质量警告 |
| **Deflection_Curves** | 沿 X 的逐点表:x / 左右 beam_y, beam_z / 左右 ref_y, ref_z / 左右 deflection / 左右 confidence |
| **Beam_Tracks** | 每片候选条带:slice_index、y_center、z_low、width、score、selected_rank 等 |
| **Reference_Lines** | 左右参考线 front/back 端点、direction、residual、confidence |
| **Representative_Points** | 左右每个代表点的 x/y/z/width/residual/confidence |
> 用 `openpyxl`、`pandas.read_excel`、Excel/LibreOffice 都可以直接读。
### 3.5 异常
| 异常类 | 触发条件 |
| --- | --- |
| `InvalidPointCloudError` | 点云 / CAD / ROI JSON 文件格式非法、字段缺失、AABB 反转 |
| `UnsupportedFormatError` | 文件后缀不在支持列表 |
| `InsufficientPointsError` | 点数过少(点云 < 256)或 ROI 过滤后无重叠 |
| `FrameInferenceError` | 自动坐标系推断失败(仅 legacy 路径) |
集成方应在外层 `try / except DeflectionError` 兜底,并把 `quality_flags` 落入日志或上层告警。
---
## 4. 配置覆盖(高级)
绝大多数场景不需要碰配置。需要微调时,通过 `--config my.json` 或 `config=` 传入嵌套 dict,与 `DEFAULT_CONFIG` 深度合并:
```python
config = {
"preprocess": {
"bilateral": {"enabled": True, "k": 32, "sigma_n_deg": 10.0},
# 也可以从外部传 passthrough,但通常用 ROI JSON 即可
},
"registration": {
"icp_max_iter": 80,
"trim_ratio": 0.15,
},
"reference": {
"low_confidence_threshold": 0.5,
},
"deflection": {
"evaluation_grid_factor": 0.5, # 更密的挠度采样
},
}
```
完整字段定义见 `underframe_deflection/config.py: DEFAULT_CONFIG`。
---
## 5. 进度回调
`compute_deflection` 支持 `progress` 回调:
```python
def on_progress(stage: str, fraction: float) -> None:
print(f"[{fraction:5.1%}] {stage}")
result = compute_deflection(points, roi_aabb=roi_aabb, progress=on_progress)
```
阶段顺序:`preprocess → frame → beam_tracking → line_fitting → reference → deflection`。
`run_measurement_pipeline` 当前未透传 progress 回调,需要时请直接调 `compute_deflection`。
---
## 6. 坐标系约定
输入点云**必须**满足以下约定,否则结果无意义:
- **X 轴**:纵向(车长方向)
- **Y 轴**:横向(车宽方向)
- **Z 轴**:高度方向,**向上为正**
- 单位:毫米
CAD 基准也必须遵循同样的轴向;ROI JSON 中的 bbox 字段在 CAD 坐标系下。
扫描点云轴向不同 → 调用前自行做置换 / 旋转。
---
## 7. 版本兼容性
- `__version__` —— 包版本
- `ALGORITHM_VERSION` —— 算法版本(升级会改变数值结果)
- `SCHEMA_VERSION` —— `report.json` 结构版本(仅在破坏性变更时递增;新字段不递增)
v1.1 新增了非破坏性的可选字段(`cad_reference / roi_source / roi_aabb / registration / preprocess.passthrough / preprocess.bilateral / roi.source / quality_flags 新值`),`SCHEMA_VERSION` 保持 `"1.0"` 不变。
---
## 8. 集成模板
```python
import logging
from underframe_deflection import (
run_measurement_pipeline,
DeflectionError,
)
log = logging.getLogger(__name__)
def measure(scan_path: str, cad_path: str, roi_path: str, out_dir: str) -> dict | None:
try:
report = run_measurement_pipeline(
input_cloud=scan_path,
cad_path=cad_path,
roi_path=roi_path,
out_dir=out_dir,
)
except DeflectionError as exc:
log.error("deflection failed: %s", exc)
return None
flags = report.get("quality_flags") or []
if flags:
log.warning("quality flags: %s", flags)
return {
"schema_version": report["schema_version"],
"algorithm_version": report["algorithm_version"],
"left_signed_mm": report["deflection"]["left"].get("selected_measurement", {}).get("signed_deflection_mm"),
"right_signed_mm": report["deflection"]["right"].get("selected_measurement", {}).get("signed_deflection_mm"),
"registration_rms_mm": report["registration"].get("rms_mm"),
"flags": flags,
}
```