Changelog¶
v0.2.0¶
What's Changed
- Update backend filename when backend isn't created on replace by @talmo in #127
- Update labels videos list on replace by @talmo in #128
- Add video writing by @talmo in #129
- Add
sio.VideoWriter
: basicimageio-ffmpeg
video writer with sensible H264 presets. This can be used as a context manager:with sio.VideoWriter("video.mp4") as vw: for frame in video: vw(frame)
- Add
sio.save_video
: high-level video writing. This can be used to quickly write a set of frames or even a wholeVideo
for easy (if inefficient) re-encoding:bad_video = sio.load_video("unseekable.avi") sio.save_video(bad_video, "seekable.mp4")
- Added
IndexError
inVideoBackend
to enable sequence protocol for iteration overVideo
s:for frame in video: pass
- Refactored
sio.io.video
tosio.io.video_reading
.
- Add
- Fixes to get JABS export to work with new data by @talmo in #132
- Make skeleton nodes mutable by @talmo in #135
- Add skeleton manipulation utilities by @talmo in #136
Skeleton
__contains__(node: NodeOrIndex)
: ReturnsTrue
if a node exists in the skeleton.rebuild_cache()
: Method allowing explicit regeneration of the caching attributes from the nodes.- Caching attributes are now named
_name_to_node_cache
and_node_to_ind_cache
, better reflecting the mapping directionality. require_node(node: NodeOrIndex, add_missing: bool = True)
: Returns aNode
given aNode
,int
orstr
. Ifadd_missing
isTrue
, the node is added or created, otherwise anIndexError
is raised. This is helpful for flexibly converting between node representations with convenient existence handling.add_nodes(list[Node | str])
: Convenience method to add a list of nodes.add_edges(edges: list[Edge | tuple[NodeOrIndex, NodeOrIndex]])
: Convenience method to add a list of edges.rename_nodes(name_map: dict[NodeOrIndex, str] | list[str])
: Method to rename nodes either by specifying a potentially partial mapping from node(s) to new name(s), or a list of new names. Handles updating both theNode.name
attributes and the cache.rename_node(old_name: NodeOrIndex, new_name: str)
: Shorter syntax for renaming a single node.remove_nodes(nodes: list[NodeOrIndex])
: Method for removing nodes from the skeleton and updating caches. Does NOT update corresponding instances.remove_node(node: NodeOrIndex)
: Shorter syntax for removing a single node.reorder_nodes(new_order: list[NodeOrIndex])
: Method for setting the order of the nodes within the skeleton with cache updating. Does NOT update corresponding instances.
Instance
/PredictedInstance
update_skeleton()
: Updates thepoints
attribute on the instance to reflect changes in the associated skeleton (removed nodes and reordering). This is called internally after updating the skeleton from theLabels
level, but also exposed for more complex data manipulation workflows.replace_skeleton(new_skeleton: Skeleton, node_map: dict[NodeOrIndex, NodeOrIndex] | None = None, rev_node_map: dict[NodeOrIndex, NodeOrIndex] | None = None)
: Method to replace the skeleton on the instance with optional capability to specify a node mapping so that data stored in thepoints
attribute is retained and associated with the right nodes in the new skeleton. Mapping is specified innode_map
from old to new nodes and defaults to mapping between node objects with the same name.rev_node_map
maps new nodes to old nodes and is used internally when calling from theLabels
level as it bypasses validation.
Labels
instances
: Convenience property that returns a generator that loops over all labeled frames and returns all instances. This can be lazily iterated over without having to construct a huge list of all the instances.rename_nodes(name_map: dict[NodeOrIndex, str] | list[str], skeleton: Skeleton | None = None)
: Method to rename nodes in a specified skeleton within the labels.remove_nodes(nodes: list[NodeOrIndex], skeleton: Skeleton | None = None)
: Method to remove nodes in a specified skeleton within the labels. This also updates all instances associated with the skeleton, removing point data for the removed nodes.reorder_nodes(new_order: list[NodeOrIndex], skeleton: Skeleton | None = None)
: Method to reorder nodes in a specified skeleton within the labels. This also updates all instances associated with the skeleton, reordering point data for the nodes.replace_skeleton(new_skeleton: Skeleton, old_skeleton: Skeleton | None = None, node_map: dict[NodeOrIndex, NodeOrIndex] | None = None)
: Method to replace a skeleton entirely within the labels, updating all instances associated with the old skeleton to use the new skeleton, optionally with node remapping to retain previous point data.
- Add more checks for video seeking/reading failure by @talmo in #138
- Fix
HDF5Video
edge cases by @talmo in #137 - Docs changelog generation by @talmo in #130
- Add
Labels.extract
,Labels.trim
andVideo.save
by @talmo in #140LabeledFrame.frame_idx
: Now always converted toint
type.Video.close()
: Now caches backend metadata toVideo.backend_metadata
to persist metadata on close.copy.deepcopy()
now works onVideo
objects even if backend is open.Video.save(save_path: str | Path, frame_inds: list[int] | np.ndarray | None = None, video_kwargs: dict[str, Any] | None = None)
: Method to save a video file to an MP4 usingVideoWriter
with an optional subset of frames.Labels.extract(inds: list[int] | list[tuple[Video, int]] | np.ndarray, copy: bool = True)
: Add method to extract a subset of frames from the labels, optionally making a copy, and return a newLabels
object.Labels.trim(save_path: str | Path, frame_inds: list[int] | np.ndarray, video: Video | int | None = None, video_kwargs: dict[str, Any] | None = None)
: Add method to extract a subset of the labels, write a video clip with the extracted friends, and adjust frame indices to match the clip.
- Docs automation by @talmo in #141
- Add more examples to docs by @talmo in #142
Full Changelog: v0.1.10...v0.2.0
v0.1.10¶
What's Changed
- Fix embedded video lookup by @talmo in #122
- Add better support for exporting and loading RGB videos from .pkg.slp files by @talmo in #125
- Fix video indexing when embedding from labels that already have embedded data by @talmo in #126
Full Changelog: v0.1.9...v0.1.10
v0.1.9¶
What's Changed
- Dependency management by @talmo in #118
- Drop
av
as a dependency since it's still a little buggy and doesn't have broad enough platform compatibility. - Pin
ndx-pose
< 0.2.0 until #104 is merged in. - Remove livecov dev tool as it was interfering with VSCode debugging.
- Drop
- Safer video loading from SLP by @talmo in #119
- Added
sio.io.utils.is_file_accessible
to check for readability by actually reading a byte. This catches permission and other esoteric filesystem errors (addresses #116). - Explicit control over whether video files should be opened when loading labels with:
sio.load_slp(..., open_videos=False)
- Explicit control over whether backend is auto-initialized when creating or using
Video
objects withVideo(..., open_backend=False)
. - More sanitization of filenames to posix/forward-slash safe forms when reading and writing SLP files.
- Added
- Fix split calculation and allow for not embedding by @talmo in #120
- Fix: The function now correctly splits the labels into training, validation, and test sets based on the specified proportions (fixes #117). Previously, the validation fraction was being computed incorrectly in cases where its relative fraction was
1.0
after taking out the train split. - Enhancement:
Labels.make_training_splits(..., embed=False)
. Previously, the function would always embed the images, which could be slow for large projects. With this change, theembed
parameter is introduced, allowing the user to choose whether to embed the images or save the labels with references to the source video files.
- Fix: The function now correctly splits the labels into training, validation, and test sets based on the specified proportions (fixes #117). Previously, the validation fraction was being computed incorrectly in cases where its relative fraction was
Full Changelog: v0.1.8...v0.1.9
v0.1.8¶
What's Changed
New Contributors
Full Changelog: v0.1.7...v0.1.8
v0.1.7¶
What's Changed
Full Changelog: v0.1.6...v0.1.7
v0.1.6¶
What's Changed
Full Changelog: v0.1.5...v0.1.6
v0.1.5¶
What's Changed
Full Changelog: v0.1.4...v0.1.5
v0.1.4¶
What's Changed
- Add support for embedding images in .pkg.slp by @talmo in #91
- Saving SLP files with embedded images will re-save the embedded images.
- Embed images into SLP files with:
labels.save("labels.pkg.slp", embed="user")
to embed frames with user-labeled instances (Instance
)labels.save("labels.pkg.slp", embed="user+suggestion")
to embed frames with user-labeled instances and suggestion frames (useful for inference after training)labels.save("labels.pkg.slp", embed="source")
to restore the source video ("unembed")
- Better reprs and QOL by @talmo in #96
- Better
__repr__
s forSkeleton
,LabeledFrame
,Labels
,Instance
,PredictedInstance
Labels.append()
andLabels.extend()
to addLabeledFrame
s now will updateLabels.tracks
,Labels.skeletons
andLabels.videos
with contents.Labels.update()
to manually updateLabels.tracks
,Labels.skeletons
andLabels.videos
with contents ofLabels.labeled_frames
andLabels.suggestions
.Labels.replace_filenames()
: multiple methods for replacing all video filenames across the project (#85).Skeleton.edge_names
to return list of edges as tuples of string names- Added docstrings to
sio.load_video
and related high levelVideo
APIs to clarify supported file formats. - Syntactic sugar: try to initialize video backend with
Video(filename)
construction (#94)
- Better
Note: This is a re-release of v0.1.3 which had a borked deployment.
Full Changelog: v0.1.2...v0.1.4
v0.1.3¶
What's Changed
- Add support for embedding images in .pkg.slp by @talmo in #91
- Saving SLP files with embedded images will re-save the embedded images.
- Embed images into SLP files with:
labels.save("labels.pkg.slp", embed="user")
to embed frames with user-labeled instances (Instance
)labels.save("labels.pkg.slp", embed="user+suggestion")
to embed frames with user-labeled instances and suggestion frames (useful for inference after training)labels.save("labels.pkg.slp", embed="source")
to restore the source video ("unembed")
- Better reprs and QOL by @talmo in #96
- Better
__repr__
s forSkeleton
,LabeledFrame
,Labels
,Instance
,PredictedInstance
Labels.append()
andLabels.extend()
to addLabeledFrame
s now will updateLabels.tracks
,Labels.skeletons
andLabels.videos
with contents.Labels.update()
to manually updateLabels.tracks
,Labels.skeletons
andLabels.videos
with contents ofLabels.labeled_frames
andLabels.suggestions
.Labels.replace_filenames()
: multiple methods for replacing all video filenames across the project (#85).Skeleton.edge_names
to return list of edges as tuples of string names- Added docstrings to
sio.load_video
and related high levelVideo
APIs to clarify supported file formats. - Syntactic sugar: try to initialize video backend with
Video(filename)
construction (#94)
- Better
Full Changelog: v0.1.2...v0.1.3
v0.1.2¶
What's Changed
Full Changelog: v0.1.1...v0.1.2
v0.1.1¶
What's Changed
- Create docs pages by @talmo in #87
- Add
ImageVideo
backend by @talmo in #88 - Add
SuggestionFrame
by @talmo in #89 - Implement
ImageVideo
support in SLP by @talmo in #90 - Bump to v0.1.1 by @talmo in #93
Full Changelog: v0.1.0...v0.1.1
v0.1.0¶
What's Changed
-
Add skeleton utilities by @talmo in #76
Skeleton.add_node
: Add a node by name or object.Skeleton.add_edge
: Add an edge by lists of names or objects.Skeleton.add_symmetry
: Add a symmetry edge by lists of names or objects.
-
Update CI and versions by @talmo in #77
- Update dependency ranges (see below)
- Update action workflow versions
- Enable M1 mac runners
- Expand python version range to 3.7-3.12
- Note: Python 3.7 is no longer tested in CI due to lack of conda-forge compatability.
- Enable pure conda-forge dependency setup
-
Fix multi-skeleton loading by @talmo in #79
- Fixes #71.
-
Add high level APIs by @talmo in #80
- Add
load_video
andload_file
high level APIs (#48)
- Add
-
Labels QOL enhancements by @talmo in #81
LabeledFrame.remove_predictions
: Remove predicted instances from a labeled frame.LabeledFrame.remove_empty_instances
: Remove instances with no visible points from a labeled frame.Labels.save
: Instance-level convenience wrapper forsio.save_file
.Labels.clean
: Remove unused or empty frames, instances, videos, skeletons and tracks.Labels.remove_predictions
: Remove predicted instances from all labeled frames (#69).Labels.__getitem__
: Now supports lists, slices, numpy arrays, tuples of(Video, frame_idx)
andVideo
.
-
Video QOL enhancements by @talmo in #82
Video.is_open
: Checks if the video exists and the backend is set.Video.open
: Opens or restarts the backend for reading.Video.close
: Closes the backend for reading.Video.exists
: Check if the filename for the video exists.Video.replace_filename
: Replace the filename and restart the backend.
Notes on dependency pins
ffmpeg < 6.1
due to imageio/imageio-ffmpeg#99h5py >= 3.8.0
due to h5py/h5py#2118python >= 3.8
due toh5py >= 3.8.0
(we still supportpython==3.7
via pip but this is not longer in CI)
Full Changelog: v0.0.14...v0.1.0
v0.0.14¶
What's Changed
Full Changelog: v0.0.13...v0.0.14
v0.0.13¶
What's Changed
Full Changelog: v0.0.12...v0.0.13
v0.0.12¶
What's Changed
- Add support for the Kumar Lab's JABS format by @SkepticRaven in #63
- Fix multi-video serialization in SLP by @talmo in #72
New Contributors
- @SkepticRaven made their first contribution in #63
Full Changelog: v0.0.11...v0.0.12
v0.0.11¶
What's Changed
Full Changelog: v0.0.10...v0.0.11
v0.0.10¶
This is a hotfix to get around installing in older environments with numpy <1.20.
What's Changed
Full Changelog: v0.0.9...v0.0.10
v0.0.9¶
What's Changed
- Fix serialization for negative anchors metadata field in SLP files by @talmo in #59
- Fix edge unpacking by @talmo in #60
- Bump to v0.0.9 and update usage docs by @talmo in #61
Full Changelog: v0.0.8...v0.0.9
v0.0.8¶
What's Changed
- Fix docstring for LabeledFrame.predicted_instances by @talmo in #43
- Parse skeleton symmetries from SLP files by @talmo in #53
- Add Labels.skeleton convenience attribute by @talmo in #54
- Write SLP files by @talmo in #55
- Create video backend automatically if filename exists. by @talmo in #56
Full Changelog: v0.0.7...v0.0.8
v0.0.7¶
What's Changed
- Pin imageio version by @talmo in #39
- Fix detection of embedded images when loading SLP files by @talmo in #40
Full Changelog: v0.0.6...v0.0.7
v0.0.6¶
What's Changed
Full Changelog: v0.0.5...v0.0.6
v0.0.5¶
What's Changed
Full Changelog: v0.0.4...v0.0.5
v0.0.4¶
What's Changed
- Fix build by including readme correctly in pyproject.toml by @talmo in #34
- Add Labels.find and Labels.video by @talmo in #35
Full Changelog: v0.0.3...v0.0.4
v0.0.3¶
What's Changed
- Update CI by @talmo in #32
- Switch to using
pyproject.toml
alone instead ofsetup.cfg
. - Remove
mypy
type enforcement -- this is too strict for a library intended to be this flexible. - Use micromamba in GitHub Actions workflow instead of miniconda
- Switch to using
- Video backends by @talmo in #31
- This PR implements the core video backends for media files, HDF5 and embedded images.
- Bump version by @talmo in #33
Full Changelog: v0.0.2...v0.0.3
v0.0.2¶
What's Changed
- Fix version and readme badge by @talmo in #19
- Add NWB support III - provenance writing by @h-mayorquin in #17
- Propagated extracted backend dict to video object by @h-mayorquin in #18
- Change equality semantics for Points and Instances by @quantumdot in #21
- Metadata not correctly propagated to nwb bug by @h-mayorquin in #23
- Add LabelStudio project support by @quantumdot in #26
- Add propagation of start time when writing nwbfile by @h-mayorquin in #29
- Refactoring pre v0.0.2 by @talmo in #27
- High-level API cleaned up to
load_nwb
,save_nwb
,load_labelstudio
,save_labelstudio
- Basic NWB loading support
- Add Label Studio functionality for inferring nodes.
- High-level API cleaned up to
New Contributors
- @quantumdot made their first contribution in #21
Full Changelog: v0.0.1...v0.0.2
v0.0.1¶
Initial stable release of the package.
What's Changed
- Initial setup by @talmo in #1
- Docstring linting and contributor guide by @talmo in #4
- Create sleap-io structures by @davidasamy in #2
- Read SLP files by @davidasamy in #3
- Initial refactor by @talmo in #5
- Performance fixes by @talmo in #6
- Added dunder
__repr__
to labels object by @h-mayorquin in #8 - Add fix for PR CI and add a test by @talmo in #9
- Add write utilities by @roomrys in #11
- Add nwb support I by @h-mayorquin in #12
- Add Labels.numpy and organize fixtures by @roomrys in #13
- Add NWB support II by @h-mayorquin in #15
- Add tests and functionality for loading provenance data by @h-mayorquin in #14
- Build workflow by @talmo in #16
New Contributors
- @talmo made their first contribution in #1
- @davidasamy made their first contribution in #2
- @h-mayorquin made their first contribution in #8
- @roomrys made their first contribution in #11
Full Changelog: https://github.com/talmolab/sleap-io/commits/v0.0.1