prompt: 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()
  
  ```
  
golden_diff: 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)
  
verification_info: {"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"}]}