instances¶
Turning per-view center peaks into animals, and animals into tracks (ADR-0063).
The center channel says where animals are in each view but not which peak across
views is one animal, and it has no memory. assign_centers triangulates every view
pair's every peak pair as one fixed-shape batch and keeps what the most views agree
with; link_step carries the slots onto the next frame by Hungarian assignment
under a step gate, causally; center_windows draws each animal's fixed-size window.
Fixed shapes keep the jitted triangulate and Rig.project from recompiling.
assign_centers ¶
assign_centers(
rig: Rig,
cands: Float[ndarray, "V C 3"],
*,
min_views: int = 2,
gate_px: float = 30.0,
min_separation_px: float = 50.0,
max_animals: int = 2,
) -> tuple[
Float[np.ndarray, "N 3"], Int[np.ndarray, "V N"]
]
One frame's center peaks -> up to max_animals 3D centers and their peaks.
cands (V, C, 3) are (x, y, score) per view in video pixels, NaN-padded; the
score is not read, a peak earning its place by the views that agree with it. A
center needs min_views support, two of them far enough from parallel and from
opposite to place it in depth (ADR-0130), a view supports a hypothesis within
gate_px, and centers within min_separation_px in every view are one animal
found twice.
Returns (centers, assigned): (max_animals, 3) world centers, NaN where unfilled,
and (V, max_animals) each view's peak index, -1 for none.
Source code in src/deeperfly/instances.py
center_windows ¶
center_windows(
rig: Rig,
centers: Float[ndarray, "N 3"],
sizes: Float[ndarray, "V 2"],
letterbox: Float[ndarray, "V 4"],
) -> Float[np.ndarray, "N V 4"]
A crop box per animal and view: the view's fixed size around the center.
One size per view per recording (ADR-0063). A slot with no center gets the view's
letterbox as a placeholder, which the caller skips. sizes is (V, 2)
(width, height) and the result (N, V, 4) boxes, both in video pixels.
Source code in src/deeperfly/instances.py
link_step ¶
link_step(
rig: Rig,
last: Float[ndarray, "N 3"],
age: Int[ndarray, N],
detections: Float[ndarray, "M 3"],
*,
max_step_px: float = 60.0,
hold_frames: int = 12,
) -> tuple[
Float[np.ndarray, "N 3"],
Int[np.ndarray, N],
Float[np.ndarray, "N 3"],
Int[np.ndarray, N],
]
Carry N track slots onto this frame's detections, causally.
Hungarian assignment on the largest reprojected distance over the views, no
velocity model and no appearance (ADR-0063). last (N, 3) and age (N,) are
each slot's last position and frames unseen; a slot held k frames may jump
(1 + k) * max_step_px, and after hold_frames it is freed. Returns
(centers, flags, last, age): the position to report (NaN when lost), uint8 flags
(0 tracked, 1 held, 2 lost), and the carried state.
Source code in src/deeperfly/instances.py
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |