We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Lightly-Crop: memory leak
When using lightly-crop some users experience a memory leak.

- [ ] Try to reproduce it.
- [ ] Fix it

--- 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/utils/cropping/crop_image_by_bounding_boxes.py`
Content:
```
1 import os.path
2 import warnings
3 from pathlib import Path
4 from typing import List
5 
6 from PIL import Image
7 from tqdm import tqdm
8 
9 from lightly.active_learning.utils import BoundingBox
10 from lightly.data import LightlyDataset
11 
12 
13 def crop_image_by_bounding_boxes(image_filepath: str, bounding_boxes: List[BoundingBox]) -> List[Image.Image]:
14     image = Image.open(image_filepath)
15     cropped_images = []
16     for bbox in bounding_boxes:
17         w, h = image.size
18         crop_box = (w * bbox.x0, h * bbox.y0, w * bbox.x1, h * bbox.y1)
19         crop_box = tuple(int(i) for i in crop_box)
20         cropped_image = image.crop(crop_box)
21         cropped_images.append(cropped_image)
22     return cropped_images
23 
24 
25 def crop_dataset_by_bounding_boxes_and_save(dataset: LightlyDataset,
26                                             output_dir: str,
27                                             bounding_boxes_list_list: List[List[BoundingBox]],
28                                             class_indices_list_list: List[List[int]],
29                                             class_names: List[str] = None
30                                             ) -> List[List[str]]:
31     """Crops all images in a dataset by the bounding boxes and saves them in the output dir
32 
33     Args:
34         dataset:
35             The dataset with the images to be cropped. Must contain M images.
36         output_dir:
37             The output directory to saved the cropped images to.
38         bounding_boxes_list_list:
39             The bounding boxes of the detections for each image. Must have M sublists, one for each image.
40             Each sublist contains the bounding boxes for each detection, thus N_m elements.
41         class_indices_list_list:
42             The object class ids of the detections for each image. Must have M sublists, one for each image.
43             Each sublist contains the bounding boxes for each detection, thus N_m elements.
44         class_names:
45             The names of the classes, used to map the class id to the class name.
46 
47 
48     Returns:
49         The filepaths to all saved cropped images. Has M sublists, one for each image.
50         Each sublist contains the filepath of the crop each detection, thus N_m elements.
51 
52     """
53     filenames_images = dataset.get_filenames()
54     if len(filenames_images) != len(bounding_boxes_list_list) or len(filenames_images) != len(class_indices_list_list):
55         raise ValueError("There must be one bounding box and class index list for each image in the datasets,"
56                          "but the lengths dont align.")
57 
58     cropped_image_filepath_list_list: List[List[Image]] = []
59 
60 
61     print(f"Cropping objects out of {len(filenames_images)} images...")
62     for filename_image, class_indices, bounding_boxes in \
63             tqdm(zip(filenames_images, class_indices_list_list, bounding_boxes_list_list)):
64 
65         if not len(class_indices) == len(bounding_boxes):
66             warnings.warn(UserWarning(f"Length of class indices ({len(class_indices)} does not equal length of bounding boxes"
67                           f"({len(bounding_boxes)}. This is an error in the input arguments. "
68                           f"Skipping this image {filename_image}."))
69             continue
70 
71         filepath_image = dataset.get_filepath_from_filename(filename_image)
72         filepath_image_base, image_extension = os.path.splitext(filepath_image)
73 
74         filepath_out_dir = os.path.join(output_dir, filename_image).replace(image_extension, '')
75         Path(filepath_out_dir).mkdir(parents=True, exist_ok=True)
76 
77         cropped_images = crop_image_by_bounding_boxes(filepath_image, bounding_boxes)
78         cropped_images_filepaths = []
79         for index, (class_index, cropped_image) in enumerate((zip(class_indices, cropped_images))):
80             if class_names:
81                 class_name = class_names[class_index]
82             else:
83                 class_name = f"class{class_index}"
84             cropped_image_last_filename = f'{index}_{class_name}{image_extension}'
85             cropped_image_filepath = os.path.join(filepath_out_dir, cropped_image_last_filename)
86             cropped_image.save(cropped_image_filepath)
87 
88             cropped_image_filename = os.path.join(filename_image.replace(image_extension, ''), cropped_image_last_filename)
89             cropped_images_filepaths.append(cropped_image_filename)
90 
91         cropped_image_filepath_list_list.append(cropped_images_filepaths)
92 
93     return cropped_image_filepath_list_list
94
```
--- 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/utils/cropping/crop_image_by_bounding_boxes.py b/lightly/utils/cropping/crop_image_by_bounding_boxes.py
--- a/lightly/utils/cropping/crop_image_by_bounding_boxes.py
+++ b/lightly/utils/cropping/crop_image_by_bounding_boxes.py
@@ -10,18 +10,6 @@
 from lightly.data import LightlyDataset
 
 
-def crop_image_by_bounding_boxes(image_filepath: str, bounding_boxes: List[BoundingBox]) -> List[Image.Image]:
-    image = Image.open(image_filepath)
-    cropped_images = []
-    for bbox in bounding_boxes:
-        w, h = image.size
-        crop_box = (w * bbox.x0, h * bbox.y0, w * bbox.x1, h * bbox.y1)
-        crop_box = tuple(int(i) for i in crop_box)
-        cropped_image = image.crop(crop_box)
-        cropped_images.append(cropped_image)
-    return cropped_images
-
-
 def crop_dataset_by_bounding_boxes_and_save(dataset: LightlyDataset,
                                             output_dir: str,
                                             bounding_boxes_list_list: List[List[BoundingBox]],
@@ -55,7 +43,7 @@
         raise ValueError("There must be one bounding box and class index list for each image in the datasets,"
                          "but the lengths dont align.")
 
-    cropped_image_filepath_list_list: List[List[Image]] = []
+    cropped_image_filepath_list_list: List[List[str]] = []
 
 
     print(f"Cropping objects out of {len(filenames_images)} images...")
@@ -71,21 +59,38 @@
         filepath_image = dataset.get_filepath_from_filename(filename_image)
         filepath_image_base, image_extension = os.path.splitext(filepath_image)
 
-        filepath_out_dir = os.path.join(output_dir, filename_image).replace(image_extension, '')
+        filepath_out_dir = os.path.join(output_dir, filename_image)\
+            .replace(image_extension, '')
         Path(filepath_out_dir).mkdir(parents=True, exist_ok=True)
 
-        cropped_images = crop_image_by_bounding_boxes(filepath_image, bounding_boxes)
+        image = Image.open(filepath_image)
+        
         cropped_images_filepaths = []
-        for index, (class_index, cropped_image) in enumerate((zip(class_indices, cropped_images))):
+        # For every image, crop out multiple cropped images, one for each
+        # bounding box
+        for index, (class_index, bbox) in \
+                enumerate((zip(class_indices, bounding_boxes))):
+
+            # determine the filename and filepath of the cropped image
             if class_names:
                 class_name = class_names[class_index]
             else:
                 class_name = f"class{class_index}"
             cropped_image_last_filename = f'{index}_{class_name}{image_extension}'
             cropped_image_filepath = os.path.join(filepath_out_dir, cropped_image_last_filename)
+
+            # crop out the image and save it
+            w, h = image.size
+            crop_box = (w * bbox.x0, h * bbox.y0, w * bbox.x1, h * bbox.y1)
+            crop_box = tuple(int(i) for i in crop_box)
+            cropped_image = image.crop(crop_box)
             cropped_image.save(cropped_image_filepath)
 
-            cropped_image_filename = os.path.join(filename_image.replace(image_extension, ''), cropped_image_last_filename)
+            # add the filename of the cropped image to the corresponding list
+            cropped_image_filename: str = os.path.join(
+                filename_image.replace(image_extension, ''),
+                cropped_image_last_filename
+            )
             cropped_images_filepaths.append(cropped_image_filename)
 
         cropped_image_filepath_list_list.append(cropped_images_filepaths)

{"golden_diff": "diff --git a/lightly/utils/cropping/crop_image_by_bounding_boxes.py b/lightly/utils/cropping/crop_image_by_bounding_boxes.py\n--- a/lightly/utils/cropping/crop_image_by_bounding_boxes.py\n+++ b/lightly/utils/cropping/crop_image_by_bounding_boxes.py\n@@ -10,18 +10,6 @@\n from lightly.data import LightlyDataset\n \n \n-def crop_image_by_bounding_boxes(image_filepath: str, bounding_boxes: List[BoundingBox]) -> List[Image.Image]:\n-    image = Image.open(image_filepath)\n-    cropped_images = []\n-    for bbox in bounding_boxes:\n-        w, h = image.size\n-        crop_box = (w * bbox.x0, h * bbox.y0, w * bbox.x1, h * bbox.y1)\n-        crop_box = tuple(int(i) for i in crop_box)\n-        cropped_image = image.crop(crop_box)\n-        cropped_images.append(cropped_image)\n-    return cropped_images\n-\n-\n def crop_dataset_by_bounding_boxes_and_save(dataset: LightlyDataset,\n                                             output_dir: str,\n                                             bounding_boxes_list_list: List[List[BoundingBox]],\n@@ -55,7 +43,7 @@\n         raise ValueError(\"There must be one bounding box and class index list for each image in the datasets,\"\n                          \"but the lengths dont align.\")\n \n-    cropped_image_filepath_list_list: List[List[Image]] = []\n+    cropped_image_filepath_list_list: List[List[str]] = []\n \n \n     print(f\"Cropping objects out of {len(filenames_images)} images...\")\n@@ -71,21 +59,38 @@\n         filepath_image = dataset.get_filepath_from_filename(filename_image)\n         filepath_image_base, image_extension = os.path.splitext(filepath_image)\n \n-        filepath_out_dir = os.path.join(output_dir, filename_image).replace(image_extension, '')\n+        filepath_out_dir = os.path.join(output_dir, filename_image)\\\n+            .replace(image_extension, '')\n         Path(filepath_out_dir).mkdir(parents=True, exist_ok=True)\n \n-        cropped_images = crop_image_by_bounding_boxes(filepath_image, bounding_boxes)\n+        image = Image.open(filepath_image)\n+        \n         cropped_images_filepaths = []\n-        for index, (class_index, cropped_image) in enumerate((zip(class_indices, cropped_images))):\n+        # For every image, crop out multiple cropped images, one for each\n+        # bounding box\n+        for index, (class_index, bbox) in \\\n+                enumerate((zip(class_indices, bounding_boxes))):\n+\n+            # determine the filename and filepath of the cropped image\n             if class_names:\n                 class_name = class_names[class_index]\n             else:\n                 class_name = f\"class{class_index}\"\n             cropped_image_last_filename = f'{index}_{class_name}{image_extension}'\n             cropped_image_filepath = os.path.join(filepath_out_dir, cropped_image_last_filename)\n+\n+            # crop out the image and save it\n+            w, h = image.size\n+            crop_box = (w * bbox.x0, h * bbox.y0, w * bbox.x1, h * bbox.y1)\n+            crop_box = tuple(int(i) for i in crop_box)\n+            cropped_image = image.crop(crop_box)\n             cropped_image.save(cropped_image_filepath)\n \n-            cropped_image_filename = os.path.join(filename_image.replace(image_extension, ''), cropped_image_last_filename)\n+            # add the filename of the cropped image to the corresponding list\n+            cropped_image_filename: str = os.path.join(\n+                filename_image.replace(image_extension, ''),\n+                cropped_image_last_filename\n+            )\n             cropped_images_filepaths.append(cropped_image_filename)\n \n         cropped_image_filepath_list_list.append(cropped_images_filepaths)\n", "issue": "Lightly-Crop: memory leak\nWhen using lightly-crop some users experience a memory leak.\r\n\r\n- [ ] Try to reproduce it.\r\n- [ ] Fix it\n", "before_files": [{"content": "import os.path\nimport warnings\nfrom pathlib import Path\nfrom typing import List\n\nfrom PIL import Image\nfrom tqdm import tqdm\n\nfrom lightly.active_learning.utils import BoundingBox\nfrom lightly.data import LightlyDataset\n\n\ndef crop_image_by_bounding_boxes(image_filepath: str, bounding_boxes: List[BoundingBox]) -> List[Image.Image]:\n    image = Image.open(image_filepath)\n    cropped_images = []\n    for bbox in bounding_boxes:\n        w, h = image.size\n        crop_box = (w * bbox.x0, h * bbox.y0, w * bbox.x1, h * bbox.y1)\n        crop_box = tuple(int(i) for i in crop_box)\n        cropped_image = image.crop(crop_box)\n        cropped_images.append(cropped_image)\n    return cropped_images\n\n\ndef crop_dataset_by_bounding_boxes_and_save(dataset: LightlyDataset,\n                                            output_dir: str,\n                                            bounding_boxes_list_list: List[List[BoundingBox]],\n                                            class_indices_list_list: List[List[int]],\n                                            class_names: List[str] = None\n                                            ) -> List[List[str]]:\n    \"\"\"Crops all images in a dataset by the bounding boxes and saves them in the output dir\n\n    Args:\n        dataset:\n            The dataset with the images to be cropped. Must contain M images.\n        output_dir:\n            The output directory to saved the cropped images to.\n        bounding_boxes_list_list:\n            The bounding boxes of the detections for each image. Must have M sublists, one for each image.\n            Each sublist contains the bounding boxes for each detection, thus N_m elements.\n        class_indices_list_list:\n            The object class ids of the detections for each image. Must have M sublists, one for each image.\n            Each sublist contains the bounding boxes for each detection, thus N_m elements.\n        class_names:\n            The names of the classes, used to map the class id to the class name.\n\n\n    Returns:\n        The filepaths to all saved cropped images. Has M sublists, one for each image.\n        Each sublist contains the filepath of the crop each detection, thus N_m elements.\n\n    \"\"\"\n    filenames_images = dataset.get_filenames()\n    if len(filenames_images) != len(bounding_boxes_list_list) or len(filenames_images) != len(class_indices_list_list):\n        raise ValueError(\"There must be one bounding box and class index list for each image in the datasets,\"\n                         \"but the lengths dont align.\")\n\n    cropped_image_filepath_list_list: List[List[Image]] = []\n\n\n    print(f\"Cropping objects out of {len(filenames_images)} images...\")\n    for filename_image, class_indices, bounding_boxes in \\\n            tqdm(zip(filenames_images, class_indices_list_list, bounding_boxes_list_list)):\n\n        if not len(class_indices) == len(bounding_boxes):\n            warnings.warn(UserWarning(f\"Length of class indices ({len(class_indices)} does not equal length of bounding boxes\"\n                          f\"({len(bounding_boxes)}. This is an error in the input arguments. \"\n                          f\"Skipping this image {filename_image}.\"))\n            continue\n\n        filepath_image = dataset.get_filepath_from_filename(filename_image)\n        filepath_image_base, image_extension = os.path.splitext(filepath_image)\n\n        filepath_out_dir = os.path.join(output_dir, filename_image).replace(image_extension, '')\n        Path(filepath_out_dir).mkdir(parents=True, exist_ok=True)\n\n        cropped_images = crop_image_by_bounding_boxes(filepath_image, bounding_boxes)\n        cropped_images_filepaths = []\n        for index, (class_index, cropped_image) in enumerate((zip(class_indices, cropped_images))):\n            if class_names:\n                class_name = class_names[class_index]\n            else:\n                class_name = f\"class{class_index}\"\n            cropped_image_last_filename = f'{index}_{class_name}{image_extension}'\n            cropped_image_filepath = os.path.join(filepath_out_dir, cropped_image_last_filename)\n            cropped_image.save(cropped_image_filepath)\n\n            cropped_image_filename = os.path.join(filename_image.replace(image_extension, ''), cropped_image_last_filename)\n            cropped_images_filepaths.append(cropped_image_filename)\n\n        cropped_image_filepath_list_list.append(cropped_images_filepaths)\n\n    return cropped_image_filepath_list_list\n", "path": "lightly/utils/cropping/crop_image_by_bounding_boxes.py"}], "after_files": [{"content": "import os.path\nimport warnings\nfrom pathlib import Path\nfrom typing import List\n\nfrom PIL import Image\nfrom tqdm import tqdm\n\nfrom lightly.active_learning.utils import BoundingBox\nfrom lightly.data import LightlyDataset\n\n\ndef crop_dataset_by_bounding_boxes_and_save(dataset: LightlyDataset,\n                                            output_dir: str,\n                                            bounding_boxes_list_list: List[List[BoundingBox]],\n                                            class_indices_list_list: List[List[int]],\n                                            class_names: List[str] = None\n                                            ) -> List[List[str]]:\n    \"\"\"Crops all images in a dataset by the bounding boxes and saves them in the output dir\n\n    Args:\n        dataset:\n            The dataset with the images to be cropped. Must contain M images.\n        output_dir:\n            The output directory to saved the cropped images to.\n        bounding_boxes_list_list:\n            The bounding boxes of the detections for each image. Must have M sublists, one for each image.\n            Each sublist contains the bounding boxes for each detection, thus N_m elements.\n        class_indices_list_list:\n            The object class ids of the detections for each image. Must have M sublists, one for each image.\n            Each sublist contains the bounding boxes for each detection, thus N_m elements.\n        class_names:\n            The names of the classes, used to map the class id to the class name.\n\n\n    Returns:\n        The filepaths to all saved cropped images. Has M sublists, one for each image.\n        Each sublist contains the filepath of the crop each detection, thus N_m elements.\n\n    \"\"\"\n    filenames_images = dataset.get_filenames()\n    if len(filenames_images) != len(bounding_boxes_list_list) or len(filenames_images) != len(class_indices_list_list):\n        raise ValueError(\"There must be one bounding box and class index list for each image in the datasets,\"\n                         \"but the lengths dont align.\")\n\n    cropped_image_filepath_list_list: List[List[str]] = []\n\n\n    print(f\"Cropping objects out of {len(filenames_images)} images...\")\n    for filename_image, class_indices, bounding_boxes in \\\n            tqdm(zip(filenames_images, class_indices_list_list, bounding_boxes_list_list)):\n\n        if not len(class_indices) == len(bounding_boxes):\n            warnings.warn(UserWarning(f\"Length of class indices ({len(class_indices)} does not equal length of bounding boxes\"\n                          f\"({len(bounding_boxes)}. This is an error in the input arguments. \"\n                          f\"Skipping this image {filename_image}.\"))\n            continue\n\n        filepath_image = dataset.get_filepath_from_filename(filename_image)\n        filepath_image_base, image_extension = os.path.splitext(filepath_image)\n\n        filepath_out_dir = os.path.join(output_dir, filename_image)\\\n            .replace(image_extension, '')\n        Path(filepath_out_dir).mkdir(parents=True, exist_ok=True)\n\n        image = Image.open(filepath_image)\n        \n        cropped_images_filepaths = []\n        # For every image, crop out multiple cropped images, one for each\n        # bounding box\n        for index, (class_index, bbox) in \\\n                enumerate((zip(class_indices, bounding_boxes))):\n\n            # determine the filename and filepath of the cropped image\n            if class_names:\n                class_name = class_names[class_index]\n            else:\n                class_name = f\"class{class_index}\"\n            cropped_image_last_filename = f'{index}_{class_name}{image_extension}'\n            cropped_image_filepath = os.path.join(filepath_out_dir, cropped_image_last_filename)\n\n            # crop out the image and save it\n            w, h = image.size\n            crop_box = (w * bbox.x0, h * bbox.y0, w * bbox.x1, h * bbox.y1)\n            crop_box = tuple(int(i) for i in crop_box)\n            cropped_image = image.crop(crop_box)\n            cropped_image.save(cropped_image_filepath)\n\n            # add the filename of the cropped image to the corresponding list\n            cropped_image_filename: str = os.path.join(\n                filename_image.replace(image_extension, ''),\n                cropped_image_last_filename\n            )\n            cropped_images_filepaths.append(cropped_image_filename)\n\n        cropped_image_filepath_list_list.append(cropped_images_filepaths)\n\n    return cropped_image_filepath_list_list\n", "path": "lightly/utils/cropping/crop_image_by_bounding_boxes.py"}]}