Skip to main content

Fast Checkerboard Demodulation desktop app for free-surface reconstruction

Project description

OpenFCD

Fast Checkerboard Demodulation for free-surface reconstruction — desktop app + CLI.

Reconstructs the free-surface height field η(x, y, t) from high-speed video of a checkerboard pattern viewed through water, using the Wildeman / Moisy synthetic schlieren FCD algorithm. Designed for thin-film wave studies, sloshing experiments, mm-scale swimming-robot wakes, and any free-surface experiment that films a patterned backdrop through a transparent fluid.

Status

v0.0.2 — early release. Core pipeline and GUI are functional; expect rough edges. Contributions welcome.

What's new in 0.0.2

  • Frame management — Shift multi-select + batch disable / enable / compute on frames; FramePickerDialog excludes disabled frames and the reference frame from selection; SimTree disabled-frame state resets on project switch.
  • QC CLIopenfcd qc-summary / noise-floor / sensitivity subcommands for per-frame QC verdicts, flat-water noise-floor stats, and calibration-sensitivity analysis.
  • GUI polish — HiDPI-aware preview colorbar at native resolution; profile-composite heatmap & waveform x-axes aligned; unified η color range across EtaMap / EtaHeatmap / ProfileScene / ProfileComposite; Qt palette theming; annotation flushed to disk before each run.

Features

  • End-to-end desktop GUI (PyQt6) with a STAR-CCM+-style 3-pane layout: simulation tree · scene tabs · properties.
  • First-class CLI (openfcd run path.ofcd) — GUI and CLI share the same pipeline, producing byte-identical results.h5.
  • Per-frame debug mode — compute a single frame, tune parameters live with a slider, re-compute without re-running the whole sequence.
  • Robust to imperfect reference frames:
    • Automatic carrier-period scale normalization when the reference was captured at a slightly different zoom
    • Optional spatial high-pass to remove non-physical low-frequency drift from cross-session ref/def pairs
  • Project files on disk*.ofcd/ directories contain a git-friendly project.yaml, snapshot runs under runs/{id}/, and annotations under annotations/default.json.
  • HDF5 results with SWMR so scripts can tail the output while a run is in progress.
  • Session resume on re-open — re-opening a previously-computed .ofcd lands directly on the last saved state: frames are filtered, reference is set, the most recent run's η overlay is restored, and the annotation ROI/mask is populated. Stale last_run_id self-heals when the result file is missing. Use File → Re-import Frames… to re-run the import flow (blocked while a run is active).
  • Window/splitter geometry persisted across sessions via QSettings.

Installation

Requires Python 3.11+.

# CLI only
pip install openfcd

# CLI + desktop GUI (PyQt6)
pip install 'openfcd[gui]'

Development install

git clone https://github.com/xunhe730/OpenFCD.git
cd OpenFCD
pip install -e '.[gui,dev]'   # editable, with GUI + test/lint extras

Quick start

GUI

python -m openfcd.gui
# or
python -m openfcd

Workflow:

  1. File → New Project → point at a folder of image frames, set the checker cell side length (mm), window thickness, fluid depth.
  2. Click a frame in the tree → Set as Reference (pick a flat-water frame captured in the same session).
  3. Draw an ROI + optional occlusion polygon on the preview.
  4. Click Compute This Frame to preview one frame.
  5. Tune the Highpass σ slider if the result shows large-scale drift.
  6. Click Run All Frames when satisfied.

CLI

# Create a new project
openfcd new myproject --image-folder /path/to/frames --pattern 'Img*.jpg'

# Edit myproject.ofcd/project.yaml for geometry & process parameters,
# then run
openfcd run myproject.ofcd

# Results land under myproject.ofcd/runs/{timestamp}/results.h5

# Render QC panels for a frame or for all frames in a run
openfcd qc-summary myproject.ofcd --run run-YYYYMMDD-HHMMSS --frame 0 -o qc.png
openfcd qc-summary myproject.ofcd --run run-YYYYMMDD-HHMMSS --all --output-dir qc/

# Estimate flat-water noise floor and calibration sensitivity
openfcd noise-floor myproject.ofcd --from-run run-YYYYMMDD-HHMMSS -o noise_floor.json
openfcd sensitivity myproject.ofcd --run run-YYYYMMDD-HHMMSS --frame 0 -o sensitivity.json

Algorithm notes

