Skip to content

Reading and writing the formats from your own code#

There are tools to read skeletons and face embeddings from your own code. Here is an example of reading from a tracked skeleton file:

import h5py
from skelshop.io import ShotSegmentedReader

with h5py.File("/path/to/my/skels.h5", "r") as skels_f:
    for shot in ShotSegmentedReader(skels_f):
        for skel_id, skel in shot:
            print(skel_id, skel)

Reference#

skelshop.io.UnsegmentedWriter #

Write a skeleton dump without any shot segmentation. This typically implies that poses are not tracked.

__init__(self, h5f, num_kps=None, **create_kwargs) special #

Constructs an unsegmented pose writer

Source code in skelshop/io.py
def __init__(self, h5f: h5py.File, num_kps=None, **create_kwargs):
    """
    Constructs an unsegmented pose writer
    """
    self.h5f = h5f
    self.num_kps = num_kps
    self.timeline_grp = self.h5f.create_group("/timeline", track_order=True)
    self.pose_grps: Dict[int, List[Any]] = {}
    self.start_frame = 0
    self.create_kwargs = create_kwargs

add_pose(self, frame_num, pose_id, pose) #

Add a pose

Source code in skelshop/io.py
def add_pose(self, frame_num: int, pose_id: int, pose: ndarray):
    """
    Add a pose
    """
    pose_grp, data, indices, indptr, last_frame_num = self._pose_grp(
        pose_id, frame_num
    )
    new_rows = frame_num - last_frame_num
    add_empty_rows_grp(indptr, data, new_rows)
    new_data = []
    new_indices = []
    for limb_idx, limb in get_pose_nz(pose):
        new_data.append(limb)
        new_indices.append(limb_idx)
    if new_data:
        grow_ds(data, len(new_data))
        grow_ds(indices, len(new_indices))
        data[-len(new_data) :] = new_data
        indices[-len(new_indices) :] = new_indices
    self.pose_grps[pose_id][-1] = frame_num

end_shot(self) #

Ends a shot. This should only be called once at the end of writing.

Source code in skelshop/io.py
def end_shot(self):
    """
    Ends a shot. This should only be called once at the end of writing.
    """
    self.timeline_grp.attrs["start_frame"] = self.start_frame
    timeline_last_frame_num = 0
    for pose_grp, data, indices, indptr, last_frame_num in self.pose_grps.values():
        add_empty_rows_grp(indptr, data, 1)
        pose_grp.attrs["end_frame"] = last_frame_num + 1
        timeline_last_frame_num = max(timeline_last_frame_num, last_frame_num)
    self.timeline_grp.attrs["end_frame"] = timeline_last_frame_num + 1

start_shot(self, start_frame=0) #

Start a shot. This should only be called once at the beginning of writing.

Source code in skelshop/io.py
def start_shot(self, start_frame: int = 0):
    """
    Start a shot. This should only be called once at the beginning of writing.
    """
    self.start_frame = start_frame

skelshop.io.ShotSegmentedWriter #

Write a skeleton dump with any shot segmentation. This typically implies that poses are are tracked.

__init__(self, h5f, num_kps=None, **create_kwargs) special #

Constructs a shot segmented writer

Source code in skelshop/io.py
def __init__(self, h5f: h5py.File, num_kps=None, **create_kwargs):
    """
    Constructs a shot segmented writer
    """
    self.h5f = h5f
    self.num_kps = num_kps
    self.h5f.create_group("/timeline", track_order=True)

    self.pose_data: Dict[int, Dict[int, ndarray]] = {}
    self.pose_starts: Dict[int, int] = {}
    self.pose_ends: Dict[int, int] = {}
    self.shot_idx = 0
    self.shot_start = 0
    self.last_frame = 0
    self.create_kwargs = create_kwargs

add_pose(self, frame_num, pose_id, pose) #

Add a pose

Source code in skelshop/io.py
def add_pose(self, frame_num: int, pose_id: int, pose: ndarray):
    """
    Add a pose
    """
    if pose_id not in self.pose_data:
        self.pose_starts[pose_id] = frame_num
        self.pose_data[pose_id] = {}
    self.pose_data[pose_id][frame_num] = pose
    self.pose_ends[pose_id] = frame_num
    self.last_frame = frame_num

end_shot(self) #

End the current shot

Source code in skelshop/io.py
def end_shot(self):
    """
    End the current shot
    """
    shot_grp = self.h5f.create_group(
        f"/timeline/shot{self.shot_idx}", track_order=True
    )
    shot_grp.attrs["start_frame"] = self.shot_start
    shot_grp.attrs["end_frame"] = self.last_frame + 1
    for pose_id, poses in self.pose_data.items():
        data: List[ndarray] = []
        indices: List[int] = []
        indptr: List[int] = []
        pose_first_frame = self.pose_starts[pose_id]
        pose_last_frame = self.pose_ends[pose_id] + 1
        last_frame_num = pose_first_frame - 1

        def add_empty_rows(num_rows):
            for _ in range(num_rows):
                indptr.append(len(data))

        for frame_num, pose in poses.items():
            add_empty_rows(frame_num - last_frame_num)
            for limb_idx, limb in get_pose_nz(pose):
                data.append(limb)
                indices.append(limb_idx)
            last_frame_num = frame_num
        # Extra empty row to insert final nnz entry
        add_empty_rows(1)

        pose_group = create_csr(
            self.h5f,
            f"/timeline/shot{self.shot_idx}/pose{pose_id}",
            self.num_kps,
            data=data,
            indices=indices,
            indptr=indptr,
            **self.create_kwargs,
        )
        pose_group.attrs["start_frame"] = pose_first_frame
        pose_group.attrs["end_frame"] = pose_last_frame
    self.pose_data = {}
    self.shot_idx += 1
    self.shot_start = self.last_frame + 1

