Spaces:
Sleeping
Sleeping
| import numpy as np | |
| import PIL | |
| from PIL import Image | |
| from PIL import ImageDraw | |
| from PIL import ImageFont | |
| from PIL import ImageColor | |
| def _is_legal_color(color): | |
| if color is None: | |
| return True | |
| if isinstance(color, str): | |
| return True | |
| return isinstance(color, (tuple, list)) and len(color) == 3 | |
| def _normalize_color(color, pil_mode, swap_rgb=False): | |
| if color is None: | |
| return color | |
| if isinstance(color, str): | |
| color = ImageColor.getrgb(color) | |
| gray = color[0] | |
| if swap_rgb: | |
| color = (color[2], color[1], color[0]) | |
| if pil_mode == 'L': | |
| color = gray | |
| return color | |
| def draw_text(image, text, position, color=(255,0,0), font=None, font_size=15): | |
| """Draws text on given image. | |
| Args: | |
| image (ndarray). | |
| text (str): text to be drawn. | |
| position (Tuple[int, int]): position where to be drawn. | |
| color (List[Union[str, Tuple[int, int, int]]]): text color. | |
| font (str): A filename or file-like object 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. | |
| References: | |
| torchvision.utils.draw_bounding_boxes | |
| """ | |
| if isinstance(image, np.ndarray): | |
| # PIL.Image.fromarray fails with uint16 arrays | |
| # https://github.com/python-pillow/Pillow/issues/1514 | |
| if (image.dtype == np.uint16) and (image.ndim != 2): | |
| image = (image / 256).astype(np.uint8) | |
| pil_image = Image.fromarray(image) | |
| elif isinstance(image, PIL.Image.Image): | |
| pil_image = image | |
| else: | |
| raise TypeError('Unsupported image type!') | |
| assert pil_image.mode in ['L', 'RGB', 'RGBA'] | |
| assert _is_legal_color(color) | |
| color = _normalize_color(color, pil_image.mode, isinstance(image, np.ndarray)) | |
| if font is None: | |
| font_object = ImageFont.load_default() | |
| else: | |
| font_object = ImageFont.truetype(font, size=font_size) | |
| draw = ImageDraw.Draw(pil_image) | |
| draw.text((position[0], position[1]), text, | |
| fill=color, font=font_object) | |
| if isinstance(image, np.ndarray): | |
| return np.asarray(pil_image) | |
| return pil_image | |
| def draw_bounding_boxes(image, boxes, labels=None, colors=None, | |
| fill=False, width=1, font=None, font_size=15): | |
| """Draws bounding boxes on given image. | |
| Args: | |
| image (ndarray). | |
| boxes (ndarray): ndarray of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. | |
| 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 or labels. | |
| fill (bool): If `True` fills the bounding box with specified color. | |
| width (int): Width of bounding box. | |
| font (str): A filename or file-like object 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. | |
| References: | |
| torchvision.utils.draw_bounding_boxes | |
| """ | |
| if isinstance(image, np.ndarray): | |
| # PIL.Image.fromarray fails with uint16 arrays | |
| # https://github.com/python-pillow/Pillow/issues/1514 | |
| if (image.dtype == np.uint16) and (image.ndim != 2): | |
| image = (image / 256).astype(np.uint8) | |
| pil_image = Image.fromarray(image) | |
| elif isinstance(image, PIL.Image.Image): | |
| pil_image = image | |
| else: | |
| raise TypeError('Unsupported image type!') | |
| pil_image = pil_image.convert('RGB') | |
| if font is None: | |
| font_object = ImageFont.load_default() | |
| else: | |
| font_object = ImageFont.truetype(font, size=font_size) | |
| if fill: | |
| draw = ImageDraw.Draw(pil_image, "RGBA") | |
| else: | |
| draw = ImageDraw.Draw(pil_image) | |
| for i, bbox in enumerate(boxes): | |
| if colors is None: | |
| color = None | |
| else: | |
| color = colors[i] | |
| assert _is_legal_color(color) | |
| color = _normalize_color(color, pil_image.mode, isinstance(image, np.ndarray)) | |
| 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,) | |
| # the first argument of ImageDraw.rectangle: | |
| # in old version only supports [(x0, y0), (x1, y1)] | |
| # in new version supports either [(x0, y0), (x1, y1)] or [x0, y0, x1, y1] | |
| draw.rectangle([(bbox[0], bbox[1]), (bbox[2], bbox[3])], width=width, outline=color, fill=fill_color) | |
| else: | |
| draw.rectangle([(bbox[0], bbox[1]), (bbox[2], bbox[3])], width=width, outline=color) | |
| if labels is not None: | |
| margin = width + 1 | |
| draw.text((bbox[0] + margin, bbox[1] + margin), labels[i], fill=color, font=font_object) | |
| if isinstance(image, np.ndarray): | |
| return np.asarray(pil_image) | |
| return pil_image | |