This repository contains the complete code, datasets, execution scripts, and analysis pipelines for the paper:
Renderer Converged Image-Based Measurements: A Verification Methodology for Synthetic Images in Uncertainty Quantification
Lloyd Fletcher, Wiera Bielajewa, and Joel Hirst
UK Atomic Energy Authority (UKAEA)
GitHub Repository
- Overview
- Quickstart: Reproducing Paper Figures
- Detailed Walkthrough of Numerical Experiments
- Experiments and Features Left Out of the Paper
- Repository Structure
- Citation & License
Synthetic image rendering is increasingly used in digital image correlation (DIC) and the grid method to evaluate systematic measurement errors before conducting expensive physical tests. However, synthetic image rendering introduces its own numerical discretisations:
-
$r_{\mathrm{px}}$ (Pixel integration resolution): The number of sub-pixel quadrature samples per axis across each camera pixel ($h_{\mathrm{cam}} / h_{\mathrm{px}}$ ). -
$r_{\mathrm{tex}}$ (Texture resolution): The texel oversampling ratio per axis relative to camera pixel pitch ($h_{\mathrm{cam}} / h_{\mathrm{tex}}$ ).
Under-resolving either parameter introduces artificial biases that can distort, interact with, or deceptively conceal the intrinsic measurement uncertainty of DIC or grid method algorithms.
This repository implements the Renderer-to-Measurement Convergence Principle, which establishes three verification criteria:
- Digitised Image Equivalence: $J_{h,b} = J_{\mathrm{ref},b} \implies \mathcal{M}\phi(J{h,b}) = \mathcal{M}\phi(J{\mathrm{ref},b})$ (guarantees identical output for deterministic measurement operators).
-
Renderer Convergence:
$\lim_{h \to 0} |I_h - I_\infty|_I = 0$ (convergence of the finite renderer to the continuous image formation operator). -
Measurement Stability: $\lim_{h \to 0} \mathcal{M}\phi(I_h) = \mathcal{M}\phi(I_\infty)$ (small residual image errors induce negligible perturbations
$\Delta u_h$ in measured kinematic fields).
The repository provides PixInt2D (custom exact analytic & numerical integrators Grid2D and Speck2D), complete integration with the high-performance Riley finite-element rasteriser via Cython bindings, and downstream measurement pipelines for 2D DIC (pyvale.dic2d) and the Grid Method.
The repository includes virtual environment tooling via uv or standard pip. Python 3.11+ is recommended.
# Clone the repository (if not already local)
git clone https://github.com/Computer-Aided-Validation-Laboratory/rcc-2d.git
cd rcc-2d
# Install editable package with development and analysis dependencies
uv pip install -e ".[dev]"
# Or using standard pip:
pip install -e ".[dev]"Before launching large render sweeps, run the lightweight unit tests and smoke verification:
# 1. Run PixInt2D unit tests against committed gold renders (32x32)
pytest -q
# 2. Run independent geometry, UV mapping, function shader, and rigid-shift smoke checks
python scripts/expall_verif.pyThe complete experimental workflow consists of four sequential stages:
# Step 1: Generate Finite Element mesh geometries and kinematic displacement fields
python data/gen_single_elem_def_data.py
python data/gen_dicconv_data.py
python data/gen_finitestar_data.py
# Step 2: Render synthetic images across all discretisation matrices
# (Runs exp1_all_render.py, exp2_all_render.py, and exp3_all_render.py)
python scripts/expall_render.py
# Step 3: Run all image and kinematic error analyses
# (Runs exp1_all_analysis.py, exp2_all_analysis.py, and exp3_all_analysis.py)
python scripts/expall_analysis.py
# Step 4: Generate all journal-ready figures and the standalone LaTeX preview
python scripts/paper_all_figs.pyAll 10 main paper figures and supplementary plots are saved to out/paper/ (in .pdf and .png at 300 DPI), and the complete article preview is compiled to out/paper/article.pdf.
Execution Modes & Resource Control:
Inscripts/exp0params_common.py, you can configureRUN_MODE(RunMode.TESTfor fast sampling levels,RunMode.ALLfor complete matrices),CORES(parallel worker allocation), andFORCE_RENDER_OVER/FORCE_ANALYSIS_OVER(resumption vs. full rebuild).
+-----------------------------------------------------------+
| rcc-2d Execution Flow |
+-----------------------------------------------------------+
|
[ Data Generation ]
data/gen_single_elem_def_data.py, gen_dicconv_data.py, ...
|
v
+---------------------------------------------+
| Image Rendering Sweeps |
+---------------------------------------------+
| Exp 1: exp1_all_render.py (Eggbox Grid) |
| Exp 2: exp2_all_render.py (Speckle Models) |
| Exp 3: exp3_all_render.py (DIC & Grid Sweeps)|
+---------------------------------------------+
|
v
+---------------------------------------------+
| Error Analysis Suites |
+---------------------------------------------+
| Exp 1: exp1_all_analysis.py (Image RMSE/GL) |
| Exp 2: exp2_all_analysis.py (Image RMSE/GL) |
| Exp 3: exp3_all_analysis.py (Disp. Errors) |
+---------------------------------------------+
|
v
[ Paper Figure Suite ]
scripts/paper_all_figs.py
|
+---------------------+---------------------+
| |
v v
out/paper/fig_*.pdf out/paper/article.pdf
(Individual Figures) (Full LaTeX Preview)
Section 3 in Paper | Figures 1, 2, and 3
Experiment 1 examines the convergence of a periodic sinusoidal eggbox grid texture against an exact closed-form pixel integral reference under rigid body translation and affine stretch.
-
Continuous Model:
$T(x,y) = I_0 + \frac{\gamma}{2}\left(1 + \cos\frac{2\pi x}{p}\right)\left(1 + \cos\frac{2\pi y}{p}\right) - \gamma$ , with grid pitch$p = 5\text{ px}$ ,$I_0 = 0.5$ ,$\gamma = 0.4$ . -
Image Resolution:
$32 \times 32\text{ px}$ , deformed by a single Quad9 element ($0.0$ to$1.0\text{ px}$ shift in$0.1\text{ px}$ increments). -
Discretisations Studied:
- Function shader integration:
$r_{\mathrm{px}} \in {1, 2, 4, 8, \dots, 512}$ with Gaussian quadrature and rectangular sub-pixel averaging. - Sampled texture renders:
$r_{\mathrm{px}} \times r_{\mathrm{tex}} \in {1, 2, \dots, 512}^2$ with Linear, Cubic Catmull–Rom, and Cubic B-spline reconstruction. - Input texture formats: Double precision (
f64) vs. pre-quantised integer (u8,u12).
- Function shader integration:
-
Key Findings:
- For continuous function shaders (
$r_{\mathrm{tex}} \to \infty$ ), Gaussian quadrature reaches exact digitised equivalence by$r_{\mathrm{px}} = 4$ . - Pre-quantised input textures (
u12) introduce an irreducible error floor under sub-pixel deformation ($\sim 0.1\text{--}0.25\text{ GL}$ ), proving that high$r_{\mathrm{px}}$ cannot reconstruct lost texture bit depth. - Diagonal refinement (
$r_{\mathrm{px}} = r_{\mathrm{tex}}$ ) provides monotonic convergence, whereas fixing$r_{\mathrm{tex}}=1$ plateaus at a high residual error.
- For continuous function shaders (
Standalone Execution:
python scripts/exp1_all_render.py
python scripts/exp1_all_analysis.py
python scripts/paper_exp1_figs.pyGenerated Paper Figures:
-
Figure 1:
fig:exp1_eggbox_function_shader_rmse— Digitised image RMSE and maximum error convergence for eggbox function shaders withGrid2DandRiley. -
Figure 2:
fig:exp1_riley_textures_u12_rmse— 12-bit digitised RMSE across the full$r_{\mathrm{px}} \times r_{\mathrm{tex}}$ matrix for Catmull–Rom reconstruction (showing resonance near$r_{\mathrm{px}} \approx r_{\mathrm{tex}}$ and the quantisation floor). -
Figure 3:
fig:exp1_riley_u12_diagonal_refinement— Diagonal$r_{\mathrm{px}} = r_{\mathrm{tex}}$ refinement comparing analytic reference with$2\times$ self-convergence.
Section 4 in Paper | Figures 4, 5, and 6 (Exp 2 Figures 1, 2, and 3)
Experiment 2 evaluates stochastic speckle patterns using two analytic formulations: continuous additive Gaussian speckles (evaluated analytically via separable error functions
-
Continuous Model:
$T(\mathbf{x}) = \sum_{i=1}^{N_s} S(\mathbf{x} - \mathbf{c}_i)$ with nominal diameter$5\text{ px}$ , area fraction$0.6$ , and randomised jitter. -
Deformation: Rigid body translations
$0.0$ to$1.0\text{ px}$ in$0.1\text{ px}$ steps. -
Discretisations Studied:
$r_{\mathrm{px}}, r_{\mathrm{tex}} \in {1, 2, 4, \dots, 512}$ , comparing continuousSpeck2Dquadrature andRileytexture reconstructions. -
Key Findings:
- Smooth Gaussian speckles readily achieve both Renderer Convergence and Digitised Image Equivalence.
- Discontinuous sharp disk speckles converge substantially more slowly; while floating-point RMSE converges monotonically, sparse
$1\text{ GL}$ boundary errors persist at practical resolutions. - Diagonal refinement (
$r_{\mathrm{px}} = r_{\mathrm{tex}}$ ) remains the only consistent path to driving renderer error to zero across all reconstruction kernels.
Standalone Execution:
python scripts/exp2_all_render.py
python scripts/exp2_all_analysis.py
python scripts/paper_exp2_figs.pyGenerated Paper Figures:
-
Figure 4 (Exp 2 Fig 1):
fig:exp2_speck2d_gauss_disk_rmse—Speck2DRMSE for Gaussian vs. sharp disk speckles across$r_{\mathrm{px}}$ with continuous textures. -
Figure 5 (Exp 2 Fig 2):
fig:exp2_texf_gauss_disk_u12_rmse—Riley12-bit texture render RMSE across$r_{\mathrm{px}} \times r_{\mathrm{tex}}$ for Gaussian and disk speckles. -
Figure 6 (Exp 2 Fig 3):
fig:exp2_texf_u12_diagonal_refinement— Diagonal refinement ($r_{\mathrm{px}} = r_{\mathrm{tex}}$ ) for speckles comparing analytic references with$2\times$ self-convergence.
Section 5 in Paper | Figures 7, 8, 9, and 10 (Exp 3 Figures 1, 2, 3, and 4)
Experiment 3 propagates the rendered images into downstream measurement algorithms: 2D DIC (pyvale.dic2d,
-
Test Cases:
-
Rigid Body Translation Sweep (
$512 \times 512\text{ px}$ ):$0.0$ to$1.0\text{ px}$ in$0.1\text{ px}$ increments. -
Refinement Path Independence: Refining
$r_{\mathrm{px}}$ at fixed$r_{\mathrm{tex}} = 1$ , refining$r_{\mathrm{tex}}$ at fixed$r_{\mathrm{px}} = 1$ , and diagonal refinement$r_{\mathrm{px}} = r_{\mathrm{tex}}$ . -
Measurement Self-Convergence: Verifying convergence against
$(2r_{\mathrm{px}}, 2r_{\mathrm{tex}})$ and finest$r_{\mathrm{px}} = r_{\mathrm{tex}} = 128$ . -
Finite-Star Chirp Gradient (
$1020 \times 252\text{ px}$ ): Spatially varying harmonic displacement on a graded Quad9 mesh ($\lambda_{\min} = 32\text{ px}$ , peak amplitude$0.5\text{ px}$ ) to probe spatial frequency coupling without undermatching.
-
Rigid Body Translation Sweep (
-
Key Findings:
- S-Curve Deception: Conventional rigid body mean bias curves can conceal severe renderer errors through spatial cancellation with intrinsic DIC interpolation bias. Only displacement RMSE against the analytic reference exposes the true error.
-
Independence in Measurement Space: Refining only
$r_{\mathrm{px}}$ or$r_{\mathrm{tex}}$ leaves a finite displacement error floor ($\sim 10^{-2}\text{ px}$ ). -
Practical Refinement Target: Diagonal refinement with
$r_{\mathrm{px}} = r_{\mathrm{tex}} \ge 8$ reduces renderer-induced displacement error below$10^{-3}\text{ px}$ ($\sim 10^{-4}\text{ px}$ for self-convergence), satisfying Measurement Stability. -
Heterogeneous Deformation: Spatially varying displacement differences are non-uniform across frequencies at low refinement, but stabilise uniformly across all frequencies when
$r_{\mathrm{px}} = r_{\mathrm{tex}} \ge 8$ .
Standalone Execution:
python scripts/exp3_all_render.py
python scripts/exp3_all_analysis.py
python scripts/paper_exp3_figs.pyGenerated Paper Figures:
-
Figure 7 (Exp 3 Fig 1):
fig:exp3_rigid_translation_bias_rmse_refinement— Rigid translation DIC mean bias vs. true displacement RMSE against the analytic reference (demonstrating how mean bias hides error). -
Figure 8 (Exp 3 Fig 2):
fig:exp3_rigid_refinement_independence_os_vs_ss— Displacement RMSE at$0.3\text{ px}$ shift for DIC and Grid Method under independent$r_{\mathrm{px}}$ , independent$r_{\mathrm{tex}}$ , and joint diagonal refinement. -
Figure 9 (Exp 3 Fig 3):
fig:exp3_rigid_self_convergence_dic_vs_grid— Displacement self-convergence for DIC and Grid Method against finest ($128$ ) and next$2\times$ diagonal refinement. -
Figure 10 (Exp 3 Fig 4):
fig:exp3_finite_star_combined— Finite-star chirp displacement fields, error difference maps, and column-wise RMSE along the spatial frequency gradient.
All figures are managed through unified formatting constants in scripts/paperparams.py and typography bindings in scripts/paperfigtex.py.
To build all 10 main paper figures, supplementary figures, and compile the full LaTeX preview article:
python scripts/paper_all_figs.pyOutputs are written to:
out/paper/: Journal-ready figure files (.pdfand.png).out/paper/article.pdf: Complete compiled A4 preview article with embedded figure floats and captions.out/paper_ext/: Extended/supplementary figures.
To keep the paper focused on the core Renderer-to-Measurement Convergence Principle, several exploratory investigations, numerical variants, and advanced engineering benchmarks developed in this repository were omitted from the final manuscript:
-
Repository Implementation:
scripts/exp1_riley_render_texfloat_uvs_psf.py,scripts/exp2_speckint2d_render_uvs_psf.py,scripts/exp3_speckint2d_render_disk_psf.py, and*_psf.pyanalysis modules. -
Why it was omitted: The paper focused on isolating sensor pixel footprint integration (uniform rectangular box filter) and texture interpolation. Adding Gaussian optical PSF blur and disk defocus convolutions changes the continuous camera kernel
$K_{\mathcal{C}}$ , adding an optical low-pass filtering dimension that obscured the basic spatial discretisation trade-off.
- Repository Implementation:
scripts/exp1_riley_render_texuint_uvs.py,scripts/exp2_riley_render_texuint.py,scripts/exp3_riley_render_texuint_ssaa.py. - Why it was omitted: Bounded integer texture storage (
u8,u12,u16) with hardware-style clamping was contrasted with quantised floating-point textures (texfq). The paper opted for simulated quantised float textures (texfq), which model finite ADC precision without non-linear texture clipping artifacts during additive accumulation.
- Repository Implementation:
data/gen_single_elem_def_data.pygenerates single-element meshes for Tri3, Tri6, Quad4, and Quad8 elements across rigid, affine, and quadratic saddle (quadsaddle) kinematic fields. - Why it was omitted: Quad9 elements provided the necessary quadratic geometric representation for all 2D tests. Lower-order linear elements (Tri3, Quad4) and Serendipity elements (Quad8) showed identical image convergence behaviour for equivalent interior strain states, so they were streamlined to single-element Quad9 formulations.
- Repository Implementation:
data/gen_dicconv_data.pygeneratesplate516_cam512_quad9_affine, andscripts/exp3_analysis_dic.pysupports affine displacement error sweeps. - Why it was omitted: The affine deformation case confirmed the exact same convergence trends as the rigid body translation sweep and the finite-star chirp test. Moving directly from rigid translation to the graded-mesh finite-star chirp provided a more concise and rigorous spatial frequency analysis.
-
Repository Implementation:
scripts/paper_ext_figs.pygenerates supplementary figures covering Nearest-Neighbour, Mitchell–Netravali, Quintic B-spline, and Lanczos-3 interpolants, alongside maximum digitised error ($e_{\infty}$ ), differing pixel fraction ($\delta_b$ ), and factor-of-2 ($h/2$ ) local convergence maps. - Why it was omitted: Linear, Catmull–Rom (interpolating), and B-spline (smoothing) were sufficient to illustrate the full spectrum of interpolant behaviours. Full factorial matrices for all kernels are retained in supplementary scripts.
rcc-2d/
├── .guides/ # Companion paper PDF
│ └── paper-render-conv-uq.pdf
├── src/pixint2d/ # PixInt2D Python package source
│ ├── core/ # Core math, digitisation, and quadrature
│ ├── grid2d/ # Analytic periodic eggbox grid renderer
│ ├── speck2d/ # Analytic Gaussian & disk speckle renderers
│ ├── mapping/ # Quad9 Newton & VTK inverse mapping
│ └── examples/ # Standalone package examples
├── data/ # FE mesh generators & pre-generated coordinates
│ ├── gen_single_elem_def_data.py # Single element mesh generator (Exp 1 & 2)
│ ├── gen_dicconv_data.py # 512x512 rigid & affine mesh generator (Exp 3)
│ └── gen_finitestar_data.py # Graded mesh chirp generator (Exp 3)
├── scripts/ # Execution, analysis, and figure generation scripts
│ ├── exp0params_common.py # Master execution configuration & job settings
│ ├── expall_render.py # All-in-one render launcher
│ ├── expall_analysis.py # All-in-one analysis launcher
│ ├── expall_verif.py # Smoke verification test
│ ├── paper_all_figs.py # Publication figure suite & LaTeX preview builder
│ ├── paper_exp1_figs.py # Experiment 1 figures (Figs 1--3)
│ ├── paper_exp2_figs.py # Experiment 2 figures (Figs 4--6)
│ ├── paper_exp3_figs.py # Experiment 3 figures (Figs 7--10)
│ ├── paper_ext_figs.py # Supplementary / extended figures
│ └── modules/ # Shared renderers, IO, and plotting helpers
├── maths/ # LaTeX derivations for exact pixel integrals
└── test/ # Pytest test suite and gold reference renders
This project is licensed under the MIT License.
If you use rcc-2d or PixInt2D in your research, please cite:
@article{fletcher2026renderer,
title = {Renderer Converged Image-Based Measurements: A Verification Methodology for Synthetic Images in Uncertainty Quantification},
author = {Fletcher, Lloyd and Bielajewa, Wiera and Hirst, Joel},
journal = {arXiv preprint / In Review},
year = {2026}
}