register_frame(self, frame_num) #

Register frame_num as existing within the current shot

Source code in skelshop/io.py
def register_frame(self, frame_num: int):
    """
    Register frame_num as existing within the current shot
    """
    self.last_frame = frame_num

start_shot(self, start_frame=None) #

Start a new shot

Source code in skelshop/io.py
def start_shot(self, start_frame=None):
    """
    Start a new shot
    """
    if start_frame is not None:
        self.shot_start = start_frame

skelshop.io.ShotSegmentedReader #

Reads a shot segmented skeleton dump.

__init__(self, h5f, bundle_cls=<class 'skelshop.pose.DumpReaderPoseBundle'>, infinite=False) special #

Constructs the reader from a HDF5 file and. If infinite is True, all shot iterators will terminate with a final empty shot which infinitely yields empty pose bundles.

Source code in skelshop/io.py
def __init__(self, h5f: h5py.File, bundle_cls=DumpReaderPoseBundle, infinite=False):
    """
    Constructs the reader from a HDF5 file and. If `infinite` is True, all
    shot iterators will terminate with a final empty shot which infinitely
    yields empty pose bundles.
    """
    self.h5f = h5f
    self.limbs = self.h5f.attrs["limbs"]
    assert self.h5f.attrs["fmt_type"] == "trackshots"
    self.mk_bundle = partial(bundle_cls, cls=POSE_CLASSES[self.h5f.attrs["mode"]])
    self.empty_bundle = self.mk_bundle({})
    self.infinite = infinite

__iter__(self) special #

Returns a shot iterator of all shots

Source code in skelshop/io.py
def __iter__(self):
    """
    Returns a shot iterator of all shots
    """
    for shot_idx, shot_name, start_frame, end_frame, mk_shot in self._iter():
        yield mk_shot()

iter_from_frame(self, start_frame) #

Returns a shot iterator starting from frame 0-index start_frame.

Source code in skelshop/io.py
def iter_from_frame(self, start_frame: int):
    """
    Returns a shot iterator starting from frame 0-index `start_frame`.
    """
    started = False
    for (
        shot_idx,
        shot_name,
        shot_start_frame,
        shot_end_frame,
        mk_shot,
    ) in self._iter(start_frame):
        if started:
            yield mk_shot()
        elif shot_start_frame <= start_frame and (
            shot_end_frame is None or start_frame < shot_end_frame
        ):
            yield mk_shot()
            started = True

iter_from_shot(self, start_shot) #

Returns a shot iterator starting from shot 0-index start_shot.

Source code in skelshop/io.py
def iter_from_shot(self, start_shot: int):
    """
    Returns a shot iterator starting from shot 0-index `start_shot`.
    """
    for shot_idx, shot_name, start_frame, end_frame, mk_shot in self._iter():
        if shot_idx >= start_shot:
            yield mk_shot()

skelshop.io.UnsegmentedReader #

Reads a non-shot segmented skeleton dump.

__iter__(self) special #

Returns a pose bundle iterator of all frames.

Source code in skelshop/io.py
def __iter__(self):
    """
    Returns a pose bundle iterator of all frames.
    """
    return iter(self.shot_reader)

iter_from(self, start_frame) #

Returns a pose bundle iterator starting at frame start_frame.

Source code in skelshop/io.py
def iter_from(self, start_frame: int):
    """
    Returns a pose bundle iterator starting at frame `start_frame`.
    """
    return self.shot_reader.iter_from(start_frame)

skelshop.io.ShotReader #

A reader for a single shot. Typically this is returned from ShotSegmentedReader.

__iter__(self) special #

Returns a pose bundle iterator of all frames.

Source code in skelshop/io.py
def __iter__(self):
    """
    Returns a pose bundle iterator of all frames.
    """
    return self.iter_from(self.start_frame)

iter_from(self, start_frame) #

Returns a pose bundle iterator starting at frame start_frame.

Source code in skelshop/io.py
def iter_from(self, start_frame):
    """
    Returns a pose bundle iterator starting at frame `start_frame`.
    """
    for frame in range(start_frame, self.end_frame):
        bundle = {}
        for pose_num, start_frame, end_frame, sparse_pose in self.poses:
            if start_frame <= frame < end_frame:
                row_num = frame - start_frame
                bundle[pose_num] = sparse_pose.get_row(row_num)
        yield self.mk_bundle(bundle)

skelshop.io.AsIfTracked #

Adapter wrapper for readers producing UntrackedDumpReaderPoseBundle such as UnsegmentedReader by default that makes them appear to produce bundles like TrackedDumpReaderPoseBundle.

skelshop.io.AsIfSingleShot #

Adapter wrapper for ShotSegmentedReader to make it act more like an UnsegmentedReader.