We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Lightly download does not work with videos
`lightly-download` does not work when trying to copy frames from an `input_dir` containing videos.

**Feedback:** It copies all the images to an output folder. The file names are correct, but the images are not the right ones.
Does this only work if I work with single images? Then I just convert them


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lightly/data/dataset.py`
Content:
```
1 """ Lightly Dataset """
2 
3 # Copyright (c) 2020. Lightly AG and its affiliates.
4 # All Rights Reserved
5 
6 import os
7 import shutil
8 import tempfile
9 
10 import PIL.Image
11 from PIL import Image
12 from typing import List, Union, Callable
13 
14 import torch.utils.data as data
15 import torchvision.datasets as datasets
16 from torchvision import transforms
17 
18 from lightly.data._helpers import _load_dataset
19 from lightly.data._helpers import DatasetFolder
20 from lightly.data._video import VideoDataset
21 from lightly.utils.io import check_filenames
22 
23 
24 def _get_filename_by_index(dataset, index):
25     """Default function which maps the index of an image to a filename.
26 
27     """
28     if isinstance(dataset, datasets.ImageFolder):
29         # filename is the path of the image relative to the dataset root
30         full_path = dataset.imgs[index][0]
31         return os.path.relpath(full_path, dataset.root)
32     elif isinstance(dataset, DatasetFolder):
33         # filename is the path of the image relative to the dataset root
34         full_path = dataset.samples[index][0]
35         return os.path.relpath(full_path, dataset.root)
36     elif isinstance(dataset, VideoDataset):
37         # filename is constructed by the video dataset
38         return dataset.get_filename(index)
39     else:
40         # dummy to prevent crashes
41         return str(index)
42 
43 
44 def _ensure_dir(path):
45     """Makes sure that the directory at path exists.
46 
47     """
48     dirname = os.path.dirname(path)
49     os.makedirs(dirname, exist_ok=True)
50 
51 
52 def _copy_image(input_dir, output_dir, filename):
53     """Copies an image from the input directory to the output directory.
54 
55     """
56     source = os.path.join(input_dir, filename)
57     target = os.path.join(output_dir, filename)
58     _ensure_dir(target)
59     shutil.copyfile(source, target)
60 
61 
62 def _save_image(image, output_dir, filename, fmt):
63     """Saves an image in the output directory.
64 
65     """
66     target = os.path.join(output_dir, filename)
67     _ensure_dir(target)
68     try:
69         # try to save the image with the specified format or
70         # derive the format from the filename (if format=None)
71         image.save(target, format=fmt)
72     except ValueError:
73         # could not determine format from filename
74         image.save(target, format='png')
75 
76 
77 def _dump_image(dataset, output_dir, filename, index, fmt):
78     """Saves a single image to the output directory.
79 
80     Will copy the image from the input directory to the output directory
81     if possible. If not (e.g. for VideoDatasets), will load the image and
82     then save it to the output directory with the specified format.
83 
84     """
85 
86     if isinstance(dataset, datasets.ImageFolder):
87         # can safely copy the image from the input to the output directory
88         _copy_image(dataset.root, output_dir, filename)
89     elif isinstance(dataset, DatasetFolder):
90         # can safely copy the image from the input to the output directory
91         _copy_image(dataset.root, output_dir, filename)
92     else:
93         # need to load the image and save it to the output directory
94         image, _ = dataset[index]
95         _save_image(image, output_dir, filename, fmt)
96 
97 
98 class LightlyDataset:
99     """Provides a uniform data interface for the embedding models.
100 
101     Should be used for all models and functions in the lightly package.
102     Returns a tuple (sample, target, fname) when accessed using __getitem__.
103 
104     The LightlyDataset supports different input sources. You can use it
105     on a folder of images. You can also use it on a folder with subfolders
106     with images (ImageNet style). If the input_dir has subfolders each subfolder
107     gets its own target label. You can also work with videos (requires pyav).
108     If there are multiple videos in the input_dir each video gets a different
109     target label assigned. If input_dir contains images and videos
110     only the videos are used.
111 
112     Can also be used in combination with the `from_torch_dataset` method
113     to load a dataset offered by torchvision (e.g. cifar10).
114 
115     Args:
116         input_dir:
117             Path to directory holding the images or videos to load.
118         transform:
119             Image transforms (as in torchvision).
120         index_to_filename:
121             Function which takes the dataset and index as input and returns
122             the filename of the file at the index. If None, uses default.
123 
124     Examples:
125         >>> # load a dataset consisting of images from a local folder
126         >>> # mydata/
127         >>> # `- img1.png
128         >>> # `- img2.png
129         >>> # `- ...
130         >>> import lightly.data as data
131         >>> dataset = data.LightlyDataset(input_dir='path/to/mydata/')
132         >>> sample, target, fname = dataset[0]
133         >>>
134         >>> # also works with subfolders
135         >>> # mydata/
136         >>> # `- subfolder1
137         >>> #     `- img1.png
138         >>> # `- subfolder2
139         >>> # ...
140         >>>
141         >>> # also works with videos
142         >>> # mydata/
143         >>> # `- video1.mp4
144         >>> # `- video2.mp4
145         >>> # `- ...
146     """
147 
148     def __init__(self,
149                  input_dir: str,
150                  transform: transforms.Compose = None,
151                  index_to_filename: Callable[[datasets.VisionDataset, int], str] = None):
152 
153         # can pass input_dir=None to create an "empty" dataset
154         self.input_dir = input_dir
155         if self.input_dir is not None:
156             self.dataset = _load_dataset(self.input_dir, transform)
157 
158         # initialize function to get filename of image
159         self.index_to_filename = _get_filename_by_index
160         if index_to_filename is not None:
161             self.index_to_filename = index_to_filename
162 
163         # if created from an input directory with filenames, check if they
164         # are valid
165         if input_dir:
166             check_filenames(self.get_filenames())
167 
168     @classmethod
169     def from_torch_dataset(cls,
170                            dataset,
171                            transform=None,
172                            index_to_filename=None):
173         """Builds a LightlyDataset from a PyTorch (or torchvision) dataset.
174 
175         Args:
176             dataset:
177                 PyTorch/torchvision dataset.
178             transform:
179                 Image transforms (as in torchvision).
180             index_to_filename:
181                 Function which takes the dataset and index as input and returns
182                 the filename of the file at the index. If None, uses default.
183 
184         Returns:
185             A LightlyDataset object.
186 
187         Examples:
188             >>> # load cifar10 from torchvision
189             >>> import torchvision
190             >>> import lightly.data as data
191             >>> base = torchvision.datasets.CIFAR10(root='./')
192             >>> dataset = data.LightlyDataset.from_torch_dataset(base)
193 
194         """
195         # create an "empty" dataset object
196         dataset_obj = cls(
197             None,
198             transform=transform,
199             index_to_filename=index_to_filename
200         )
201 
202         # populate it with the torch dataset
203         dataset_obj.dataset = dataset
204         return dataset_obj
205 
206     def __getitem__(self, index: int):
207         """Returns (sample, target, fname) of item at index.
208 
209         Args:
210             index:
211                 Index of the queried item.
212 
213         Returns:
214             The image, target, and filename of the item at index.
215 
216         """
217         fname = self.index_to_filename(self.dataset, index)
218         sample, target = self.dataset.__getitem__(index)
219 
220         return sample, target, fname
221 
222     def __len__(self):
223         """Returns the length of the dataset.
224 
225         """
226         return len(self.dataset)
227 
228     def __add__(self, other):
229         """Adds another item to the dataset.
230 
231         """
232         raise NotImplementedError()
233 
234     def get_filenames(self) -> List[str]:
235         """Returns all filenames in the dataset.
236 
237         """
238         list_of_filenames = []
239         for index in range(len(self)):
240             fname = self.index_to_filename(self.dataset, index)
241             list_of_filenames.append(fname)
242         return list_of_filenames
243 
244     def dump(self,
245              output_dir: str,
246              filenames: Union[List[str], None] = None,
247              format: Union[str, None] = None):
248         """Saves images in the dataset to the output directory.
249 
250         Will copy the images from the input directory to the output directory
251         if possible. If not (e.g. for VideoDatasets), will load the images and
252         then save them to the output directory with the specified format.
253 
254         Args:
255             output_dir:
256                 Output directory where the image is stored.
257             filenames:
258                 Filenames of the images to store. If None, stores all images.
259             format:
260                 Image format. Can be any pillow image format (png, jpg, ...).
261                 By default we try to use the same format as the input data. If
262                 not possible (e.g. for videos) we dump the image 
263                 as a png image to prevent compression artifacts.
264 
265         """
266 
267         if self.dataset.transform is not None:
268             raise RuntimeError('Cannot dump dataset which applies transforms!')
269 
270         # create directory if it doesn't exist yet
271         os.makedirs(output_dir, exist_ok=True)
272 
273         # dump all the files if no filenames were passed, otherwise dump only
274         # the ones referenced in the list
275         if filenames is None:
276             indices = [i for i in range(self.__len__())]
277             filenames = self.get_filenames()
278         else:
279             indices = []
280             all_filenames = self.get_filenames()
281             for i in range(len(filenames)):
282                 if filenames[i] in all_filenames:
283                     indices.append(i)
284 
285         # dump images
286         for i, filename in zip(indices, filenames):
287             _dump_image(self.dataset, output_dir, filename, i, fmt=format)
288 
289     def get_filepath_from_filename(self, filename: str, image: PIL.Image.Image = None):
290         """Returns the filepath given the filename of the image
291 
292         There are three cases:
293         - The dataset is a regular dataset with the images in the input dir.
294         - The dataset is a video dataset, thus the images have to be saved in a temporary folder.
295         - The dataset is a torch dataset, thus the images have to be saved in a temporary folder.
296         Args:
297             filename:
298                 The filename of the image
299             image:
300                 The image corresponding to the filename
301 
302         Returns:
303             The filename to the image, either the exiting one (case 1) or a newly created jpg (case 2, 3)
304 
305         """
306 
307         has_input_dir = hasattr(self, 'input_dir') and isinstance(self.input_dir, str)
308         if has_input_dir:
309             path_to_image = os.path.join(self.input_dir, filename)
310             if os.path.isfile(path_to_image):
311                 # Case 1
312                 return path_to_image
313 
314         if image is None:
315             raise ValueError("The parameter image must not be None for VideoDatasets and TorchDatasets")
316 
317         # Case 2 and 3
318         folder_path = tempfile.mkdtemp()
319         filepath = os.path.join(folder_path,filename) + '.jpg'
320         image.save(filepath)
321         return filepath
322 
323 
324     @property
325     def transform(self):
326         """Getter for the transform of the dataset.
327 
328         """
329         return self.dataset.transform
330 
331     @transform.setter
332     def transform(self, t):
333         """Setter for the transform of the dataset.
334 
335         """
336         self.dataset.transform = t
337
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lightly/data/dataset.py b/lightly/data/dataset.py
--- a/lightly/data/dataset.py
+++ b/lightly/data/dataset.py
@@ -4,6 +4,7 @@
 # All Rights Reserved
 
 import os
