Skip to content

Commit

Permalink
Improve docstrings, add multi-version support to epic_kitchens.meta
Browse files Browse the repository at this point in the history
* Consolidate docstring format to Google's style
* Add sphinx intersphinx cross-links support
* Add `set_version` to `epic_kitchens.meta` to change to different label
  versions
  • Loading branch information
willprice committed Nov 19, 2018
1 parent 1c8a32c commit c8cc5a4
Show file tree
Hide file tree
Showing 19 changed files with 293 additions and 234 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
to view arbitrary action segments RGB or Flow contained in a `EpicVideoDataset`
using `moviepy`. This is useful when sifting through results per instance.

## Changes
* Improve documentation and bring it all in line with google doc string
standards

# Version 1.5.0

## Features
Expand Down
8 changes: 7 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,10 @@
# -- Options for intersphinx extension ---------------------------------------

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {"https://docs.python.org/3": None}
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"moviepy": ("https://zulko.github.io/moviepy", None),
"numpy": ("http://docs.scipy.org/doc/numpy", None),
"PIL": ("https://pillow.readthedocs.io/en/stable/", None),
"pandas": ("http://pandas.pydata.org/pandas-docs/stable/", None),
}
4 changes: 2 additions & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
epic-kitchens
epic-kitchens
=============

`EPIC Kitchens`_ is an egocentric vision dataset, visit the website to
Expand All @@ -11,7 +11,7 @@ Have a look at `EPIC-mini`_ for example usage.


.. toctree::
:maxdepth: 2
:maxdepth: 3

epic_kitchens.rst
cli_tools.rst
Expand Down
2 changes: 1 addition & 1 deletion epic_kitchens/__version__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__title__ = "epic-kitchens"
__description__ = "EPIC Kitchens action dataset support library"
__version__ = "1.5.0"
__version__ = "1.6.0"
__author__ = "EPIC KITCHENS"
__author_email__ = "[email protected]"
__license__ = "MIT"
Expand Down
80 changes: 53 additions & 27 deletions epic_kitchens/dataset/epic_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
from epic_kitchens.dataset.video_dataset import VideoDataset, VideoSegment


SegmentFilter = Callable[[VideoSegment], bool]
ClassGetter = Callable[[Dict[str, Any]], Any]
VideoTransform = Callable[[List[PIL.Image.Image]], List[PIL.Image.Image]]


def _verb_class_getter(metadata):
return int(metadata[VERB_CLASS_COL])

Expand Down Expand Up @@ -38,7 +43,7 @@ def _noun_class_getter(metadata):