FCD measures η by comparing the apparent displacement of a checkerboard pattern seen through the water surface. The algorithm steps:

  1. Flatfield (openfcd.core.flatfield) — divide out smooth illumination variation using a Gaussian background.
  2. Carrier detection (openfcd.core.fcd.calculate_carriers) — find the two dominant spatial-frequency peaks of the checkerboard in k-space.
  3. Scale normalization (openfcd.core.registration) — if the reference and deformed frames were shot at slightly different zooms, rescale the reference to match the deformed frame's carrier period. Triggers at 0.5 % mismatch.
  4. Occlusion inpaint — mask the robot/object and replace with a synthesized carrier field so the FCD demodulation sees continuous texture.
  5. Cosine taper — soften image boundaries to suppress FFT edge artifacts.
  6. Demodulation + phase unwrap (openfcd.core.fcd.fcd) — extract the pixel-displacement field (u, v) at each carrier.
  7. Poisson integration (fftinvgrad) — integrate (u, v) to get the apparent depth, then calibrate to mm using the optical stack geometry.
  8. Post-processing — plane detrend, filament suppression, optional high-pass filter, edge NaN margin.

geometry.pattern_period_mm is the legacy project-file key, but its physical meaning is checker_cell_mm: the side length of one single checkerboard cell, not the full black-white cycle. The carrier calibration assumes |k_phys| = π√2 / checker_cell_mm.

Each computed frame stores a QC verdict (PASS, WARN, or FAIL) plus the stats and QC maps used to reach it. The default warning/fail thresholds are kept under project.qc: saturated ratio 0.001, invalid ratio 0.20, carrier amplitude median minimum 1e-6, normalized Poisson/curl residual warning 0.10 and fail 0.20, and phase warning at 0.7π / fail at 0.9π. These are conservative starting points and should be calibrated against flat-water data for each optical setup.

Physical correctness depends on the reference frame. Best results come from a flat-water reference captured in the same acquisition session as the deformed frames. For cross-session references the high-pass filter (slider in the GUI, process.highpass_sigma_px in project.yaml) removes low-frequency drift.

Project structure

openfcd/
├── core/          # FCD algorithm (fcd, flatfield, inpaint, mask, …)
├── geometry/      # Optical-stack calibration
├── io/            # project.yaml schema, HDF5 results, annotations
├── pipeline/      # Stage protocol + orchestration
├── cli/           # Typer CLI (new / run / replay / project)
└── gui/           # PyQt6 GUI (main window, panels, scenes, renderers)

Development

# Run tests
pytest

# Lint
ruff check openfcd tests

Golden-comparison tests (tests/golden/) require a local BOS reference dataset. Set OPENFCD_BOS_ROOT to the dataset root to enable them; otherwise they are skipped.

License

MIT — see LICENSE for full text.

Acknowledgements

The FCD method is due to Moisy, Rabaud & Salsac (2009), "A synthetic Schlieren method for the measurement of the topography of a liquid interface", and Wildeman (2018), "Real-time quantitative Schlieren imaging by fast Fourier demodulation of a checkered backdrop". This project's reference implementation follows Wildeman's pyfcd approach, extended with a PyQt6 GUI, CLI, and engineering polish for experimental use.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openfcd-0.0.2.tar.gz (243.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openfcd-0.0.2-py3-none-any.whl (213.4 kB view details)

Uploaded Python 3

File details

Details for the file openfcd-0.0.2.tar.gz.

File metadata

  • Download URL: openfcd-0.0.2.tar.gz
  • Upload date:
  • Size: 243.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for openfcd-0.0.2.tar.gz
Algorithm Hash digest
SHA256 5523a4d9b7fd382cbc52df60f45bb7c1b15300ac84eca89abd3c6fe9dac6d91a
MD5 ec96072c595b45b945bc450ec8777746
BLAKE2b-256 6a90118edc7369368a6bce289503960691168653bdb6452e66256f012ff0d0e5

See more details on using hashes here.

File details

Details for the file openfcd-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: openfcd-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 213.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for openfcd-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1e8ebdbdbd8db2f6eb28f9aa66fbf46ce73a3fb02d56d1c8b8175513d4c02f20
MD5 3135c9d0f5be23564e8cd00485a2b726
BLAKE2b-256 22c246ff9c6df7abad7634bccded057681ef1a56b1099df68b37c35cd410d487

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page