pipeline¶
Orchestration: a run over projects, covering a frame set, reproducible.
It owns which projects a run covers, where its files live, which frames each stage already covers and what to do when one project fails, and does no math: run is the driver, stages one function per stage table, plan what a run means before it runs.
Context
dataclass
¶
What every stage is handed: the run config, the recording, and where to write.
Attributes:
| Name | Type | Description |
|---|---|---|
cfg |
RunConfig
|
The typed run config. |
recording |
Recording
|
The project's recording: its videos and frame count. |
skeleton |
Skeleton
|
The project's skeleton, the |
results |
Results
|
Its open results file. |
rig |
Rig | None
|
The geometry in force, the |
facts |
Facts
|
What the fingerprints hash besides the tables. |
layout |
Layout
|
Which views each video carries (the project's). |
labels |
Callable[[], Labels] | None
|
Loads the project's hand labels, raising a |
detector |
DetectorCache | None
|
The shared detector handle, or |
log |
Callable[[str], None]
|
Where progress lines go. |
todo |
Mapping[str, ndarray]
|
Per stage, the frames it computes in this invocation (the coverage plan, coverage_plan); a stage absent here computes every frame. |
renders |
Path | None
|
The folder |
force |
bool
|
Whether the invocation recomputes what it could reuse, such as the static crop an earlier invocation found. |
observer |
RunObserver | None
|
Who watches the run, handed each detector pass; |
Source code in src/deeperfly/pipeline/stages.py
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 | |
frame_size ¶
The (height, width) a view's pixels live in: its video's frame.
frames ¶
The frames stage computes here, increasing absolute indices.
need_rig ¶
The geometry in force, for a stage that reads it.
Raises:
| Type | Description |
|---|---|
StageError
|
If the run reads no camera parameters, which prepare rules out for every stage that needs them. |
Source code in src/deeperfly/pipeline/stages.py
points ¶
The keypoint indices a point selector claims, in skeleton order.
Source code in src/deeperfly/pipeline/stages.py
read ¶
Resolve a data reference: a stored stage array, or the hand labels.
With frames, only those frames, which the stage that wrote the array must
cover; without, the whole array.
Raises:
| Type | Description |
|---|---|
StageError
|
If no stage has written the array (one left out with |
Source code in src/deeperfly/pipeline/stages.py
read_animal ¶
read, with the animal axis peeled off: one animal's copy of an array.
An array about the recording rather than an animal, and the hand labels, come back whole.
Source code in src/deeperfly/pipeline/stages.py
DetectorCache
dataclass
¶
The run's nets, loaded once, shared by every project; torch on first use.
Source code in src/deeperfly/pipeline/stages.py
loaded_device
property
¶
The device the nets were loaded on, or None before the first get.
get ¶
(models, device) for predict_recording, loading on first call.
Source code in src/deeperfly/pipeline/stages.py
get_locator ¶
The run's full-frame locator, loaded once; None when it names none.
Source code in src/deeperfly/pipeline/stages.py
ProjectOutcome
dataclass
¶
What happened for one project.
Attributes:
| Name | Type | Description |
|---|---|---|
project |
str
|
Its name in the invocation (project_names). |
results |
Path
|
Its run's results file. |
ran |
tuple[str, ...]
|
The stages that computed frames. |
cached |
tuple[str, ...]
|
The stages with nothing to compute: the frames asked for were covered, under a matching fingerprint. |
error |
str | None
|
The message of the failure that stopped it, or |
Source code in src/deeperfly/pipeline/run.py
RunObserver ¶
Bases: Protocol
The calls a run makes, in order, to whoever watches it.
Source code in src/deeperfly/pipeline/observe.py
RunStopped ¶
RunSummary
dataclass
¶
The whole invocation's outcome.
Attributes:
| Name | Type | Description |
|---|---|---|
out |
Path | None
|
The |
stages |
tuple[str, ...]
|
The stages selected for this run. |
outcomes |
tuple[ProjectOutcome, ...]
|
One entry per project, in run order. |
name |
str
|
The run's name, shared by every project. |
Source code in src/deeperfly/pipeline/run.py
StageError ¶
run_projects ¶
run_projects(
cfg: RunConfig,
paths: Sequence[str | Path],
*,
only: Sequence[str] = (),
skip: Sequence[str] = (),
out: Path | None = None,
force: bool = False,
name: str | None = None,
frames: Sequence[int | str] | None = None,
log: Callable[[str], None] = print,
observer: RunObserver | None = None,
) -> RunSummary
Apply a run config to the projects some paths stand for, and say what happened.
Each path is resolved as every command resolves one, a directory of videos
getting the default project
(resolve_projects). The run's name is
name, else the config's, else the time of this call, shared by every project
(run_name) and claimed in each, with -2,
-3 when another invocation holds it
(claim_run_name). frames stands
in for the config's frames; out puts each project's files in
<out>/<project name>/ (run_paths). force
recomputes every frame asked for of every selected stage and lets another config
take over a run of this name, dropping the stages whose fingerprint moved. A
project that fails carries its message in the summary instead of raising.
observer is told each step as it happens
(RunObserver).
Raises:
| Type | Description |
|---|---|
ConfigError
|
If the stage selection or the name fails, which is the invocation being wrong. |
(FileNotFoundError, ValueError)
|
If a path stands for no project, or two paths for one; nothing has run then. |
Source code in src/deeperfly/pipeline/run.py
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 | |
What a run tells someone watching it, as it goes (ADR-0126).
run_projects hands each step of a run to an
observer, such as deeperfly run's live view, which the pipeline does not import. An
observer that wants the run to end raises RunStopped from any call; it unwinds as
Ctrl-C does.
RunObserver ¶
Bases: Protocol
The calls a run makes, in order, to whoever watches it.
Source code in src/deeperfly/pipeline/observe.py
What a run means before it runs: its projects, stages, fingerprints and frames.
The paths an invocation names resolved to projects (ADR-0081), the stage selection
(--only, --skip), the camera parameters a run starts from resolved against a
project (ADR-0086), the run's name and files (results/<name>.h5 and its .toml,
renders/<name>/), the frame set an invocation asks for, each stage's fingerprint
(ADR-0035), and the coverage plan: which frames each stage computes, given what the
run already covers (ADR-0082).
Facts
dataclass
¶
What a fingerprint hashes besides the config's stage tables.
Attributes:
| Name | Type | Description |
|---|---|---|
animals |
int
|
How many animals are tracked. |
mirrored |
tuple[str, ...]
|
The mirrored views, in the rig's order. |
views |
dict[str, Any]
|
The initial camera parameters, per view, as data; empty when the run reads none. |
Source code in src/deeperfly/pipeline/plan.py
of
classmethod
¶
A project's facts: its animals and mirrored views, and the initial values.
From the manifest and the resolved [calibration]
(initial_calibration); no
video is opened.
Source code in src/deeperfly/pipeline/plan.py
RunPaths
dataclass
¶
Where one project's run lives.
Attributes:
| Name | Type | Description |
|---|---|---|
results |
Path
|
The results file, |
config |
Path
|
The run config copied verbatim, |
renders |
Path
|
The folder the |
Source code in src/deeperfly/pipeline/plan.py
claim_run_name ¶
claim_run_name(
stamp: str,
projects: Sequence[tuple[str, Project]],
out: Path | None,
config_text: str,
) -> tuple[str, list[Path | OSError]]
A default run name that no project of the invocation holds, claimed in each.
stamp, else stamp-2, stamp-3, ...: the first under which no project has
the run's .h5 or .toml (run_paths).
Each project's .toml is created exclusively, holding config_text, so another
invocation in the same second, in this process or another, finds the name taken
and moves on (ADR-0082). Returns the name and, per project in order, the file
claimed or the error that kept the project from claiming it, which fails that
project alone.
Source code in src/deeperfly/pipeline/plan.py
collision ¶
What a run of this name holding another config says.
coverage_plan ¶
coverage_plan(
cfg: RunConfig,
stages: Sequence[str],
results: Results,
requested: ndarray,
facts: Facts,
*,
force: bool,
log: Callable[[str], None],
) -> dict[str, np.ndarray]
The frames each selected stage computes in this invocation (ADR-0082).
Decided before any stage runs, in pipeline order. A stage whose stored
fingerprint moved covers nothing (its group is dropped when it begins); it
computes the frames asked for that it does not cover, plus the ones a stage it
derives from, directly or not, computes in this invocation, and with force
every frame asked for. bundle_adjustment solves one calibration, so it
computes every frame or none: all of them when it never finished, its
fingerprint moved, or force. render cannot patch a video, so it draws every
frame asked for unless those are covered and nothing it reads is recomputed. A
stage with nothing to compute is logged as cached, with how many frames it
covers.
Source code in src/deeperfly/pipeline/plan.py
describe ¶
describe(
cfg: RunConfig,
stages: Sequence[str],
paths: Sequence[str | Path],
out: Path | None = None,
*,
name: str,
frames: Sequence[int | str] | None = None,
force: bool = False,
) -> tuple[list[str], int]
The dry run: the selected stages, then what each project would do.
Each path is resolved as the run resolves it but nothing is created: a directory
of videos is planned against the default project the run would create, built in
memory. A project is checked, its calibration resolved and its recording opened
exactly as a run would, so one the config does not fit shows here, with its frame
set, its run's file and the coverage plan against what that file already covers
(coverage_plan). frames stands in for
the config's. Returns the report's lines and how many projects would fail.
Raises:
| Type | Description |
|---|---|
(FileNotFoundError, ValueError)
|
As resolve_projects. |
Source code in src/deeperfly/pipeline/plan.py
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | |
downstream ¶
The stages whose output derives from stage's, in pipeline order.
Transitive over UPSTREAM: smoothing and ik read the 2D as well as the 3D
their tables name, and whatever came from a stage's values is stale with them.
Source code in src/deeperfly/pipeline/plan.py
fingerprint ¶
A stage's fingerprint: its table, everything upstream, and the rig (ADR-0035).
The payload is the stage's table and every table upstream, the animal count and
the mirrored views (which decide what the detector sees), and the initial
calibration's values past [pose2d] or when several animals are tracked. A key
at its default and a key omitted hash the same; the [bundle_adjustment] stage
stamps the fingerprint on the rig it writes.
Source code in src/deeperfly/pipeline/plan.py
forced_conflict ¶
forced_conflict(
cfg: RunConfig,
stages: Sequence[str],
results: Results,
facts: Facts,
) -> str | None
Why --force refuses this selection over results; None when it does not.
A stage --force would drop unselected
(forced_drops) that a selected stage
reads would leave that stage reading nothing, or the initial rig in place of the
solved one. The invocation is refused before anything is written instead, so the
stored stage stays; selecting it too recomputes it under the new config. A stage
whose table the config no longer has is read by none, so it is dropped.
Source code in src/deeperfly/pipeline/plan.py
forced_drop_line ¶
What a run and its dry run say of a stage --force drops unselected.
Source code in src/deeperfly/pipeline/plan.py
forced_drops ¶
forced_drops(
cfg: RunConfig,
stages: Sequence[str],
results: Results,
facts: Facts,
) -> dict[str, int]
The stored stages --force drops without running them, with what each covers.
--force lets a config take over a run and drops every stage whose fingerprint
moved (ADR-0082). A selected stage is dropped when it begins; one left out with
--only or --skip never begins, so it is one of these, lest the file and its
.toml claim a config that did not compute it.
Source code in src/deeperfly/pipeline/plan.py
frame_set ¶
The frames an invocation covers: indices and slices, unioned and sorted.
Each entry is an index or a "start:stop:step" slice with Python's semantics
over range(n_frames); empty means every frame. The frame set is outside every
fingerprint.
Raises:
| Type | Description |
|---|---|
ValueError
|
On a malformed or negative entry, an index at or past
|
Source code in src/deeperfly/pipeline/plan.py
initial_calibration ¶
[calibration] resolved into values for project; None without the table.
from = "active" and an id copy that calibration of the project, and a file is
read; either way the values are a deep copy, so editing or deleting the file
later does not reach the run, and a copy of a project calibration records its id
as copied_from (ADR-0086). Inline placements are taken as written, each view
mirrored as the manifest says. The views come out in the manifest's order,
checked against it (placed_views).
Raises:
| Type | Description |
|---|---|
ValueError
|
If the project has no active calibration or no such id, the file is not a calibration, or the views do not match the manifest. |
OSError
|
If the file cannot be read. |
Source code in src/deeperfly/pipeline/plan.py
prepare ¶
prepare(
cfg: RunConfig, project: Project, points: Sequence[str]
) -> tuple[Calibration | None, Facts]
Check a config against a project and resolve what the run starts from.
check_project against the
project's views, animals and points, then the initial calibration when the run
reads one (uses_rig); a pose2d-only run of one
animal reads and stores none, whatever [calibration] says.
Raises:
| Type | Description |
|---|---|
ConfigError
|
If the config does not fit the project. |
ValueError
|
If the run needs camera parameters and |
OSError
|
If a calibration file cannot be read. |
Source code in src/deeperfly/pipeline/plan.py
resolve_projects ¶
resolve_projects(
paths: Sequence[str | Path],
*,
create: bool = True,
log: Callable[[str], None] = print,
) -> list[tuple[str, Project]]
The project each path stands for, named as the invocation names them.
One rule for every path (ADR-0081): a project is used as is; else
<path>/deeperfly/ if that is one; else a directory of video files gets the
default project there (default), written and
logged with create, and without it only built in memory. Every path is
checked, its default project built and the names worked out
(project_names), before anything is written.
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If a path does not exist. |
ValueError
|
If a path is neither a project nor a directory of videos it can make the default project of, or two paths stand for one project. |
Source code in src/deeperfly/pipeline/plan.py
run_name ¶
What a run is called: --name, else the config's name, else the time.
The default is %y%m%d_%H%M%S at now (default: the call), taken once per
invocation and shared by every project of it; the run claims it, or -2, -3
when another invocation holds it
(claim_run_name; ADR-0082).
Raises:
| Type | Description |
|---|---|
ConfigError
|
If |
Source code in src/deeperfly/pipeline/plan.py
run_paths ¶
run_paths(
project: Project | Path,
name: str,
out: Path | None = None,
*,
label: str | None = None,
) -> RunPaths
A run's files: results/<name>.{h5,toml} and renders/<name>/ (ADR-0082).
They go in the project folder (a Project, or the folder one would be created
in); with out, in <out>/<label>/ instead, as <name>.{h5,toml} and
renders/<name>/, the label being the project's name on its own unless given
(project_names).
Source code in src/deeperfly/pipeline/plan.py
select_stages ¶
select_stages(
cfg: RunConfig,
only: tuple[str, ...] = (),
skip: tuple[str, ...] = (),
) -> list[str]
The stages to execute: the enabled ones, narrowed by --only and --skip.
Narrowing does not re-validate: --only render renders from results a previous
run wrote, so the references it checks are still the whole config's.
Raises:
| Type | Description |
|---|---|
ConfigError
|
If a name is not a stage, or is not enabled here. |
Source code in src/deeperfly/pipeline/plan.py
uses_rig ¶
Whether a run reads camera parameters: a geometry stage, or the tracker.
The driver: a run over projects, stage by stage, over a frame set.
A run is one results file per project, results/<name>.h5 with its config copied to
results/<name>.toml in the project folder (ADR-0082). Each path is resolved to a
project, a directory of videos getting the default one (ADR-0081). For each project
the driver checks the config against it, resolves the camera parameters the run
starts from (ADR-0086), opens its recording, works out the frames asked for, continues
the run of that name when its config is the same apart from name and frames
(another is refused unless force), decides from each stage's coverage and
fingerprint which frames it computes
(coverage_plan), and walks the selected
stages in order. Recomputing frames clears the coverage of every stage that reads
them, so a later invocation recomputes those too; a stage whose fingerprint moved is
dropped when it begins (ADR-0035). A cached [bundle_adjustment] still hands its rig
to the stages after it. A project is the unit of failure (ADR-0037): one that fails
is reported and the run moves on.
ProjectOutcome
dataclass
¶
What happened for one project.
Attributes:
| Name | Type | Description |
|---|---|---|
project |
str
|
Its name in the invocation (project_names). |
results |
Path
|
Its run's results file. |
ran |
tuple[str, ...]
|
The stages that computed frames. |
cached |
tuple[str, ...]
|
The stages with nothing to compute: the frames asked for were covered, under a matching fingerprint. |
error |
str | None
|
The message of the failure that stopped it, or |
Source code in src/deeperfly/pipeline/run.py
RunSummary
dataclass
¶
The whole invocation's outcome.
Attributes:
| Name | Type | Description |
|---|---|---|
out |
Path | None
|
The |
stages |
tuple[str, ...]
|
The stages selected for this run. |
outcomes |
tuple[ProjectOutcome, ...]
|
One entry per project, in run order. |
name |
str
|
The run's name, shared by every project. |
Source code in src/deeperfly/pipeline/run.py
run_projects ¶
run_projects(
cfg: RunConfig,
paths: Sequence[str | Path],
*,
only: Sequence[str] = (),
skip: Sequence[str] = (),
out: Path | None = None,
force: bool = False,
name: str | None = None,
frames: Sequence[int | str] | None = None,
log: Callable[[str], None] = print,
observer: RunObserver | None = None,
) -> RunSummary
Apply a run config to the projects some paths stand for, and say what happened.
Each path is resolved as every command resolves one, a directory of videos
getting the default project
(resolve_projects). The run's name is
name, else the config's, else the time of this call, shared by every project
(run_name) and claimed in each, with -2,
-3 when another invocation holds it
(claim_run_name). frames stands
in for the config's frames; out puts each project's files in
<out>/<project name>/ (run_paths). force
recomputes every frame asked for of every selected stage and lets another config
take over a run of this name, dropping the stages whose fingerprint moved. A
project that fails carries its message in the summary instead of raising.
observer is told each step as it happens
(RunObserver).
Raises:
| Type | Description |
|---|---|
ConfigError
|
If the stage selection or the name fails, which is the invocation being wrong. |
(FileNotFoundError, ValueError)
|
If a path stands for no project, or two paths for one; nothing has run then. |
Source code in src/deeperfly/pipeline/run.py
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 | |
One function per run stage: read what is upstream, compute, write the arrays.
Each stage takes a Context (the run config, the
project's recording and skeleton, its results file, the geometry in force and the frames
the coverage plan hands it), reads its inputs at those frames by the references the
schema declares and writes its group's arrays there; the driver owns the order, the
coverage plan and the logging. A temporal stage (smoothing, correction, IK) runs once
per stretch of its frames and writes each as it completes, so a stretch sees no frame
outside it (ADR-0082); an array without T is rewritten by every stretch, the last
one winning.
Context
dataclass
¶
What every stage is handed: the run config, the recording, and where to write.
Attributes:
| Name | Type | Description |
|---|---|---|
cfg |
RunConfig
|
The typed run config. |
recording |
Recording
|
The project's recording: its videos and frame count. |
skeleton |
Skeleton
|
The project's skeleton, the |
results |
Results
|
Its open results file. |
rig |
Rig | None
|
The geometry in force, the |
facts |
Facts
|
What the fingerprints hash besides the tables. |
layout |
Layout
|
Which views each video carries (the project's). |
labels |
Callable[[], Labels] | None
|
Loads the project's hand labels, raising a |
detector |
DetectorCache | None
|
The shared detector handle, or |
log |
Callable[[str], None]
|
Where progress lines go. |
todo |
Mapping[str, ndarray]
|
Per stage, the frames it computes in this invocation (the coverage plan, coverage_plan); a stage absent here computes every frame. |
renders |
Path | None
|
The folder |
force |
bool
|
Whether the invocation recomputes what it could reuse, such as the static crop an earlier invocation found. |
observer |
RunObserver | None
|
Who watches the run, handed each detector pass; |
Source code in src/deeperfly/pipeline/stages.py
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 | |
frame_size ¶
The (height, width) a view's pixels live in: its video's frame.
frames ¶
The frames stage computes here, increasing absolute indices.
need_rig ¶
The geometry in force, for a stage that reads it.
Raises:
| Type | Description |
|---|---|
StageError
|
If the run reads no camera parameters, which prepare rules out for every stage that needs them. |
Source code in src/deeperfly/pipeline/stages.py
points ¶
The keypoint indices a point selector claims, in skeleton order.
Source code in src/deeperfly/pipeline/stages.py
read ¶
Resolve a data reference: a stored stage array, or the hand labels.
With frames, only those frames, which the stage that wrote the array must
cover; without, the whole array.
Raises:
| Type | Description |
|---|---|
StageError
|
If no stage has written the array (one left out with |
Source code in src/deeperfly/pipeline/stages.py
read_animal ¶
read, with the animal axis peeled off: one animal's copy of an array.
An array about the recording rather than an animal, and the hand labels, come back whole.
Source code in src/deeperfly/pipeline/stages.py
DetectorCache
dataclass
¶
The run's nets, loaded once, shared by every project; torch on first use.
Source code in src/deeperfly/pipeline/stages.py
loaded_device
property
¶
The device the nets were loaded on, or None before the first get.
get ¶
(models, device) for predict_recording, loading on first call.
Source code in src/deeperfly/pipeline/stages.py
get_locator ¶
The run's full-frame locator, loaded once; None when it names none.
Source code in src/deeperfly/pipeline/stages.py
StageError ¶
predict_options ¶
predict_options(
cfg: RunConfig,
skeleton: Skeleton,
animals: int,
*,
batch: int | None = None,
) -> PredictOptions
The config's [pose2d] knobs as the one record pose2d.predict reads.
animals is the project's; batch stands in for [compute] batch, and each
frame runs once per animal.
Source code in src/deeperfly/pipeline/stages.py
resolved_video ¶
One video's settings with [render]'s defaults filled in, layers as records.
The per-video overrides let one video render 20 frames while the others keep every frame.
Source code in src/deeperfly/pipeline/stages.py
run_ball ¶
[ball]: track the treadmill ball -> ball/*, in the world frame.
The ball's radius is fitted once to its outline in the [ball] outline views, on
frames spread over the opening contact_frames the 3D covers, starting from a
guess from the leg tips that rest on it, which also orient the animal on it. Each
stretch then has its center filtered and smoothed over every frame from the
outlines, and its rotation tracked by spintrack in [ball] view from where the
outline puts the ball at its start; rotation restarts at zero with every
stretch, and a frame standing alone is refused (ADR-0144).
Source code in src/deeperfly/pipeline/stages.py
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 | |
run_bundle_adjustment ¶
[bundle_adjustment]: refine the run's calibration on its own 2D.
The sampled detector points or hand labels are fitted from the rig in force, which
the solved rig replaces for the stages after it and is stored as
bundle_adjustment/views. Animal 0 only: the rig is the project's, not an
animal's.
Source code in src/deeperfly/pipeline/stages.py
run_correction ¶
[correction]: hold the static points still, then symmetrize -> points.
In that order: with one plane per stretch the symmetrization is affine, so a point already made static stays static through it. One stretch at a time, each with its own static positions and plane.
Source code in src/deeperfly/pipeline/stages.py
run_ik ¶
[ik]: fit the body model to the 3D -> angles, points, the chain fit.
points is the fitted joints in the skeleton's point order, so it reprojects like
any 3D track; chain_scale and chain_offset size and place the head and abdomen
(ADR-0066), which lets a mesh layer draw the fit rather than the model. One
stretch at a time, the last fitted one's chains kept; a stretch no animal has any
3D in is written as NaN once another has given the arrays their shape.
Source code in src/deeperfly/pipeline/stages.py
run_pose2d ¶
[pose2d]: the detector over the run's frames -> pose2d/points, conf, ...
One write per stretch of the frames the coverage plan hands it (ADR-0082), each
covering what it wrote as it completes, so a pass that fails keeps the stretches
it finished; a tracker reading a locator writes a long stretch in parts as it
goes, the tracker carrying on across them (ADR-0139). The static crop comes from the
config, else from the frames this run already covers, else is discovered on the
frames asked for (always, with --force;
pose2d.predict); an ensemble collapses inside the
forward pass. Every array leads with the animal, and a per-frame window above one
animal also writes the tracker's centers, track_flags and center_candidates.
crops holds what each animal ran through, per view and frame. Only the tracker
reads the rig.
Source code in src/deeperfly/pipeline/stages.py
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 | |
run_pose3d ¶
[pose3d]: lift the 2D to one 3D per keypoint -> points, reproj_error.
inliers are the views each point's consensus kept and support their summed
vote (consensus_support), what
tells a point to trust from one to doubt (ADR-0132). A point whose kept views all
look along one line, such as a ventral and a dorsal view alone, is NaN with its
inliers kept: those views fix it across the line and nowhere along it
(placed_in_depth, ADR-0135).
"pictorial" and "election" read the candidate sets and also write
selected/points and selected/conf, the candidate each view settled on, which
their reproj_error is against (pictorial). A veto
keeps its views out of every triangulation. One animal at a time.
Source code in src/deeperfly/pipeline/stages.py
run_render ¶
[render]: each [render.outputs.<name>] to renders/<run>/<name>.mp4.
A video cannot be patched, so every output is drawn anew over the frames asked for that its range keeps (render_video), and the stage's group, which holds no array, then covers exactly the frames asked for: a rerun asking for no more, with nothing upstream recomputed, skips the encode.
Source code in src/deeperfly/pipeline/stages.py
run_smoothing ¶
[smoothing]: the geometric EKS over the 2D -> points, var, smooth_param.
The smoother observes the 2D through the rig (ADR-0062): the decode, or what the
pictorial method re-selected; [pose3d] only initializes it. Where several
animals share the frame it observes the views [pose3d]'s consensus kept and no
others: a view that left the consensus there mostly saw the other animal
(ADR-0133). One animal at a time, which keeps the animal axis off the smoother's
own ensemble axis. One stretch at a time, smooth_param fitted on each and the
last one's kept.
Source code in src/deeperfly/pipeline/stages.py
stack_animals ¶
synthetic_views ¶
[render.views] as the renderer's own records.