算法更新: delivery v1.2.1、平整度v1.5、测距v2.2、整车配准v1.3 适配器: vehicle-registration 新增、各算法 manifest 和 adapter 更新 后端: taskCadFiles/source 字段迁移、derivedPointClouds 注册、取消任务联动 前端: ElapsedTime 时长显示、两步算法流程、canRun 逻辑修复 文档: 新增5份算法性能分析报告
207 lines
10 KiB
Python
207 lines
10 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
common = argparse.ArgumentParser(add_help=False)
|
|
common.add_argument("--config", default=argparse.SUPPRESS, help="YAML config path, default uses built-in settings")
|
|
|
|
parser = argparse.ArgumentParser(description="Industrial geometry measurement workflow")
|
|
parser.add_argument("--config", default=None, help="YAML config path, default uses built-in settings")
|
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
|
|
cad = subparsers.add_parser("cad2mesh", parents=[common], help="Convert STEP CAD to STL Mesh")
|
|
cad.add_argument("--cad", required=False, help="Input STEP file")
|
|
cad.add_argument("--mesh", required=False, help="Output STL file")
|
|
cad.add_argument("--precision", type=float, default=None, help="Mesh precision in mm")
|
|
|
|
denoise = subparsers.add_parser("denoise", parents=[common], help="Add noise and run denoise filters")
|
|
denoise.add_argument("--pointcloud", "-p", default=None, help="Input clean PLY point cloud")
|
|
denoise.add_argument("--noise-std", type=float, default=None, help="Gaussian noise std")
|
|
denoise.add_argument("--no-visualize", action="store_true", help="Disable Open3D windows")
|
|
|
|
registration = subparsers.add_parser("registration", parents=[common], help="Run simulated point-cloud registration")
|
|
registration.add_argument("--pointcloud", "-p", default=None, help="Input PLY point cloud")
|
|
registration.add_argument("--mesh", "-m", default=None, help="Reference STL/OBJ/PLY mesh")
|
|
registration.add_argument("--voxel-size", "-v", type=float, default=None, help="Registration voxel size")
|
|
registration.add_argument("--roll", type=float, default=None, help="Rotation around X axis in degrees")
|
|
registration.add_argument("--pitch", type=float, default=None, help="Rotation around Y axis in degrees")
|
|
registration.add_argument("--yaw", type=float, default=None, help="Rotation around Z axis in degrees")
|
|
registration.add_argument("--trans-range", type=float, default=None, help="Random translation range")
|
|
registration.add_argument("--no-visualize", action="store_true", help="Disable Open3D windows")
|
|
|
|
contour = subparsers.add_parser(
|
|
"contour",
|
|
parents=[common],
|
|
help="Quick contour/flatness/planarity evaluation against STEP CAD",
|
|
)
|
|
contour.add_argument("--pointcloud", "-p", default=None, help="Input PLY point cloud")
|
|
contour.add_argument("--cad", "-c", default=None, help="Reference STEP CAD file")
|
|
contour.add_argument("--mesh", "-m", default=None, help="Legacy reference STL/OBJ/PLY mesh")
|
|
contour.add_argument(
|
|
"--tasks",
|
|
default=None,
|
|
help="Comma-separated task ids or sample names. Example: 13 expands 13_1/13_2; 13_1 runs that sample only.",
|
|
)
|
|
contour.add_argument("--all", action="store_true", help="Run contour evaluation for all Mesh/CAD ids under data root")
|
|
contour.add_argument("--data-root", default="datasets", help="Dataset root for --tasks/--all batch mode")
|
|
contour.add_argument(
|
|
"--pointcloud-kind",
|
|
choices=["noise", "clean"],
|
|
default="noise",
|
|
help="Point cloud source for batch mode: noise=Noise_PointCloud, clean=PointCloud",
|
|
)
|
|
contour.add_argument("--mesh-deflection", type=float, default=None, help="CAD meshing deflection")
|
|
contour.add_argument("--point-chunk-size", type=int, default=None, help="Point chunk size")
|
|
contour.add_argument("--triangle-chunk-size", type=int, default=None, help="Triangle chunk size")
|
|
contour.add_argument("--save", default=None, help="Optional colored point-cloud output path")
|
|
contour.add_argument(
|
|
"--excel-output",
|
|
nargs="?",
|
|
const="excel/contour.xlsx",
|
|
default=None,
|
|
help="Optional Excel output path; defaults to excel/contour.xlsx when used without a value",
|
|
)
|
|
contour.add_argument(
|
|
"--result-template",
|
|
default="excel/测量结果.xlsx",
|
|
help="Measurement-result template used by --excel-output",
|
|
)
|
|
contour.add_argument(
|
|
"--combined-context-pointcloud",
|
|
default="datasets/train/train_2_10M.ply",
|
|
help="Full point cloud to include in batch combined_contour.ply",
|
|
)
|
|
contour.add_argument("--no-visualize", action="store_true", help="Disable Open3D windows")
|
|
|
|
curvature = subparsers.add_parser("curvature", parents=[common], help="Estimate and visualize point-cloud curvature")
|
|
curvature.add_argument("--pointcloud", "-p", default=None, help="Input PLY point cloud")
|
|
curvature.add_argument("--radius", type=float, default=None, help="Neighborhood radius")
|
|
curvature.add_argument("--max-nn", type=int, default=None, help="Max neighbor count")
|
|
curvature.add_argument("--color-scale", type=float, default=None, help="Color scale")
|
|
curvature.add_argument("--save", default=None, help="Optional colored point-cloud output path")
|
|
curvature.add_argument("--no-visualize", action="store_true", help="Disable Open3D windows")
|
|
|
|
plane = subparsers.add_parser("plane", parents=[common], help="Estimate plane with RANSAC")
|
|
plane.add_argument("--pointcloud", "-p", default=None, help="Optional input PLY point cloud")
|
|
plane.add_argument("--threshold-mm", type=float, default=None, help="RANSAC distance threshold in mm")
|
|
plane.add_argument("--max-iterations", type=int, default=None, help="RANSAC max iterations")
|
|
plane.add_argument("--no-visualize", action="store_true", help="Disable Open3D windows")
|
|
|
|
translate_align = subparsers.add_parser(
|
|
"translate-align",
|
|
parents=[common],
|
|
help="Translate-align point cloud to STEP CAD with front/tail centroids",
|
|
)
|
|
translate_align.add_argument("--cad", "-c", default="datasets/CAD/M02.stp", help="Reference STEP CAD file")
|
|
translate_align.add_argument(
|
|
"--pointcloud",
|
|
"-p",
|
|
default="datasets/shift_test_output/",
|
|
help="Input PLY point cloud or a directory containing shifted_whole_pointcloud.ply",
|
|
)
|
|
translate_align.add_argument("--output-dir", "-o", default="results", help="Output directory")
|
|
translate_align.add_argument("--axis", choices=["x", "y", "z"], default="x", help="Train length axis")
|
|
translate_align.add_argument("--crop-ratio", type=float, default=0.01, help="Front/tail crop ratio")
|
|
translate_align.add_argument("--mesh-deflection", type=float, default=0.1, help="CAD meshing deflection")
|
|
translate_align.add_argument("--cad-sample-points", type=int, default=30000, help="Points sampled from CAD mesh")
|
|
translate_align.add_argument("--local-sample-points", type=int, default=1000, help="Points sampled from each end")
|
|
translate_align.add_argument("--scale-pointcloud", type=float, default=1.0, help="Scale factor applied to point cloud")
|
|
translate_align.add_argument("--no-visualize", action="store_true", help="Disable Open3D windows")
|
|
|
|
full = subparsers.add_parser("full", parents=[common], help="Run configured full workflow")
|
|
full.add_argument("--no-visualize", action="store_true", help="Disable Open3D windows")
|
|
|
|
return parser
|
|
|
|
|
|
def main() -> None:
|
|
parser = build_parser()
|
|
args = parser.parse_args()
|
|
from pipeline import MeasurementPipeline
|
|
|
|
pipeline = MeasurementPipeline(config_path=args.config)
|
|
|
|
if args.command == "cad2mesh":
|
|
pipeline.run_cad2mesh(cad_path=args.cad, mesh_path=args.mesh, precision=args.precision)
|
|
elif args.command == "denoise":
|
|
pipeline.run_denoise(pointcloud_path=args.pointcloud, noise_std=args.noise_std, no_visualize=args.no_visualize)
|
|
elif args.command == "registration":
|
|
pipeline.run_registration(
|
|
pointcloud_path=args.pointcloud,
|
|
mesh_path=args.mesh,
|
|
voxel_size=args.voxel_size,
|
|
roll=args.roll,
|
|
pitch=args.pitch,
|
|
yaw=args.yaw,
|
|
trans_range=args.trans_range,
|
|
no_visualize=args.no_visualize,
|
|
)
|
|
elif args.command == "contour":
|
|
if args.all or args.tasks:
|
|
pipeline.run_contour_batch(
|
|
task_ids=args.tasks,
|
|
all_tasks=args.all,
|
|
data_root=args.data_root,
|
|
pointcloud_kind=args.pointcloud_kind,
|
|
mesh_deflection=args.mesh_deflection,
|
|
point_chunk_size=args.point_chunk_size,
|
|
triangle_chunk_size=args.triangle_chunk_size,
|
|
save_path=args.save,
|
|
excel_output_path=args.excel_output,
|
|
result_template_path=args.result_template,
|
|
combined_context_pointcloud_path=args.combined_context_pointcloud,
|
|
no_visualize=args.no_visualize,
|
|
)
|
|
else:
|
|
pipeline.run_contour(
|
|
pointcloud_path=args.pointcloud,
|
|
cad_path=args.cad,
|
|
mesh_path=args.mesh,
|
|
mesh_deflection=args.mesh_deflection,
|
|
point_chunk_size=args.point_chunk_size,
|
|
triangle_chunk_size=args.triangle_chunk_size,
|
|
save_path=args.save,
|
|
excel_output_path=args.excel_output,
|
|
result_template_path=args.result_template,
|
|
no_visualize=args.no_visualize,
|
|
)
|
|
elif args.command == "curvature":
|
|
pipeline.run_curvature(
|
|
pointcloud_path=args.pointcloud,
|
|
radius=args.radius,
|
|
max_nn=args.max_nn,
|
|
color_scale=args.color_scale,
|
|
save_path=args.save,
|
|
no_visualize=args.no_visualize,
|
|
)
|
|
elif args.command == "plane":
|
|
pipeline.run_plane(
|
|
pointcloud_path=args.pointcloud,
|
|
threshold_mm=args.threshold_mm,
|
|
max_iterations=args.max_iterations,
|
|
no_visualize=args.no_visualize,
|
|
)
|
|
elif args.command == "translate-align":
|
|
pipeline.run_translate_align_pointcloud_to_cad(
|
|
cad_path=args.cad,
|
|
pointcloud_path=args.pointcloud,
|
|
output_dir=args.output_dir,
|
|
axis=args.axis,
|
|
crop_ratio=args.crop_ratio,
|
|
mesh_deflection=args.mesh_deflection,
|
|
cad_sample_points=args.cad_sample_points,
|
|
local_sample_points=args.local_sample_points,
|
|
scale_pointcloud=args.scale_pointcloud,
|
|
no_visualize=args.no_visualize,
|
|
)
|
|
elif args.command == "full":
|
|
pipeline.run_full(no_visualize=args.no_visualize)
|
|
else:
|
|
parser.error(f"Unsupported command: {args.command}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|