Skip to main content

A faithful Python port of OFIQ v1.1.0 (ISO/IEC 29794-5 face image quality), matching the reference within ±1.

Project description

ofiqpy — a faithful Python port of OFIQ v1.1.0

CI & Release Docs PyPI Python License: MIT

A behavior-preserving Python reimplementation of the BSI OFIQ ISO/IEC 29794-5 face image quality library. ofiqpy reuses OFIQ's own model files and reproduces its exact .cpp algorithms, matching the live OFIQ reference to within ±1 per component (the ISO/IEC 29794-5 Annex A.2 conformance criterion).

📖 Docs: https://avhbac.github.io/ofiqpy/

Status: full coverage + near-exact parity. All 27 ISO components + UnifiedQualityScore, an OFIQ-compatible CSV writer, a CLI, and a parallel batch runner — all gated against live OFIQSampleApp. Validated on 1,000+ real CelebA images: 27/28 components fully conformant (±1 on every image, most bit-exact); ~99.99% of all component-image pairs within ±1. The rare per-image residuals are numerical boundaries of discrete/learned models (RTrees vote, AdaBoost score, round tie), not algorithm gaps.

Install & run

pip install ofiqpy
export OFIQPY_OFIQ_DATA=/path/to/OFIQ-Project/data   # OFIQ's models (not bundled)

ofiqpy -i face.jpg -o out.csv                        # CLI
from ofiqpy import assess
scores = assess("face.jpg")            # {component: (raw, scalar)}
print(scores["UnifiedQualityScore"])   # (magnitude, 0-100)

See Installation and Quickstart.

Design

  • Same weights. Models are loaded directly from the reference checkout OFIQ-Project/data/models/ via config.py (SSD caffemodel, ADNet-98 ONNX, 3DDFA-V2 ONNX, BiSeNet parsing ONNX, occlusion-seg ONNX, ssim-248 ONNX, MagFace ONNX). No re-training, no substitute backbones.
  • Same math. Detection, ADNet landmark crop/denorm, the 5-point LMEDS similarity alignment to 616×616, the landmarked-region mask, tmetric, the generic h·(a+s·sigmoid(x;x0,w)) scalar mapping, and each measure are ported line-faithfully from OFIQ's C++ (see per-module docstrings for file:line provenance).
  • Same versions. The isolated .venv pins OpenCV 4.5.5 and onnxruntime 1.18.1 to match OFIQ's build (libofiq_lib.so links OpenCV 4.5.5; bundles onnxruntime 1.18.1).
  • Gated, not asserted. tests/verify_ofiq.py runs live OFIQ and checks |port_scalar − ofiq_scalar| ≤ 1 per image; tests/gate_slice.py reports it.

Conformance (1,000+ real CelebA images, port vs live OFIQ, ISO Annex A ±1)

Validated on 1,197 real CelebA images: 27 of 28 components fully conformant (±1 on every image), 24 of them bit-exact (maxΔ=0). ~99.99% of all component-image pairs are within ISO ±1 (mean |Δ| ≤ 0.02 for every component).

The rare per-image residuals:

  • Sharpness — 1 image at Δ=2: OFIQ's RTrees vote count differs by exactly 2 trees at a split-threshold knife-edge (a sub-LSB feature difference flips 2 borderline votes through the step-function forest). Bit-exact on the rest.
  • BackgroundUniformity / ExpressionNeutrality / NoHeadCoverings — one ±1 image each, a single sigmoid/round boundary.

Sharpness (RTrees) and ExpressionNeutrality (dual EfficientNet + AdaBoost) run OFIQ's own cv2.ml / ONNX models; UnifiedQualityScore runs OFIQ's MagFace ONNX. These four residuals are numerical boundaries of discrete/learned models, not algorithm gaps.

How parity was reached (the residual was a bug, not a build limit)

An earlier version of this port was only ~96% conformant, and the residual was wrongly attributed to a build-level OpenCV float difference. To test that, ctypes bridges were built against OFIQ's own conan OpenCV static libs (native/ofiq_cv.cpp, ofiq_ssd.cpp) and used to compare OFIQ's compiled estimateAffinePartial2D, warpAffine, resize, and the SSD dnn forward pass against the pip opencv-python wheel. Every OpenCV operation was bit-identical — which disproved the build-level theory and localized the divergence to the ADNet landmark back-projection: OFIQ scales landmarks back with squareBox.height / 256 (adnet_landmarks.cpp:313), but makeSquareBoundingBox's floor/ceil can leave the box 1px non-square, and the port had used the width. On exactly-square detector boxes it matched; otherwise it drifted ~1px, propagating (via the alignment source points → affine → whole aligned face) into every landmark-sensitive measure. One-character fix (width→height); all 27 non-model components went bit-exact.

