Skip to main content

ISO/IEC 29794-5 component-aligned synthetic face image quality degradation pipeline

Project description

ofiq-syngen

PyPI version Python 3.9+ License: MIT DOI CI

ISO/IEC 29794-5 component-aligned synthetic face image quality degradation pipeline.

ofiq-syngen generates controlled quality degradations mapped to specific ISO/IEC 29794-5 (OFIQ) quality components. Each degradation function targets a known OFIQ scalar component -- Sharpness, CompressionArtifacts, HeadPoseYaw, etc. -- producing ground-truth (image, degradation, delta-OFIQ) triplets for training quality-aware biometric systems. All 27 OFIQ-measurable components are covered with deterministic, seed-reproducible degradation operators; OFIQ-binary parity vectors verify each operator degrades its target scalar in the correct direction.

Visual gallery: see docs/gallery/INDEX.md for severity strips of every component on a canonical face image.

Installation

The package ships in tiers. Pick the one that matches the operators you need.

# Tier 1 — core 28 OFIQ operators (always works, no GPU)
pip install ofiq-syngen

# Tier 2 — add pandas for batch dataset generation
pip install ofiq-syngen[pandas]

# Tier 3 — add Stable Diffusion / InstructPix2Pix paths for photorealistic
# expression + occluder degradations (downloads SD checkpoint on first use)
pip install ofiq-syngen[diffusion]

# Tier 4 — add 3D head pose pipeline (DECA + FLAME + pyrender)
# After install, run: ofiq-syngen install-assets
pip install ofiq-syngen[three_d]

# Everything (research / publication runs)
pip install ofiq-syngen[all]

Tier 4 needs the FLAME 2020 morphable face model, which is license-gated and cannot be redistributed. After pip install ofiq-syngen[three_d]:

  1. Register at https://flame.is.tue.mpg.de/ (academic; ~24h approval).
  2. Download FLAME2020.zip, unzip, copy generic_model.pkl into the path shown by ofiq-syngen check-assets.
  3. Run ofiq-syngen install-assets to download the public DECA pretrained weights and the BFM-2009 derivatives.

See INSTALL.md for the full per-tier walkthrough and LICENSE_NOTICES.md for third-party attributions (FLAME, DECA, BFM-2009, CelebA, VGGFace2, FFHQ, Stable Diffusion, OFIQ).

Air-gapped / offline environments

Set OFIQ_SYNGEN_OFFLINE=1 to disable every network fetch. Any operator that would download an asset raises RuntimeError with a clear message naming the asset to pre-stage.

GPU vs CPU

# Auto-detect (default): use CUDA if torch reports it available, else CPU
ofiq-syngen --device auto degrade ...

# Force CPU
ofiq-syngen --device cpu degrade ...

# Force CUDA (requires onnxruntime-gpu, install with [gpu] extra)
ofiq-syngen --device cuda degrade ...

Quick Start

import cv2
from ofiq_syngen import DegradationPipeline, DegradationConfig

# Load a face image (BGR, uint8)
image = cv2.imread("face.jpg")

# Create pipeline with default settings
pipeline = DegradationPipeline()

# Apply a single degradation
degraded, meta = pipeline.degrade_single(
    image, component="Sharpness.scalar", severity=0.6
)
cv2.imwrite("degraded.jpg", degraded)
print(meta)
# {'target_component': 'Sharpness.scalar', 'degradation_type': 'Gaussian blur [§7.3.8]',
#  'severity': 0.6, 'seed': 42}

# Sweep severity levels
config = DegradationConfig(severity_levels=[0.0, 0.25, 0.5, 0.75, 1.0])
pipeline = DegradationPipeline(config)
results = pipeline.degrade_sweep(image, "CompressionArtifacts.scalar")

# Apply one degradation per component
all_results = pipeline.degrade_all_components(image, severity=0.5)

CLI Usage

# Apply a single degradation
ofiq-syngen degrade --component Sharpness --severity 0.6 --output degraded.jpg input.jpg

