ofiqpy
ofiqpy is a Python reimplementation of the fixed, canonical BSI OFIQ v1.1.0
quality-assessment profile. It computes the 27 ISO/IEC 29794-5 components exposed by
OFIQ v1.1.0 plus UnifiedQualityScore using OFIQ's model files.
ofiqpy supports one exact contract:
- OFIQ source tag
v1.1.0, commitbb5dc91d00477e02ce53d2530d28e35021484393. - The canonical
ofiq_config.jaxnwith SHA-256e117286706d799a1e23130db01cfdff7ef36d157b22ecf68dd196052a8a8d0b3. - Twelve exact model artifacts totaling 453,497,937 bytes.
OFIQConfighashes every required artifact before creating inference sessions. - All 28 canonical output components. Arbitrary JAXN measure lists, scalar overrides, and the full C++ API are not implemented.
Confirmed parity evidence
The strict gate runs the live C++ OFIQSampleApp and this package on all 28 real BSI
conformance images. It rejects missing images, duplicate identities, missing components,
non-numeric values, and status mismatches.
At the 0.2.0 source state on 2026-08-16:
| Observation | Result |
|---|---|
| Official C++ conformance suite | 787 / 787 passed |
| Image/component observations | 784 / 784 present |
| Scalar values exactly equal | 784 / 784 |
| Scalar values within tolerance 0 | 784 / 784 |
| Success/FailureToAssess status equal | 784 / 784 |
| Raw values equal at six-decimal CSV precision | 698 to 702 / 784 across verified Linux runs |
| Raw values within the named component policy | 784 / 784 |
Raw values determine the verdict under the immutable
bsi-ofiq-v1.1.0-cpu-raw-csv-v1 component policy. The policy compares the six-decimal
values emitted by OFIQSampleApp; ten deterministic components require equality and each
remaining component has a unit-specific bound and rationale. Raw values are excluded only
when either implementation reports FailureToAssess, where OFIQ does not define a raw
result. The diagnostic exact count was 698 on the GitHub Python 3.11.15 runner and 702 on
the local Python 3.11.14 verification host. This environment-sensitive count is reported,
but it does not determine conformance. The earlier unbound 1,197-image and universal
bit-exactness claims are not used as release evidence.
A separate, non-redistributed diagnostic reran the recovered 1,197-image CelebA selection with aggregate provenance. All 33,516 statuses matched; 33,483 scalars were exact and all were within one point; all 33,430 defined raw comparisons met the component policy. This binds the currently available bytes but does not retroactively prove that the original unhashed run used identical bytes. See Conformance.
Install and configure
python -m pip install ofiqpy
git clone --branch v1.1.0 https://github.com/BSI-OFIQ/OFIQ-Project.git ../OFIQ-Project
(
cd ../OFIQ-Project/scripts
sh build.sh
)
export OFIQPY_OFIQ_ROOT="$(cd ../OFIQ-Project && pwd)"
export OFIQPY_OFIQ_DATA="$OFIQPY_OFIQ_ROOT/data"
The OFIQ build downloads the separately licensed models and BSI test images. ofiqpy
does not bundle or redistribute those files. Initialization stops with an integrity error
if the downloaded configuration or any required model differs from the verified profile.
Python API
Use Assessor when status and failure information matters:
import os
from pathlib import Path
from ofiqpy import Assessor
from ofiqpy.config import OFIQConfig
data_root = Path(os.environ["OFIQPY_OFIQ_DATA"])
assessor = Assessor(OFIQConfig(data_root=data_root))
result = assessor.assess(data_root / "tests" / "images" / "r-01-frontal.png")
print(result.status)
print(result.components["UnifiedQualityScore"])
Assessor loads and validates the complete model graph before assessment and serializes
access to mutable OpenCV/ONNX sessions. A component exception produces a typed
FailureToAssess only for that component or compound component group; unaffected results
are retained.
The original mapping API remains as a compatibility adapter:
import os
from pathlib import Path
from ofiqpy import assess
image = Path(os.environ["OFIQPY_OFIQ_DATA"]) / "tests" / "images" / "r-01-frontal.png"
scores = assess(image)
print(scores["UnifiedQualityScore"])
It returns {component: (raw, scalar)} and returns an empty mapping only when no face is
detected. Unreadable paths, invalid arrays, and preprocessing failures raise instead of
being collapsed into a no-face result. New integrations should use Assessor.assess or
assess_typed when the typed failure detail is required.
CLI and batch
ofiqpy \
-i "$OFIQPY_OFIQ_DATA/tests/images/r-01-frontal.png" \
-o assessment.csv
python -m ofiqpy.batch \
-i "$OFIQPY_OFIQ_DATA/tests/images" \
-o assessments.csv \
--resume
The semicolon CSV uses the canonical 28-component OFIQ column order and preserves the
full supplied/discovered image path. CSV quoting protects delimiters in paths. Resume
validates the exact header and row width and uses the full path identity, so recursive
duplicate basenames do not collide. Batch execution defaults to one worker because each
worker owns a complete model graph; additional workers require an explicit -w value and
start with Python's clean spawn process context. An unreadable image or preprocessing
failure exits nonzero rather than silently writing a whole-image sentinel row.
On the tested 64-image real-data workload, version 0.2.0 processed 2.649 images/s at one worker, 2.391 at two, and 2.140 at four; median process-tree RSS rose from 1.292 GiB to 2.450 and 4.723 GiB. One worker is therefore the measured default for that host, not a universal optimum. See Runtime performance.
Reproduce the strict gate
python -m ofiqpy.conformance \
--ofiq-root "$OFIQPY_OFIQ_ROOT" \
--images "$OFIQPY_OFIQ_DATA/tests/images" \
--expected-count 28 \
--scalar-tolerance 0 \
--source-root "$PWD" \
--report conformance-report.json
The command exits nonzero for any conformance failure or incomplete comparison. The JSON report binds the source tree, OFIQ and ofiqpy commits, official binary and library hashes, canonical config/model hashes, and the complete input set.
License and attribution
ofiqpy is MIT-licensed. OFIQ is developed by the German Federal Office for Information
Security (BSI) and is also MIT-licensed. OFIQ's models have their own license terms; review
the license files downloaded into the OFIQ data directory before redistribution.
This project is independent and is not endorsed by ISO, IEC, or BSI.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ofiqpy-0.2.0.tar.gz.
File metadata
- Download URL: ofiqpy-0.2.0.tar.gz
- Upload date:
- Size: 232.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2371e1aa4c4cd2ba298b90cbb1364d6d4200e955fffcde2427a51bc8f2c34f4c
|
|
| MD5 |
1b94cf1be637269ac7d3c5011c716699
|
|
| BLAKE2b-256 |
77a7f01570a84ced1c08a5d9f9a847f7da834cbbb3811ea6f7d51a8c973f6578
|
Provenance
The following attestation bundles were made for ofiqpy-0.2.0.tar.gz:
Publisher:
workflow.yml on AVHBAC/ofiqpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ofiqpy-0.2.0.tar.gz -
Subject digest:
2371e1aa4c4cd2ba298b90cbb1364d6d4200e955fffcde2427a51bc8f2c34f4c - Sigstore transparency entry: 2496093211
- Sigstore integration time:
-
Permalink:
AVHBAC/ofiqpy@65bb10c3f7cb38a27b6397284a02cf4fcf7d42db -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/AVHBAC
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@65bb10c3f7cb38a27b6397284a02cf4fcf7d42db -
Trigger Event:
push
-
Statement type:
File details
Details for the file ofiqpy-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ofiqpy-0.2.0-py3-none-any.whl
- Upload date:
- Size: 50.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45f9662f4c188b39f37b32161a6fdf68da6c43d24a0b942d271be1f7dc006338
|
|
| MD5 |
eb3bead8f088f229528877302c640b0f
|
|
| BLAKE2b-256 |
c54fa275d7b1479d00874bdf61448cebe4c7610d4e502571de42eaf5df40fcfe
|
Provenance
The following attestation bundles were made for ofiqpy-0.2.0-py3-none-any.whl:
Publisher:
workflow.yml on AVHBAC/ofiqpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ofiqpy-0.2.0-py3-none-any.whl -
Subject digest:
45f9662f4c188b39f37b32161a6fdf68da6c43d24a0b942d271be1f7dc006338 - Sigstore transparency entry: 2496094011
- Sigstore integration time:
-
Permalink:
AVHBAC/ofiqpy@65bb10c3f7cb38a27b6397284a02cf4fcf7d42db -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/AVHBAC
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@65bb10c3f7cb38a27b6397284a02cf4fcf7d42db -
Trigger Event:
push
-
Statement type: