| """ |
| CLI entry point for LightweightMR reconstruction. |
| Usage: |
| python -m lightweightmr --input path/to/pointcloud.ply --output path/to/mesh.ply |
| """ |
| import argparse |
| import os |
| import sys |
| from .optimize import Runner |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser(description="LightweightMR — pure-Python mesh reconstruction") |
| parser.add_argument("--input", "-i", required=True, help="Input point cloud (.ply, .pcd, .xyz)") |
| parser.add_argument("--output", "-o", required=True, help="Output mesh file (.ply or .obj)") |
| parser.add_argument("--device", default="cpu", help="torch device: cpu or cuda") |
| parser.add_argument("--out-dir", default="./output", help="Intermediate outputs directory") |
| parser.add_argument("--sdf-iters", type=int, default=20_000, help="SDF training iterations") |
| parser.add_argument("--vg-iters", type=int, default=8_000, help="Vertex generation iterations") |
| parser.add_argument("--sdf-lr", type=float, default=1e-3, help="SDF learning rate") |
| parser.add_argument("--vg-lr", type=float, default=1e-3, help="VG learning rate") |
| parser.add_argument("--sdf-batch", type=int, default=5_000, help="SDF batch size") |
| parser.add_argument("--vertices", type=int, default=3_400, help="Target number of vertices") |
| parser.add_argument("--update-size", type=int, default=5, help="Curriculum update steps") |
| parser.add_argument("--update-ratio", type=float, default=1.2, help="Curriculum growth ratio") |
| parser.add_argument("--k-samples", type=int, default=21, help="Tetrahedron interior samples") |
| parser.add_argument("--multires", type=int, default=8, help="Positional encoding frequencies") |
| parser.add_argument("--queries-size", type=int, default=1_000_000, help="SDF query sample count") |
| parser.add_argument("--surface-queries", type=int, default=200_000, help="Surface query count") |
| parser.add_argument("--project-sdf-level", type=float, default=0.0, help="SDD projection level") |
| parser.add_argument("--save-freq", type=int, default=2_000, help="Checkpoint save frequency") |
| parser.add_argument("--resume-sdf", default=None, help="Resume from SDF checkpoint .pth") |
|
|
| args = parser.parse_args() |
|
|
| if not os.path.exists(args.input): |
| print(f"ERROR: input file not found: {args.input}") |
| sys.exit(1) |
|
|
| runner = Runner( |
| pointcloud_path=args.input, |
| out_dir=args.out_dir, |
| device=args.device, |
| sdf_iters=args.sdf_iters, |
| vg_iters=args.vg_iters, |
| sdf_lr=args.sdf_lr, |
| vg_lr=args.vg_lr, |
| sdf_batch=args.sdf_batch, |
| vertices_size=args.vertices, |
| update_size=args.update_size, |
| update_ratio=args.update_ratio, |
| k_samples=args.k_samples, |
| multires=args.multires, |
| queries_size=args.queries_size, |
| surface_queries=args.surface_queries, |
| project_sdf_level=args.project_sdf_level, |
| save_freq=args.save_freq, |
| ) |
|
|
| if args.resume_sdf: |
| print(f"Loading SDF checkpoint: {args.resume_sdf}") |
| runner.load_sdf_checkpoint(args.resume_sdf) |
|
|
| v, f = runner.run(mesh_path=args.output) |
| print(f"\nDone! Mesh: {len(v)} vertices, {len(f)} faces") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|