# 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 **坐标系坑(必读)**: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/.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` 主版本。