|
|
from PIL import Image, ImageColor |
|
|
|
|
|
|
|
|
import numpy as np |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def mask_to_xyxy(mask: np.ndarray, verbose: bool = False) -> tuple: |
|
|
"""Convert a binary mask of shape (h, w) to |
|
|
xyxy bounding box format (top-left and bottom-right coordinates). |
|
|
""" |
|
|
ys, xs = np.where(mask) |
|
|
if len(xs) == 0 or len(ys) == 0: |
|
|
if verbose: |
|
|
logger.warning("mask_to_xyxy: No object found in the mask") |
|
|
return None |
|
|
x_min = np.min(xs) |
|
|
y_min = np.min(ys) |
|
|
x_max = np.max(xs) |
|
|
y_max = np.max(ys) |
|
|
xyxy = (x_min, y_min, x_max, y_max) |
|
|
xyxy = tuple([int(i) for i in xyxy]) |
|
|
return xyxy |
|
|
|
|
|
|
|
|
def annotate_detections( |
|
|
im: Image.Image, |
|
|
l_obj: list, |
|
|
color_key: str = "class", |
|
|
bbox_width: int = 1, |
|
|
label_key: str = "object_id", |
|
|
color_dict: dict = {}, |
|
|
): |
|
|
|
|
|
color_list = list( |
|
|
mcolors.XKCD_COLORS.items() |
|
|
) |
|
|
unique_color_keys = list( |
|
|
set([o[color_key] for o in l_obj if color_key in o.keys()]) |
|
|
) |
|
|
|
|
|
for obj in l_obj: |
|
|
color_index = unique_color_keys.index(obj[color_key]) |
|
|
bbox_color = ( |
|
|
color_dict[obj[color_key]] if color_dict else color_list[color_index][1] |
|
|
) |
|
|
im = ( |
|
|
im_draw_bbox( |
|
|
im, |
|
|
color=bbox_color, |
|
|
width=bbox_width, |
|
|
caption=(str(obj[label_key]) if label_key else None), |
|
|
**obj["boundingBox"], |
|
|
use_bbv=True, |
|
|
) |
|
|
if "boundingBox" in obj.keys() |
|
|
else im_draw_point( |
|
|
im, |
|
|
**obj["point"], |
|
|
width=bbox_width, |
|
|
caption=(str(obj[label_key]) if label_key else None), |
|
|
color=bbox_color, |
|
|
) |
|
|
) |
|
|
return im |
|
|
|
|
|
|
|
|
def annotate_masks( |
|
|
im: Image.Image, masks: list, mask_alpha: float = 0.9, bbox_width: int = 3 |
|
|
) -> Image.Image: |
|
|
"""returns an annotated pillow image""" |
|
|
masks = [ |
|
|
b64_mask_decode(m).astype(np.uint8) if isinstance(m, str) else m for m in masks |
|
|
] |
|
|
segs = [] |
|
|
for i, m in enumerate(masks): |
|
|
x0, y0, x1, y1 = mask_to_xyxy(m) |
|
|
segs.append( |
|
|
{ |
|
|
"object_id": i, |
|
|
"boundingBox": {"x0": x0, "y0": y0, "x1": x1, "y1": y1}, |
|
|
} |
|
|
) |
|
|
ann_im = np.array(im) |
|
|
for i, m in enumerate(masks): |
|
|
m_color = list(mcolors.XKCD_COLORS.items())[i] |
|
|
ann_im = im_color_mask( |
|
|
ann_im, |
|
|
mask_array=m, |
|
|
alpha=mask_alpha, |
|
|
rbg_tup=ImageColor.getrgb(m_color[1]), |
|
|
) |
|
|
ann_im = annotate_detections( |
|
|
ann_im, |
|
|
l_obj=segs, |
|
|
color_key="object_id", |
|
|
label_key="object_id", |
|
|
bbox_width=bbox_width, |
|
|
) |
|
|
return ann_im |
|
|
|