# Sweep 10 severity levels
ofiq-syngen sweep --component Sharpness --levels 10 --output-dir ./output input.jpg

# List all supported components
ofiq-syngen list-components

# List components in a specific standards preset
ofiq-syngen list-components --preset icao-strict

# Print the multi-standard cross-reference (29794-5, 19794-5, ICAO 9303 P9)
ofiq-syngen show-standards
ofiq-syngen show-standards --preset icao-strict

# Generate a full dataset (requires pandas)
ofiq-syngen generate-dataset --images-dir ./faces --output-dir ./degraded --max-images 100

# Generate a dataset filtered to a standards preset
ofiq-syngen generate-dataset --images-dir ./faces --preset icao-strict --output-dir ./icao

Standards presets

--preset selects a curated component subset. Three presets ship today:

Preset Components Source
iso-29794-5 All 28 ISO/IEC 29794-5:2024 (default scope of the package)
iso-19794-5 All 28 ISO/IEC 19794-5:2011 (every component maps to a 19794-5 clause)
icao-strict 22 Components with alignment=exact against ICAO 9303 Part 9 §3.2

Preset definitions live in src/ofiq_syngen/standards.py and trace back to docs/standards/MAPPING.csv (CSV is the source of truth). See docs/standards/MAPPING.md for the full per-component cross-reference.

Component Coverage

All 27 OFIQ scalar components are covered. Section references follow ISO/IEC FDIS 29794-5:2024 (= IS:2025).

OFIQ Component FDIS § Degradation Severity Range
BackgroundUniformity.scalar §7.3.2 Background noise intensity: 0 -> 200
IlluminationUniformity.scalar §7.3.3 Gradient lighting gradient: 0% -> 80% drop
LuminanceMean.scalar §7.3.4.2 Brightness reduction factor: 1.0 -> 0.15
LuminanceVariance.scalar §7.3.4.3 Variance compression factor: 1.0 -> 0.1
UnderExposurePrevention.scalar §7.3.5 Under-exposure factor: 1.0 -> 0.15
OverExposurePrevention.scalar §7.3.6 Over-exposure factor: 1.0 -> 3.5
DynamicRange.scalar §7.3.7 Dynamic range compression range: 100% -> 10%
Sharpness.scalar §7.3.8 Gaussian blur sigma: 0.5 -> 10.5
Sharpness.scalar §7.3.8 Motion blur kernel: 3 -> 31px
Sharpness.scalar §7.3.8 Additive Gaussian noise sigma: 0 -> 80
CompressionArtifacts.scalar §7.3.9 JPEG compression Q: 100 -> 5
NaturalColour.scalar §7.3.10 CIELAB a*/b* shift in ROI zones shift: 0 -> 60
RadialDistortion.scalar Annex D.2.1 Barrel distortion (no QAA in IS:2025) k: 0 -> 0.5
EyesOpen.scalar §7.4.3 Landmark-warped eye closure closure: 0% -> 90%
MouthClosed.scalar §7.4.4 Landmark-warped mouth opening opening: 0 -> 0.25t
EyesVisible.scalar §7.4.5 EVZ-targeted eye occlusion coverage: 0% -> 80%
MouthOcclusionPrevention.scalar §7.4.6 Polygon-targeted mouth occlusion coverage: 0% -> 100%
FaceOcclusionPrevention.scalar §7.4.7 Face-masked rectangular occlusion area: 0% -> 60%
InterEyeDistance.scalar §7.4.8 Pad-and-shrink (face smaller in frame) scale: 1.0 -> 0.3
HeadSize.scalar §7.4.9 Pad-and-shrink (same mechanism as IED) scale: 1.0 -> 0.3
HeadPoseYaw.scalar §7.4.11.2 Perspective yaw rotation squeeze: 0% -> 50%
HeadPosePitch.scalar §7.4.11.3 Perspective pitch tilt squeeze: 0% -> 40%
HeadPoseRoll.scalar §7.4.11.4 In-plane rotation angle: 0 -> +/-30 deg
LeftwardCropOfTheFaceImage.scalar §7.4.10.1 Leftward image shift (v0.4.0 fix) shift: 0% -> 40%
RightwardCropOfTheFaceImage.scalar §7.4.10.2 Rightward image shift (v0.4.0 fix) shift: 0% -> 40%
MarginAboveOfTheFaceImage.scalar §7.4.10.3 Upward image shift (v0.4.0 fix) shift: 0% -> 40%
MarginBelowOfTheFaceImage.scalar §7.4.10.4 Downward image shift (v0.4.0 fix) shift: 0% -> 40%
SingleFacePresent.scalar §7.4.2 Face insertion via Poisson blending area ratio: 0 -> 0.4
ExpressionNeutrality.scalar §7.4.12 Landmark-warped expression displacement: 0 -> 0.15t
NoHeadCoverings.scalar §7.4.13 Synthetic hat overlay coverage: 0% -> 100%

