live¶
Poses as they are computed, held for a reader that may or may not be watching.
A producer, such as deeperfly run's detector passes or a tracker on a rig that is
recording, publishes moments: a frame index, and per animal and view the keypoints in
video pixels, their confidences and the window they were read through. A reader takes
JSON-ready payloads off the feed, so any channel can carry them. A feed nobody watches
counts what it is given and keeps nothing (ADR-0126).
Nothing here knows about a transport, a pipeline or a model, and nothing of the package is imported: plain arrays in, plain dicts out.
PoseFeed ¶
Moments a producer publishes, kept only while a reader is watching.
A reader calls watched on every look; the feed is active for IDLE_S after
the last one, or always when forced. While it is not, publish counts the
moments and returns. While it is, the last history moments go into a ring, the
per-view confidence is bucketed into a trend, and every so often the last frame's
images are copied for a reader to take (capture). A new capture waits until the
previous one has been taken, at most MAX_CAPTURE_HZ, and comes regardless after
1 / MIN_CAPTURE_HZ seconds.
Every method is safe to call from any thread.
Source code in src/deeperfly/live/feed.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 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 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | |
__init__ ¶
__init__(
*,
forced: bool = False,
history: int = HISTORY,
clock: Callable[[], float] = time.monotonic,
) -> None
An empty feed, forced to keep what it is given whether watched or not.
history is how many moments it holds; clock the seconds it measures by.
Source code in src/deeperfly/live/feed.py
attach_3d ¶
What a 3D stage made of some frames, replacing what an earlier one made.
points3d (T, N, K, 3) and their reprojection (T, N, V, K, 2) in video
pixels, at frames (T,).
Source code in src/deeperfly/live/feed.py
capture ¶
The captured frame's image of source, (frame, (H, W) uint8), if any.
Source code in src/deeperfly/live/feed.py
fill ¶
Put moments read back from storage into the history, uncounted.
For a reader that opened after the moments went by: the history takes them
as publish would, but they are no part of the rate, the trend or a capture.
Source code in src/deeperfly/live/feed.py
held_frames ¶
moment_payload ¶
One held moment as JSON-ready data, or None when there is none.
frame alone is that frame, or the nearest held one; with step 1 or -1 it
is the next held frame after it or the last before it. None is the newest.
Points and boxes are rounded to 0.1 px, None where missing; three_d is
the 3D attached at the frame, if any.
Source code in src/deeperfly/live/feed.py
publish ¶
publish(
frames,
points,
conf,
boxes=None,
images: Sequence[ndarray] | None = None,
times=None,
) -> None
Take T moments: their frames (T,) and what was found at them.
points (T, N, V, K, 2) in video pixels and conf (T, N, V, K); boxes (T, N,
V, 4) the windows they were read through; images per source (T, H, W)
uint8; times (T,) integer nanoseconds. Nothing is kept by reference.
Source code in src/deeperfly/live/feed.py
set_errors ¶
A reprojection error per view name, in pixels, kept beside the others.
Source code in src/deeperfly/live/feed.py
set_meta ¶
set_meta(
*,
views: Sequence[str],
sources: Sequence[dict],
point_names: Sequence[str],
edges: Sequence[Sequence[int]],
point_colors: Sequence[str] = (),
edge_colors: Sequence[str] = (),
animals: int = 1,
n_frames: int | None = None,
fps: float | None = None,
name: str = "",
) -> None
Describe what the moments are of, which forgets every moment before.
sources is one {"name", "views", "size"} per image a moment carries:
the views drawn on it by index into views, and its [width, height].
Source code in src/deeperfly/live/feed.py
state_payload ¶
What a reader polls: counts, the live moment, the history, the trend.
meta, three_d (the frames 3D is attached at) and errors come only when
the feed's version is past since; trend holds the buckets from id
trend_from on.
Source code in src/deeperfly/live/feed.py
cells ¶
An array as nested lists, NaN as None, rounded to digits if given.
Source code in src/deeperfly/live/feed.py
points ¶
Points (or boxes) along the last axis as nested lists, None for any with NaN.
The labeling GUI's shape for a missing point ([x, y] | null), so a page tests
one value, not each coordinate.
Source code in src/deeperfly/live/feed.py
deeperfly run as its live view sees it (ADR-0126).
RunWatch is the run's observer (RunObserver): - it feeds each detector pass to a PoseFeed; - it keeps the stages' progress and the log's tail as the page's status; - it reads back what the 3D stages made of the frames the feed holds; - it turns a Stop into RunStopped.
The results file is read only from the observer calls, which run on the run's own thread. Nothing here may fail the run: an error of its own turns the watch off, says so once in the log, and the run goes on.
RunWatch ¶
What a live page reads about a run: its feed, its status and its Stop.
The observer calls come from the run's thread; status, read_frame and
request_stop from the server's.
Source code in src/deeperfly/live/run.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 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 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | |
__init__ ¶
__init__(
feed: PoseFeed,
*,
facts: Sequence[tuple[str, str]] = (),
config_text: str = "",
log: Callable[[str], None] = print,
clock: Callable[[], float] = time.monotonic,
) -> None
A watch over a run that has not started, feeding feed.
facts are (label, value) pairs the page lists about the run, such as
its config file and weights; log is where the watch reports its own
trouble.
Source code in src/deeperfly/live/run.py
close ¶
Let go of the decoders the page's frames were read with.
finish ¶
The run ended: done, failed or stopped, the stage it was in with it.
Source code in src/deeperfly/live/run.py
log ¶
pose2d_block ¶
project_finished ¶
Note how a project ended; a failure marks the stage it failed in.
Source code in src/deeperfly/live/run.py
project_started ¶
Describe the project's views and videos to the feed, which starts afresh.
Source code in src/deeperfly/live/run.py
read_frame ¶
One video's frame, decoded on the reader's thread, or None if out of reach.
Each video keeps one decoder open while the project runs, as the labeling GUI's do, so stepping through the history decodes forward instead of seeking.
Source code in src/deeperfly/live/run.py
request_stop ¶
Ask the run to stop at its next pass or stage, or in STOP_GRACE_S anyway.
A run deep in one long call (a fit, a solve) reaches no boundary for a while; it is then interrupted as Ctrl-C would interrupt it.
Source code in src/deeperfly/live/run.py
run_started ¶
Note the run's name, its projects and its stages.
Source code in src/deeperfly/live/run.py
stage_cached ¶
stage_finished ¶
Mark a stage done and read back the 3D it made.
Source code in src/deeperfly/live/run.py
stage_started ¶
Mark a stage running, after reading back 3D the page has not seen yet.
Source code in src/deeperfly/live/run.py
status ¶
The page's status block: facts, projects, steps, the log, the actions.
Source code in src/deeperfly/live/run.py
A browser page over a pose feed, served from the process that feeds it (ADR-0126).
build_live_app makes the FastAPI app: the page,
the GUI's static modules, and an API that a token guards.
serve_live runs it on a thread of its own beside the
producer. The feed, the status and the actions are the caller's; deeperfly run passes
its RunWatch's.
Every API request marks the feed watched, so a page that is open is what keeps a run capturing, and closing it lets the run go back to counting.
build_live_app ¶
build_live_app(
feed: PoseFeed,
*,
status: Callable[[], dict] = dict,
actions: Mapping[str, Callable[[], None]] | None = None,
frame_reader: Callable[[int, int], ndarray | None]
| None = None,
token: str | None = None,
) -> FastAPI
The live page's app over feed, no server attached.
status() is the producer's own block of the state (see
RunWatch.status); actions are what the
page's buttons call by name; frame_reader(source, frame) decodes a frame the
feed did not capture, or answers None. With a token, every API request must
carry it in an X-Deeperfly-Token header.
Source code in src/deeperfly/live/server.py
jpeg ¶
A frame as a JPEG, halved until it is at most MAX_WIDTH wide.
The page draws it over the video's own size, so a smaller image moves no point.
Source code in src/deeperfly/live/server.py
serve_live ¶
serve_live(
app: FastAPI,
*,
host: str = "127.0.0.1",
port: int | None = None,
) -> tuple[str, Callable[[], None]]
Serve app on a daemon thread: its base URL, and a function that stops it.
port None is LIVE_PORT or the next free one.
Raises:
| Type | Description |
|---|---|
OSError
|
If no port could be bound. |