The bridges in native/ are diagnostic only — the runtime uses pip cv2, which is bit-identical to OFIQ's OpenCV. No source build of OpenCV was needed.

Layout

ofiqpy/
  config.py            JAXN loader + OFIQ model resolver + sigmoid params
  sigmoid.py           OFIQ ScalarConversion (Measure.h:271-285)
  session.py           shared preprocessing products
  pipeline.py          detect -> pose -> landmarks -> align -> parse -> occlusion -> region
  detectors/ssd.py     SSD (OpenCV DNN, Caffe)
  landmarks/adnet.py   ADNet-98 + square-crop helpers
  align.py             616x616 alignment, landmarked region (GetFaceMask), tmetric, luminance
  pose/tddfa.py        3DDFA-V2 pose
  segmentation/        BiSeNet parsing, face-occlusion seg
  measures/
    core.py            model cache + dispatch; C03/C09/C17/C20, unified, HeadPose (slot swap)
    geometry.py        C11,C12,C13,C19,C24-C27
    pixel.py           C01,C02,C04(var),C05,C06,C07,C10
    models.py          C08 Sharpness (RTrees), C14/C15/C16 occlusion, C18 Expression
    helpers.py         get_distance/get_middle, c_round, landmark index maps
  output.py            OFIQ-format CSV (named cols, raw + .scalar)
  cli.py               OFIQSampleApp-compatible CLI
tests/
  verify_ofiq.py       runs live OFIQ, ±1 gate
  gate_slice.py        full-coverage conformance runner

Run

export OFIQPY_OFIQ_DATA=/path/to/OFIQ-Project/data

ofiqpy -i <image|dir> -o out.csv               # single / small runs (OFIQ-format CSV)
python -m ofiqpy.batch -i <dir> -o out.csv -w 8 --resume   # parallel batch

# reproduce the conformance gate (needs a built OFIQSampleApp)
export OFIQPY_OFIQ_ROOT=/path/to/OFIQ-Project
export OFIQPY_TEST_IMAGES=/path/to/images
python tests/gate_slice.py 1000

Full documentation: https://avhbac.github.io/ofiqpy/.

License & attribution

ofiqpy is released under the MIT License.

It is a faithful port of OFIQ (Open Source Face Image Quality), developed by the German Federal Office for Information Security (BSI), Copyright © 2024, MIT-licensed (https://github.com/BSI-OFIQ/OFIQ-Project). Please acknowledge OFIQ when using ofiqpy.

Models are not bundled. ofiqpy loads OFIQ's own model files at runtime; they ship with OFIQ and may be licensed separately (see OFIQ's LICENSE.md). Obtain them from an OFIQ install and set OFIQPY_OFIQ_DATA. See NOTICE and the licensing docs.

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

ofiqpy-0.1.1.tar.gz (45.0 kB view details)

Uploaded Source

Built Distribution

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

ofiqpy-0.1.1-py3-none-any.whl (34.2 kB view details)

Uploaded Python 3

File details

Details for the file ofiqpy-0.1.1.tar.gz.

File metadata

  • Download URL: ofiqpy-0.1.1.tar.gz
  • Upload date:
  • Size: 45.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ofiqpy-0.1.1.tar.gz
Algorithm Hash digest
SHA256 9e6681ded33f6db598e657640e64fc01405d2525b985ef5c119d8a0e5f9a3864
MD5 1eee6b707267abbd3327bd7aed7b9d97
BLAKE2b-256 edaa6c7b1e11783a383e6c40ade7276ec19645432d7b26c1ea47aa59f9d83d52

See more details on using hashes here.

Provenance

The following attestation bundles were made for ofiqpy-0.1.1.tar.gz:

Publisher: workflow.yml on AVHBAC/ofiqpy

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

File details

Details for the file ofiqpy-0.1.1-py3-none-any.whl.

File metadata

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

File hashes

Hashes for ofiqpy-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a728f40d0bd57e7582c4a6a84b5330dc2facc0644a3f0ee315af590d2ca2af4a
MD5 aa634f9a547514a5fa196802909af4dc
BLAKE2b-256 bd992a37f9ee3f8fd72dd909d2b0de6847a99cf79dee89f60a3079861faf68f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for ofiqpy-0.1.1-py3-none-any.whl:

Publisher: workflow.yml on AVHBAC/ofiqpy

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