- 算法包替换为 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++ 依赖
114 lines
4.7 KiB
Python
114 lines
4.7 KiB
Python
"""Integration entry point — the contract for the software integrator.
|
|
|
|
Three input files, one Excel output:
|
|
|
|
--roi ROI JSON (6-key AABB crop hyper-parameters, in the cloud frame)
|
|
--cloud full-vehicle point cloud PLY (may be multi-GB; cropped by streaming)
|
|
--stp theoretical CAD STEP file (recorded for audit/traceability)
|
|
--out output directory (gets eval_report.xlsx + intermediates)
|
|
|
|
The cloud is cropped to the ROI inside the algorithm (no external
|
|
pre-processing needed), the coupler panel is measured, and the two
|
|
deflection angles + intermediate values are written to an .xlsx report.
|
|
|
|
Example::
|
|
|
|
python examples/run_integration.py \
|
|
--roi examples/roi_train2_coupler.json \
|
|
--cloud E:/BaiduNetdiskDownload/pointsCloud_data/train_2_1T.ply \
|
|
--stp E:/BaiduNetdiskDownload/pointsCloud_data/m000004802418tc01_asm.stp \
|
|
--out runs/train2_integration \
|
|
--profile train2_coupler
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import logging
|
|
import time
|
|
from pathlib import Path
|
|
|
|
from coupler_panel.exceptions import CouplerError
|
|
from coupler_panel.pipeline import run_coupler_measurement_pipeline
|
|
from coupler_panel.reporting import build_row_from_summary, write_excel_report
|
|
from coupler_panel.roi_select import load_roi_json
|
|
|
|
|
|
def _build_parser() -> argparse.ArgumentParser:
|
|
p = argparse.ArgumentParser(description=__doc__)
|
|
p.add_argument("--roi", type=Path, required=True, help="ROI JSON (6-key AABB).")
|
|
p.add_argument("--cloud", type=Path, required=True, help="Full-vehicle point cloud PLY.")
|
|
p.add_argument("--stp", type=Path, default=None, help="Theoretical CAD STEP (audit).")
|
|
p.add_argument("--out", type=Path, required=True, help="Output directory.")
|
|
p.add_argument("--profile", type=str, default="train2_coupler",
|
|
help="Config profile (default: train2_coupler).")
|
|
p.add_argument("--config", type=Path, default=None, help="Optional YAML override.")
|
|
p.add_argument("--gt-theta-right", type=float, default=0.0,
|
|
help="Known/expected theta_right (deg) for the error column. Default 0.")
|
|
p.add_argument("--gt-theta-ref", type=float, default=0.0,
|
|
help="Known/expected theta_ref (deg) for the error column. Default 0.")
|
|
p.add_argument("--sample-id", type=str, default=None, help="Row label in the report.")
|
|
return p
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s")
|
|
log = logging.getLogger("run_integration")
|
|
args = _build_parser().parse_args(argv)
|
|
|
|
roi_spec = load_roi_json(args.roi)
|
|
log.info("ROI bbox: x[%g,%g] y[%g,%g] z[%g,%g]",
|
|
roi_spec.x_min, roi_spec.x_max, roi_spec.y_min,
|
|
roi_spec.y_max, roi_spec.z_min, roi_spec.z_max)
|
|
log.info("cloud: %s", args.cloud)
|
|
log.info("stp (audit): %s", args.stp)
|
|
|
|
sample_id = args.sample_id or args.cloud.stem
|
|
|
|
t0 = time.perf_counter()
|
|
try:
|
|
result = run_coupler_measurement_pipeline(
|
|
input_cloud=args.cloud,
|
|
out_dir=args.out,
|
|
config_path=args.config,
|
|
profile=args.profile,
|
|
roi_spec=roi_spec,
|
|
progress=lambda s, f: log.info("[%5.1f%%] %s", f * 100, s),
|
|
)
|
|
except CouplerError as exc:
|
|
log.error("measurement failed: %s", exc)
|
|
return 2
|
|
pipeline_seconds = time.perf_counter() - t0
|
|
|
|
# n_points after ROI crop is recorded in <out>/roi.json diagnostics.
|
|
import json as _json
|
|
roi_diag = _json.loads((args.out / "roi.json").read_text(encoding="utf-8"))
|
|
n_roi = int(roi_diag.get("diagnostics", {}).get("n_out", 0))
|
|
n_in = int(roi_diag.get("diagnostics", {}).get("n_in", n_roi))
|
|
|
|
row = build_row_from_summary(
|
|
sample_id=sample_id,
|
|
ply_path=str(args.cloud),
|
|
roi_kind=f"aabb {roi_spec.x_min:.0f}-{roi_spec.x_max:.0f},"
|
|
f"{roi_spec.y_min:.0f}-{roi_spec.y_max:.0f},"
|
|
f"{roi_spec.z_min:.0f}-{roi_spec.z_max:.0f}",
|
|
measured=result.to_dict(),
|
|
gt_angles=(args.gt_theta_right, args.gt_theta_ref),
|
|
registration=None,
|
|
n_points_in=n_in,
|
|
n_points_after_roi=n_roi,
|
|
pipeline_seconds=pipeline_seconds,
|
|
)
|
|
# Record the STP path in the row's extra metadata (audit trail).
|
|
row.extra["stp_audit_path"] = str(args.stp) if args.stp else ""
|
|
|
|
xlsx = write_excel_report([row], args.out / "eval_report.xlsx")
|
|
log.info("theta_right=%+.4f theta_ref=%+.4f flags=%s",
|
|
result.theta_right_deg, result.theta_ref_deg, result.quality_flags)
|
|
log.info("wrote %s", xlsx)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|