Changelog¶
v0.5.1¶
🎯 Summary
This release introduces powerful merging capabilities for annotation workflows, enhanced image sequence handling, and improved developer tooling. The highlight is the new comprehensive merging system that enables human-in-the-loop (HITL) workflows and smart combination of multiple annotation sources.
✨ New Features
Comprehensive Merging System (#216)
- New
Labels.merge()
method with configurable strategies for combining annotations from multiple sources - Smart merge strategies that preserve user labels over predictions
- Instance matching with spatial, identity, and IoU-based methods
- Skeleton harmonization for consistent structure across merged data
- Video path resolution with automatic path repair
- Progress tracking and provenance metadata for merge operations
# Merge annotations with smart conflict resolution
merged = labels1.merge(labels2, strategy="smart")
# Custom merge with specific matchers
merged = labels1.merge(
labels2,
video_matcher="shape", # Match videos by dimensions
instance_matcher="iou", # Match instances by overlap
conflict_strategy="user" # Prefer user annotations
)
See the new Merging guide for more information.
Enhanced ImageVideo
support for merging (#219)
- Image deduplication with new
IMAGE_DEDUP
matcher - Shape-based matching for merging videos with same dimensions
- CVAT format support with automatic track preservation
- New Video methods:
has_overlapping_images()
- Check for duplicate framesmatches_shape()
- Compare video dimensionsdeduplicate_with()
- Remove duplicate framesmerge_with()
- Combine image sequences
# Remove duplicate images from a video
video_dedup = video.deduplicate_with(other_video)
# Check if videos have the same shape
if video1.matches_shape(video2):
merged = video1.merge_with(video2)
🐛 Bug Fixes
Fixed Duplicate Skeleton Symmetries (#217)
- Resolved issue where legacy SLEAP files could create duplicate symmetry relationships
- Ensures clean YAML exports without redundant symmetry definitions
🔧 Improvements
Developer Tooling (#218)
- New coverage analysis script (
scripts/cov_summary.py
) for PR-aware coverage reporting - GitHub CLI integration for targeted coverage analysis of changed files
- Simplified coverage command with line-by-line annotations
# Quick coverage check with annotations
uv run pytest -q --maxfail=1 --cov --cov-branch && uv run coverage annotate
# Get coverage for PR changes only
uv run python scripts/cov_summary.py
📚 Documentation
Improved Documentation Structure (#220)
- Restructured merging documentation with detailed algorithm explanations
- Enhanced examples with visual improvements using MkDocs Material
- Added mermaid flowcharts and behavior matrices for better understanding
- Improved organization with progressive disclosure of complex topics
💡 Why These Changes Matter
The v0.5.1 release significantly enhances sleap-io's capabilities for real-world annotation workflows:
- HITL Workflows: The new merging system enables seamless integration of manual corrections with model predictions
- Data Consolidation: Easily combine annotations from multiple annotators or sessions
- Video Management: Better handling of image sequences with automatic deduplication
- Developer Experience: Improved tooling for maintaining code quality and test coverage
📋 Changelog
- #216: Implement comprehensive merging system for annotation files (@talmo)
- #217: Fix duplicate skeleton symmetries from legacy SLEAP files (@talmo)
- #218: Add coverage summary script and update coverage command (@talmo)
- #219: Deduplicate merging for
ImageVideo
and add better CVAT support (@talmo) - #220: Documentation improvements for merging capabilities (@talmo)
Full Changelog: v0.5.0...v0.5.1
v0.5.0¶
Summary
Overview
The v0.5.0 release of sleap-io represents a major leap forward in format compatibility, development tooling, and data management capabilities. This release introduces support for five new pose tracking formats (COCO, DeepLabCut, TIFF stacks, and enhanced Ultralytics), adds powerful multi-dataset management with LabelsSet
, and modernizes the development workflow with UV package manager. The release also includes critical bug fixes, performance improvements, and comprehensive documentation updates.
🚀 New Features
Multi-Dataset Management with LabelsSet (#197)
sleap-io now provides a powerful LabelsSet
container for managing multiple Labels
objects, enabling seamless handling of train/val/test splits and dataset collections.
This feature includes:
- Hybrid dictionary/tuple interface for flexible access patterns
- Automatic split creation from existing datasets
- Batch I/O operations for entire dataset collections
- Backward-compatible API that doesn't break existing code
Usage:
import sleap_io as sio
# Create train/val/test splits
splits = labels.make_training_splits(n_train=0.8, n_test=0.1)
# Access as dictionary
train = splits["train"]
val = splits["val"]
test = splits["test"]
# Or unpack as tuple (backward compatible)
train, val, test = splits
# Save all splits at once
splits.save("splits/", embed=True) # Creates train.pkg.slp, val.pkg.slp, test.pkg.slp
# Load multi-split datasets
labels_set = sio.load_labels_set("path/to/splits/")
COCO-Style Dataset Support (#199)
Added comprehensive support for reading COCO pose format, enabling integration with the broader computer vision ecosystem.
Features:
- Automatic skeleton creation from COCO categories
- Multi-species support with different skeletons per category
- Flexible directory structure handling (flat, nested, categorized)
- Binary and ternary visibility encodings
- Memory-efficient shared video objects for images
Usage:
import sleap_io as sio
# Load COCO annotations
labels = sio.load_file("annotations.json", format="coco")
# Load with custom image root
labels = sio.load_file("coco_data.json", dataset_root="/path/to/images")
# Load multi-split COCO dataset
labels_set = sio.load_labels_set("dataset/", format="coco")
DeepLabCut Training Data Support (#201)
Implemented complete support for reading DeepLabCut CSV files, supporting all DLC format variations.
Capabilities:
- Single-animal tracking (SADLC)
- Multi-animal tracking (MADLC)
- Multi-animal with identity tracking (MAUDLC)
- Automatic format detection from CSV headers
- Proper video grouping from image directories
Usage:
import sleap_io as sio
# Load DLC annotations
labels = sio.load_file("CollectedData_scorer.csv")
# Access the data
print(f"Found {len(labels.labeled_frames)} labeled frames")
for lf in labels.labeled_frames:
for instance in lf.instances:
if instance.track:
print(f"Individual '{instance.track.name}': {instance.numpy()}")
TIFF Stack Support (#195)
Added native support for multi-page TIFF files through a new TiffVideo
backend.
Features:
- Automatic detection of single vs multi-page TIFFs
- Frame-by-frame access for TIFF stacks
- Full SLP serialization support
- Backward compatibility with older SLEAP versions
Usage:
import sleap_io as sio
# Load multi-page TIFF
video = sio.Video.from_filename("multipage_stack.tif")
print(f"Stack has {video.shape[0]} frames")
# Use in labels
labels = sio.Labels()
labels.videos.append(video)
labels.save("project.slp") # TiffVideo metadata preserved
Video Plugin Management (#202)
Introduced comprehensive control over video backend selection to handle platform-specific codec issues.
New capabilities:
- Global default plugin setting
- Flexible plugin name aliases (case-insensitive)
- Runtime plugin switching on existing videos
- Batch plugin changes for entire projects
Usage:
import sleap_io as sio
# Set global default
sio.set_default_video_plugin("opencv") # or "cv2", "cv", "ocv"
# Load with specific plugin
video = sio.load_video("video.mp4", plugin="FFMPEG")
# Switch plugin on existing video
video.set_video_plugin("pyav") # or "av", "PyAV"
# Batch change for all videos in project
labels = sio.load_slp("project.slp")
labels.set_video_plugin("opencv")
🐛 Bug Fixes
Fixed Skeleton Node Order Decoding (#208)
- Fixed incorrect node ordering when loading skeletons from training configs with non-sequential py/ids
- Resolved edge connection errors that occurred with complex skeletons
- Added comprehensive tests for node and edge order preservation
Impact: Skeletons loaded from training configs now correctly preserve their structure and edge connections.
🔧 Improvements
Performance: Labels.replace_filenames Control (#213)
Added open_videos
parameter to Labels.replace_filenames()
for better performance when working with network storage:
# Replace paths without opening videos (faster on network storage)
labels.replace_filenames(
prefix_map={"/old/network/path": "/new/network/path"},
open_videos=False # Avoid costly file checks
)
Impact: Significantly faster filename replacement operations when dealing with many files on network storage.
Development Workflow: UV Migration (#214)
Migrated CI/CD and development tooling from conda to UV for dramatic performance improvements:
- 10-100x faster dependency resolution and installation
- CI runtime reduced from ~12 minutes to ~2 minutes
- Single tool for all Python/package management tasks
- PyPI trusted publisher for improved security
Developer experience:
# One-line setup
uv sync --all-extras
# All commands now use uv run prefix
uv run pytest tests/
uv run ruff check sleap_io tests
uv build
Tooling: Unified Linting with Ruff (#194)
Replaced black and pydocstyle with ruff for unified, faster code quality checks:
- Single tool for both formatting and linting
- Significantly faster CI runs
- Fixed 50+ code quality issues during migration
- Consistent configuration and error reporting
Documentation Enhancements (#203, #215)
Comprehensive documentation improvements for both AI assistants and human contributors:
- Added Claude Code integration with
.claude/commands
directory - Visual data model diagram with relationships
- Modernized CONTRIBUTING.md with Quick Start section
- Updated all examples to use UV commands
- Streamlined testing and coverage workflows
📦 Dependencies
- Added
pyyaml
for YAML skeleton support (from v0.4.0) - Made OpenCV and PyAV optional dependencies with modular installation
- Removed hard conda dependencies in favor of pip/UV
🔄 Migration Notes
Optional Video Backend Dependencies
Video backends are now optional to reduce installation size:
# Basic installation (no video backends)
pip install sleap-io
# With specific backends
pip install sleap-io[opencv] # OpenCV only
pip install sleap-io[av] # PyAV only
pip install sleap-io[all] # All backends
Development Setup
For developers, UV is now the recommended tool:
# Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh
# Setup development environment
uv sync --all-extras
# Run commands with uv run prefix
uv run pytest tests/
Conda environments still work but use pip under the hood for simplicity.
No Breaking API Changes
All existing APIs remain compatible. New features are additive and do not affect existing functionality.
🎯 Why These Changes Matter
- Format Ecosystem: Support for COCO and DeepLabCut enables integration with the broader pose tracking community
- Dataset Management:
LabelsSet
provides professional-grade tools for managing train/val/test splits - Performance: UV migration and video control features dramatically improve development and runtime speed
- Media Flexibility: TIFF support and plugin management handle diverse video formats and platform requirements
- Developer Experience: Modern tooling and documentation reduce friction for contributors
- Code Quality: Ruff migration ensures consistent, high-quality code across the project
This release significantly expands sleap-io's capabilities as a universal pose tracking data utility, improving compatibility with external tools, performance for large-scale operations, and the overall development experience.
Changelog
- Replace black/pydocstyle with ruff in CI by @talmo in #194
- Add TIFF support for multi-page stacks by @talmo in #195
- Add LabelsSet for multi-label and split handling by @talmo in #197
- Add COCO-style dataset support by @talmo in #199
- Add DLC training data support by @talmo in #201
- Video plugin conveniences by @talmo in #202
- Fix skeleton node order decoding by @talmo in #208
- Migrate CI from conda to UV by @talmo in #214
- Update to 0.5.0 and refresh docs by @talmo in #203
- Add
open_videos
parameter toLabels.replace_filenames
method by @talmo in #213 - Documentation improvements for Claude Code and contributors by @talmo in #215
Full Changelog: v0.4.1...v0.5.0
v0.4.1¶
Summary
Overview
The v0.4.1 release of sleap-io introduces experimental Ultralytics YOLO pose format support, enhances skeleton loading capabilities, and provides important improvements to video reference handling in saved files. This release focuses on expanding format compatibility and giving users more control over their workflow when working with package files and predictions.
🚀 New Features
Ultralytics YOLO Pose Format Support (#183) [Experimental]
sleap-io now provides experimental support for reading and writing pose annotations in the Ultralytics YOLO pose format, enabling seamless integration with YOLO-based pose estimation workflows.
Note: This is an initial implementation that has not yet been battle-tested in production environments. Please report any issues or edge cases you encounter.
This feature includes:
- Full support for YOLO's normalized coordinate system
- Multi-instance pose annotations
- Automatic skeleton configuration from
data.yaml
files - Integration with train/val/test splits
Usage:
import sleap_io as sio
# Load YOLO pose annotations
labels = sio.load_ultralytics(
labels_dir="path/to/labels",
image_dir="path/to/images",
data_yaml="path/to/data.yaml"
)
# Save in YOLO format with train/val/test splits
sio.save_ultralytics(
labels,
save_dir="yolo_dataset",
split_fractions=(0.8, 0.1, 0.1) # 80% train, 10% val, 10% test
)
# Also works via the generic API
labels = sio.load_file("path/to/labels/*.txt") # Auto-detects YOLO format
labels.save("output_dir", format="ultralytics")
Video Reference Restoration Control (#192)
Added fine-grained control over video references when saving SLEAP files. This is particularly useful when working with predictions made on .pkg.slp
files, allowing you to maintain references to the specific package files used for inference.
Usage:
import sleap_io as sio
# Load a package file used for training/inference
labels = sio.load_file("train.pkg.slp")
# Run inference...
# Save predictions while preserving reference to train.pkg.slp
labels.save("predictions.slp", embed=False, restore_original_videos=False)
# Default behavior still restores original video references
labels.save("predictions_default.slp") # Links to original video files
Benefits:
- Track which exact dataset split was used for predictions
- Compare inference results across different models
- Maintain data lineage for reproducible workflows
🐛 Bug Fixes
Critical Fix: Skeleton Decoding for Complex Skeletons (#185) 🚨
- Fixed a critical bug introduced in v0.4.0 where skeletons with 32+ nodes or non-sequential py/id assignments would fail to decode
- Removed hardcoded assumptions about py/id patterns that only worked for simple skeletons
- Now correctly handles arbitrary py/id assignments in skeleton data
Impact: This bug affected v0.4.0 and prevented users with complex skeletons (e.g., full fly body models with 32 nodes) from loading their data. If you use complex skeletons and are on v0.4.0, upgrading to v0.4.1 is strongly recommended.
🔧 Improvements
Enhanced Skeleton Loading API (#187)
The load_skeleton()
function now intelligently loads skeletons from multiple sources:
.slp
files: Extract skeletons directly from SLEAP project files- Training config JSON: Automatically detect and extract embedded skeletons
- Existing formats: Continue to support standalone skeleton JSON/YAML files
Usage:
import sleap_io as sio
# Load from various sources
skeleton = sio.load_skeleton("project.slp") # From SLEAP project
skeleton = sio.load_skeleton("training_config.json") # From training config
skeleton = sio.load_skeleton("skeleton.yaml") # Standalone YAML
skeleton = sio.load_skeleton("skeleton.json") # Standalone JSON
Strengthened Test Coverage (#190)
- Enhanced skeleton test assertions with specific expected values
- Improved test clarity and regression detection
- Ensures skeleton loading behavior is consistent and reliable
📦 Dependencies
No new dependencies added in this release.
🔄 Migration Notes
Video Reference Behavior
The new restore_original_videos
parameter defaults to True
, maintaining existing behavior:
# These are equivalent (default behavior preserved)
labels.save("output.slp")
labels.save("output.slp", restore_original_videos=True)
# New option to preserve package file references
labels.save("output.slp", restore_original_videos=False)
No Breaking API Changes
All existing APIs remain compatible. New features are additive and do not affect existing functionality.
🎯 Why These Changes Matter
- Format Interoperability: YOLO pose format support enables integration with a wider ecosystem of pose estimation tools
- Workflow Control: Video reference preservation gives users control over their data lineage and prediction tracking
- Reliability: Bug fixes for complex skeletons ensure sleap-io works with diverse anatomical models
- Developer Experience: Enhanced skeleton loading API reduces code complexity when working with different file formats
- Quality Assurance: Improved test coverage ensures long-term stability and catches regressions early
This release strengthens sleap-io's position as a versatile tool for pose tracking data management, improving both compatibility with external tools and control over complex workflows.
Changelog
- Add Ultralytics YOLO pose format support by @talmo in #183
- Fix skeleton decoding for non-sequential py/id assignments by @talmo in #185
- Skeleton API enhancements by @talmo in #187
- Strengthen skeleton test assertions by @talmo in #190
- Add video reference restoration control by @talmo in #192
- Bump to v0.4.1 by @talmo in #193
Full Changelog: v0.4.0...v0.4.1
v0.4.0¶
Summary
Overview
The v0.4.0 release of sleap-io introduces significant improvements to skeleton file handling, enhances the package file (.pkg.slp) saving performance, and fixes several important bugs. This release focuses on making skeleton data more accessible and improving the user experience when working with large datasets.
🚀 New Features
Standalone Skeleton Serialization (#178)
sleap-io now supports reading and writing skeleton files independently from label files. This feature enables:
- Loading skeleton definitions from
.json
files in SLEAP's jsonpickle format - Saving skeletons for reuse across projects
- Working with multiple skeletons in a single file
Usage:
import sleap_io as sio
# Load a skeleton
skeleton = sio.load_skeleton("skeleton.json")
# Save a skeleton
sio.save_skeleton(skeleton, "output.json")
# Also works with lists of skeletons
skeletons = sio.load_skeleton("multiple_skeletons.json")
sio.save_skeleton(skeletons, "output.json")
YAML Skeleton Format Support (#179)
Added support for human-readable YAML format for skeleton files, making it easier to:
- Manually create and edit skeleton definitions
- Version control skeleton configurations
- Share skeleton templates between projects
Usage:
import sleap_io as sio
# Load from YAML
skeleton = sio.load_skeleton("skeleton.yaml")
# Save to YAML
sio.save_skeleton(skeleton, "output.yml")
Example YAML format:
Skeleton-0:
nodes:
- name: head
- name: thorax
- name: abdomen
edges:
- source:
name: head
destination:
name: thorax
symmetries:
- - name: eyeL
- name: eyeR
Frame Embedding Progress Bar (#174)
Added a progress bar when embedding frames into .pkg.slp
files, providing:
- Visual feedback during long embedding operations
- Better user experience when working with large datasets
- Estimate of remaining time for completion
🐛 Bug Fixes
Fixed Package File Saving with Embedded Videos (#177)
- Changed default behavior:
embed=False
is now the default for fast-saving - Prevented data loss: Added detection for self-referential paths
- Fixed video referencing: Correctly handles external video references
Impact: Users can now quickly save .pkg.slp
files without re-embedding frames, significantly improving save performance for large projects.
Usage:
# Fast save (default behavior)
labels.save("file.slp") # embed=False by default
# Explicitly re-embed frames
labels.save("file.slp", embed=True)
Fixed ImageVideo Backend Metadata Serialization (#173)
- Fixed compatibility issue with core SLEAP when using
ImageVideo
backend - Resolved
cattrs
class inference errors - Maintained backward compatibility with existing files
Impact: Users working with image sequences no longer encounter errors when loading files in core SLEAP.
🔧 Improvements
SLP Format v1.3 Support (#176)
- Added explicit support for SLEAP label format version 1.3
- Enhanced tracking score support on
Instance
objects - Added comprehensive tests for format compatibility
Impact: Full compatibility with the latest SLEAP format features, including improved tracking metrics.
📦 Dependencies
- Added
pyyaml
dependency for YAML skeleton format support
🔄 Migration Notes
Default Embedding Behavior Change
The default behavior for saving .pkg.slp
files has changed:
- Before v0.4.0:
embed=True
(re-embeds all frames) - After v0.4.0:
embed=False
(references existing files)
To maintain previous behavior, explicitly set embed=True
:
labels.save("output.pkg.slp", embed=True)
No Breaking API Changes
All existing APIs remain compatible. New features are additive and do not affect existing functionality.
🎯 Why These Changes Matter
- Skeleton Management: Standalone skeleton files enable better project organization and reusability
- Performance: Fast-saving package files dramatically reduces save times for large datasets
- User Experience: Progress bars and better error messages improve workflow transparency
- Compatibility: Bug fixes ensure smooth interoperability with core SLEAP
- Flexibility: YAML format provides a human-friendly alternative for skeleton configuration
This release enhances sleap-io's capabilities as a standalone utility for pose tracking data management while maintaining full compatibility with the SLEAP ecosystem.
Changelog
- Fix the backend metadata being serialized to SLP for ImageVideo backends by @talmo in #173
- Frame embedding progress bar by @talmo in #174
- Implement SLP format v1.3 by @talmo in #176
- Fix saving package files with embedded videos by @talmo in #177
- Standalone Skeleton serialization/deserialization by @talmo in #178
- Add YAML support for skeleton serialization by @talmo in #179
- Bump to v0.4.0 by @talmo in #180
Full Changelog: v0.3.0...v0.4.0
v0.3.0¶
What's Changed
- Add skeleton symmetry QOL enhancements by @talmo in #144
- Add support for writing to nwb with ndx-pose > 0.2.0 by @h-mayorquin in #143
- Check for existence of source video when creating from pkg.slp by @talmo in #148
- Add
Camera
class by @roomrys in #145 - Add CameraGroup class by @roomrys in #146
- Minimize NWB testing time by @talmo in #155
- Implement points array backend by @talmo in #154
- Fix saving .pkg.slp with empty videos by @talmo in #156
- Add all MV data structures by @roomrys in #151
- Integrate recording session with labels by @roomrys in #153
- Remove geometric functionality by @roomrys in #158
- Refactor data handling and implement setitem for Instances by @talmo in #161
- Support user instances in
Labels.numpy()
by @talmo in #162 - Implement
update_from_numpy
method for instance updating from tracks array by @talmo in #163 - Add
Labels.from_numpy
constructor by @talmo in #166 - Add repr for mv classes by @roomrys in #167
- Add codespell support (config, workflow to detect/not fix) and make it fix some typos by @yarikoptic in #168
- Update ndx-pose dependency to version >=0.2.1 in environment.yml by @lochhh in #169
- Remove OpenCV dependency for Rodrigues transformation by @talmo in #170
- Bump to v0.3.0 by @talmo in #171
New Contributors
- @yarikoptic made their first contribution in #168
Full Changelog: v0.2.0...v0.3.0
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