Coverage notes

All 27 measurable OFIQ components have direct degraders. Three subject-related components — ExpressionNeutrality, NoHeadCoverings, SingleFacePresent — use generative operators (landmark RBF warps, synthetic overlays, Poisson-blended face inserts respectively) that depend on OFIQ ONNX models classifying the synthetic content correctly. Effectiveness against the OFIQ classifier is verified via the parity manifest (tests/fixtures/ofiq_parity/).

Severity Levels

All degradation functions accept a severity parameter in the range [0.0, 1.0]:

  • 0.0 -- No degradation (identity or near-identity transform)
  • 0.5 -- Moderate degradation (good default for influence matrix calibration)
  • 1.0 -- Maximum degradation (image heavily distorted)

The mapping from severity to physical parameters is function-specific. For example, Sharpness.scalar with Gaussian blur maps severity 0.0 to sigma=0.5 and severity 1.0 to sigma=10.5. See the coverage table above for each function's range.

All functions are deterministic given a seed. Use the seed parameter for reproducible experiments.

Entanglement and the Influence Matrix

A key design insight: degradations are not independent. Applying Gaussian blur (targeting Sharpness) also affects NaturalColour, DynamicRange, and other components. Pretending degradations are orthogonal leads to incorrect training signals.

The pipeline addresses this with an empirical influence matrix W[d, c]:

W[d, c] = mean(|delta_OFIQ_c|) when degradation d is applied at severity 0.5

To build it:

  1. Generate a degradation dataset with generate_dataset()
  2. Run OFIQ on all original and degraded images (externally)
  3. Call build_influence_matrix() with the manifest and OFIQ scores
from pathlib import Path
from ofiq_syngen import DegradationPipeline, DegradationConfig

pipeline = DegradationPipeline(DegradationConfig())

# Step 1: Generate degraded images
manifest = pipeline.generate_dataset(
    image_dir=Path("./faces"),
    output_dir=Path("./degraded"),
    max_images=100,
)

# Step 2: Run OFIQ externally, producing a CSV with scalar scores
# ofiq_scores = pd.read_csv("ofiq_results.csv")

# Step 3: Build the influence matrix
# matrix = DegradationPipeline.build_influence_matrix(
#     manifest, ofiq_scores, ofiq_scalar_cols=[...]
# )

The resulting matrix reveals cross-component effects and can be used to weight multi-task training losses appropriately.

Standards Mapping

Every component carries a triple cross-reference: ISO/IEC 29794-5 (the quality measurement standard OFIQ implements), ISO/IEC 19794-5 (the face image data interchange format ICAO references), and ICAO Doc 9303 Part 9 (the travel-document specification).

