The layout: which views each video carries, and which of them are mirrored.
A rig that folds several views into one frame (hexaview's two videos, each seeing the
arena directly and twice through prisms) needs this one fact, apart from the
geometry: it is fixed until the rig is rebuilt, where geometry is solved per
project, and labeling and training crops need mirrored before any calibration
exists. An empty layout is the 1:1 case, every view reading the video of its name.
layout = Layout({"cam": ["front", "back", "left"]}, mirrored=["left"])
layout.video_of("left") # "cam"
Layout
dataclass
Which views each video carries, and which of them are mirrored.
Attributes:
| Name |
Type |
Description |
views_by_video |
Mapping[str, Sequence[str]]
|
video name -> the views it carries, in order; empty for a
1:1 rig.
|
mirrored |
Sequence[str]
|
The views the apparatus reflects, in the order given.
|
Source code in src/deeperfly/layout.py
| @dataclass(frozen=True)
class Layout:
"""Which views each video carries, and which of them are mirrored.
Attributes:
views_by_video: `video name -> the views it carries`, in order; empty for a
1:1 rig.
mirrored: The views the apparatus reflects, in the order given.
"""
views_by_video: Mapping[str, Sequence[str]] = field(default_factory=dict)
mirrored: Sequence[str] = ()
def __post_init__(self) -> None:
"""Store both fields as tuples and refuse an inconsistent layout.
Raises:
ValueError: If a view is carried by two videos, or a mirrored name is not
a view this layout knows.
"""
by_video = {v: tuple(views) for v, views in self.views_by_video.items()}
object.__setattr__(self, "views_by_video", by_video)
object.__setattr__(self, "mirrored", tuple(dict.fromkeys(self.mirrored)))
carrier: dict[str, str] = {}
for video, views in by_video.items():
for view in views:
if view in carrier:
raise ValueError(
f"view {view!r} is carried by both "
f"{carrier[view]!r} and {video!r}"
)
carrier[view] = video
unknown = [v for v in self.mirrored if carrier and v not in carrier]
if unknown:
raise ValueError(
"mirrored names no view of this layout: " + ", ".join(unknown)
)
def video_of(self, view: str) -> str:
"""The video a view's frames come from; the view's own name in a 1:1 rig."""
return next((v for v, ws in self.views_by_video.items() if view in ws), view)
def videos_of(self, views: Iterable[str]) -> list[str]:
"""The videos some views read, each once, in the order the views first need."""
return list(dict.fromkeys(self.video_of(v) for v in views))
def views_in(self, video: str) -> list[str]:
"""The views a video carries, in order; just the video in a 1:1 rig."""
return list(self.views_by_video.get(video, (video,)))
def is_mirrored(self, view: str) -> bool:
"""Whether the apparatus reflects this view (a prism view)."""
return view in self.mirrored
def frame_sizes(
self, views: Iterable[str], videos: Mapping[str, Video]
) -> dict[str, tuple[int, int]]:
"""Each view's frame `(height, width)`: that of the video it reads."""
return {view: videos[self.video_of(view)].size for view in views}
|
__post_init__
Store both fields as tuples and refuse an inconsistent layout.
Raises:
| Type |
Description |
ValueError
|
If a view is carried by two videos, or a mirrored name is not
a view this layout knows.
|
Source code in src/deeperfly/layout.py
| def __post_init__(self) -> None:
"""Store both fields as tuples and refuse an inconsistent layout.
Raises:
ValueError: If a view is carried by two videos, or a mirrored name is not
a view this layout knows.
"""
by_video = {v: tuple(views) for v, views in self.views_by_video.items()}
object.__setattr__(self, "views_by_video", by_video)
object.__setattr__(self, "mirrored", tuple(dict.fromkeys(self.mirrored)))
carrier: dict[str, str] = {}
for video, views in by_video.items():
for view in views:
if view in carrier:
raise ValueError(
f"view {view!r} is carried by both "
f"{carrier[view]!r} and {video!r}"
)
carrier[view] = video
unknown = [v for v in self.mirrored if carrier and v not in carrier]
if unknown:
raise ValueError(
"mirrored names no view of this layout: " + ", ".join(unknown)
)
|
frame_sizes
frame_sizes(
views: Iterable[str], videos: Mapping[str, Video]
) -> dict[str, tuple[int, int]]
Each view's frame (height, width): that of the video it reads.
Source code in src/deeperfly/layout.py
| def frame_sizes(
self, views: Iterable[str], videos: Mapping[str, Video]
) -> dict[str, tuple[int, int]]:
"""Each view's frame `(height, width)`: that of the video it reads."""
return {view: videos[self.video_of(view)].size for view in views}
|
is_mirrored
is_mirrored(view: str) -> bool
Whether the apparatus reflects this view (a prism view).
Source code in src/deeperfly/layout.py
| def is_mirrored(self, view: str) -> bool:
"""Whether the apparatus reflects this view (a prism view)."""
return view in self.mirrored
|
video_of
video_of(view: str) -> str
The video a view's frames come from; the view's own name in a 1:1 rig.
Source code in src/deeperfly/layout.py
| def video_of(self, view: str) -> str:
"""The video a view's frames come from; the view's own name in a 1:1 rig."""
return next((v for v, ws in self.views_by_video.items() if view in ws), view)
|
videos_of
videos_of(views: Iterable[str]) -> list[str]
The videos some views read, each once, in the order the views first need.
Source code in src/deeperfly/layout.py
| def videos_of(self, views: Iterable[str]) -> list[str]:
"""The videos some views read, each once, in the order the views first need."""
return list(dict.fromkeys(self.video_of(v) for v in views))
|
views_in
views_in(video: str) -> list[str]
The views a video carries, in order; just the video in a 1:1 rig.
Source code in src/deeperfly/layout.py
| def views_in(self, video: str) -> list[str]:
"""The views a video carries, in order; just the video in a 1:1 rig."""
return list(self.views_by_video.get(video, (video,)))
|