Charles Kabui
commited on
Commit
·
e18f153
1
Parent(s):
daba8b1
visualize_bboxes_on_image
Browse files- utils/remove_duplicates.py +15 -0
- utils/show_tile_images.py +53 -0
- utils/visualize_bboxes_on_image.py +66 -0
utils/remove_duplicates.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
def remove_duplicates(items: list, key=lambda x: x, show_process=False):
|
| 2 |
+
'''
|
| 3 |
+
Remove duplicates from a list of items
|
| 4 |
+
Args:
|
| 5 |
+
items: List of items
|
| 6 |
+
key: Function to get the key of the item
|
| 7 |
+
show_process: Whether to show the process or not
|
| 8 |
+
Returns:
|
| 9 |
+
List: List of items without duplicates
|
| 10 |
+
'''
|
| 11 |
+
progress = lambda x, *, desc: x
|
| 12 |
+
if show_process:
|
| 13 |
+
import tqdm
|
| 14 |
+
progress = tqdm.tqdm
|
| 15 |
+
return list({key(item): item for item in progress(items, desc='Deduping...')}.values())
|
utils/show_tile_images.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from utils.fig2img import fig2img
|
| 2 |
+
import matplotlib.pyplot as plt
|
| 3 |
+
import numpy as np
|
| 4 |
+
from PIL import Image
|
| 5 |
+
from typing import List
|
| 6 |
+
|
| 7 |
+
def show_tile_images(
|
| 8 |
+
images: List[np.ndarray | Image.Image],
|
| 9 |
+
width_parts: int,
|
| 10 |
+
figsize = None,
|
| 11 |
+
space = 0.0,
|
| 12 |
+
pad = False,
|
| 13 |
+
figcolor = 'white',
|
| 14 |
+
titles: List[str] = None,
|
| 15 |
+
title_color: str = None,
|
| 16 |
+
title_background_color: str = None,
|
| 17 |
+
title_font_size: int = None):
|
| 18 |
+
'''
|
| 19 |
+
Show images in a tile format
|
| 20 |
+
Args:
|
| 21 |
+
images: List of images to show
|
| 22 |
+
width_parts: Number of images to show in a row
|
| 23 |
+
figsize: Size of the figure
|
| 24 |
+
space: Space between images
|
| 25 |
+
pad: Whether to pad the images or not
|
| 26 |
+
figcolor: Background color of the figure
|
| 27 |
+
titles: Titles of the images
|
| 28 |
+
title_color: Color of the title
|
| 29 |
+
title_background_color: Background color of the title
|
| 30 |
+
title_font_size: Font size of the title
|
| 31 |
+
Returns:
|
| 32 |
+
Image: Image of the figure
|
| 33 |
+
'''
|
| 34 |
+
height = int(np.ceil(len(images) / width_parts))
|
| 35 |
+
fig, axs = plt.subplots(height, width_parts, figsize=figsize if figsize != None else (8 * 2, 12 * height))
|
| 36 |
+
fig.patch.set_facecolor(figcolor)
|
| 37 |
+
axes = axs.flatten() if isinstance(axs, np.ndarray) else [axs]
|
| 38 |
+
titles = (titles or []) + np.full(len(images) - len(titles or []), None).tolist()
|
| 39 |
+
for img, ax, title in zip(images, axes, titles):
|
| 40 |
+
if title:
|
| 41 |
+
params = {k: v for k, v in { 'color': title_color, 'backgroundcolor': title_background_color, 'fontsize': title_font_size }.items() if v is not None}
|
| 42 |
+
ax.set_title(title, **params)
|
| 43 |
+
ax.imshow(img.convert("RGB") if not isinstance(img, np.ndarray) else img)
|
| 44 |
+
ax.axis('off')
|
| 45 |
+
if pad:
|
| 46 |
+
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=space, hspace=space)
|
| 47 |
+
fig.tight_layout(h_pad=space, w_pad = space, pad = space)
|
| 48 |
+
else:
|
| 49 |
+
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=space, hspace=space)
|
| 50 |
+
fig.tight_layout(h_pad=space, w_pad = space, pad = 0)
|
| 51 |
+
plt.margins()
|
| 52 |
+
plt.close()
|
| 53 |
+
return fig2img(fig)
|
utils/visualize_bboxes_on_image.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is used to visualize bounding boxes on an image
|
| 2 |
+
from urllib.parse import urlparse
|
| 3 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 4 |
+
import numpy as np
|
| 5 |
+
import requests
|
| 6 |
+
from typing import List
|
| 7 |
+
from functools import cache
|
| 8 |
+
|
| 9 |
+
@cache
|
| 10 |
+
def get_font(path_or_url: str = 'https://github.com/googlefonts/roboto/raw/main/src/hinted/Roboto-Regular.ttf', size: int = 10):
|
| 11 |
+
if urlparse(path_or_url).scheme in ["http", "https"]: # Online
|
| 12 |
+
return ImageFont.truetype(requests.get(path_or_url, stream=True).raw, size=size)
|
| 13 |
+
else: # Local
|
| 14 |
+
return ImageFont.truetype(path_or_url, size=size)
|
| 15 |
+
|
| 16 |
+
def visualize_bboxes_on_image(
|
| 17 |
+
image: Image.Image,
|
| 18 |
+
bboxes: List[List[int]],
|
| 19 |
+
titles: List[str] = None,
|
| 20 |
+
width = 2,
|
| 21 |
+
bbox_color="red",
|
| 22 |
+
label_text_color="black",
|
| 23 |
+
label_rectangle_color="red",
|
| 24 |
+
convert_to_x0y0x1y1 = None,
|
| 25 |
+
label_text_padding = 2,
|
| 26 |
+
label_rectangle_left_padding=10,
|
| 27 |
+
label_rectangle_top_padding=10,
|
| 28 |
+
label_text_size = 10) -> Image.Image:
|
| 29 |
+
'''
|
| 30 |
+
Visualize bounding boxes on an image
|
| 31 |
+
Args:
|
| 32 |
+
image: Image to visualize
|
| 33 |
+
bboxes: List of bounding boxes
|
| 34 |
+
titles: Titles of the bounding boxes
|
| 35 |
+
width: Width of the bounding box
|
| 36 |
+
bbox_color: Color of the bounding box
|
| 37 |
+
label_text_color: Color of the label text
|
| 38 |
+
label_rectangle_color: Color of the label rectangle
|
| 39 |
+
convert_to_x0y0x1y1: Function to convert bounding box to x0y0x1y1 format
|
| 40 |
+
label_text_padding: Padding of the label text
|
| 41 |
+
label_rectangle_left_padding: Left padding of the label rectangle
|
| 42 |
+
label_rectangle_top_padding: Top padding of the label rectangle
|
| 43 |
+
label_text_size: Font size of the label text
|
| 44 |
+
Returns:
|
| 45 |
+
Image: Image with bounding boxes'''
|
| 46 |
+
image = image.copy().convert("RGB")
|
| 47 |
+
draw = ImageDraw.Draw(image)
|
| 48 |
+
font = get_font(size = label_text_size)
|
| 49 |
+
titles = (titles or []) + np.full(len(bboxes) - len(titles or []), None).tolist()
|
| 50 |
+
for bbox, title in zip(bboxes, titles):
|
| 51 |
+
x0, y0, x1, y1 = convert_to_x0y0x1y1(bbox) if convert_to_x0y0x1y1 is not None else bbox
|
| 52 |
+
draw.rectangle([x0, y0, x1, y1], outline=bbox_color, width=width)
|
| 53 |
+
if title is not None:
|
| 54 |
+
title = title + " " + str(bbox)
|
| 55 |
+
text_position = (x0 + label_rectangle_left_padding, y0 - label_rectangle_top_padding)
|
| 56 |
+
text_bbox_left, text_bbox_top, text_bbox_right, text_bbox_bottom = draw.textbbox(text_position, title, font=font)
|
| 57 |
+
draw.rectangle(
|
| 58 |
+
(
|
| 59 |
+
text_bbox_left - label_text_padding,
|
| 60 |
+
text_bbox_top - label_text_padding,
|
| 61 |
+
text_bbox_right + label_text_padding,
|
| 62 |
+
text_bbox_bottom + label_text_padding
|
| 63 |
+
),
|
| 64 |
+
fill=label_rectangle_color)
|
| 65 |
+
draw.text(text_position, title, font=font, fill=label_text_color)
|
| 66 |
+
return image
|