We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add fill parameter to utils.draw_bounding_boxes.
## 🚀 Feature

Fill parameter allows creating a semi-transparent box. This is particularly useful for Mask RCNN Model.
This would complete utils for Object detection and Instance Segmentation (least with rectangular boxes)

## Motivation

In Instance segmentation models, we also care about masks, not just the bounding box. Fill parameter allows us to fill in a semi-transparent way. Also, this parameter is optional hence it does not affect performance.

## Pitch

Add a param fill as follows
```
fill: Optional[List[Union[str, Tuple[int, int, int]]]] = None,

```

Here is complete running code with a few edits

```
@torch.no_grad()
def draw_bounding_boxes(
    image: torch.Tensor,
    boxes: torch.Tensor,
    labels: Optional[List[str]] = None,
    colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
    fill: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
    width: int = 1,
    font: Optional[str] = None,
    font_size: int = 10
) -> torch.Tensor:

    """
    Draws bounding boxes on given image.
    The values of the input image should be uint8 between 0 and 255.
    Args:
        image (Tensor): Tensor of shape (C x H x W)
        bboxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that
            the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and
            `0 <= ymin < ymax < H`.
        labels (List[str]): List containing the labels of bounding boxes.
        colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can
            be represented as `str` or `Tuple[int, int, int]`.
        fill: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
        width (int): Width of bounding box.
        font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may
            also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,
            `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.
        font_size (int): The requested font size in points.
    """

    if not isinstance(image, torch.Tensor):
        raise TypeError(f"Tensor expected, got {type(image)}")
    elif image.dtype != torch.uint8:
        raise ValueError(f"Tensor uint8 expected, got {image.dtype}")
    elif image.dim() != 3:
        raise ValueError("Pass individual images, not batches")

    ndarr = image.permute(1, 2, 0).numpy()
    img_to_draw = Image.fromarray(ndarr)

    img_boxes = boxes.to(torch.int64).tolist()

    draw = ImageDraw.Draw(img_to_draw, "RGBA")

    txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)

    for i, bbox in enumerate(img_boxes):
        color = None if colors is None else colors[i]
        draw.rectangle(bbox, width=width, outline=color, fill=fill)

        if labels is not None:
            draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)

    return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1)
```

This makes mask RCNN output more clear, and people can play with fill parameter such as confidence based fill, fill with colors different per class, etc.

## Additional context

I can send PR for this :sweat_smile:  I'm attaching outputs of above code.

![draw_boxes_util2](https://user-images.githubusercontent.com/47158509/105579984-b0b14680-5daf-11eb-89fa-9c525608dcca.png)

(Sorry PyTorch logo :pray: )

![draw_boxes_util](https://user-images.githubusercontent.com/47158509/105579987-b3ac3700-5daf-11eb-9280-8390f86721b5.png)



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `torchvision/utils.py`
Content:
```
1 from typing import Union, Optional, List, Tuple, Text, BinaryIO
2 import pathlib
3 import torch
4 import math
5 import warnings
6 import numpy as np
7 from PIL import Image, ImageDraw
8 from PIL import ImageFont
9 
10 __all__ = ["make_grid", "save_image", "draw_bounding_boxes"]
11 
12 
13 @torch.no_grad()
14 def make_grid(
15     tensor: Union[torch.Tensor, List[torch.Tensor]],
16     nrow: int = 8,
17     padding: int = 2,
18     normalize: bool = False,
19     value_range: Optional[Tuple[int, int]] = None,
20     scale_each: bool = False,
21     pad_value: int = 0,
22     **kwargs
23 ) -> torch.Tensor:
24     """Make a grid of images.
25 
26     Args:
27         tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)
28             or a list of images all of the same size.
29         nrow (int, optional): Number of images displayed in each row of the grid.
30             The final grid size is ``(B / nrow, nrow)``. Default: ``8``.
31         padding (int, optional): amount of padding. Default: ``2``.
32         normalize (bool, optional): If True, shift the image to the range (0, 1),
33             by the min and max values specified by :attr:`range`. Default: ``False``.
34         value_range (tuple, optional): tuple (min, max) where min and max are numbers,
35             then these numbers are used to normalize the image. By default, min and max
36             are computed from the tensor.
37         scale_each (bool, optional): If ``True``, scale each image in the batch of
38             images separately rather than the (min, max) over all images. Default: ``False``.
39         pad_value (float, optional): Value for the padded pixels. Default: ``0``.
40 
41     Example:
42         See this notebook `here <https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91>`_
43 
44     """
45     if not (torch.is_tensor(tensor) or
46             (isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))):
47         raise TypeError(f'tensor or list of tensors expected, got {type(tensor)}')
48 
49     if "range" in kwargs.keys():
50         warning = "range will be deprecated, please use value_range instead."
51         warnings.warn(warning)
52         value_range = kwargs["range"]
53 
54     # if list of tensors, convert to a 4D mini-batch Tensor
55     if isinstance(tensor, list):
56         tensor = torch.stack(tensor, dim=0)
57 
58     if tensor.dim() == 2:  # single image H x W
59         tensor = tensor.unsqueeze(0)
60     if tensor.dim() == 3:  # single image
61         if tensor.size(0) == 1:  # if single-channel, convert to 3-channel
62             tensor = torch.cat((tensor, tensor, tensor), 0)
63         tensor = tensor.unsqueeze(0)
64 
65     if tensor.dim() == 4 and tensor.size(1) == 1:  # single-channel images
66         tensor = torch.cat((tensor, tensor, tensor), 1)
67 
68     if normalize is True:
69         tensor = tensor.clone()  # avoid modifying tensor in-place
70         if value_range is not None:
71             assert isinstance(value_range, tuple), \
72                 "value_range has to be a tuple (min, max) if specified. min and max are numbers"
73 
74         def norm_ip(img, low, high):
75             img.clamp_(min=low, max=high)
76             img.sub_(low).div_(max(high - low, 1e-5))
77 
78         def norm_range(t, value_range):
79             if value_range is not None:
80                 norm_ip(t, value_range[0], value_range[1])
81             else:
82                 norm_ip(t, float(t.min()), float(t.max()))
83 
84         if scale_each is True:
85             for t in tensor:  # loop over mini-batch dimension
86                 norm_range(t, value_range)
87         else:
88             norm_range(tensor, value_range)
89 
90     if tensor.size(0) == 1:
91         return tensor.squeeze(0)
92 
93     # make the mini-batch of images into a grid
94     nmaps = tensor.size(0)
95     xmaps = min(nrow, nmaps)
96     ymaps = int(math.ceil(float(nmaps) / xmaps))
97     height, width = int(tensor.size(2) + padding), int(tensor.size(3) + padding)
98     num_channels = tensor.size(1)
99     grid = tensor.new_full((num_channels, height * ymaps + padding, width * xmaps + padding), pad_value)
100     k = 0
101     for y in range(ymaps):
102         for x in range(xmaps):
103             if k >= nmaps:
104                 break
105             # Tensor.copy_() is a valid method but seems to be missing from the stubs
106             # https://pytorch.org/docs/stable/tensors.html#torch.Tensor.copy_
107             grid.narrow(1, y * height + padding, height - padding).narrow(  # type: ignore[attr-defined]
108                 2, x * width + padding, width - padding
109             ).copy_(tensor[k])
110             k = k + 1
111     return grid
112 
113 
114 @torch.no_grad()
115 def save_image(
116     tensor: Union[torch.Tensor, List[torch.Tensor]],
117     fp: Union[Text, pathlib.Path, BinaryIO],
118     format: Optional[str] = None,
119     **kwargs
120 ) -> None:
121     """Save a given Tensor into an image file.
122 
123     Args:
124         tensor (Tensor or list): Image to be saved. If given a mini-batch tensor,
125             saves the tensor as a grid of images by calling ``make_grid``.
126         fp (string or file object): A filename or a file object
127         format(Optional):  If omitted, the format to use is determined from the filename extension.
128             If a file object was used instead of a filename, this parameter should always be used.
129         **kwargs: Other arguments are documented in ``make_grid``.
130     """
131 
132     grid = make_grid(tensor, **kwargs)
133     # Add 0.5 after unnormalizing to [0, 255] to round to nearest integer
134     ndarr = grid.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to('cpu', torch.uint8).numpy()
135     im = Image.fromarray(ndarr)
136     im.save(fp, format=format)
137 
138 
139 @torch.no_grad()
140 def draw_bounding_boxes(
141     image: torch.Tensor,
142     boxes: torch.Tensor,
143     labels: Optional[List[str]] = None,
144     colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
145     width: int = 1,
146     font: Optional[str] = None,
147     font_size: int = 10
148 ) -> torch.Tensor:
149 
150     """
151     Draws bounding boxes on given image.
152     The values of the input image should be uint8 between 0 and 255.
153 
154     Args:
155         image (Tensor): Tensor of shape (C x H x W)
156         boxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that
157             the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and
158             `0 <= ymin < ymax < H`.
159         labels (List[str]): List containing the labels of bounding boxes.
160         colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can
161             be represented as `str` or `Tuple[int, int, int]`.
162         width (int): Width of bounding box.
163         font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may
164             also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,
165             `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.
166         font_size (int): The requested font size in points.
167     """
168 
169     if not isinstance(image, torch.Tensor):
170         raise TypeError(f"Tensor expected, got {type(image)}")
171     elif image.dtype != torch.uint8:
172         raise ValueError(f"Tensor uint8 expected, got {image.dtype}")
173     elif image.dim() != 3:
174         raise ValueError("Pass individual images, not batches")
175 
176     ndarr = image.permute(1, 2, 0).numpy()
177     img_to_draw = Image.fromarray(ndarr)
178 
179     img_boxes = boxes.to(torch.int64).tolist()
180 
181     draw = ImageDraw.Draw(img_to_draw)
182     txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)
183 
184     for i, bbox in enumerate(img_boxes):
185         color = None if colors is None else colors[i]
186         draw.rectangle(bbox, width=width, outline=color)
187 
188         if labels is not None:
189             draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)
190 
191     return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1)
192
```
--- 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/torchvision/utils.py b/torchvision/utils.py
--- a/torchvision/utils.py
+++ b/torchvision/utils.py
@@ -4,8 +4,7 @@
 import math
 import warnings
 import numpy as np
