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
|