- 算法包替换为 delivery_v1.2(coupler_panel 新增 autotune/layer_select,underframe_deflection 新增 single_beam 管线),删除 delivery_v1.1 - manifests/adapters 的 PYTHONPATH 与版本说明同步更新到 v1.2 - 新增任务级 CAD 文件支持(task_cad_files 表、上传/读取路由、TaskManager 全选与加载显示) - 新增 train-measurement 自定义前端面板(YAML 编辑器 + 可视化 ROI 配置 + 3D 取点) - PointCloudViewer 支持 PLY 叠加层渲染与 ROI 拾取 - Dockerfile 改用 Miniforge 安装 pythonocc-core,修复 libgomp/libstdc++ 依赖
257 lines
11 KiB
Markdown
257 lines
11 KiB
Markdown
# coupler_panel — 集成开发者使用指南
|
||
|
||
> 高铁车钩面板偏转角测量算法
|
||
>
|
||
> **主输入:ROI JSON + 点云 PLY + CAD STP(三件套)**
|
||
> **主输出:含两个方向偏转角的 Excel 报表**
|
||
|
||
---
|
||
|
||
## 1. 一句话集成
|
||
|
||
```python
|
||
from coupler_panel.pipeline import run_coupler_measurement_pipeline
|
||
from coupler_panel.roi_select import load_roi_json
|
||
|
||
result = run_coupler_measurement_pipeline(
|
||
input_cloud = "train_2_1T.ply", # 待测点云(可为整车,内部按 ROI 流式裁剪)
|
||
out_dir = "runs/today", # 中间产物 + report.json 落盘
|
||
profile = "train2_coupler", # 该零件 profile
|
||
roi_spec = load_roi_json("roi.json"), # ROI = 裁剪超参数 ./examples/roi_train2_coupler.json
|
||
)
|
||
print(result.theta_right_deg, result.theta_ref_deg) # 两个偏转角
|
||
print(result.dx_y_max_mm, result.dx_z_max_mm) # 最大 x 偏差
|
||
```
|
||
|
||
要直接产出 Excel,用集成入口脚本(§3)。
|
||
|
||
---
|
||
|
||
## 2. 安装
|
||
|
||
```bash
|
||
python -m pip install -r requirements.txt # 锁定版本(Python 3.10 验证)
|
||
pip install -e ".[all]" # core + cloud + cad + viz + report
|
||
```
|
||
|
||
按需子集见 `pyproject.toml` 的 extras:`[cloud]` `[cad]` `[viz]` `[report]`。
|
||
|
||
---
|
||
|
||
## 3. 集成入口(三文件 → Excel)
|
||
|
||
`examples/run_integration.py` 是给集成方的标准入口:
|
||
|
||
```bash
|
||
python examples/run_integration.py \
|
||
--roi examples/roi_train2_coupler.json \ # ROI JSON
|
||
--cloud /path/to/train_2_1T.ply \ # 整车点云(可多 GB)
|
||
--stp /path/to/asm.stp \ # CAD STP(审计)
|
||
--out runs/train2 \ # 输出目录
|
||
--profile train2_coupler
|
||
```
|
||
|
||
产出 `runs/train2/eval_report.xlsx`(30 列,见 §7)+ 全部中间产物。
|
||
|
||
可选参数:`--gt-theta-right` / `--gt-theta-ref`(已知理论偏转,用于误差列,默认 0)、`--sample-id`、`--config`。
|
||
|
||
---
|
||
|
||
## 4. 三件输入说明
|
||
|
||
### 4.1 ROI JSON(裁剪超参数)
|
||
|
||
6-key 轴对齐包围盒,**坐标系必须与点云一致**,单位 mm:
|
||
|
||
```json
|
||
{
|
||
"x_min": 11526.0, "x_max": 11733.0,
|
||
"y_min": 588.0, "y_max": 1192.0,
|
||
"z_min": -950.0, "z_max": 950.0
|
||
}
|
||
```
|
||
|
||
- 点 `(x,y,z)` 保留条件:`x_min<=x<=x_max ∧ y_min<=y<=y_max ∧ z_min<=z<=z_max`
|
||
- 必须 `min<max`,否则报 `ValueError`;多余 key(如 `comment`)忽略
|
||
- **算法直接拿这六个数裁剪**。当输入是二进制 PLY 且 ROI 是有限 bbox 时,走**流式裁剪**(memmap 分块,不整体加载),可处理 GB 级整车点云
|
||
- 想全保留:传 `roi_json=None` 或 `roi_spec=default_roi_spec()`(±∞)
|
||
- 裁剪诊断写到 `out_dir/roi.json`(`mode`、`n_in`、`n_out`、`bbox`)
|
||
|
||
> **坐标系坑(必读)**:ROI 的六个边界写在**点云自己的坐标系**里。若点云是 x=车长 / y=车高 / z=车宽(部分整车数据集如此),ROI 也按此填。ROI 裁出 0 点时算法抛 `InsufficientPointsError` 并提示检查坐标系。
|
||
|
||
### 4.2 点云 PLY
|
||
|
||
- 支持 `.ply`(二进制/ASCII)/ `.pcd` / `.xyz` / `.txt` / `.csv`
|
||
- 单位 **mm**;算法只读 x/y/z 前三列(颜色/法向等额外列容忍)
|
||
- **可为整车扫描**(多 GB)——ROI 流式裁剪后才进入算法
|
||
- **算法不做配准**:假设上游扫描端外参已标定、点云已在 CAD/车体帧(原因见 §8)
|
||
|
||
### 4.3 CAD STP
|
||
|
||
当前 STP 的角色取决于规模:
|
||
|
||
- **单零件 STP**:可被 `parse_cad` 解析,用于提供面板法向 seed + 自动整定检测参数(见 §6)。传 `cad_stp_path=...`。
|
||
- **整车装配 STP**(数百 MB、数千实例):项目的 `parse_cad`(单零件设计)无法处理,此时 STP 仅作**审计/可追溯**输入(路径记入报表),不参与计算——检测参数由 profile 提供、法向用 PCA。
|
||
|
||
> 若将来需要从整车 STP 提取目标几何,需另写装配级 XCAF 解析(不能复用单零件 `parse_cad`)。
|
||
|
||
---
|
||
|
||
## 5. 主入口 API
|
||
|
||
```python
|
||
def run_coupler_measurement_pipeline(
|
||
input_cloud : str | Path, # 必填:点云路径(可整车)
|
||
out_dir : str | Path, # 必填:输出目录
|
||
*,
|
||
config_path : str | Path | None = None, # 可选:自定义 YAML / dict
|
||
profile : str = "auto", # 可选:preset profile
|
||
cad_stp_path: str | Path | None = None, # 可选:单零件 STP(法向 + autotune)
|
||
roi_spec : ROISpec | None = None, # 二选一:内存 ROI 对象
|
||
roi_json : str | Path | None = None, # 二选一:ROI JSON 路径
|
||
progress : Callable[[str, float], None] | None = None,
|
||
) -> CouplerMeasurement
|
||
```
|
||
|
||
**算法链路**:
|
||
|
||
```
|
||
crop_ply_bbox(流式 ROI 裁剪)
|
||
→ [layer_select] 沿法向隔离前层(profile 开关,去多层重叠)
|
||
→ [autotune] 从 CAD 孔径 + 点距自整定(仅默认 profile + 单零件 CAD 时)
|
||
→ denoise_cloud
|
||
→ compute_coupler_measurement
|
||
validate → detect 4 holes → build frame
|
||
→ extract ROI → fit plane(RANSAC+SVD) → metrics
|
||
```
|
||
|
||
**profile 选择**:
|
||
- 有匹配 profile(如 `train2_coupler` / `lu1_af4`)→ 直接指定,最稳。
|
||
- 无 profile 但传了单零件 `cad_stp_path` → `profile="auto"`,走自动整定(§6)。
|
||
|
||
**配置覆盖**:`config_path` 可传 dict 覆盖任意 `configs/default.yaml` 字段。
|
||
|
||
### 5.1 返回值 `CouplerMeasurement`
|
||
|
||
```python
|
||
theta_right_deg, theta_ref_deg # 两个偏转角(度)
|
||
D_y_max_mm, D_z_max_mm # 两方向最大距中心偏差
|
||
dx_y_max_mm, dx_z_max_mm # 最大 x 向偏差
|
||
center_C, normal # 面板中心、拟合法向(n_x>0)
|
||
holes, plane, frame # 4 孔 / 平面 / 参考系子结构
|
||
quality_flags, timings, report # 诊断;report == out_dir/report.json
|
||
result.to_dict() # 完全 JSON 化
|
||
```
|
||
|
||
### 5.2 异常
|
||
|
||
```
|
||
CouplerError
|
||
├── InvalidPointCloudError / UnsupportedFormatError 输入非法 / 格式不支持
|
||
├── InsufficientPointsError 点数过少 / ROI 裁出 0 点
|
||
├── CADParseError STP 解析失败
|
||
├── HoleDetectionError 4 孔检测失败
|
||
└── PlaneFitError 平面拟合失败
|
||
```
|
||
|
||
非致命问题在 `result.quality_flags`(如 `plane_inlier_ratio_low`)。
|
||
|
||
---
|
||
|
||
## 6. 检测参数:profile vs 自动整定
|
||
|
||
不同零件的定位孔半径、是否有中心孔、点云密度都不同,检测参数必须匹配,否则报 `HoleDetectionError: only N hole-shaped cavities found`。两种适配方式:
|
||
|
||
1. **per-part profile(推荐用于已知零件)**:`configs/profiles/<name>.yaml` 写死该零件的孔径带、面积窗、是否前层隔离等。已有 `train2_coupler`(整车车钩面板)、`lu1_af4`(单零件车钩面板)。
|
||
2. **autotune(单零件 + 默认 profile 时)**:传单零件 `cad_stp_path` 且 `profile=auto`、无 `config`,算法从 CAD 定位孔半径 + 去噪后点距自动推导检测参数(`coupler_panel/detection/autotune.py`)。指定具体 profile 或 config 时**完全跳过**。
|
||
|
||
> 整车场景用 profile(`train2_coupler`),因为整车 STP 不能 parse、autotune 不可用。
|
||
|
||
---
|
||
|
||
## 7. 输出
|
||
|
||
### 7.1 Excel 报表(`out_dir/eval_report.xlsx`,30 列)
|
||
|
||
样本标识、输入 PLY、ROI kind、**θ_right / θ_ref 的 GT/预测/误差**、D_y/D_z_max、dx_y/dx_z_max、中心 C(x/y/z)、法向 n(x/y/z)、平面内点率/残差、配准 RMSE/最大残差(主路径恒空)、ROI 前后点数、quality_flags、**算法运行时间 `Algorithm runtime (s)`**(输入→返回整段 wall-clock)、内核阶段累计、算法/schema 版本。
|
||
|
||
多组结果用 `coupler_panel.reporting.write_excel_report(rows, path)` 合并成一张表。
|
||
|
||
### 7.2 落盘中间产物(`out_dir/`)
|
||
|
||
| 文件 | 内容 |
|
||
|---|---|
|
||
| `config.resolved.yaml` | 实际生效的合并配置 |
|
||
| `roi.json` | ROI spec + 裁剪诊断 |
|
||
| `01_gt.json` | (单零件 CAD parse 时)审计 GT |
|
||
| `02_sampled.ply` | ROI 裁剪后的点云 |
|
||
| `transformed.ply` | (前层隔离开启时)隔离后的层 |
|
||
| `05_denoised.ply` | 去噪后点云(喂给测量算法的最终点云) |
|
||
| `report.json` | 完整结果,等于 `result.to_dict()` |
|
||
|
||
---
|
||
|
||
## 8. 为什么不做配准
|
||
|
||
车钩面板的 4 个定位孔与面板一起刚体旋转。用「扫到的 4 孔 → CAD 原始 4 孔」做 Kabsch,会精确解出「扫描器位姿 · 面板偏转」的复合刚体变换并反向作用,把偏转随位姿误差**一起消掉**,下游再读不到偏转——这是几何性质,不是 bug。
|
||
|
||
故主算法假设上游扫描端外参标定、点云已在车体帧。研究路径 `run_from_cad_pipeline`(含 Kabsch + 注入 oracle)完整保留作上限对照。
|
||
|
||
---
|
||
|
||
## 9. 集成模板
|
||
|
||
```python
|
||
import logging, time, json
|
||
from pathlib import Path
|
||
from coupler_panel.pipeline import run_coupler_measurement_pipeline
|
||
from coupler_panel.roi_select import load_roi_json
|
||
from coupler_panel.reporting import build_row_from_summary, write_excel_report
|
||
from coupler_panel.exceptions import CouplerError
|
||
|
||
log = logging.getLogger(__name__)
|
||
|
||
def measure(cloud, roi_json, stp, out_dir, profile="train2_coupler"):
|
||
t0 = time.perf_counter()
|
||
try:
|
||
r = run_coupler_measurement_pipeline(
|
||
input_cloud=cloud, out_dir=out_dir,
|
||
profile=profile, roi_spec=load_roi_json(roi_json))
|
||
except CouplerError as e:
|
||
log.error("measurement failed: %s", e)
|
||
return None
|
||
dt = time.perf_counter() - t0
|
||
|
||
diag = json.loads((Path(out_dir)/"roi.json").read_text(encoding="utf-8"))["diagnostics"]
|
||
row = build_row_from_summary(
|
||
sample_id=Path(cloud).stem, ply_path=str(cloud), roi_kind="aabb",
|
||
measured=r.to_dict(), gt_angles=(0.0, 0.0), registration=None,
|
||
n_points_in=diag.get("n_in", 0), n_points_after_roi=diag.get("n_out", 0),
|
||
pipeline_seconds=dt)
|
||
write_excel_report([row], Path(out_dir)/"eval_report.xlsx")
|
||
return r
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 坐标 & 单位速查
|
||
|
||
| 量 | 单位 | 说明 |
|
||
|---|---|---|
|
||
| 点云坐标 | mm | 轴含义由数据集决定(见 README / §4.1) |
|
||
| 偏转角 | 度 | `θ_right=atan2(n_y,n_x)`、`θ_ref=atan2(n_z,n_x)` |
|
||
| 法向 | 单位向量 | 强制 `n_x>0` |
|
||
| `right_axis_sign` | ±1 | 右方向符号(profile `metrics` 配置) |
|
||
|
||
---
|
||
|
||
## 11. 版本兼容
|
||
|
||
| 标识 | 含义 |
|
||
|---|---|
|
||
| `coupler_panel.__version__` | 包版本(语义化) |
|
||
| `coupler_panel.ALGORITHM_VERSION` | 算法版本,升级时**数值可能变化** |
|
||
| `coupler_panel.SCHEMA_VERSION` | 结果结构版本,仅破坏性变更递增 |
|
||
|
||
建议:落库时记录 `algorithm_version`;反序列化 `report.json` 时校验 `schema_version` 主版本。
|