Skip to content

Pipeline System

Pipelines are the core processing units in OpenBiometrics. Each pipeline chains together multiple models into a single process() call that takes raw input and returns structured results.

The FacePipeline is the primary pipeline. It runs every detected face through a sequence of stages:

Image → Detect → Quality → Align → Embed → Liveness → Demographics → Results

Each stage is optional and controlled by configuration:

StageConfig FlagOutput
DetectAlways onBounding boxes, landmarks, confidence
Qualityenable_qualityOverall score, sharpness, brightness, head pose
AlignAlways on (post-detect)112x112 aligned face crop
EmbedRequires w600k_r50.onnx model512-d embedding vector
Livenessenable_livenessLive/spoof classification, confidence score
Demographicsenable_demographicsEstimated age and gender
from openbiometrics.core.pipeline import FacePipeline, PipelineConfig
import cv2
config = PipelineConfig(
models_dir="./models",
ctx_id=0, # GPU device (-1 for CPU)
det_thresh=0.5, # Detection confidence threshold
enable_liveness=True,
enable_demographics=True,
enable_quality=True,
quality_gate=False, # If True, skip embedding when quality fails
)
pipeline = FacePipeline(config)
pipeline.load()
image = cv2.imread("photo.jpg")
results = pipeline.process(image)
for r in results:
print(f"Bbox: {r.face.bbox}")
print(f"Quality: {r.quality.overall_score}/100")
print(f"Embedding shape: {r.embedding.shape}")
print(f"Age: {r.age}, Gender: {r.gender}")
print(f"Live: {r.is_live} ({r.liveness_score:.2f})")

Each detected face produces a FaceResult:

FieldTypeDescription
faceDetectedFaceRaw detection (bbox, landmarks, aligned crop)
qualityQualityReport | NoneQuality assessment
embeddingndarray | None512-d face embedding
ageint | NoneEstimated age
genderstr | None"M" or "F"
is_livebool | NoneReal face vs spoof
liveness_scorefloat | NoneLiveness confidence 0-1
identitystr | NoneMatched identity label (after watchlist search)
identity_scorefloat | NoneMatch similarity score

The pipeline has a built-in verify() method:

is_match, similarity = pipeline.verify(image1, image2)
print(f"Match: {is_match}, Similarity: {similarity:.3f}")

This processes both images, extracts embeddings from the top face in each, and compares them.

When quality_gate=True, faces that fail quality assessment are returned early without an embedding. This is useful for enrollment flows where you only want high-quality face data:

config = PipelineConfig(
enable_quality=True,
quality_gate=True, # No embedding for low-quality faces
)
pipeline = FacePipeline(config)
pipeline.load()
results = pipeline.process(image)
for r in results:
if r.embedding is None:
print(f"Rejected: {r.quality.reasons}")
else:
print(f"Accepted: quality={r.quality.overall_score}")

The document pipeline processes identity documents (passports, ID cards, driver licenses):

Image → Detect Document → Warp → OCR → MRZ Parse → Face Extraction
StageConfig FlagOutput
DetectAlways onDocument bounding box and type
WarpAlways on (post-detect)Perspective-corrected document image
OCRenable_ocrExtracted text fields
MRZenable_mrzParsed MRZ data (name, DOB, nationality, etc.)
Face Extractionenable_face_extractionCropped photo from the document
from openbiometrics import BiometricKernel, BiometricConfig
from openbiometrics.config import DocumentConfig
config = BiometricConfig(
document=DocumentConfig(
enabled=True,
enable_ocr=True,
enable_mrz=True,
enable_face_extraction=True,
),
)
kernel = BiometricKernel(config)
kernel.load()
if kernel.document is not None:
result = kernel.document.scan(document_image)
print(f"Document type: {result.document_type}")
print(f"MRZ surname: {result.mrz.parsed.surname}")
print(f"Face photo shape: {result.face_crop.shape}")

Requires the document extra: pip install openbiometrics-engine[document].

Pipelines are independent objects. You can run them standalone without the full kernel:

# Face pipeline only, no kernel needed
from openbiometrics.core.pipeline import FacePipeline, PipelineConfig
pipeline = FacePipeline(PipelineConfig(models_dir="./models"))
pipeline.load()
results = pipeline.process(image)

Or combine pipeline results in your own application logic:

kernel = BiometricKernel(config)
kernel.load()
# Detect face on document, then verify against selfie
if kernel.document is not None:
doc_result = kernel.document.scan(id_card_image)
doc_face = doc_result.face_crop
is_match, score = kernel.face.verify(doc_face, selfie_image)
print(f"Document face matches selfie: {is_match} ({score:.2f})")

The kernel manages lifecycle and configuration, but the pipelines do the actual work and can be mixed freely.