feat: 升级算法包 delivery_v1.1 → v1.2,新增任务级 CAD 与测距面板
- 算法包替换为 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++ 依赖
This commit is contained in:
176
alg/delivery_v1.2/underframe_deflection/cli.py
Normal file
176
alg/delivery_v1.2/underframe_deflection/cli.py
Normal file
@@ -0,0 +1,176 @@
|
||||
"""Command-line entry point installed by ``pyproject.toml``.
|
||||
|
||||
The DEFAULT mode is single-beam measurement: the ROI(s) already isolate one
|
||||
beam each, the cloud is cropped and measured directly (no registration, no
|
||||
dual-beam tracking). Provide ``--roi`` for one beam, or ``--left-roi`` and
|
||||
``--right-roi`` to measure both in one invocation.
|
||||
|
||||
The legacy dual-beam pipeline (registration + left/right tracking on a
|
||||
car-bottom slab) is still available via ``--mode dual``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Measure underframe longitudinal beam deflection from a point cloud.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mode",
|
||||
default="single",
|
||||
choices=["single", "dual"],
|
||||
help="'single' (default): ROI isolates one beam, measure directly. "
|
||||
"'dual': legacy car-bottom slab with left+right tracking + registration.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input-cloud",
|
||||
required=True,
|
||||
help="Path to input scan point cloud (.ply or .xyz). Large binary PLYs "
|
||||
"are stream-cropped by the ROI in single mode.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-dir",
|
||||
required=True,
|
||||
help="Output directory for report.json/.xlsx, CSV, and PNG.",
|
||||
)
|
||||
# --- single mode ---
|
||||
parser.add_argument(
|
||||
"--roi",
|
||||
default=None,
|
||||
help="Single mode: ROI JSON isolating ONE beam (native frame "
|
||||
"x=length, y=height, z=width).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--left-roi",
|
||||
default=None,
|
||||
help="Single mode: ROI JSON for the left beam (use with --right-roi).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--right-roi",
|
||||
default=None,
|
||||
help="Single mode: ROI JSON for the right beam (use with --left-roi).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--side",
|
||||
default=None,
|
||||
help="Single mode label for --roi (left/right); inferred from the file name if omitted.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--enable-registration",
|
||||
action="store_true",
|
||||
help="Single mode: rigidly align the cloud to --cad before measuring. "
|
||||
"Default OFF (cloud assumed already registered). Requires --cad as a "
|
||||
"sampled .ply/.stl/.obj (.stp must be converted first).",
|
||||
)
|
||||
# --- shared ---
|
||||
parser.add_argument(
|
||||
"--config",
|
||||
default=None,
|
||||
help="Optional JSON config override file.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-excel",
|
||||
action="store_true",
|
||||
help="Skip writing the .xlsx report.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-plot",
|
||||
action="store_true",
|
||||
help="Single mode: skip the PNG plot.",
|
||||
)
|
||||
# --- dual (legacy) mode ---
|
||||
parser.add_argument(
|
||||
"--cad",
|
||||
default=None,
|
||||
help="Dual mode: CAD reference (.ply/.xyz/.stl/.obj) for registration.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--profile",
|
||||
default="auto",
|
||||
choices=["auto", "M", "TC", "TP", "custom"],
|
||||
help="Dual mode: profile for scale-related tuning.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-registration",
|
||||
action="store_true",
|
||||
help="Dual mode: bypass ICP even when --cad is supplied.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-bilateral",
|
||||
action="store_true",
|
||||
help="Dual mode: disable bilateral denoising.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input-axis",
|
||||
default="y_up",
|
||||
choices=["z_up", "y_up"],
|
||||
help="Dual mode: height axis convention (default y_up).",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def _load_config(path):
|
||||
if not path:
|
||||
return None
|
||||
import json
|
||||
from pathlib import Path
|
||||
return json.loads(Path(path).read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
|
||||
if args.mode == "single":
|
||||
from .single_beam_pipeline import run_single_beam_pipeline, run_both_beams
|
||||
config = _load_config(args.config)
|
||||
if args.left_roi and args.right_roi:
|
||||
run_both_beams(
|
||||
input_cloud=args.input_cloud,
|
||||
left_roi=args.left_roi,
|
||||
right_roi=args.right_roi,
|
||||
out_dir=args.out_dir,
|
||||
config=config,
|
||||
cad_path=args.cad,
|
||||
enable_registration=args.enable_registration,
|
||||
skip_excel=args.skip_excel,
|
||||
skip_plot=args.skip_plot,
|
||||
)
|
||||
elif args.roi:
|
||||
run_single_beam_pipeline(
|
||||
input_cloud=args.input_cloud,
|
||||
roi_path=args.roi,
|
||||
out_dir=args.out_dir,
|
||||
side=args.side,
|
||||
config=config,
|
||||
cad_path=args.cad,
|
||||
enable_registration=args.enable_registration,
|
||||
skip_excel=args.skip_excel,
|
||||
skip_plot=args.skip_plot,
|
||||
)
|
||||
else:
|
||||
raise SystemExit(
|
||||
"single mode requires --roi (one beam) or both --left-roi and --right-roi."
|
||||
)
|
||||
return
|
||||
|
||||
# dual (legacy) mode
|
||||
from .pipeline import run_measurement_pipeline
|
||||
run_measurement_pipeline(
|
||||
input_cloud=args.input_cloud,
|
||||
out_dir=args.out_dir,
|
||||
config_path=args.config,
|
||||
profile=args.profile,
|
||||
cad_path=args.cad,
|
||||
roi_path=args.roi,
|
||||
skip_registration=args.skip_registration,
|
||||
enable_bilateral=not args.no_bilateral,
|
||||
skip_excel=args.skip_excel,
|
||||
input_axis=args.input_axis,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user