Forráskód Böngészése

fix(backend): make GenRecon reconstruct actually run on the genrecon LXC

- COLMAP headless: QT_QPA_PLATFORM=offscreen + CPU SIFT/matching (apt COLMAP
  aborts on Qt/EGL in a headless container).
- Checkpoint run-dir layout: the released .pt files are raw LoRA state_dicts
  with no embedded config; point --ss/shape/tex_ckpt at
  ckpts/{ss,shape,tex}/checkpoints/*.pt so load_train_config finds the matching
  configs/gen training config.json.
- Pass the README-validated Iphone cleaning knobs (chunk_size_factor,
  stat_std_ratio, radius_nb_points, radius_m, proj_batch_voxels), config-driven
  so plain-video (non-ARKit, arbitrary-scale) captures can loosen radius_m.
Oivo Agent 1 hete
szülő
commit
c6d70dc961
2 módosított fájl, 35 hozzáadás és 7 törlés
  1. 12 0
      backend/config.py
  2. 23 7
      backend/pipeline.py

+ 12 - 0
backend/config.py

@@ -35,6 +35,18 @@ NUM_IMGS_PER_SCENE = int(os.environ.get("GENRECON_NUM_IMGS", "999"))
 PIPELINE_CONFIG = os.environ.get("GENRECON_PIPELINE_CONFIG", "configs/pipelines/texture.json")
 MAX_UPLOAD_MB = int(os.environ.get("GENRECON_MAX_UPLOAD_MB", "2048"))
 
+# reconstruct_scene.py Iphone-mode knobs. pipeline.py MUST pass these — when
+# omitted, the chunker falls back to more aggressive internal defaults
+# (stat_std_ratio 2.0) that can strip a sparse COLMAP cloud to 0 points and
+# crash the PLY export. These are the README-validated values; radius_m is a
+# metric radius, so on arbitrary-scale COLMAP clouds (plain video, no ARKit)
+# loosen it (raise radius_m / lower radius_nb_points) if cleaning wipes points.
+CHUNK_SIZE_FACTOR = os.environ.get("GENRECON_CHUNK_SIZE_FACTOR", "1.08")
+STAT_STD_RATIO = os.environ.get("GENRECON_STAT_STD_RATIO", "3.0")
+RADIUS_NB_POINTS = os.environ.get("GENRECON_RADIUS_NB_POINTS", "7")
+RADIUS_M = os.environ.get("GENRECON_RADIUS_M", "0.2")
+PROJ_BATCH_VOXELS = os.environ.get("GENRECON_PROJ_BATCH_VOXELS", "2048")
+
 JOBS_DIR.mkdir(parents=True, exist_ok=True)
 
 # Stage order + the progress band each stage fills (start, end).

+ 23 - 7
backend/pipeline.py

@@ -79,16 +79,22 @@ def run_colmap(job: Path, log: Log) -> None:
     sparse.mkdir(exist_ok=True)
     out.mkdir(exist_ok=True)
     C = config.COLMAP_BIN
+    # COLMAP links Qt and aborts on QApplication init in a headless container
+    # (no display). QT_QPA_PLATFORM=offscreen makes every CLI subcommand run
+    # without a display. SIFT extract/match are forced to CPU because the apt
+    # COLMAP build's GPU SIFT needs an OpenGL/EGL context we don't have headless.
+    cenv = dict(os.environ, QT_QPA_PLATFORM="offscreen")
     _run([C, "feature_extractor", "--database_path", str(db), "--image_path", str(images),
-          "--ImageReader.single_camera", "1"], cwd=job, log=log)
-    _run([C, "exhaustive_matcher", "--database_path", str(db)], cwd=job, log=log)
+          "--ImageReader.single_camera", "1", "--SiftExtraction.use_gpu", "0"], cwd=job, log=log, env=cenv)
+    _run([C, "exhaustive_matcher", "--database_path", str(db),
+          "--SiftMatching.use_gpu", "0"], cwd=job, log=log, env=cenv)
     _run([C, "mapper", "--database_path", str(db), "--image_path", str(images),
-          "--output_path", str(sparse)], cwd=job, log=log)
+          "--output_path", str(sparse)], cwd=job, log=log, env=cenv)
     model = sparse / "0"
     if not model.exists():
         raise RuntimeError("COLMAP mapper produced no model — not enough overlapping views?")
     _run([C, "model_converter", "--input_path", str(model),
-          "--output_path", str(out), "--output_type", "TXT"], cwd=job, log=log)
+          "--output_path", str(out), "--output_type", "TXT"], cwd=job, log=log, env=cenv)
     if not (out / "cameras.txt").exists():
         raise RuntimeError("COLMAP did not write colmap/cameras.txt")
 
@@ -100,11 +106,21 @@ def _reconstruct_cmd(job: Path) -> list[str]:
         "--mode", "Iphone",
         "--path", str(job),
         "--output_path", str(job / "out"),
-        "--ss_ckpt", str(ck / "sparse_structure.pt"),
-        "--shape_ckpt", str(ck / "shape_slat.pt"),
-        "--tex_ckpt", str(ck / "texture_slat.pt"),
+        # GenRecon derives each stage's training config as <parent-of-ckpt-dir>/config.json
+        # (setup_utils.load_train_config), so each checkpoint lives in its own
+        # run dir: <ck>/<stage>/checkpoints/<name>.pt + <ck>/<stage>/config.json
+        # (the matching configs/gen/*/genrecon*.json). Weights are symlinked so
+        # the flat 13.7GB download is not duplicated.
+        "--ss_ckpt", str(ck / "ss" / "checkpoints" / "sparse_structure.pt"),
+        "--shape_ckpt", str(ck / "shape" / "checkpoints" / "shape_slat.pt"),
+        "--tex_ckpt", str(ck / "tex" / "checkpoints" / "texture_slat.pt"),
         "--pipeline_config", config.PIPELINE_CONFIG,
         "--num_imgs_per_scene", str(config.NUM_IMGS_PER_SCENE),
+        "--chunk_size_factor", str(config.CHUNK_SIZE_FACTOR),
+        "--stat_std_ratio", str(config.STAT_STD_RATIO),
+        "--radius_nb_points", str(config.RADIUS_NB_POINTS),
+        "--radius_m", str(config.RADIUS_M),
+        "--proj_batch_voxels", str(config.PROJ_BATCH_VOXELS),
     ])