class GulpVideoSegment(VideoSegment):
""" SegmentRecord for a video segment stored in a gulp file.
"""SegmentRecord for a video segment stored in a gulp file.
Assumes that the video segment has the following metadata in the gulp file:
- id
Expand All @@ -55,11 +60,12 @@ def __init__(
self.gulp_index = gulp_metadata_dict[UID_COL]

@property
def id(self):
def id(self) -> str:
"""ID of video segment"""
return self.gulp_index

@property
def label(self):
def label(self) -> Any:
cls = self.class_getter(self.metadata)
# WARNING: this type check should be removed once we regulp our data
# so that classes are ints in the metadata json
Expand All @@ -70,6 +76,7 @@ def label(self):

@property
def num_frames(self) -> int:
"""Number of video frames"""
return self.metadata["num_frames"]

def __getitem__(self, item):
Expand All @@ -90,39 +97,38 @@ def __repr__(self):


class EpicVideoDataset(VideoDataset):
"""VideoDataset for gulped RGB frames"""

def __init__(
self,
gulp_path: Union[Path, str],
class_type: str,
*,
with_metadata: bool = False,
class_getter: Optional[Callable[[Dict[str, Any]], Any]] = None,
segment_filter: Optional[Callable[[VideoSegment], bool]] = None,
sample_transform: Optional[
Callable[[List[PIL.Image.Image]], List[PIL.Image.Image]]
] = None
class_getter: Optional[ClassGetter] = None,
segment_filter: Optional[SegmentFilter] = None,
sample_transform: Optional[VideoTransform] = None
) -> None:
"""
Args:
gulp_path: Path to gulp directory containing the gulped EPIC RGB or flow frames
class_type: One of verb, noun, verb+noun, None, determines what label the segment
returns. ``None`` should be used for loading test datasets.
with_metadata: When True the segments will yield a tuple (metadata, class) where the
class is defined by the class getter and the metadata is the raw dictionary stored
in the gulp file.
Parameters
----------
gulp_path
Path to gulp directory containing the gulped EPIC RGB or flow frames
class_type
One of verb, noun, verb+noun, None, determines what label the segment returns.
None should be used for loading test datasets
with_metadata
When True the segments will yield a tuple (metadata, class) where the class is defined by the
class getter and the metadata is the raw dictionary stored in the gulp file.
class_getter
Optionally provide a callable that takes in the gulp dict representing the segment from which
you should return the class you wish the segment to have
segment_filter
Optionally provide a callable that takes a segment and returns True if you want to keep the
segment in the dataset, or False if you wish to exclude it
sample_transform
Optionally provide a sample transform function which takes a list of PIL images and transforms
each of them. This is applied on the frames just before returning from load_frames
class_getter: Optionally provide a callable that takes in the gulp dict representing the
segment from which you should return the class you wish the segment to have.
segment_filter: Optionally provide a callable that takes a segment and returns True if
you want to keep the segment in the dataset, or False if you wish to exclude it.
sample_transform: Optionally provide a sample transform function which takes a list of
PIL images and transforms each of them. This is applied on the frames just before
returning from :meth:`load_frames`.
"""
super().__init__(
_class_count[class_type],
Expand All @@ -144,11 +150,26 @@ class getter and the metadata is the raw dictionary stored in the gulp file.

@property
def video_segments(self) -> List[VideoSegment]:
"""
List of video segments that are present in the dataset. The describe the start and stop
times of the clip and its class.
"""
return list(self._video_segments.values())

def load_frames(
self, segment: VideoSegment, indices: Optional[Iterable[int]] = None
) -> List[PIL.Image.Image]:
"""
Load frame(s) from gulp directory.
Args:
segment: Video segment to load
indices: Frames indices to read
Returns:
Frames indexed by ``indices`` from the ``segment``.
"""
if indices is None:
indices = range(0, segment.num_frames)
selected_frames = [] # type: List[PIL.Image.Image]
Expand Down Expand Up @@ -189,6 +210,11 @@ def _sample_video_at_index(


class EpicVideoFlowDataset(EpicVideoDataset):
"""VideoDataset for loading gulped flow. The loader assumes that flow :math:`u`, :math:`v`
frames are stored alternately in a flat manner: :math:`[u_0, v_0, u_1, v_1, \ldots, u_n, v_n]`
"""

def _sample_video_at_index(
self, record: VideoSegment, index: int
) -> List[PIL.Image.Image]:
Expand Down
2 changes: 1 addition & 1 deletion epic_kitchens/dataset/video_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class VideoDataset(ABC):
A dataset interface for use with :class:`TsnDataset`. Implement this interface if you
wish to use your dataset with TSN.
We cannot use torch.utils.data.Dataset because we need to yield information about
We cannot use :class:`torch.utils.data.Dataset` because we need to yield information about
the number of frames per video, which we can't do with the standard
torch.utils.data.Dataset.
"""
Expand Down
2 changes: 1 addition & 1 deletion epic_kitchens/gulp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
""" Dataset Adapters for GulpIO.
This module contains two adapters for 'gulping' both RGB and flow frames
which can then be used with the ``EpicVideoDataset`` classes.
which can then be used with the :class:`EpicVideoDataset` classes.
"""

from . import adapter
58 changes: 31 additions & 27 deletions epic_kitchens/gulp/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,38 @@ def __init__(
self,
video_segment_dir: str,
annotations_df: pd.DataFrame,
frame_size=-1,
extension="jpg",
labelled=True,
frame_size: int = -1,
extension: str = "jpg",
labelled: bool = True,
) -> None:
""" Gulp all action segments in ``annotations_df`` reading the dumped frames from
``video_segment_dir``
Args:
video_segment_dir: Root directory containing segmented frames::
frame-segments/
├── P01
│   ├── P01_01
│   | ├── P01_01_0_open-door
│   | | ├── frame_0000000008.jpg
│   | | ...
│   | | ├── frame_0000000202.jpg
│   | ...
│   | ├── P01_01_329_put-down-plate
│   | | ├── frame_0000098424.jpg
│   | | ...
│   | | ├── frame_0000098501.jpg
│   ...
annotations_df: DataFrame containing labels to be gulped.
frame_size (optional): Size of shortest edge of the frame, if not already this size then it will
video_segment_dir:
Root directory containing segmented frames::
frame-segments/
├── P01
│   ├── P01_01
│   | ├── P01_01_0_open-door
│   | | ├── frame_0000000008.jpg
│   | | ...
│   | | ├── frame_0000000202.jpg
│   | ...
│   | ├── P01_01_329_put-down-plate
│   | | ├── frame_0000098424.jpg
│   | | ...
│   | | ├── frame_0000098501.jpg
│   ...
annotations_df:
DataFrame containing labels to be gulped.
frame_size:
Size of shortest edge of the frame, if not already this size then it will
be resized.
extension (optional): Extension of dumped frames.
extension:
Extension of dumped frames.
"""
self.video_segment_dir = video_segment_dir
self.frame_size = int(frame_size)
Expand All @@ -66,11 +70,12 @@ def iter_data(self, slice_element=None) -> Iterator[Result]:
Args:
slice_element (optional): If not specified all frames for the segment will be returned
Returns:
dictionary with the fields:
Yields:
dict: dictionary with the fields
* ``meta``: All metadata corresponding to the segment, this is the same as the data
in the labels csv
* ``frames``: list of :py:class:`PIL.Image` corresponding to the frames specified
* ``frames``: list of :class:`PIL.Image.Image` corresponding to the frames specified
in ``slice_element``
* ``id``: UID corresponding to segment
"""
Expand Down Expand Up @@ -128,8 +133,7 @@ def _find_frames(self, folder):


class EpicFlowDatasetAdapter(EpicDatasetAdapter):
"""Gulp Dataset Adapter for Gulping flow frames extracted from the EPIC-KITCHENS dataset
"""
"""Gulp Dataset Adapter for Gulping flow frames extracted from the EPIC-KITCHENS dataset"""

def iter_data(self, slice_element=None):
slice_element = slice_element or slice(0, len(self))
Expand Down
Loading

0 comments on commit c8cc5a4

Please sign in to comment.