feat: 算法升级、整车配准集成与性能分析文档

算法更新: delivery v1.2.1、平整度v1.5、测距v2.2、整车配准v1.3
适配器: vehicle-registration 新增、各算法 manifest 和 adapter 更新
后端: taskCadFiles/source 字段迁移、derivedPointClouds 注册、取消任务联动
前端: ElapsedTime 时长显示、两步算法流程、canRun 逻辑修复
文档: 新增5份算法性能分析报告
This commit is contained in:
2026-06-25 08:22:20 +00:00
parent cec0766e67
commit 29f1d45d66
266 changed files with 1311475 additions and 2846 deletions

View File

@@ -1,10 +1,10 @@
"""flatness-suite 算法适配器 (v1.2)。
"""flatness-suite 算法适配器 (v1.5)。
v1.2 变更:
- 算法目录从 alg/平整度、平面度、轮廓测量/ → alg/point_porj/
- 入口从独立脚本(importlib 加载)→ MeasurementPipeline 类
- run_plane / run_curvature / run_contour 统一通过 MeasurementPipeline 调用
- 点云路径通过 config["paths"]["pointcloud"] 注入,不再依赖 open3d 直接读取
v1.5 变更:
- 算法目录从 alg/point_porj → alg/平整度、平面度、轮廓测量v1.5
- 新增 car_part_v1/ 多车型 STEP CAD 模板
- run_contour 新增 Excel 报表输出(excel_output_path)
- pipeline 新增 result_template_path / combined_context_pointcloud_path 参数
约定:
- module=all:plane + curvature(contour 需要 CAD STL,缺失时跳过)
@@ -25,7 +25,6 @@ from typing import Any
sys.path.insert(0, str(Path(__file__).parent))
from _plugin_io import (
emit_progress,
ensure_ascii_ply,
first_pointcloud,
load_input,
write_error_result,
@@ -41,8 +40,9 @@ def _safe_float(v: object) -> float | None:
def _find_alg_dir(alg_root: str) -> Path:
"""定位 point_porj 目录,支持多种可能的路径。"""
"""定位平整度算法目录,支持多个历史版本路径,优先使用最新版。"""
candidates = [
Path(alg_root) / "平整度、平面度、轮廓测量v1.5",
Path(alg_root) / "point_porj",
Path(alg_root) / "平整度、平面度、轮廓测量v1.2" / "point_porj",
Path(alg_root) / "平整度、平面度、轮廓测量" / "point_porj",
@@ -51,9 +51,9 @@ def _find_alg_dir(alg_root: str) -> Path:
if c.is_dir() and (c / "pipeline.py").exists():
return c
raise RuntimeError(
f"找不到 point_porj 算法目录,已尝试:\n"
f"找不到平整度算法目录,已尝试:\n"
+ "\n".join(f" {c}" for c in candidates)
+ "\n请确认 alg/ 下已解压 point_porj/。"
+ "\n请确认 alg/ 下已解压 平整度、平面度、轮廓测量v1.5/。"
)
@@ -105,8 +105,47 @@ def main() -> int:
pc_path_raw = first_pointcloud(payload)
emit_progress(0.10, f"读取点云:{os.path.basename(pc_path_raw)}")
# 二进制 PLY → ASCII PLY(算法内置 reader 不依赖 open3d)
pc_path = ensure_ascii_ply(pc_path_raw, out_dir / "_ply_cache")
# ── ROI 裁剪(整车点云场景下必须填写,否则算法极慢)──────────────────────
def _f(key: str) -> float | None:
v = config.get(key)
try:
return float(v) if v is not None and str(v).strip() != "" else None
except (TypeError, ValueError):
return None
x_min, x_max = _f("roiXMin"), _f("roiXMax")
y_min, y_max = _f("roiYMin"), _f("roiYMax")
z_min, z_max = _f("roiZMin"), _f("roiZMax")
has_roi = any(v is not None for v in (x_min, x_max, y_min, y_max, z_min, z_max))
if has_roi:
emit_progress(0.12, "ROI 裁剪中…")
import numpy as np
import open3d as o3d # type: ignore
pcd = o3d.io.read_point_cloud(pc_path_raw)
pts = np.asarray(pcd.points)
mask = np.ones(len(pts), dtype=bool)
if x_min is not None: mask &= pts[:, 0] >= x_min
if x_max is not None: mask &= pts[:, 0] <= x_max
if y_min is not None: mask &= pts[:, 1] >= y_min
if y_max is not None: mask &= pts[:, 1] <= y_max
if z_min is not None: mask &= pts[:, 2] >= z_min
if z_max is not None: mask &= pts[:, 2] <= z_max
n_total, n_crop = len(pts), int(mask.sum())
if n_crop == 0:
raise RuntimeError(
f"ROI 裁剪后无点(原始 {n_total} 点),请检查坐标范围是否正确。"
)
cropped = pcd.select_by_index(np.where(mask)[0])
roi_ply = out_dir / "_roi_cropped.ply"
# 二进制写出,算法用 o3d 读所以支持二进制,比 ASCII 快很多
o3d.io.write_point_cloud(str(roi_ply), cropped, write_ascii=False)
pc_path_raw = str(roi_ply)
emit_progress(0.14, f"ROI 裁剪完成:{n_total} → {n_crop} 点")
# v1.5 用 o3d.io.read_point_cloud 读取,直接支持二进制 PLY,无需转 ASCII
pc_path = pc_path_raw
module = str(config.get("module") or "all")
emit_progress(0.15, f"初始化 MeasurementPipeline(module={module})")