Doc Path Purpose
Mapping table (rendered) docs/standards/MAPPING.md Human-readable per-component cross-reference, grouped by OFIQ section
Mapping table (machine) docs/standards/MAPPING.csv CSV source of truth used by the test suite
Source pinning docs/standards/SOURCES.md Standard editions referenced, OFIQ version pin, mapping confidence convention
OFIQ source provenance docs/standards/PROVENANCE.md Per-component citation of the OFIQ C++ Execute() line ranges
Per-component status docs/theory/COMPONENT_STATUS.md Single-page rollup: standards + provenance + test + parity status
ISO 29794-5 coverage docs/ISO_COVERAGE.md Coverage matrix per clause with update protocol
Failure modes docs/FAILURE_MODES.md Per-component edge cases, ctx-fallback behavior, known limitations
Citation guide docs/CITING.md The four canonical references to cite together when using this package
Upstream policy OFIQ_UPSTREAM.md Relationship to BSI OFIQ-Project; what would be candidates to upstream
Benchmarks benchmarks/README.md Throughput + best-in-class adapter framework + competitor catalog
Gallery docs/gallery/README.md Per-component severity-grid visualization (regenerated locally)
Real-time capture demo examples/README_realtime.md Webcam capture with live OFIQ-aligned quality feedback
JOSS paper paper/paper.md Submission-ready ~1000-word software paper

Programmatic access:

from ofiq_syngen.standards import (
    STANDARDS_REFS,           # dict[component_name, StandardRefs]
    ICAO_STRICT_COMPONENTS,   # list of component names in the icao-strict preset
    get_refs,                 # accessor: get_refs("Sharpness.scalar")
    components_by_alignment,  # filter: by 'exact' / 'partial' / 'absent'
    components_by_confidence, # filter: by 'verified' / 'derived' / 'uncertain'
)

refs = get_refs("BackgroundUniformity.scalar")
print(refs.iso_29794_5, refs.icao_9303, refs.alignment)
# Background uniformity   3.2.3 background   exact

The ComponentDegradation dataclass returned by the registry also carries the standard_refs field for in-pipeline access.

References

  • OFIQ Algorithm Book: BSI Technical Report, Open Source Face Image Quality (OFIQ), Algorithm Book V1.2. Available at: https://www.bsi.bund.de/OFIQ
  • ISO/IEC 29794-5: Information technology -- Biometric sample quality -- Part 5: Face image data.

Citation

If you use this package in your research, please cite:

@software{storey2026ofiqsyngen,
  author = {Storey, Aaron},
  title = {ofiq-syngen: ISO/IEC 29794-5 Component-Aligned Synthetic Face Image Quality Degradation Pipeline},
  year = {2026},
  url = {https://github.com/astoreyai/ofiq-syngen},
}

License

MIT License. See LICENSE for details.

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

ofiq_syngen-0.5.2.tar.gz (7.6 MB view details)

Uploaded Source

Built Distribution

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

ofiq_syngen-0.5.2-py3-none-any.whl (149.5 kB view details)

Uploaded Python 3

File details

Details for the file ofiq_syngen-0.5.2.tar.gz.

File metadata

  • Download URL: ofiq_syngen-0.5.2.tar.gz
  • Upload date:
  • Size: 7.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ofiq_syngen-0.5.2.tar.gz
Algorithm Hash digest
SHA256 de5bd6fbf34a60c23d8d548cf8887530343127d993fecc2c1ac47f3d832d5fbe
MD5 974ebc724eb15bbae2a3840240834605
BLAKE2b-256 93f31f872088a1e2dbeba355d496e035438e6e4ab138c846f1037f8ff13829ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for ofiq_syngen-0.5.2.tar.gz:

Publisher: release.yml on astoreyai/ofiq-syngen

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ofiq_syngen-0.5.2-py3-none-any.whl.

File metadata

  • Download URL: ofiq_syngen-0.5.2-py3-none-any.whl
  • Upload date:
  • Size: 149.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ofiq_syngen-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 075a89c35113940cd348d6170af4065c2918a2b7dba48a40a537c107f4a9165f
MD5 b1fd8855e208c25240e2aafe910d75d6
BLAKE2b-256 d82ad986a6b65b81ea699149b71fc51e81da28759483ab43f898ba66c65b202a

See more details on using hashes here.

Provenance

The following attestation bundles were made for ofiq_syngen-0.5.2-py3-none-any.whl:

Publisher: release.yml on astoreyai/ofiq-syngen

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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