Skip to content

Types (Data Structures)

All public data structures used by the FaceHub API. These are pure data containers (mostly NamedTuple subclasses) returned by detectors, recognizers, trackers, and the pipeline.


BBox

Bounding box with four integer coordinates.

from face_hub import BBox

bbox = BBox(x1=100, y1=50, x2=300, y2=250)
print(bbox.to_tuple())  # (100, 50, 300, 250)
print(bbox.width)       # 200
print(bbox.height)      # 200
print(bbox.area)        # 40000
Attribute Type Description
x1 int Left
y1 int Top
x2 int Right
y2 int Bottom

Methods

Method Returns Description
to_tuple() (int, int, int, int) (x1, y1, x2, y2)

Computed Properties

Property Description
width x2 - x1
height y2 - y1
area width * height

DetectionResult

Bare detection result — bounding box + confidence, no embedding.

from face_hub import DetectionResult, BBox

det = DetectionResult(
    bbox=BBox(100, 50, 300, 250),
    confidence=0.92,
)
print(det)

Returned by FaceDetector.detect().

Attribute Type Description
bbox BBox Bounding box
confidence float Detection confidence [0.0, 1.0]

DetectionWithEmbedding

Detection result with an optional 512-dim embedding and quality flag.

Returned by FaceDetector.detect_with_embeddings().

from face_hub import DetectionWithEmbedding, BBox
import numpy as np

det = DetectionWithEmbedding(
    bbox=BBox(100, 50, 300, 250),
    confidence=0.92,
    embedding=np.array([...]) if embedding_available else None,
    quality_pass=True,
)

if det.has_embedding:
    print(det.embedding.shape)  # (512,)
Attribute Type Description
bbox BBox Bounding box
confidence float Detection confidence
embedding np.ndarray \| None 512-dim L2-normalized embedding, or None
quality_pass bool Whether the face passes quality filter

Properties

Property Description
has_embedding True if embedding is not None

TrackedFace

A tracked face with temporal identity smoothing.

Returned by FaceTracker.update().

from face_hub import TrackedFace, BBox

face = TrackedFace(
    track_id=3,
    bbox=BBox(100, 50, 300, 250),
    name="Alice",
    age=15,
    is_confirmed=True,
    confidence=0.78,
)
Attribute Type Description
track_id int Stable ID assigned by the tracker
bbox BBox Current bounding box
name str Recognized name or "Unknown"
age int Frames since this track was created
is_confirmed bool Identity passed majority-vote smoothing
confidence float Average cosine similarity for confirmed tracks

Properties

Property Type Description
is_known bool True if the name is not "Unknown" (also "Unknown" constant)

TrackedFace States

State is_confirmed is_known Meaning
Unknown False False Not recognized; unstable
Pending False True Recognizer matched someone, but not enough frames yet
Confirmed True True Identity confirmed by majority vote across smooth_frames frames

PipelineResult

The result returned by FaceHubPipeline.process_frame().

from face_hub.pipeline import PipelineResult

result = pipeline.process_frame()
if result is not None:
    print(f"FPS: {result.fps}")
    print(f"Faces detected: {result.total_faces}")
    for face in result.tracked_faces:
        print(face.track_id, face.name, face.is_confirmed)
Attribute Type Description
frame np.ndarray The BGR frame that was processed
tracked_faces List[TrackedFace] All tracked faces in this frame
fps float Running average FPS
total_faces int Number of faces in this frame (same as len(tracked_faces))

Properties

Property Type Description
known_faces List[TrackedFace] Faces where is_known is True
confirmed_faces List[TrackedFace] Faces where is_confirmed is True
unknown_faces List[TrackedFace] Faces where is_known is False

PhotoFace

One face found in one photo. Stored in PhotoClassificationResult.faces.

from face_hub import PhotoFace, BBox

face = PhotoFace(
    photo_id="party1.jpg",
    bbox=BBox(100, 50, 300, 250),
    det_confidence=0.92,
    label="person_001",
    similarity=0.71,
)
Attribute Type Description
photo_id str Id of the photo the face was found in
bbox BBox Bounding box of the face
det_confidence float Detection confidence [0.0, 1.0]
label str Person name, cluster label (person_001, ...), or UNKNOWN_SENTINEL
similarity float Cosine similarity to the matched person / cluster centroid

PhotoGroup

A group of photos that contain the same person.

Attribute Type Description
label str Person name or cluster label
photo_ids List[str] Unique photo ids, in first-appearance order
face_count int Total faces of this person across the group

Computed Properties

Property Description
photo_count len(photo_ids)

Note

A photo containing several people appears in several groups, so photo_count values across groups do not sum to total_photos.


PhotoClassificationResult

