算法更新: delivery v1.2.1、平整度v1.5、测距v2.2、整车配准v1.3 适配器: vehicle-registration 新增、各算法 manifest 和 adapter 更新 后端: taskCadFiles/source 字段迁移、derivedPointClouds 注册、取消任务联动 前端: ElapsedTime 时长显示、两步算法流程、canRun 逻辑修复 文档: 新增5份算法性能分析报告
11 KiB
coupler_panel — 集成开发者使用指南
高铁车钩面板偏转角测量算法
主输入:ROI JSON + 点云 PLY + CAD STP(三件套) 主输出:含两个方向偏转角的 Excel 报表
1. 一句话集成
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. 安装
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 是给集成方的标准入口:
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:
{
"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
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
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。两种适配方式:
- per-part profile(推荐用于已知零件):
configs/profiles/<name>.yaml写死该零件的孔径带、面积窗、是否前层隔离等。已有train2_coupler(整车车钩面板)、lu1_af4(单零件车钩面板)。 - 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. 集成模板
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 主版本。