-from PIL import Image, ImageDraw
-from PIL import ImageFont
+from PIL import Image, ImageDraw, ImageFont, ImageColor
 
 __all__ = ["make_grid", "save_image", "draw_bounding_boxes"]
 
@@ -142,6 +141,7 @@
     boxes: torch.Tensor,
     labels: Optional[List[str]] = None,
     colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
+    fill: Optional[bool] = False,
     width: int = 1,
     font: Optional[str] = None,
     font_size: int = 10
@@ -150,6 +150,7 @@
     """
     Draws bounding boxes on given image.
     The values of the input image should be uint8 between 0 and 255.
+    If filled, Resulting Tensor should be saved as PNG image.
 
     Args:
         image (Tensor): Tensor of shape (C x H x W)
@@ -159,6 +160,7 @@
         labels (List[str]): List containing the labels of bounding boxes.
         colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can
             be represented as `str` or `Tuple[int, int, int]`.
+        fill (bool): If `True` fills the bounding box with specified color.
         width (int): Width of bounding box.
         font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may
             also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,
@@ -178,12 +180,31 @@
 
     img_boxes = boxes.to(torch.int64).tolist()
 
-    draw = ImageDraw.Draw(img_to_draw)
+    if fill:
+        draw = ImageDraw.Draw(img_to_draw, "RGBA")
+
+    else:
+        draw = ImageDraw.Draw(img_to_draw)
+
     txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)
 
     for i, bbox in enumerate(img_boxes):
-        color = None if colors is None else colors[i]
-        draw.rectangle(bbox, width=width, outline=color)
+        if colors is None:
+            color = None
+        else:
+            color = colors[i]
+
+        if fill:
+            if color is None:
+                fill_color = (255, 255, 255, 100)
+            elif isinstance(color, str):
+                # This will automatically raise Error if rgb cannot be parsed.
+                fill_color = ImageColor.getrgb(color) + (100,)
+            elif isinstance(color, tuple):
+                fill_color = color + (100,)
+            draw.rectangle(bbox, width=width, outline=color, fill=fill_color)
+        else:
+            draw.rectangle(bbox, width=width, outline=color)
 
         if labels is not None:
             draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)

{"golden_diff": "diff --git a/torchvision/utils.py b/torchvision/utils.py\n--- a/torchvision/utils.py\n+++ b/torchvision/utils.py\n@@ -4,8 +4,7 @@\n import math\n import warnings\n import numpy as np\n-from PIL import Image, ImageDraw\n-from PIL import ImageFont\n+from PIL import Image, ImageDraw, ImageFont, ImageColor\n \n __all__ = [\"make_grid\", \"save_image\", \"draw_bounding_boxes\"]\n \n@@ -142,6 +141,7 @@\n     boxes: torch.Tensor,\n     labels: Optional[List[str]] = None,\n     colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,\n+    fill: Optional[bool] = False,\n     width: int = 1,\n     font: Optional[str] = None,\n     font_size: int = 10\n@@ -150,6 +150,7 @@\n     \"\"\"\n     Draws bounding boxes on given image.\n     The values of the input image should be uint8 between 0 and 255.\n+    If filled, Resulting Tensor should be saved as PNG image.\n \n     Args:\n         image (Tensor): Tensor of shape (C x H x W)\n@@ -159,6 +160,7 @@\n         labels (List[str]): List containing the labels of bounding boxes.\n         colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can\n             be represented as `str` or `Tuple[int, int, int]`.\n+        fill (bool): If `True` fills the bounding box with specified color.\n         width (int): Width of bounding box.\n         font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may\n             also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,\n@@ -178,12 +180,31 @@\n \n     img_boxes = boxes.to(torch.int64).tolist()\n \n-    draw = ImageDraw.Draw(img_to_draw)\n+    if fill:\n+        draw = ImageDraw.Draw(img_to_draw, \"RGBA\")\n+\n+    else:\n+        draw = ImageDraw.Draw(img_to_draw)\n+\n     txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)\n \n     for i, bbox in enumerate(img_boxes):\n-        color = None if colors is None else colors[i]\n-        draw.rectangle(bbox, width=width, outline=color)\n+        if colors is None:\n+            color = None\n+        else:\n+            color = colors[i]\n+\n+        if fill:\n+            if color is None:\n+                fill_color = (255, 255, 255, 100)\n+            elif isinstance(color, str):\n+                # This will automatically raise Error if rgb cannot be parsed.\n+                fill_color = ImageColor.getrgb(color) + (100,)\n+            elif isinstance(color, tuple):\n+                fill_color = color + (100,)\n+            draw.rectangle(bbox, width=width, outline=color, fill=fill_color)\n+        else:\n+            draw.rectangle(bbox, width=width, outline=color)\n \n         if labels is not None:\n             draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)\n", "issue": "Add fill parameter to utils.draw_bounding_boxes.\n## \ud83d\ude80 Feature\r\n\r\nFill parameter allows creating a semi-transparent box. This is particularly useful for Mask RCNN Model.\r\nThis would complete utils for Object detection and Instance Segmentation (least with rectangular boxes)\r\n\r\n## Motivation\r\n\r\nIn Instance segmentation models, we also care about masks, not just the bounding box. Fill parameter allows us to fill in a semi-transparent way. Also, this parameter is optional hence it does not affect performance.\r\n\r\n## Pitch\r\n\r\nAdd a param fill as follows\r\n```\r\nfill: Optional[List[Union[str, Tuple[int, int, int]]]] = None,\r\n\r\n```\r\n\r\nHere is complete running code with a few edits\r\n\r\n```\r\n@torch.no_grad()\r\ndef draw_bounding_boxes(\r\n    image: torch.Tensor,\r\n    boxes: torch.Tensor,\r\n    labels: Optional[List[str]] = None,\r\n    colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,\r\n    fill: Optional[List[Union[str, Tuple[int, int, int]]]] = None,\r\n    width: int = 1,\r\n    font: Optional[str] = None,\r\n    font_size: int = 10\r\n) -> torch.Tensor:\r\n\r\n    \"\"\"\r\n    Draws bounding boxes on given image.\r\n    The values of the input image should be uint8 between 0 and 255.\r\n    Args:\r\n        image (Tensor): Tensor of shape (C x H x W)\r\n        bboxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that\r\n            the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and\r\n            `0 <= ymin < ymax < H`.\r\n        labels (List[str]): List containing the labels of bounding boxes.\r\n        colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can\r\n            be represented as `str` or `Tuple[int, int, int]`.\r\n        fill: Optional[List[Union[str, Tuple[int, int, int]]]] = None,\r\n        width (int): Width of bounding box.\r\n        font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may\r\n            also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,\r\n            `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.\r\n        font_size (int): The requested font size in points.\r\n    \"\"\"\r\n\r\n    if not isinstance(image, torch.Tensor):\r\n        raise TypeError(f\"Tensor expected, got {type(image)}\")\r\n    elif image.dtype != torch.uint8:\r\n        raise ValueError(f\"Tensor uint8 expected, got {image.dtype}\")\r\n    elif image.dim() != 3:\r\n        raise ValueError(\"Pass individual images, not batches\")\r\n\r\n    ndarr = image.permute(1, 2, 0).numpy()\r\n    img_to_draw = Image.fromarray(ndarr)\r\n\r\n    img_boxes = boxes.to(torch.int64).tolist()\r\n\r\n    draw = ImageDraw.Draw(img_to_draw, \"RGBA\")\r\n\r\n    txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)\r\n\r\n    for i, bbox in enumerate(img_boxes):\r\n        color = None if colors is None else colors[i]\r\n        draw.rectangle(bbox, width=width, outline=color, fill=fill)\r\n\r\n        if labels is not None:\r\n            draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)\r\n\r\n    return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1)\r\n```\r\n\r\nThis makes mask RCNN output more clear, and people can play with fill parameter such as confidence based fill, fill with colors different per class, etc.\r\n\r\n## Additional context\r\n\r\nI can send PR for this :sweat_smile:  I'm attaching outputs of above code.\r\n\r\n![draw_boxes_util2](https://user-images.githubusercontent.com/47158509/105579984-b0b14680-5daf-11eb-89fa-9c525608dcca.png)\r\n\r\n(Sorry PyTorch logo :pray: )\r\n\r\n![draw_boxes_util](https://user-images.githubusercontent.com/47158509/105579987-b3ac3700-5daf-11eb-9280-8390f86721b5.png)\r\n\r\n\n", "before_files": [{"content": "from typing import Union, Optional, List, Tuple, Text, BinaryIO\nimport pathlib\nimport torch\nimport math\nimport warnings\nimport numpy as np\nfrom PIL import Image, ImageDraw\nfrom PIL import ImageFont\n\n__all__ = [\"make_grid\", \"save_image\", \"draw_bounding_boxes\"]\n\n\n@torch.no_grad()\ndef make_grid(\n    tensor: Union[torch.Tensor, List[torch.Tensor]],\n    nrow: int = 8,\n    padding: int = 2,\n    normalize: bool = False,\n    value_range: Optional[Tuple[int, int]] = None,\n    scale_each: bool = False,\n    pad_value: int = 0,\n    **kwargs\n) -> torch.Tensor:\n    \"\"\"Make a grid of images.\n\n    Args:\n        tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)\n            or a list of images all of the same size.\n        nrow (int, optional): Number of images displayed in each row of the grid.\n            The final grid size is ``(B / nrow, nrow)``. Default: ``8``.\n        padding (int, optional): amount of padding. Default: ``2``.\n        normalize (bool, optional): If True, shift the image to the range (0, 1),\n            by the min and max values specified by :attr:`range`. Default: ``False``.\n        value_range (tuple, optional): tuple (min, max) where min and max are numbers,\n            then these numbers are used to normalize the image. By default, min and max\n            are computed from the tensor.\n        scale_each (bool, optional): If ``True``, scale each image in the batch of\n            images separately rather than the (min, max) over all images. Default: ``False``.\n        pad_value (float, optional): Value for the padded pixels. Default: ``0``.\n\n    Example:\n        See this notebook `here <https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91>`_\n\n    \"\"\"\n    if not (torch.is_tensor(tensor) or\n            (isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))):\n        raise TypeError(f'tensor or list of tensors expected, got {type(tensor)}')\n\n    if \"range\" in kwargs.keys():\n        warning = \"range will be deprecated, please use value_range instead.\"\n        warnings.warn(warning)\n        value_range = kwargs[\"range\"]\n\n    # if list of tensors, convert to a 4D mini-batch Tensor\n    if isinstance(tensor, list):\n        tensor = torch.stack(tensor, dim=0)\n\n    if tensor.dim() == 2:  # single image H x W\n        tensor = tensor.unsqueeze(0)\n    if tensor.dim() == 3:  # single image\n        if tensor.size(0) == 1:  # if single-channel, convert to 3-channel\n            tensor = torch.cat((tensor, tensor, tensor), 0)\n        tensor = tensor.unsqueeze(0)\n\n    if tensor.dim() == 4 and tensor.size(1) == 1:  # single-channel images\n        tensor = torch.cat((tensor, tensor, tensor), 1)\n\n    if normalize is True:\n        tensor = tensor.clone()  # avoid modifying tensor in-place\n        if value_range is not None:\n            assert isinstance(value_range, tuple), \\\n                \"value_range has to be a tuple (min, max) if specified. min and max are numbers\"\n\n        def norm_ip(img, low, high):\n            img.clamp_(min=low, max=high)\n            img.sub_(low).div_(max(high - low, 1e-5))\n\n        def norm_range(t, value_range):\n            if value_range is not None:\n                norm_ip(t, value_range[0], value_range[1])\n            else:\n                norm_ip(t, float(t.min()), float(t.max()))\n\n        if scale_each is True:\n            for t in tensor:  # loop over mini-batch dimension\n                norm_range(t, value_range)\n        else:\n            norm_range(tensor, value_range)\n\n    if tensor.size(0) == 1:\n        return tensor.squeeze(0)\n\n    # make the mini-batch of images into a grid\n    nmaps = tensor.size(0)\n    xmaps = min(nrow, nmaps)\n    ymaps = int(math.ceil(float(nmaps) / xmaps))\n    height, width = int(tensor.size(2) + padding), int(tensor.size(3) + padding)\n    num_channels = tensor.size(1)\n    grid = tensor.new_full((num_channels, height * ymaps + padding, width * xmaps + padding), pad_value)\n    k = 0\n    for y in range(ymaps):\n        for x in range(xmaps):\n            if k >= nmaps:\n                break\n            # Tensor.copy_() is a valid method but seems to be missing from the stubs\n            # https://pytorch.org/docs/stable/tensors.html#torch.Tensor.copy_\n            grid.narrow(1, y * height + padding, height - padding).narrow(  # type: ignore[attr-defined]\n                2, x * width + padding, width - padding\n            ).copy_(tensor[k])\n            k = k + 1\n    return grid\n\n\n@torch.no_grad()\ndef save_image(\n    tensor: Union[torch.Tensor, List[torch.Tensor]],\n    fp: Union[Text, pathlib.Path, BinaryIO],\n    format: Optional[str] = None,\n    **kwargs\n) -> None:\n    \"\"\"Save a given Tensor into an image file.\n\n    Args:\n        tensor (Tensor or list): Image to be saved. If given a mini-batch tensor,\n            saves the tensor as a grid of images by calling ``make_grid``.\n        fp (string or file object): A filename or a file object\n        format(Optional):  If omitted, the format to use is determined from the filename extension.\n            If a file object was used instead of a filename, this parameter should always be used.\n        **kwargs: Other arguments are documented in ``make_grid``.\n    \"\"\"\n\n    grid = make_grid(tensor, **kwargs)\n    # Add 0.5 after unnormalizing to [0, 255] to round to nearest integer\n    ndarr = grid.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to('cpu', torch.uint8).numpy()\n    im = Image.fromarray(ndarr)\n    im.save(fp, format=format)\n\n\n@torch.no_grad()\ndef draw_bounding_boxes(\n    image: torch.Tensor,\n    boxes: torch.Tensor,\n    labels: Optional[List[str]] = None,\n    colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,\n    width: int = 1,\n    font: Optional[str] = None,\n    font_size: int = 10\n) -> torch.Tensor:\n\n    \"\"\"\n    Draws bounding boxes on given image.\n    The values of the input image should be uint8 between 0 and 255.\n\n    Args:\n        image (Tensor): Tensor of shape (C x H x W)\n        boxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that\n            the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and\n            `0 <= ymin < ymax < H`.\n        labels (List[str]): List containing the labels of bounding boxes.\n        colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can\n            be represented as `str` or `Tuple[int, int, int]`.\n        width (int): Width of bounding box.\n        font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may\n            also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,\n            `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.\n        font_size (int): The requested font size in points.\n    \"\"\"\n\n    if not isinstance(image, torch.Tensor):\n        raise TypeError(f\"Tensor expected, got {type(image)}\")\n    elif image.dtype != torch.uint8:\n        raise ValueError(f\"Tensor uint8 expected, got {image.dtype}\")\n    elif image.dim() != 3:\n        raise ValueError(\"Pass individual images, not batches\")\n\n    ndarr = image.permute(1, 2, 0).numpy()\n    img_to_draw = Image.fromarray(ndarr)\n\n    img_boxes = boxes.to(torch.int64).tolist()\n\n    draw = ImageDraw.Draw(img_to_draw)\n    txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)\n\n    for i, bbox in enumerate(img_boxes):\n        color = None if colors is None else colors[i]\n        draw.rectangle(bbox, width=width, outline=color)\n\n        if labels is not None:\n            draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)\n\n    return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1)\n", "path": "torchvision/utils.py"}], "after_files": [{"content": "from typing import Union, Optional, List, Tuple, Text, BinaryIO\nimport pathlib\nimport torch\nimport math\nimport warnings\nimport numpy as np\nfrom PIL import Image, ImageDraw, ImageFont, ImageColor\n\n__all__ = [\"make_grid\", \"save_image\", \"draw_bounding_boxes\"]\n\n\n@torch.no_grad()\ndef make_grid(\n    tensor: Union[torch.Tensor, List[torch.Tensor]],\n    nrow: int = 8,\n    padding: int = 2,\n    normalize: bool = False,\n    value_range: Optional[Tuple[int, int]] = None,\n    scale_each: bool = False,\n    pad_value: int = 0,\n    **kwargs\n) -> torch.Tensor:\n    \"\"\"Make a grid of images.\n\n    Args:\n        tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)\n            or a list of images all of the same size.\n        nrow (int, optional): Number of images displayed in each row of the grid.\n            The final grid size is ``(B / nrow, nrow)``. Default: ``8``.\n        padding (int, optional): amount of padding. Default: ``2``.\n        normalize (bool, optional): If True, shift the image to the range (0, 1),\n            by the min and max values specified by :attr:`range`. Default: ``False``.\n        value_range (tuple, optional): tuple (min, max) where min and max are numbers,\n            then these numbers are used to normalize the image. By default, min and max\n            are computed from the tensor.\n        scale_each (bool, optional): If ``True``, scale each image in the batch of\n            images separately rather than the (min, max) over all images. Default: ``False``.\n        pad_value (float, optional): Value for the padded pixels. Default: ``0``.\n\n    Example:\n        See this notebook `here <https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91>`_\n\n    \"\"\"\n    if not (torch.is_tensor(tensor) or\n            (isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))):\n        raise TypeError(f'tensor or list of tensors expected, got {type(tensor)}')\n\n    if \"range\" in kwargs.keys():\n        warning = \"range will be deprecated, please use value_range instead.\"\n        warnings.warn(warning)\n        value_range = kwargs[\"range\"]\n\n    # if list of tensors, convert to a 4D mini-batch Tensor\n    if isinstance(tensor, list):\n        tensor = torch.stack(tensor, dim=0)\n\n    if tensor.dim() == 2:  # single image H x W\n        tensor = tensor.unsqueeze(0)\n    if tensor.dim() == 3:  # single image\n        if tensor.size(0) == 1:  # if single-channel, convert to 3-channel\n            tensor = torch.cat((tensor, tensor, tensor), 0)\n        tensor = tensor.unsqueeze(0)\n\n    if tensor.dim() == 4 and tensor.size(1) == 1:  # single-channel images\n        tensor = torch.cat((tensor, tensor, tensor), 1)\n\n    if normalize is True:\n        tensor = tensor.clone()  # avoid modifying tensor in-place\n        if value_range is not None:\n            assert isinstance(value_range, tuple), \\\n                \"value_range has to be a tuple (min, max) if specified. min and max are numbers\"\n\n        def norm_ip(img, low, high):\n            img.clamp_(min=low, max=high)\n            img.sub_(low).div_(max(high - low, 1e-5))\n\n        def norm_range(t, value_range):\n            if value_range is not None:\n                norm_ip(t, value_range[0], value_range[1])\n            else:\n                norm_ip(t, float(t.min()), float(t.max()))\n\n        if scale_each is True:\n            for t in tensor:  # loop over mini-batch dimension\n                norm_range(t, value_range)\n        else:\n            norm_range(tensor, value_range)\n\n    if tensor.size(0) == 1:\n        return tensor.squeeze(0)\n\n    # make the mini-batch of images into a grid\n    nmaps = tensor.size(0)\n    xmaps = min(nrow, nmaps)\n    ymaps = int(math.ceil(float(nmaps) / xmaps))\n    height, width = int(tensor.size(2) + padding), int(tensor.size(3) + padding)\n    num_channels = tensor.size(1)\n    grid = tensor.new_full((num_channels, height * ymaps + padding, width * xmaps + padding), pad_value)\n    k = 0\n    for y in range(ymaps):\n        for x in range(xmaps):\n            if k >= nmaps:\n                break\n            # Tensor.copy_() is a valid method but seems to be missing from the stubs\n            # https://pytorch.org/docs/stable/tensors.html#torch.Tensor.copy_\n            grid.narrow(1, y * height + padding, height - padding).narrow(  # type: ignore[attr-defined]\n                2, x * width + padding, width - padding\n            ).copy_(tensor[k])\n            k = k + 1\n    return grid\n\n\n@torch.no_grad()\ndef save_image(\n    tensor: Union[torch.Tensor, List[torch.Tensor]],\n    fp: Union[Text, pathlib.Path, BinaryIO],\n    format: Optional[str] = None,\n    **kwargs\n) -> None:\n    \"\"\"Save a given Tensor into an image file.\n\n    Args:\n        tensor (Tensor or list): Image to be saved. If given a mini-batch tensor,\n            saves the tensor as a grid of images by calling ``make_grid``.\n        fp (string or file object): A filename or a file object\n        format(Optional):  If omitted, the format to use is determined from the filename extension.\n            If a file object was used instead of a filename, this parameter should always be used.\n        **kwargs: Other arguments are documented in ``make_grid``.\n    \"\"\"\n\n    grid = make_grid(tensor, **kwargs)\n    # Add 0.5 after unnormalizing to [0, 255] to round to nearest integer\n    ndarr = grid.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to('cpu', torch.uint8).numpy()\n    im = Image.fromarray(ndarr)\n    im.save(fp, format=format)\n\n\n@torch.no_grad()\ndef draw_bounding_boxes(\n    image: torch.Tensor,\n    boxes: torch.Tensor,\n    labels: Optional[List[str]] = None,\n    colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,\n    fill: Optional[bool] = False,\n    width: int = 1,\n    font: Optional[str] = None,\n    font_size: int = 10\n) -> torch.Tensor:\n\n    \"\"\"\n    Draws bounding boxes on given image.\n    The values of the input image should be uint8 between 0 and 255.\n    If filled, Resulting Tensor should be saved as PNG image.\n\n    Args:\n        image (Tensor): Tensor of shape (C x H x W)\n        boxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that\n            the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and\n            `0 <= ymin < ymax < H`.\n        labels (List[str]): List containing the labels of bounding boxes.\n        colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can\n            be represented as `str` or `Tuple[int, int, int]`.\n        fill (bool): If `True` fills the bounding box with specified color.\n        width (int): Width of bounding box.\n        font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may\n            also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,\n            `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.\n        font_size (int): The requested font size in points.\n    \"\"\"\n\n    if not isinstance(image, torch.Tensor):\n        raise TypeError(f\"Tensor expected, got {type(image)}\")\n    elif image.dtype != torch.uint8:\n        raise ValueError(f\"Tensor uint8 expected, got {image.dtype}\")\n    elif image.dim() != 3:\n        raise ValueError(\"Pass individual images, not batches\")\n\n    ndarr = image.permute(1, 2, 0).numpy()\n    img_to_draw = Image.fromarray(ndarr)\n\n    img_boxes = boxes.to(torch.int64).tolist()\n\n    if fill:\n        draw = ImageDraw.Draw(img_to_draw, \"RGBA\")\n\n    else:\n        draw = ImageDraw.Draw(img_to_draw)\n\n    txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)\n\n    for i, bbox in enumerate(img_boxes):\n        if colors is None:\n            color = None\n        else:\n            color = colors[i]\n\n        if fill:\n            if color is None:\n                fill_color = (255, 255, 255, 100)\n            elif isinstance(color, str):\n                # This will automatically raise Error if rgb cannot be parsed.\n                fill_color = ImageColor.getrgb(color) + (100,)\n            elif isinstance(color, tuple):\n                fill_color = color + (100,)\n            draw.rectangle(bbox, width=width, outline=color, fill=fill_color)\n        else:\n            draw.rectangle(bbox, width=width, outline=color)\n\n        if labels is not None:\n            draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)\n\n    return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1)\n", "path": "torchvision/utils.py"}]}