+import bisect
 import shutil
 import tempfile
 
@@ -277,10 +278,14 @@
             filenames = self.get_filenames()
         else:
             indices = []
+            filenames = sorted(filenames)
             all_filenames = self.get_filenames()
-            for i in range(len(filenames)):
-                if filenames[i] in all_filenames:
-                    indices.append(i)
+            for index, filename in enumerate(all_filenames):
+                filename_index = bisect.bisect_left(filenames, filename)
+                # make sure the filename exists in filenames
+                if filename_index < len(filenames) and \
+                    filenames[filename_index] == filename:
+                    indices.append(index)
 
         # dump images
         for i, filename in zip(indices, filenames):

{"golden_diff": "diff --git a/lightly/data/dataset.py b/lightly/data/dataset.py\n--- a/lightly/data/dataset.py\n+++ b/lightly/data/dataset.py\n@@ -4,6 +4,7 @@\n # All Rights Reserved\n \n import os\n+import bisect\n import shutil\n import tempfile\n \n@@ -277,10 +278,14 @@\n             filenames = self.get_filenames()\n         else:\n             indices = []\n+            filenames = sorted(filenames)\n             all_filenames = self.get_filenames()\n-            for i in range(len(filenames)):\n-                if filenames[i] in all_filenames:\n-                    indices.append(i)\n+            for index, filename in enumerate(all_filenames):\n+                filename_index = bisect.bisect_left(filenames, filename)\n+                # make sure the filename exists in filenames\n+                if filename_index < len(filenames) and \\\n+                    filenames[filename_index] == filename:\n+                    indices.append(index)\n \n         # dump images\n         for i, filename in zip(indices, filenames):\n", "issue": "Lightly download does not work with videos\n`lightly-download` does not work when trying to copy frames from an `input_dir` containing videos.\r\n\r\n**Feedback:** It copies all the images to an output folder. The file names are correct, but the images are not the right ones.\r\nDoes this only work if I work with single images? Then I just convert them\r\n\n", "before_files": [{"content": "\"\"\" Lightly Dataset \"\"\"\n\n# Copyright (c) 2020. Lightly AG and its affiliates.\n# All Rights Reserved\n\nimport os\nimport shutil\nimport tempfile\n\nimport PIL.Image\nfrom PIL import Image\nfrom typing import List, Union, Callable\n\nimport torch.utils.data as data\nimport torchvision.datasets as datasets\nfrom torchvision import transforms\n\nfrom lightly.data._helpers import _load_dataset\nfrom lightly.data._helpers import DatasetFolder\nfrom lightly.data._video import VideoDataset\nfrom lightly.utils.io import check_filenames\n\n\ndef _get_filename_by_index(dataset, index):\n    \"\"\"Default function which maps the index of an image to a filename.\n\n    \"\"\"\n    if isinstance(dataset, datasets.ImageFolder):\n        # filename is the path of the image relative to the dataset root\n        full_path = dataset.imgs[index][0]\n        return os.path.relpath(full_path, dataset.root)\n    elif isinstance(dataset, DatasetFolder):\n        # filename is the path of the image relative to the dataset root\n        full_path = dataset.samples[index][0]\n        return os.path.relpath(full_path, dataset.root)\n    elif isinstance(dataset, VideoDataset):\n        # filename is constructed by the video dataset\n        return dataset.get_filename(index)\n    else:\n        # dummy to prevent crashes\n        return str(index)\n\n\ndef _ensure_dir(path):\n    \"\"\"Makes sure that the directory at path exists.\n\n    \"\"\"\n    dirname = os.path.dirname(path)\n    os.makedirs(dirname, exist_ok=True)\n\n\ndef _copy_image(input_dir, output_dir, filename):\n    \"\"\"Copies an image from the input directory to the output directory.\n\n    \"\"\"\n    source = os.path.join(input_dir, filename)\n    target = os.path.join(output_dir, filename)\n    _ensure_dir(target)\n    shutil.copyfile(source, target)\n\n\ndef _save_image(image, output_dir, filename, fmt):\n    \"\"\"Saves an image in the output directory.\n\n    \"\"\"\n    target = os.path.join(output_dir, filename)\n    _ensure_dir(target)\n    try:\n        # try to save the image with the specified format or\n        # derive the format from the filename (if format=None)\n        image.save(target, format=fmt)\n    except ValueError:\n        # could not determine format from filename\n        image.save(target, format='png')\n\n\ndef _dump_image(dataset, output_dir, filename, index, fmt):\n    \"\"\"Saves a single image to the output directory.\n\n    Will copy the image from the input directory to the output directory\n    if possible. If not (e.g. for VideoDatasets), will load the image and\n    then save it to the output directory with the specified format.\n\n    \"\"\"\n\n    if isinstance(dataset, datasets.ImageFolder):\n        # can safely copy the image from the input to the output directory\n        _copy_image(dataset.root, output_dir, filename)\n    elif isinstance(dataset, DatasetFolder):\n        # can safely copy the image from the input to the output directory\n        _copy_image(dataset.root, output_dir, filename)\n    else:\n        # need to load the image and save it to the output directory\n        image, _ = dataset[index]\n        _save_image(image, output_dir, filename, fmt)\n\n\nclass LightlyDataset:\n    \"\"\"Provides a uniform data interface for the embedding models.\n\n    Should be used for all models and functions in the lightly package.\n    Returns a tuple (sample, target, fname) when accessed using __getitem__.\n\n    The LightlyDataset supports different input sources. You can use it\n    on a folder of images. You can also use it on a folder with subfolders\n    with images (ImageNet style). If the input_dir has subfolders each subfolder\n    gets its own target label. You can also work with videos (requires pyav).\n    If there are multiple videos in the input_dir each video gets a different\n    target label assigned. If input_dir contains images and videos\n    only the videos are used.\n\n    Can also be used in combination with the `from_torch_dataset` method\n    to load a dataset offered by torchvision (e.g. cifar10).\n\n    Args:\n        input_dir:\n            Path to directory holding the images or videos to load.\n        transform:\n            Image transforms (as in torchvision).\n        index_to_filename:\n            Function which takes the dataset and index as input and returns\n            the filename of the file at the index. If None, uses default.\n\n    Examples:\n        >>> # load a dataset consisting of images from a local folder\n        >>> # mydata/\n        >>> # `- img1.png\n        >>> # `- img2.png\n        >>> # `- ...\n        >>> import lightly.data as data\n        >>> dataset = data.LightlyDataset(input_dir='path/to/mydata/')\n        >>> sample, target, fname = dataset[0]\n        >>>\n        >>> # also works with subfolders\n        >>> # mydata/\n        >>> # `- subfolder1\n        >>> #     `- img1.png\n        >>> # `- subfolder2\n        >>> # ...\n        >>>\n        >>> # also works with videos\n        >>> # mydata/\n        >>> # `- video1.mp4\n        >>> # `- video2.mp4\n        >>> # `- ...\n    \"\"\"\n\n    def __init__(self,\n                 input_dir: str,\n                 transform: transforms.Compose = None,\n                 index_to_filename: Callable[[datasets.VisionDataset, int], str] = None):\n\n        # can pass input_dir=None to create an \"empty\" dataset\n        self.input_dir = input_dir\n        if self.input_dir is not None:\n            self.dataset = _load_dataset(self.input_dir, transform)\n\n        # initialize function to get filename of image\n        self.index_to_filename = _get_filename_by_index\n        if index_to_filename is not None:\n            self.index_to_filename = index_to_filename\n\n        # if created from an input directory with filenames, check if they\n        # are valid\n        if input_dir:\n            check_filenames(self.get_filenames())\n\n    @classmethod\n    def from_torch_dataset(cls,\n                           dataset,\n                           transform=None,\n                           index_to_filename=None):\n        \"\"\"Builds a LightlyDataset from a PyTorch (or torchvision) dataset.\n\n        Args:\n            dataset:\n                PyTorch/torchvision dataset.\n            transform:\n                Image transforms (as in torchvision).\n            index_to_filename:\n                Function which takes the dataset and index as input and returns\n                the filename of the file at the index. If None, uses default.\n\n        Returns:\n            A LightlyDataset object.\n\n        Examples:\n            >>> # load cifar10 from torchvision\n            >>> import torchvision\n            >>> import lightly.data as data\n            >>> base = torchvision.datasets.CIFAR10(root='./')\n            >>> dataset = data.LightlyDataset.from_torch_dataset(base)\n\n        \"\"\"\n        # create an \"empty\" dataset object\n        dataset_obj = cls(\n            None,\n            transform=transform,\n            index_to_filename=index_to_filename\n        )\n\n        # populate it with the torch dataset\n        dataset_obj.dataset = dataset\n        return dataset_obj\n\n    def __getitem__(self, index: int):\n        \"\"\"Returns (sample, target, fname) of item at index.\n\n        Args:\n            index:\n                Index of the queried item.\n\n        Returns:\n            The image, target, and filename of the item at index.\n\n        \"\"\"\n        fname = self.index_to_filename(self.dataset, index)\n        sample, target = self.dataset.__getitem__(index)\n\n        return sample, target, fname\n\n    def __len__(self):\n        \"\"\"Returns the length of the dataset.\n\n        \"\"\"\n        return len(self.dataset)\n\n    def __add__(self, other):\n        \"\"\"Adds another item to the dataset.\n\n        \"\"\"\n        raise NotImplementedError()\n\n    def get_filenames(self) -> List[str]:\n        \"\"\"Returns all filenames in the dataset.\n\n        \"\"\"\n        list_of_filenames = []\n        for index in range(len(self)):\n            fname = self.index_to_filename(self.dataset, index)\n            list_of_filenames.append(fname)\n        return list_of_filenames\n\n    def dump(self,\n             output_dir: str,\n             filenames: Union[List[str], None] = None,\n             format: Union[str, None] = None):\n        \"\"\"Saves images in the dataset to the output directory.\n\n        Will copy the images from the input directory to the output directory\n        if possible. If not (e.g. for VideoDatasets), will load the images and\n        then save them to the output directory with the specified format.\n\n        Args:\n            output_dir:\n                Output directory where the image is stored.\n            filenames:\n                Filenames of the images to store. If None, stores all images.\n            format:\n                Image format. Can be any pillow image format (png, jpg, ...).\n                By default we try to use the same format as the input data. If\n                not possible (e.g. for videos) we dump the image \n                as a png image to prevent compression artifacts.\n\n        \"\"\"\n\n        if self.dataset.transform is not None:\n            raise RuntimeError('Cannot dump dataset which applies transforms!')\n\n        # create directory if it doesn't exist yet\n        os.makedirs(output_dir, exist_ok=True)\n\n        # dump all the files if no filenames were passed, otherwise dump only\n        # the ones referenced in the list\n        if filenames is None:\n            indices = [i for i in range(self.__len__())]\n            filenames = self.get_filenames()\n        else:\n            indices = []\n            all_filenames = self.get_filenames()\n            for i in range(len(filenames)):\n                if filenames[i] in all_filenames:\n                    indices.append(i)\n\n        # dump images\n        for i, filename in zip(indices, filenames):\n            _dump_image(self.dataset, output_dir, filename, i, fmt=format)\n\n    def get_filepath_from_filename(self, filename: str, image: PIL.Image.Image = None):\n        \"\"\"Returns the filepath given the filename of the image\n\n        There are three cases:\n        - The dataset is a regular dataset with the images in the input dir.\n        - The dataset is a video dataset, thus the images have to be saved in a temporary folder.\n        - The dataset is a torch dataset, thus the images have to be saved in a temporary folder.\n        Args:\n            filename:\n                The filename of the image\n            image:\n                The image corresponding to the filename\n\n        Returns:\n            The filename to the image, either the exiting one (case 1) or a newly created jpg (case 2, 3)\n\n        \"\"\"\n\n        has_input_dir = hasattr(self, 'input_dir') and isinstance(self.input_dir, str)\n        if has_input_dir:\n            path_to_image = os.path.join(self.input_dir, filename)\n            if os.path.isfile(path_to_image):\n                # Case 1\n                return path_to_image\n\n        if image is None:\n            raise ValueError(\"The parameter image must not be None for VideoDatasets and TorchDatasets\")\n\n        # Case 2 and 3\n        folder_path = tempfile.mkdtemp()\n        filepath = os.path.join(folder_path,filename) + '.jpg'\n        image.save(filepath)\n        return filepath\n\n\n    @property\n    def transform(self):\n        \"\"\"Getter for the transform of the dataset.\n\n        \"\"\"\n        return self.dataset.transform\n\n    @transform.setter\n    def transform(self, t):\n        \"\"\"Setter for the transform of the dataset.\n\n        \"\"\"\n        self.dataset.transform = t\n", "path": "lightly/data/dataset.py"}], "after_files": [{"content": "\"\"\" Lightly Dataset \"\"\"\n\n# Copyright (c) 2020. Lightly AG and its affiliates.\n# All Rights Reserved\n\nimport os\nimport bisect\nimport shutil\nimport tempfile\n\nimport PIL.Image\nfrom PIL import Image\nfrom typing import List, Union, Callable\n\nimport torch.utils.data as data\nimport torchvision.datasets as datasets\nfrom torchvision import transforms\n\nfrom lightly.data._helpers import _load_dataset\nfrom lightly.data._helpers import DatasetFolder\nfrom lightly.data._video import VideoDataset\nfrom lightly.utils.io import check_filenames\n\n\ndef _get_filename_by_index(dataset, index):\n    \"\"\"Default function which maps the index of an image to a filename.\n\n    \"\"\"\n    if isinstance(dataset, datasets.ImageFolder):\n        # filename is the path of the image relative to the dataset root\n        full_path = dataset.imgs[index][0]\n        return os.path.relpath(full_path, dataset.root)\n    elif isinstance(dataset, DatasetFolder):\n        # filename is the path of the image relative to the dataset root\n        full_path = dataset.samples[index][0]\n        return os.path.relpath(full_path, dataset.root)\n    elif isinstance(dataset, VideoDataset):\n        # filename is constructed by the video dataset\n        return dataset.get_filename(index)\n    else:\n        # dummy to prevent crashes\n        return str(index)\n\n\ndef _ensure_dir(path):\n    \"\"\"Makes sure that the directory at path exists.\n\n    \"\"\"\n    dirname = os.path.dirname(path)\n    os.makedirs(dirname, exist_ok=True)\n\n\ndef _copy_image(input_dir, output_dir, filename):\n    \"\"\"Copies an image from the input directory to the output directory.\n\n    \"\"\"\n    source = os.path.join(input_dir, filename)\n    target = os.path.join(output_dir, filename)\n    _ensure_dir(target)\n    shutil.copyfile(source, target)\n\n\ndef _save_image(image, output_dir, filename, fmt):\n    \"\"\"Saves an image in the output directory.\n\n    \"\"\"\n    target = os.path.join(output_dir, filename)\n    _ensure_dir(target)\n    try:\n        # try to save the image with the specified format or\n        # derive the format from the filename (if format=None)\n        image.save(target, format=fmt)\n    except ValueError:\n        # could not determine format from filename\n        image.save(target, format='png')\n\n\ndef _dump_image(dataset, output_dir, filename, index, fmt):\n    \"\"\"Saves a single image to the output directory.\n\n    Will copy the image from the input directory to the output directory\n    if possible. If not (e.g. for VideoDatasets), will load the image and\n    then save it to the output directory with the specified format.\n\n    \"\"\"\n\n    if isinstance(dataset, datasets.ImageFolder):\n        # can safely copy the image from the input to the output directory\n        _copy_image(dataset.root, output_dir, filename)\n    elif isinstance(dataset, DatasetFolder):\n        # can safely copy the image from the input to the output directory\n        _copy_image(dataset.root, output_dir, filename)\n    else:\n        # need to load the image and save it to the output directory\n        image, _ = dataset[index]\n        _save_image(image, output_dir, filename, fmt)\n\n\nclass LightlyDataset:\n    \"\"\"Provides a uniform data interface for the embedding models.\n\n    Should be used for all models and functions in the lightly package.\n    Returns a tuple (sample, target, fname) when accessed using __getitem__.\n\n    The LightlyDataset supports different input sources. You can use it\n    on a folder of images. You can also use it on a folder with subfolders\n    with images (ImageNet style). If the input_dir has subfolders each subfolder\n    gets its own target label. You can also work with videos (requires pyav).\n    If there are multiple videos in the input_dir each video gets a different\n    target label assigned. If input_dir contains images and videos\n    only the videos are used.\n\n    Can also be used in combination with the `from_torch_dataset` method\n    to load a dataset offered by torchvision (e.g. cifar10).\n\n    Args:\n        input_dir:\n            Path to directory holding the images or videos to load.\n        transform:\n            Image transforms (as in torchvision).\n        index_to_filename:\n            Function which takes the dataset and index as input and returns\n            the filename of the file at the index. If None, uses default.\n\n    Examples:\n        >>> # load a dataset consisting of images from a local folder\n        >>> # mydata/\n        >>> # `- img1.png\n        >>> # `- img2.png\n        >>> # `- ...\n        >>> import lightly.data as data\n        >>> dataset = data.LightlyDataset(input_dir='path/to/mydata/')\n        >>> sample, target, fname = dataset[0]\n        >>>\n        >>> # also works with subfolders\n        >>> # mydata/\n        >>> # `- subfolder1\n        >>> #     `- img1.png\n        >>> # `- subfolder2\n        >>> # ...\n        >>>\n        >>> # also works with videos\n        >>> # mydata/\n        >>> # `- video1.mp4\n        >>> # `- video2.mp4\n        >>> # `- ...\n    \"\"\"\n\n    def __init__(self,\n                 input_dir: str,\n                 transform: transforms.Compose = None,\n                 index_to_filename: Callable[[datasets.VisionDataset, int], str] = None):\n\n        # can pass input_dir=None to create an \"empty\" dataset\n        self.input_dir = input_dir\n        if self.input_dir is not None:\n            self.dataset = _load_dataset(self.input_dir, transform)\n\n        # initialize function to get filename of image\n        self.index_to_filename = _get_filename_by_index\n        if index_to_filename is not None:\n            self.index_to_filename = index_to_filename\n\n        # if created from an input directory with filenames, check if they\n        # are valid\n        if input_dir:\n            check_filenames(self.get_filenames())\n\n    @classmethod\n    def from_torch_dataset(cls,\n                           dataset,\n                           transform=None,\n                           index_to_filename=None):\n        \"\"\"Builds a LightlyDataset from a PyTorch (or torchvision) dataset.\n\n        Args:\n            dataset:\n                PyTorch/torchvision dataset.\n            transform:\n                Image transforms (as in torchvision).\n            index_to_filename:\n                Function which takes the dataset and index as input and returns\n                the filename of the file at the index. If None, uses default.\n\n        Returns:\n            A LightlyDataset object.\n\n        Examples:\n            >>> # load cifar10 from torchvision\n            >>> import torchvision\n            >>> import lightly.data as data\n            >>> base = torchvision.datasets.CIFAR10(root='./')\n            >>> dataset = data.LightlyDataset.from_torch_dataset(base)\n\n        \"\"\"\n        # create an \"empty\" dataset object\n        dataset_obj = cls(\n            None,\n            transform=transform,\n            index_to_filename=index_to_filename\n        )\n\n        # populate it with the torch dataset\n        dataset_obj.dataset = dataset\n        return dataset_obj\n\n    def __getitem__(self, index: int):\n        \"\"\"Returns (sample, target, fname) of item at index.\n\n        Args:\n            index:\n                Index of the queried item.\n\n        Returns:\n            The image, target, and filename of the item at index.\n\n        \"\"\"\n        fname = self.index_to_filename(self.dataset, index)\n        sample, target = self.dataset.__getitem__(index)\n\n        return sample, target, fname\n\n    def __len__(self):\n        \"\"\"Returns the length of the dataset.\n\n        \"\"\"\n        return len(self.dataset)\n\n    def __add__(self, other):\n        \"\"\"Adds another item to the dataset.\n\n        \"\"\"\n        raise NotImplementedError()\n\n    def get_filenames(self) -> List[str]:\n        \"\"\"Returns all filenames in the dataset.\n\n        \"\"\"\n        list_of_filenames = []\n        for index in range(len(self)):\n            fname = self.index_to_filename(self.dataset, index)\n            list_of_filenames.append(fname)\n        return list_of_filenames\n\n    def dump(self,\n             output_dir: str,\n             filenames: Union[List[str], None] = None,\n             format: Union[str, None] = None):\n        \"\"\"Saves images in the dataset to the output directory.\n\n        Will copy the images from the input directory to the output directory\n        if possible. If not (e.g. for VideoDatasets), will load the images and\n        then save them to the output directory with the specified format.\n\n        Args:\n            output_dir:\n                Output directory where the image is stored.\n            filenames:\n                Filenames of the images to store. If None, stores all images.\n            format:\n                Image format. Can be any pillow image format (png, jpg, ...).\n                By default we try to use the same format as the input data. If\n                not possible (e.g. for videos) we dump the image \n                as a png image to prevent compression artifacts.\n\n        \"\"\"\n\n        if self.dataset.transform is not None:\n            raise RuntimeError('Cannot dump dataset which applies transforms!')\n\n        # create directory if it doesn't exist yet\n        os.makedirs(output_dir, exist_ok=True)\n\n        # dump all the files if no filenames were passed, otherwise dump only\n        # the ones referenced in the list\n        if filenames is None:\n            indices = [i for i in range(self.__len__())]\n            filenames = self.get_filenames()\n        else:\n            indices = []\n            filenames = sorted(filenames)\n            all_filenames = self.get_filenames()\n            for index, filename in enumerate(all_filenames):\n                filename_index = bisect.bisect_left(filenames, filename)\n                # make sure the filename exists in filenames\n                if filename_index < len(filenames) and \\\n                    filenames[filename_index] == filename:\n                    indices.append(index)\n\n        # dump images\n        for i, filename in zip(indices, filenames):\n            _dump_image(self.dataset, output_dir, filename, i, fmt=format)\n\n    def get_filepath_from_filename(self, filename: str, image: PIL.Image.Image = None):\n        \"\"\"Returns the filepath given the filename of the image\n\n        There are three cases:\n        - The dataset is a regular dataset with the images in the input dir.\n        - The dataset is a video dataset, thus the images have to be saved in a temporary folder.\n        - The dataset is a torch dataset, thus the images have to be saved in a temporary folder.\n        Args:\n            filename:\n                The filename of the image\n            image:\n                The image corresponding to the filename\n\n        Returns:\n            The filename to the image, either the exiting one (case 1) or a newly created jpg (case 2, 3)\n\n        \"\"\"\n\n        has_input_dir = hasattr(self, 'input_dir') and isinstance(self.input_dir, str)\n        if has_input_dir:\n            path_to_image = os.path.join(self.input_dir, filename)\n            if os.path.isfile(path_to_image):\n                # Case 1\n                return path_to_image\n\n        if image is None:\n            raise ValueError(\"The parameter image must not be None for VideoDatasets and TorchDatasets\")\n\n        # Case 2 and 3\n        folder_path = tempfile.mkdtemp()\n        filepath = os.path.join(folder_path,filename) + '.jpg'\n        image.save(filepath)\n        return filepath\n\n\n    @property\n    def transform(self):\n        \"\"\"Getter for the transform of the dataset.\n\n        \"\"\"\n        return self.dataset.transform\n\n    @transform.setter\n    def transform(self, t):\n        \"\"\"Setter for the transform of the dataset.\n\n        \"\"\"\n        self.dataset.transform = t\n", "path": "lightly/data/dataset.py"}]}