Skip to content

v0.2.0 — reproducible source-built engine (COLMAP 4.0.4 + OpenMVS 2.4.0)

Choose a tag to compare

@leiverkus leiverkus released this 11 Jun 21:31
· 92 commits to main since this release
9028ba2

Added

  • First full end-to-end run on the CPU image. The complete chain — COLMAP
    sparse → image_undistorter → OpenMVS DensifyPointCloudReconstructMesh
    RefineMeshTextureMesh — now runs to completion on the CPU/arm64 image
    against a real 70-image dataset, producing a textured OBJ. This closes the main
    open 0.2.0 validation item (the engine had never been run through on a dataset).
  • Both images unified on COLMAP 4.0.4 + OpenMVS v2.4.0. The CUDA/production
    Dockerfile and the CPU Dockerfile.cpu now build the identical engine from
    the identical pinned sources and recipe — the only differences are the CUDA
    base image and the three -D*CUDA* flags. No image builds COLMAP 3.x any more.
  • OpenMVS bumped to v2.4.0 (both images). v2.3.0's DensifyPointCloud
    corrupts the heap and aborts on arm64 (it falls back off SSE); v2.4.0 swaps the
    FLANN nearest-neighbour code for nanoflann and runs the full dense+mesh chain
    cleanly. 2.4.0 needs two libs newer than Ubuntu 22.04 ships — nanoflann ≥1.5
    and CGAL ≥6.0 — both header-only, so both Dockerfiles vendor pinned releases
    (NANOFLANN_VERSION, CGAL_VERSION) rather than bumping the base off 22.04
    (which would lose PDAL, dropped from 24.04). Two small source patches keep it
    building against jammy's OpenCV (disable the hard libjxl requirement; map the
    one OpenCV-4.7-only JXL write constant to the JPEG one — we emit no JPEG-XL).
  • matcher=vocab_tree now works. Image-retrieval matching for large sets:
    each image bakes in a SHA256-pinned vocabulary tree in the format its COLMAP
    expects (FAISS for COLMAP 4). Previously the option was selectable but always
    aborted with the opaque "Cannot process dataset".

Fixed

  • CPU pipeline could not start: opaque "Cannot process dataset". A chain of
    failures, each masking the next, all surfacing only as NodeODM's generic error:
    • run.sh applied the default use-gpu=true even on the CUDA-less CPU image,
      so COLMAP's SIFT aborted ("Cannot use Sift GPU without CUDA or OpenGL"). It
      now probes for a usable GPU (nvidia-smi -L) and falls back to CPU with a
      loud warning when none is present.
    • COLMAP's CPU SIFT extractor OOM-killed itself fanning out over all cores on
      large images; the CPU SIFT/match thread count is now capped
      (EFFIGIES_CPU_THREADS, default 4).
    • COLMAP's CPU FLANN matcher segfaulted holding a full match block in memory;
      the exhaustive block size is capped on the CPU path
      (EFFIGIES_CPU_MATCH_BLOCK, default 10).
    • InterfaceCOLMAP was fed the raw sparse/0 model instead of an undistorted
      workspace; sparse_colmap.sh now runs colmap image_undistorter and
      InterfaceCOLMAP reads $WORK/dense with the correct --image-folder.
    • dense_openmvs.sh passed --cuda-device unconditionally; the CPU OpenMVS
      build rejects it. The flag is now probed and passed only on CUDA builds.
  • Source-built, pinned Dockerfile. COLMAP (4.0.4) and OpenMVS (v2.4.0)
    are now compiled from upstream source with CUDA, replacing the distro packages;
    Eigen/CGAL/Boost/OpenCV come from Ubuntu 22.04. Versions are declared as build
    ARGs and a build-time which gate fails the build loudly if colmap,
    DensifyPointCloud, ReconstructMesh, RefineMesh, TextureMesh,
    InterfaceCOLMAP or pdal is missing.
  • Georeferenced point cloud output. New helpers/pointcloud_to_laz.py applies
    the georef similarity to scene_dense.ply and writes
    odm_georeferenced_model.laz via PDAL (full projected coordinates, LAS
    scale/offset for precision), and optionally builds an EPT tileset
    (entwine_pointcloud/) for the Potree viewer when entwine/untwine is
    present. map_outputs.py maps the LAZ + EPT into the WebODM paths, with the raw
    PLY kept as a documented fallback.
  • CPU test image (Dockerfile.cpu) — same pinned engine built without CUDA,
    for local integration testing on machines without an NVIDIA GPU (e.g. Apple
    Silicon). Plus docs/DEPLOYMENT.md (local CPU + GPU host recipes, WebODM node
    wiring) and a .dockerignore.
  • Unit tests for the point-cloud transform matrix (tests/test_pointcloud.py) and
    the NodeODM options translation (tests/test_options.py); the local runner and
    CI now execute every tests/test_*.py.

Fixed

  • Options were incompatible with NodeODM. options.json was a flat list, but
    NodeODM (libs/odmInfo.js) expects an argparse-style descriptor object keyed by
    --flag; it was serving every option as name="0".."12" with the wrong types.
    helpers/optionsToJson.py now translates our list into NodeODM's schema (enum
    choices, <class 'int'>/float, bool via default, valid metavar domains),
    so WebODM builds the correct task UI. (Found by actually running the node.)
  • Options shim could not find options.json. It resolved the path with
    abspath(__file__), which does not follow the NodeODM symlink — it looked in
    /opt/NodeODM. Now prefers ODM_PATH and falls back to realpath.
  • mesh-decimate domain changed to float: 0 <= x <= 1 so it passes NodeODM's
    checkDomain validation on task submission.

Notes

  • NodeODM hard-skips a --gcp UI option (WebODM handles GCP upload natively), so
    the gcp option is intentionally not shown; run.sh still auto-detects
    gcp_list.txt. The node is verified to build, run, serve all options and be
    reachable on the WebODM network; a full processing run on a dataset is the
    remaining 0.2.0 validation.

Planned

See ROADMAP.md. Still open for 0.2.0: a full end-to-end processing
run on a real dataset, a verified VCGlib commit pin, and confirming the
InterfaceCOLMAP/InterfaceOpenSfM binary names across OpenMVS builds. Beyond
that: multi-view GCP triangulation (0.3.0).