Skip to content

Working with sign-language-data-loading

sign-language-data-loading (imported as sldl) loads sign language datasets stored as WebDataset shards — poses, videos and temporal annotations — and hands you back plain numpy/pandas samples. sign-language-tools picks up from there: augmenting the poses, and visualizing or playing back the sample.

pip install sign-language-data-loading

Loading a sample

from sldl import SignLanguageDataset
from sldl.configs import LSFBContConfig

dataset = SignLanguageDataset.from_config(
    LSFBContConfig(
        root="path/to/lsfb-cont",
        split="testing",
        load_videos=False,
    )
)

sample = dataset[42]
sample["poses"]                 # dict[str, np.ndarray], e.g. {"upper_pose": (T, 23, 3), ...}
sample["annotations"]           # dict[str, pandas.DataFrame], per annotation track

For isolated-sign datasets, use sldl.configs.LSFBIsolConfig instead — each sample is then a single sign with a sample["label"] instead of a DataFrame of annotations.

Augmenting the poses

The pose arrays returned by sldl are plain (T, L, C) numpy arrays, so they plug directly into pose transforms:

from sign_language_tools.common.transforms import Compose
from sign_language_tools.pose.transforms import InterpolateMissing, TemporalRandomCrop, HorizontalFlip

augment = Compose([
    InterpolateMissing(),
    TemporalRandomCrop(size=64),
    HorizontalFlip(),
])

upper_pose = augment(sample["poses"]["upper_pose"])

Visualizing the sample

Play back the pose keypoints with the VideoPlayer, using the MediaPipe edge definitions to draw the skeleton:

from sign_language_tools.player import VideoPlayer
from sign_language_tools.pose.mediapipe.edges import UPPER_POSE_EDGES, HAND_EDGES

player = VideoPlayer()
player.attach_empty(width=800, height=600, name="pose data")
player.attach_poses(sample["poses"]["upper_pose"], UPPER_POSE_EDGES, parent_name="pose data")
player.attach_poses(
    sample["poses"]["left_hand"], HAND_EDGES, edge_color=(255, 0, 0), parent_name="pose data",
)
player.attach_poses(
    sample["poses"]["right_hand"], HAND_EDGES, edge_color=(0, 0, 255), parent_name="pose data",
)
player.play(speed=0.5)

If the dataset sample also carries a video (load_videos=True), attach it with player.attach_video_tensor(sample["video"], fps=...) (or attach_video_file if you have the raw file path) as the root component instead of attach_empty, and attach the poses as its children.

Converting annotations for training

Continuous samples carry their annotations as a pandas.DataFrame of gloss segments (start_frame, end_frame, lemma, ...). Convert them to a dense per-frame label vector with the annotations transforms, e.g. to train a frame-level classifier:

import numpy as np
from sign_language_tools.annotations.transforms import SegmentsToFrameLabels

annotations = sample["annotations"]["both_hands"]
segments = annotations[["start_frame", "end_frame"]].to_numpy()

frame_labels = SegmentsToFrameLabels()(segments, vector_size=sample["n_frames"])

Batching for training

sldl.SignLanguageCollator batches samples (padding pose sequences and building a mask), and the common transforms Compose/ApplyToAll can be passed as the dataset's transform to apply pose augmentation per-sample before batching:

from torch.utils.data import DataLoader
from sldl import SignLanguageCollator

loader = DataLoader(dataset, batch_size=8, collate_fn=SignLanguageCollator())
batch = next(iter(loader))
batch["poses"]["upper_pose"].shape   # (batch, max_n_frames, ...)
batch["masks"].shape                 # (batch, max_n_frames)