Skip to content

Commit

Permalink
Add support for embedding images in .pkg.slp (#91)
Browse files Browse the repository at this point in the history
* Add serialization to dict at the video object level

* Store and retrieve video backend metadata

* Try to restore source video when available

* Rename symbol

* Use backend metadata when available when serializing

* Fix backend metadata factory

* Re-embed videos when saving labels with embedded videos

* Fix serialization and logic for checking for embedded images

* Fix multi-frame decoding

* Fix docstring order

* Add method to embed a list of frames and update the objects

* Fix order of operations

* Add embed_videos

* Fix mid-level embedding function

* Hash videos by ID

* Add property to return embedded frame indices

* Hash LabeledFrame by ID and add convenience checks for instance types

* Labels.user_labeled_frames

* Fix JABS

* Tests

* Add live coverage support

* Expose high level embedding

* Separate replace video and support restoring source

* Lint

* Add Video(filename) syntactic sugar

* Coverage

* Windows test fix

* Windows test fix again

* Fix test
  • Loading branch information
talmo authored Jun 5, 2024
1 parent 4af9f38 commit f6f939b
Show file tree
Hide file tree
Showing 15 changed files with 700 additions and 139 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ coverage.xml
*.py,cover
.hypothesis/
.pytest_cache/
lcov.info

# Translations
*.mo
Expand Down
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ We check for coverage by parsing the outputs from `pytest` and uploading to [Cod
All changes should aim to increase or maintain test coverage.
### Live coverage
*The following steps are based on [this guide](https://jasonstitt.com/perfect-python-live-test-coverage).*
1. If you already have an environment installed, `pip install -e ."[dev]"` to make sure you have the latest dev tools (namely `pytest-watch`).
2. Install the [Coverage Gutters extension](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters) in VS Code.
3. Open a terminal, `conda activate sleap-io` and then run `ptw` to automatically run tests. This will generate a new `lcov.info` file when it's done.
4. Enable the coverage gutters by using **Ctrl/Cmd**+**Shift**+**P**, then **Coverage Gutters: Display Coverage**.
### Code style
To standardize formatting conventions, we use [`black`](https://black.readthedocs.io/en/stable/).
Expand Down
24 changes: 15 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ name = "sleap-io"
authors = [
{name = "Liezl Maree", email = "[email protected]"},
{name = "David Samy", email = "[email protected]"},
{name = "Talmo Pereira", email = "[email protected]"}
]
{name = "Talmo Pereira", email = "[email protected]"}]
description="Standalone utilities for working with pose data from SLEAP and other tools."
requires-python = ">=3.7"
keywords = ["sleap", "pose tracking", "pose estimation", "behavior"]
Expand All @@ -19,8 +18,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12"
]
"Programming Language :: Python :: 3.12"]
dependencies = [
"numpy",
"attrs",
Expand All @@ -31,8 +29,7 @@ dependencies = [
"simplejson",
"imageio",
"imageio-ffmpeg",
"av"
]
"av"]
dynamic = ["version", "readme"]

[tool.setuptools.dynamic]
Expand All @@ -43,6 +40,7 @@ readme = {file = ["README.md"], content-type="text/markdown"}
dev = [
"pytest",
"pytest-cov",
"pytest-watch",
"black",
"pydocstyle",
"toml",
Expand All @@ -52,16 +50,24 @@ dev = [
"mkdocs-jupyter",
"mkdocstrings[python]>=0.18",
"mkdocs-gen-files",
"mkdocs-literate-nav"
]
"mkdocs-literate-nav"]

[project.urls]
Homepage = "https://sleap.ai"
Homepage = "https://io.sleap.ai"
Repository = "https://github.com/talmolab/sleap-io"

[tool.setuptools.packages.find]
exclude = ["site"]

[tool.black]
line-length = 88

[pydocstyle]
convention = "google"
match-dir = "sleap_io"

[tool.coverage.run]
source = ["livecov"]

[tool.pytest.ini_options]
addopts = "--cov sleap_io --cov-report=lcov:lcov.info --cov-report=term"
3 changes: 2 additions & 1 deletion sleap_io/io/jabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def read_labels(
frames: List[LabeledFrame] = []
# Video name is the pose file minus the suffix
video_name = re.sub(r"(_pose_est_v[2-6])?\.h5", ".avi", labels_path)
video = Video.from_filename(video_name)
if not skeleton:
skeleton = JABS_DEFAULT_SKELETON
tracks = {}
Expand Down Expand Up @@ -166,7 +167,7 @@ def read_labels(
)
if new_instance:
instances.append(new_instance)
frame_label = LabeledFrame(Video(video_name), frame_idx, instances)
frame_label = LabeledFrame(video, frame_idx, instances)
frames.append(frame_label)
return Labels(frames)

Expand Down
10 changes: 8 additions & 2 deletions sleap_io/io/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ def load_slp(filename: str) -> Labels:
return slp.read_labels(filename)


def save_slp(labels: Labels, filename: str):
def save_slp(
labels: Labels, filename: str, embed: str | list[tuple[Video, int]] | None = None
):
"""Save a SLEAP dataset to a `.slp` file.
Args:
labels: A SLEAP `Labels` object (see `load_slp`).
filename: Path to save labels to ending with `.slp`.
embed: One of `"user"`, `"suggestions"`, `"user+suggestions"`, `"source"` or
list of tuples of `(video, frame_idx)` specifying the frames to embed. If
`"source"` is specified, no images will be embedded and the source video
will be restored if available.
"""
return slp.write_labels(filename, labels)
return slp.write_labels(filename, labels, embed=embed)


def load_nwb(filename: str) -> Labels:
Expand Down
Loading

0 comments on commit f6f939b

Please sign in to comment.