Pipeline API¶
Object Tracking¶
body_eye_sync.pipeline.object_tracking
¶
Object tracking using BoxMOT
BoundingBox
dataclass
¶
boxes_from_tracks(tracks)
¶
Drawable boxes for one frame's BoxMOT tracks array.
Source code in src/body_eye_sync/pipeline/object_tracking.py
default_device()
¶
Pick the fastest available device as a BoxMOT/Ultralytics device string.
Source code in src/body_eye_sync/pipeline/object_tracking.py
detect_tracklets(video_path, detector='yolov8n', reid='osnet_x0_25_msmt17', tracker='botsort', device=None, object_classes=(0,))
¶
Track objects in a video, yielding BoxMOT's per-frame result.
Runs BoxMOT (object detection + ReID tracking) and yields each frame's
:class:~boxmot.engine.tracking.results.FrameResult as soon as it is
computed, so callers can display or accumulate it live. Each result exposes
frame_idx (1-based) and tracks -- an (n, 8) array of
x1, y1, x2, y2, id, conf, cls, det_ind. Every frame is yielded, including
frames with no detections (their tracks is empty). Stop iterating to
cancel tracking early.
object_classes are the COCO class ids to detect; the default (0,) is
people only. device is a BoxMOT/Ultralytics device string (e.g. "0",
"mps", "cpu"); when None the fastest available device is chosen
automatically. The detections sharing a track id form a tracklet, and
conf is the per-frame confidence of the object detector.
Source code in src/body_eye_sync/pipeline/object_tracking.py
tracks_to_dataframe(frames)
¶
Stack (frame_idx, tracks) pairs into the stored tracklets DataFrame.
Returns a :class:pandas.DataFrame with columns
frame, track_id, x1, y1, x2, y2, conf, frame and track_id as
integers -- a compact numeric form to store and analyse. Frames with no
detections contribute no rows.
Source code in src/body_eye_sync/pipeline/object_tracking.py
Face Detection¶
body_eye_sync.pipeline.face_detection
¶
Face detection inside tracked person boxes using InsightFace
FaceBox
dataclass
¶
A single detected face: its bounding box plus face-specific attributes.
box is the face's bounding box, in video-pixel coordinates, carrying the
tracked person's track_id. landmarks holds the five (x, y)
keypoints in :data:LANDMARK_NAMES order. embedding is the InsightFace
ArcFace recognition vector (L2-normalised), kept for later identity
clustering; None if the model pack has no recognition head.
Source code in src/body_eye_sync/pipeline/face_detection.py
FaceFrameResult
dataclass
¶
default_providers()
¶
Pick ONNX Runtime providers, using CUDA only on a usable NVIDIA GPU.
Source code in src/body_eye_sync/pipeline/face_detection.py
detect_faces(video_path, boxes_by_frame, model_name='buffalo_l', det_size=640, det_thresh=0.5, providers=None)
¶
Detect one face per tracked person box, yielding a result per frame.
boxes_by_frame maps a 0-based frame index to that frame's tracked person
:class:BoundingBoxes, as produced by object tracking. For each such frame
the person crop is run through InsightFace; the highest scoring face above
det_thresh is kept, its bounding box and five landmarks offset back into
full-frame coordinates and tagged with the box's track_id. Every
requested frame is yielded -- including frames where no face cleared the
threshold (their faces is empty) -- so callers can show progress and
cancel responsively. Stop iterating to cancel early.
Source code in src/body_eye_sync/pipeline/face_detection.py
face_box_from_row(row)
¶
Rebuild a drawable :class:FaceBox from a merged DataFrame row.
Source code in src/body_eye_sync/pipeline/face_detection.py
faces_to_dataframe(frames)
¶
Stack per-frame face results into a DataFrame keyed on (frame, track_id).
Returns a :class:pandas.DataFrame with columns frame, track_id plus
:data:FACE_COLUMNS, ready to left-merge onto the stored tracks. Frames with
no detected faces contribute no rows.
Source code in src/body_eye_sync/pipeline/face_detection.py
Body Pose¶
body_eye_sync.pipeline.body_pose
¶
Body pose detection inside tracked person boxes using Ultralytics YOLO pose.
BodyPose
dataclass
¶
A single detected body pose for one tracked person box.
box is the YOLO pose bounding box, in video-pixel coordinates, carrying
the tracked person's track_id. keypoints holds (x, y, score)
triples in :data:KEYPOINT_NAMES order.
Source code in src/body_eye_sync/pipeline/body_pose.py
PoseFrameResult
dataclass
¶
detect_body_poses(video_path, boxes_by_frame, model_name=DEFAULT_MODEL_NAME, conf=0.25, device=None)
¶
Detect one body pose per tracked person box, yielding a result per frame.
boxes_by_frame maps a 0-based frame index to that frame's tracked person
:class:BoundingBoxes. For each requested frame, each person crop is passed
through an Ultralytics YOLO pose model; the highest scoring pose in the crop
is kept, its bounding box and COCO keypoints are offset back into full-frame
coordinates and tagged with the person's track_id. Every requested frame
is yielded, including frames where no pose cleared conf.
Source code in src/body_eye_sync/pipeline/body_pose.py
pose_from_row(row)
¶
Rebuild a drawable :class:BodyPose from a merged DataFrame row.
Source code in src/body_eye_sync/pipeline/body_pose.py
poses_to_dataframe(frames)
¶
Stack per-frame pose results into a DataFrame keyed on (frame, track_id).
Returns a :class:pandas.DataFrame with columns frame, track_id plus
:data:POSE_COLUMNS, ready to left-merge onto the stored tracks. Frames with
no detected poses contribute no rows.
Source code in src/body_eye_sync/pipeline/body_pose.py
Transcription¶
body_eye_sync.pipeline.transcription
¶
Speech transcription using Whisper-family models.
This says what was said and when, on the recording's own clock. Who said it is not something one recording can answer, and is worked out later by comparing the experiment's recordings against each other.
TranscriptSegment
dataclass
¶
One stretch of speech as Whisper segmented it.
Whisper's segmentation follows sentence and pause structure, so a segment is a natural unit of speech but not necessarily one person's turn.
Source code in src/body_eye_sync/pipeline/transcription.py
Word
dataclass
¶
transcribe(audio_path, model_name, language=None, beam_size=5, vad_filter=True, device='auto', compute_type='default')
¶
Transcribe a whole recording, yielding a result per Whisper segment.
language is an ISO 639-1 code such as "de"; None detects it from
the first 30 seconds. vad_filter skips silent stretches, which both
speeds the pass up and suppresses the text Whisper otherwise invents to fill
silence. Segments are yielded as they are decoded, so callers can show
progress; stop iterating to cancel.
device is "auto", "cpu" or "cuda"; "auto" uses a GPU when
the machine has one. CTranslate2 loads its CUDA libraries by name the first
time it uses a GPU, so a machine whose CUDA does not match the one it was
built against fails here rather than transcribing more slowly on the CPU.
Source code in src/body_eye_sync/pipeline/transcription.py
transcript_to_dataframes(transcript)
¶
Stack a transcript into a segments table and a per-word table.
The segments are numbered by segment_id in the order they were spoken,
with :data:SEGMENT_COLUMNS; each word carries the segment_id it came
from and its position within it, with :data:WORD_COLUMNS.
Source code in src/body_eye_sync/pipeline/transcription.py
Loudness¶
body_eye_sync.pipeline.loudness
¶
How loud a recording is over time, measured from its audio.
measure_loudness(path)
¶
How loud a recording is over time, one row every :data:HOP_SECONDS.
level_db is the chunk's RMS level in dB and time is its middle, on
the recording's own clock. A recording too short to fill a single chunk
measures as no rows at all.
Source code in src/body_eye_sync/pipeline/loudness.py
Model Cache¶
body_eye_sync.pipeline.model_cache
¶
Shared on-disk cache for downloaded model weights.
A single cross-platform cache directory that every pipeline step routes its
model downloads into, rather than scattering them across per-library defaults
(Ultralytics' working directory, InsightFace's ~/.insightface).
cached_model_path(model_ref)
¶
Route a bare weights filename into the shared model cache.
Given only a bare name (e.g. yolo26m.pt), Ultralytics downloads the
weights into the current working directory. Rewriting it to an absolute path
under :func:model_cache_dir makes the download land in the shared cache
instead. An explicit path (one with a directory part) or an already-existing
file is returned unchanged.
Source code in src/body_eye_sync/pipeline/model_cache.py
model_cache_dir()
¶
Directory all downloaded model weights are cached in (cross-platform).