Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ venv/
**/_version.py

# uv
uv.lock
uv.lock
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ recursive-exclude * __pycache__
recursive-exclude * *.py[co]
recursive-exclude docs *
recursive-exclude tests *
recursive-exclude examples *
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
# Notes
# - all projects I tried are with a single video
# - in LP example project: no video directory
# - sleap io assumes frame paths are: (....)/ `labeled-data` / video-name / img0000x.extension
# - sleap-io assumes frame paths have minimally:
# labeled-data/<video-name>/<img-name>.<ext>
# - <img-name> must contain the (sequence of) digits representing
# the frame index
# - if <img-name> is alphanumerical, the last sequence of digits is assumed to
# be the frame index
# - when loading DLC files with sleap-io: the frames need to exist

# %%
from pathlib import Path

from poseinterface.io import format_dlc_annotations_file
from poseinterface.io import annotations_to_coco

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Input data: DLC project with a single video
Expand All @@ -22,7 +27,7 @@
/ "DLC-openfield-Pranav-2018-10-30"
/ "labeled-data"
/ "m4s1"
/ Path("CollectedData_Pranav.csv")
/ "CollectedData_Pranav.csv"
)

# Output path
Expand All @@ -35,8 +40,6 @@
# %%%%%%%%%%%%
# Export as COCO

out_json = format_dlc_annotations_file(
dlc_annotations_files_csv, out_coco_json
)
out_json = annotations_to_coco(dlc_annotations_files_csv, out_coco_json)

# %%
74 changes: 55 additions & 19 deletions poseinterface/io.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,71 @@
from pathlib import Path

from sleap_io.io import coco, dlc
import sleap_io as sio
from sleap_io.io import dlc

_EMPTY_LABELS_ERROR_MSG = {
"default": (
"No annotations could be extracted from the input file."
"Please check that the input file contains labeled frames."
),
"dlc": (
"Ensure that the paths to the labelled frames are in the "
"standard DLC project format: "
"labeled-data / <video-name> / "
"<filename-with-frame-number>.<extension>"
"and that the frames files exist."
),
}

def format_dlc_annotations_file(

def annotations_to_coco(
input_path: Path,
output_json_path: Path,
*,
coco_image_filenames: str | list[str] | None = None,
coco_visibility_encoding: str = "ternary",
) -> dict:
"""Export input DLC annotations file to COCO format."""
# Read annotations as Labels object
labels = dlc.load_dlc(input_path, video_search_paths=None)
) -> Path:
"""Export annotations file to COCO format.

Parameters
----------
input_path : pathlib.Path
Path to the input annotations file.
output_json_path : pathlib.Path
Path to save the output COCO JSON file.
coco_image_filenames : str | list[str] | None, optional
Optional image filenames to use in the COCO JSON. If provided,
must be a single string (for single-frame videos) or a list of
strings matching the number of labeled frames. If None (default),
generates filenames from video filenames and frame indices.
coco_visibility_encoding : str, optional
Encoding scheme for keypoint visibility in the COCO JSON file.
Options are "ternary" (0: not labeled, 1: labeled but not visible,
2: labeled and visible) or "binary" (0: not visible, 1: visible).
Default is "ternary".

Returns
-------
pathlib.Path
Path to the saved COCO JSON file.

Notes
-----
The format of the input annotations file is automatically inferred based
on its extension. See :func:`sleap_io.io.main.load_file` for supported
formats.
"""
labels = sio.load_file(input_path)
# Check if labels object is empty
if len(labels.labeled_frames) == 0:
raise ValueError(
"No annotations could be extracted from the input file."
"Please check the paths to the labelled frames are in the "
"standard DLC project format: "
"labeled-data / <video-name> / "
"<filename-with-frame-number>.<extension>"
"and that the frames files exist."
)

# Export Labels object to COCO
coco.write_labels(
error_msg = _EMPTY_LABELS_ERROR_MSG["default"]
if dlc.is_dlc_file(input_path):
error_msg += _EMPTY_LABELS_ERROR_MSG["dlc"]
raise ValueError(error_msg)
sio.save_coco(
labels,
output_json_path,
visibility_encoding=coco_visibility_encoding,
image_filenames=coco_image_filenames,
visibility_encoding=coco_visibility_encoding,
)

return output_json_path
Loading