annie.core.models

Domain models for Annie.

These are pure data structures with no I/O and no framework dependencies. They form the vocabulary shared by every other layer: parsers produce them, the service layer arranges them into a manifest, and the UI renders them.

The geometry uses image-pixel coordinates with the origin at the top-left, x increasing rightwards and y increasing downwards — the convention used by the underlying detection/tracking CSV files.

Attributes

LANDMARK_NAMES

The five named facial landmark points carried by every detection row.

RowStatus

The three states a manifest row can be in. See annie.scanning.

NO_ACTIVE_TRACK

Sentinel track_id meaning "no active / protagonist track".

Classes

BBox

A single face bounding box with confidence and named landmarks.

FrameAnnotation

All face boxes belonging to a single video frame.

Event

A temporal annotation produced by the Annotator tab.

VideoEntry

One Browse row: a single video with all of its annotations aggregated.

Functions

hit_test(→ int | None)

Return the track_id of the box under a click, or None.

Module Contents

annie.core.models.LANDMARK_NAMES: tuple[str, ...] = ('left_eye', 'right_eye', 'nose', 'left_mouth', 'right_mouth')

The five named facial landmark points carried by every detection row.

Ordered to match the shared 17-column CSV schema.

annie.core.models.RowStatus

The three states a manifest row can be in. See annie.scanning.

class annie.core.models.BBox[source]

A single face bounding box with confidence and named landmarks.

x

Left edge of the box, in pixels.

y

Top edge of the box, in pixels.

w

Box width, in pixels.

h

Box height, in pixels.

score

Detector confidence in [0, 1].

landmarks

Mapping of landmark name (see LANDMARK_NAMES) to its (x, y) pixel coordinate.

track_id

The owning track’s id when the box came from a .track file, otherwise None (e.g. a raw .vdet detection).

property x2: int

Right edge of the box (x + w), in pixels.

property y2: int

Bottom edge of the box (y + h), in pixels.

property area: int

Box area in square pixels (clamped to be non-negative).

contains(px: int, py: int) → bool[source]

Return whether the pixel (px, py) lies inside this box (inclusive).

Parameters:
  • px – X coordinate of the query point, in pixels.

  • py – Y coordinate of the query point, in pixels.

Returns:

True if the point is within the box bounds, False otherwise.

class annie.core.models.FrameAnnotation[source]

All face boxes belonging to a single video frame.

A .vdet frame may carry several boxes (one per detected face); a .track frame carries exactly one.

frame_idx

Zero-based frame index within the source video.

boxes

The bounding boxes present on this frame.

class annie.core.models.Event[source]

A temporal annotation produced by the Annotator tab.

event_id

Stable identifier, unique within a video’s annotation file.

name

Human-readable label.

start

Start time in seconds.

end

End time in seconds.

metadata

Optional free-form key/value extras.

annie.core.models.NO_ACTIVE_TRACK = -1

Sentinel track_id meaning “no active / protagonist track”.

class annie.core.models.VideoEntry[source]

One Browse row: a single video with all of its annotations aggregated.

Unlike a per-annotation fan-out, a video is represented once and carries its raw detections (.vdet) together with every derived track. This is what the Browse tab renders and what the overview metrics are computed from.

video_id

The video stem used for matching, labelling, and as the review key.

video_path

Path to the source .mp4, or None when annotation-only.

vdet_path

Path to the raw-detection .vdet, or None if absent.

track_paths

Paths to the video’s __track{N}.csv files, ordered by track id.

track_ids

The track indices, aligned with track_paths.

active_track_id

The resolved protagonist track id, or -1 if none.

status

One of RowStatus.

labels

Per-video label values gathered from CSV label sources, keyed by column name (e.g. {"Sentiment": "negative", "Angry": "0.33"}). Drives the Browse label tags and the label filters.

label_origins

Where each label value came from, keyed like labels — e.g. "intake.xlsx › visits · subject = 4021" for a table row, or "path field {part}" for a nested-layout field. Shown on hover in Browse.

row_id

The video’s 1-based position in the whole scanned dataset, assigned once by annie.dataset.scanning over the full sorted manifest. It identifies the sample, not its slot in whatever list is on screen: filtering the Browse tab or queueing a subset into the Annotator leaves each row’s number untouched, so “I stopped at 3400” still means something after a restart. 0 when unassigned (an entry built by hand rather than by a scan).

property has_video: bool

Whether a source video file is present.

property has_vdet: bool

Whether a raw-detection .vdet is present.

property has_track: bool

Whether at least one track file is present.

property has_active_track: bool

Whether a valid protagonist track is assigned (active_track_id >= 0).

property label: str

The on-screen label (the video id).

property key: str

Stable per-video identity, used as the SQLite review-status key.

annie.core.models.hit_test(click_xy: tuple[int, int], annotation: FrameAnnotation, *, smallest_wins: bool = True) → int | None[source]

Return the track_id of the box under a click, or None.

Used by the protagonist correction flow: the click is tested against every box on the frame. When boxes overlap, the smallest enclosing box wins by default (configurable), which makes it possible to select a face nested inside a larger one.

Parameters:
  • click_xy – The (x, y) click position in image-pixel space.

  • annotation – The boxes drawn on the clicked frame.

  • smallest_wins – If True, ties break to the smallest-area box; if False, to the largest.

Returns:

The enclosing box’s track_id, or None if the click hit no box (or the hit box has no track id).