Returned by PhotoClassifier.classify_photos() and the classify_photos() helper. See Photo Classifier for usage.

result = classifier.classify_photos(photos)

print(result.groups)            # {"person_001": PhotoGroup(...), ...}
print(result.no_face_photos)    # photos with no usable face
print(result.summary())         # {"person_001": 3, "person_002": 1}
Attribute Type Description
groups Dict[str, PhotoGroup] Label → group, in first-appearance order
faces List[PhotoFace] Every usable face across all photos
no_face_photos List[str] Photos with no usable face
unreadable_photos List[str] Photos that failed to decode
total_photos int Always len(images)

Properties

Property Type Description
labels List[str] All group labels in first-appearance order
total_faces int len(faces)

Methods

Method Returns Description
photos_of(label) List[str] Photo ids of a person / cluster (empty if unknown label)
labels_of(photo_id) List[str] All labels found in one photo
summary() Dict[str, int] Label → photo count, plus __no_face__ / __unreadable__ entries

ExportResult

Returned by export_to_folders().

export = export_to_folders(result, "sorted/")

print(export.exported)      # {"person_001": ["sorted/person_001/a.jpg", ...], ...}
print(export.total_files)   # total files written (multi-person photos counted per folder)
print(export.skipped)       # photo ids that are not existing files
print(export.errors)        # photo id → error message
Attribute Type Description
exported Dict[str, List[str]] Folder label → written file paths
skipped List[str] Photo ids that are not existing files (e.g. array inputs)
errors Dict[str, str] Photo id → error message

Properties

Property Type Description
total_files int Total files written across all folders
labels List[str] Folder labels that received files

Constants

UNKNOWN_SENTINEL

from face_hub import UNKNOWN_SENTINEL

print(UNKNOWN_SENTINEL)  # "Unknown"

The string "Unknown". Compare recognition results against this:

name, conf = recognizer.recognize(embedding)
if name == UNKNOWN_SENTINEL:
    print("Not recognized")

Usage Patterns

Filter Faces by State

result = pipeline.process_frame()
if result is None:
    return

# Known (recognized by name)
for face in result.known_faces:
    print(f"✓ {face.name} ({face.confidence:.0%})")

# Confirmed (stable identity)
for face in result.confirmed_faces:
    print(f"[Confirmed] {face.name} track={face.track_id}")

# Unknown
for face in result.unknown_faces:
    print(f"? Unknown face at {face.bbox.to_tuple()}")

Working with BBox

from face_hub import BBox

# Create from coordinates
bbox = BBox(10, 20, 200, 220)

# Unpack
x1, y1, x2, y2 = bbox.to_tuple()

# Center point
cx = (bbox.x1 + bbox.x2) // 2
cy = (bbox.y1 + bbox.y2) // 2

# Size
print(f"Size: {bbox.width}×{bbox.height}, Area: {bbox.area}px²")

# Crop face from frame
import cv2
face_roi = frame[bbox.y1:bbox.y2, bbox.x1:bbox.x2]

Check if Embedding is Present

results = detector.detect_with_embeddings(frame)
for det in results:
    if det.has_embedding:
        # Safe to access det.embedding
        print(det.embedding.shape)   # (512,)
        print(det.embedding.dtype)   # float32
    else:
        print("No embedding — face was filtered out by quality check")

Convert to JSON-Serializable

import json

def tracked_face_to_dict(face):
    return {
        "track_id": face.track_id,
        "bbox": list(face.bbox.to_tuple()),
        "name": face.name,
        "is_confirmed": face.is_confirmed,
        "confidence": round(face.confidence, 4),
        "age": face.age,
    }

result = pipeline.process_frame()
if result:
    faces_data = [tracked_face_to_dict(f) for f in result.tracked_faces]
    print(json.dumps(faces_data, indent=2))

Accumulate All Faces Over Time

all_faces = {}

while pipeline.is_running:
    result = pipeline.process_frame()
    if result is None:
        continue

    for face in result.tracked_faces:
        if face.is_confirmed and face.is_known:
            all_faces[face.track_id] = {
                "name": face.name,
                "confidence": face.confidence,
                "age": face.age,
            }

    # Show everyone who has appeared so far
    for tid, info in all_faces.items():
        print(f"Track {tid}: {info['name']} (appeared {info['age']} frames ago)")

Notes

  • All data types in face_hub are NamedTuple subclasses, making them lightweight, immutable, and iterable.
  • DetectionWithEmbedding.embedding is None when quality filtering rejects the face. Always check has_embedding before accessing it.
  • TrackedFace.name equals "Unknown" (UNKNOWN_SENTINEL) when no match is found or the track is not yet confirmed.
  • BBox coordinates are zero-indexed and in image pixel space; they are always integers (clamped to frame boundaries).