| import os.path as osp |
| import os |
| import matplotlib.pyplot as plt |
| import torch |
| import cv2 |
| import math |
|
|
| import numpy as np |
| import tqdm |
| from cv2 import findContours |
| from dl_ext.primitive import safe_zip |
| from dl_ext.timer import EvalTime |
|
|
|
|
| def plot_confidence(confidence): |
| n = len(confidence) |
| plt.plot(np.arange(n), confidence) |
| plt.show() |
|
|
|
|
| def image_grid( |
| images, |
| rows=None, |
| cols=None, |
| fill: bool = True, |
| show_axes: bool = False, |
| rgb=None, |
| show=True, |
| label=None, |
| **kwargs |
| ): |
| """ |
| A util function for plotting a grid of images. |
| Args: |
| images: (N, H, W, 4) array of RGBA images |
| rows: number of rows in the grid |
| cols: number of columns in the grid |
| fill: boolean indicating if the space between images should be filled |
| show_axes: boolean indicating if the axes of the plots should be visible |
| rgb: boolean, If True, only RGB channels are plotted. |
| If False, only the alpha channel is plotted. |
| Returns: |
| None |
| """ |
| evaltime = EvalTime(disable=True) |
| evaltime('') |
| if isinstance(images, torch.Tensor): |
| images = images.detach().cpu() |
| if len(images[0].shape) == 2: |
| rgb = False |
| if images[0].shape[-1] == 2: |
| |
| images = [flow_to_image(im) for im in images] |
| if (rows is None) != (cols is None): |
| raise ValueError("Specify either both rows and cols or neither.") |
|
|
| if rows is None: |
| rows = int(len(images) ** 0.5) |
| cols = math.ceil(len(images) / rows) |
|
|
| gridspec_kw = {"wspace": 0.0, "hspace": 0.0} if fill else {} |
| if len(images) < 50: |
| figsize = (10, 10) |
| else: |
| figsize = (15, 15) |
| evaltime('0.5') |
| plt.figure(figsize=figsize) |
| |
| if label: |
| |
| plt.suptitle(label, fontsize=30) |
| |
| |
| evaltime('subplots') |
|
|
| |
| for i in range(len(images)): |
| |
| plt.subplot(rows, cols, i + 1) |
| if rgb: |
| |
| plt.imshow(images[i][..., :3], **kwargs) |
| |
| else: |
| |
| plt.imshow(images[i], **kwargs) |
| |
| if not show_axes: |
| plt.axis('off') |
| |
| |
| plt.title(f'{i}') |
| |
| evaltime('2') |
| if show: |
| plt.show() |
| |
|
|
|
|
| def depth_grid( |
| depths, |
| rows=None, |
| cols=None, |
| fill: bool = True, |
| show_axes: bool = False, |
| ): |
| """ |
| A util function for plotting a grid of images. |
| Args: |
| images: (N, H, W, 4) array of RGBA images |
| rows: number of rows in the grid |
| cols: number of columns in the grid |
| fill: boolean indicating if the space between images should be filled |
| show_axes: boolean indicating if the axes of the plots should be visible |
| rgb: boolean, If True, only RGB channels are plotted. |
| If False, only the alpha channel is plotted. |
| Returns: |
| None |
| """ |
| if (rows is None) != (cols is None): |
| raise ValueError("Specify either both rows and cols or neither.") |
|
|
| if rows is None: |
| rows = len(depths) |
| cols = 1 |
|
|
| gridspec_kw = {"wspace": 0.0, "hspace": 0.0} if fill else {} |
| fig, axarr = plt.subplots(rows, cols, gridspec_kw=gridspec_kw, figsize=(15, 9)) |
| bleed = 0 |
| fig.subplots_adjust(left=bleed, bottom=bleed, right=(1 - bleed), top=(1 - bleed)) |
|
|
| for ax, im in zip(axarr.ravel(), depths): |
| ax.imshow(im) |
| if not show_axes: |
| ax.set_axis_off() |
| plt.show() |
|
|
|
|
| def hover_masks_on_imgs(images, masks): |
| masks = np.array(masks) |
| new_imgs = [] |
| tids = list(range(1, masks.max() + 1)) |
| colors = colormap(rgb=True, lighten=True) |
| for im, mask in tqdm.tqdm(safe_zip(images, masks), total=len(images)): |
| for tid in tids: |
| im = vis_mask( |
| im, |
| (mask == tid).astype(np.uint8), |
| color=colors[tid], |
| alpha=0.5, |
| border_alpha=0.5, |
| border_color=[255, 255, 255], |
| border_thick=3) |
| new_imgs.append(im) |
| return new_imgs |
|
|
|
|
| def vis_mask(img, |
| mask, |
| color=[255, 255, 255], |
| alpha=0.4, |
| show_border=True, |
| border_alpha=0.5, |
| border_thick=1, |
| border_color=None): |
| """Visualizes a single binary mask.""" |
| if isinstance(mask, torch.Tensor): |
| from anypose.utils.pn_utils import to_array |
| mask = to_array(mask > 0).astype(np.uint8) |
| img = img.astype(np.float32) |
| idx = np.nonzero(mask) |
|
|
| img[idx[0], idx[1], :] *= 1.0 - alpha |
| img[idx[0], idx[1], :] += [alpha * x for x in color] |
|
|
| if show_border: |
| contours, _ = findContours( |
| mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) |
| |
| if border_color is None: |
| border_color = color |
| if not isinstance(border_color, list): |
| border_color = border_color.tolist() |
| if border_alpha < 1: |
| with_border = img.copy() |
| cv2.drawContours(with_border, contours, -1, border_color, |
| border_thick, cv2.LINE_AA) |
| img = (1 - border_alpha) * img + border_alpha * with_border |
| else: |
| cv2.drawContours(img, contours, -1, border_color, border_thick, |
| cv2.LINE_AA) |
|
|
| return img.astype(np.uint8) |
|
|
|
|
| def colormap(rgb=False, lighten=True): |
| """Copied from Detectron codebase.""" |
| color_list = np.array( |
| [ |
| 0.000, 0.447, 0.741, |
| 0.850, 0.325, 0.098, |
| 0.929, 0.694, 0.125, |
| 0.494, 0.184, 0.556, |
| 0.466, 0.674, 0.188, |
| 0.301, 0.745, 0.933, |
| 0.635, 0.078, 0.184, |
| 0.300, 0.300, 0.300, |
| 0.600, 0.600, 0.600, |
| 1.000, 0.000, 0.000, |
| 1.000, 0.500, 0.000, |
| 0.749, 0.749, 0.000, |
| 0.000, 1.000, 0.000, |
| 0.000, 0.000, 1.000, |
| 0.667, 0.000, 1.000, |
| 0.333, 0.333, 0.000, |
| 0.333, 0.667, 0.000, |
| 0.333, 1.000, 0.000, |
| 0.667, 0.333, 0.000, |
| 0.667, 0.667, 0.000, |
| 0.667, 1.000, 0.000, |
| 1.000, 0.333, 0.000, |
| 1.000, 0.667, 0.000, |
| 1.000, 1.000, 0.000, |
| 0.000, 0.333, 0.500, |
| 0.000, 0.667, 0.500, |
| 0.000, 1.000, 0.500, |
| 0.333, 0.000, 0.500, |
| 0.333, 0.333, 0.500, |
| 0.333, 0.667, 0.500, |
| 0.333, 1.000, 0.500, |
| 0.667, 0.000, 0.500, |
| 0.667, 0.333, 0.500, |
| 0.667, 0.667, 0.500, |
| 0.667, 1.000, 0.500, |
| 1.000, 0.000, 0.500, |
| 1.000, 0.333, 0.500, |
| 1.000, 0.667, 0.500, |
| 1.000, 1.000, 0.500, |
| 0.000, 0.333, 1.000, |
| 0.000, 0.667, 1.000, |
| 0.000, 1.000, 1.000, |
| 0.333, 0.000, 1.000, |
| 0.333, 0.333, 1.000, |
| 0.333, 0.667, 1.000, |
| 0.333, 1.000, 1.000, |
| 0.667, 0.000, 1.000, |
| 0.667, 0.333, 1.000, |
| 0.667, 0.667, 1.000, |
| 0.667, 1.000, 1.000, |
| 1.000, 0.000, 1.000, |
| 1.000, 0.333, 1.000, |
| 1.000, 0.667, 1.000, |
| 0.167, 0.000, 0.000, |
| 0.333, 0.000, 0.000, |
| 0.500, 0.000, 0.000, |
| 0.667, 0.000, 0.000, |
| 0.833, 0.000, 0.000, |
| 1.000, 0.000, 0.000, |
| 0.000, 0.167, 0.000, |
| 0.000, 0.333, 0.000, |
| 0.000, 0.500, 0.000, |
| 0.000, 0.667, 0.000, |
| 0.000, 0.833, 0.000, |
| 0.000, 1.000, 0.000, |
| 0.000, 0.000, 0.167, |
| 0.000, 0.000, 0.333, |
| 0.000, 0.000, 0.500, |
| 0.000, 0.000, 0.667, |
| 0.000, 0.000, 0.833, |
| 0.000, 0.000, 1.000, |
| 0.000, 0.000, 0.000, |
| 0.143, 0.143, 0.143, |
| 0.286, 0.286, 0.286, |
| 0.429, 0.429, 0.429, |
| 0.571, 0.571, 0.571, |
| 0.714, 0.714, 0.714, |
| 0.857, 0.857, 0.857, |
| 1.000, 1.000, 1.000 |
| ] |
| ).astype(np.float32) |
| color_list = color_list.reshape((-1, 3)) |
| if not rgb: |
| color_list = color_list[:, ::-1] |
|
|
| if lighten: |
| |
| |
| w_ratio = 0.4 |
| color_list = (color_list * (1 - w_ratio) + w_ratio) |
| return color_list * 255 |
|
|
|
|
| def vis_layer_mask(masks, save_path=None): |
| masks = torch.as_tensor(masks) |
| tids = masks.unique().tolist() |
| tids.remove(0) |
| for tid in tqdm.tqdm(tids): |
| show = save_path is None |
| image_grid(masks == tid, label=f'{tid}', show=show) |
| if save_path: |
| os.makedirs(osp.dirname(save_path), exist_ok=True) |
| plt.savefig(save_path % tid) |
| plt.close('all') |
|
|
|
|
| def show(x, **kwargs): |
| if isinstance(x, torch.Tensor): |
| x = x.detach().cpu() |
| plt.imshow(x, **kwargs) |
| plt.show() |
|
|
|
|
| def vis_title(rgb, text, shift_y=30): |
| tmp = rgb.copy() |
| shift_x = rgb.shape[1] // 2 |
| cv2.putText(tmp, text, |
| (shift_x, shift_y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), thickness=2, lineType=cv2.LINE_AA) |
| return tmp |
|
|