Source code for gluoncv.utils.viz.mask

"""Bounding box visualization functions."""
from __future__ import absolute_import, division

import numpy as np
import mxnet as mx

[docs]def expand_mask(masks, bboxes, im_shape, scores=None, thresh=0.5, scale=1.0, sortby=None): """Expand instance segmentation mask to full image size. Parameters ---------- masks : numpy.ndarray or mxnet.nd.NDArray Binary images with shape `N, M, M` bboxes : numpy.ndarray or mxnet.nd.NDArray Bounding boxes with shape `N, 4`. Where `N` is the number of boxes im_shape : tuple Tuple of length 2: (width, height) scores : numpy.ndarray or mxnet.nd.NDArray, optional Confidence scores of the provided `bboxes` with shape `N`. thresh : float, optional, default 0.5 Display threshold if `scores` is provided. Scores with less than `thresh` will be ignored in display, this is visually more elegant if you have a large number of bounding boxes with very small scores. sortby : str, optional, default None If not None, sort the color palette for masks by the given attributes of each bounding box. Valid inputs are 'area', 'xmin', 'ymin', 'xmax', 'ymax'. scale : float The scale of output image, which may affect the positions of boxes Returns ------- numpy.ndarray Binary images with shape `N, height, width` numpy.ndarray Index array of sorted masks """ from ...data.transforms.mask import fill if len(masks) != len(bboxes): raise ValueError('The length of bboxes and masks mismatch, {} vs {}' .format(len(bboxes), len(masks))) if scores is not None and len(masks) != len(scores): raise ValueError('The length of scores and masks mismatch, {} vs {}' .format(len(scores), len(masks))) if isinstance(masks, mx.nd.NDArray): masks = masks.asnumpy() if isinstance(bboxes, mx.nd.NDArray): bboxes = bboxes.asnumpy() if isinstance(scores, mx.nd.NDArray): scores = scores.asnumpy() if sortby is not None: if sortby == 'area': areas = (bboxes[:, 2] - bboxes[:, 0]) * (bboxes[:, 3] - bboxes[:, 1]) sorted_inds = np.argsort(-areas) elif sortby == 'xmin': sorted_inds = np.argsort(-bboxes[:, 0]) elif sortby == 'ymin': sorted_inds = np.argsort(-bboxes[:, 1]) elif sortby == 'xmax': sorted_inds = np.argsort(-bboxes[:, 2]) elif sortby == 'ymax': sorted_inds = np.argsort(-bboxes[:, 3]) else: raise ValueError('argument sortby cannot take value {}' .format(sortby)) else: sorted_inds = np.argsort(range(len(masks))) bboxes *= scale valid = np.where(scores >= thresh)[0] sorted_inds = sorted_inds[valid] masks = masks[valid] bboxes = bboxes[valid] full_masks = fill(masks, bboxes, im_shape) return full_masks, sorted_inds
[docs]def plot_mask(img, masks, alpha=0.5): """Visualize segmentation mask. Parameters ---------- img : numpy.ndarray or mxnet.nd.NDArray Image with shape `H, W, 3`. masks : numpy.ndarray or mxnet.nd.NDArray Binary images with shape `N, H, W`. alpha : float, optional, default 0.5 Transparency of plotted mask Returns ------- numpy.ndarray The image plotted with segmentation masks """ if isinstance(img, mx.nd.NDArray): img = img.asnumpy() if isinstance(masks, mx.nd.NDArray): masks = masks.asnumpy() for mask in masks: color = np.random.random(3) * 255 mask = np.repeat((mask > 0)[:, :, np.newaxis], repeats=3, axis=2) img = np.where(mask, img * (1 - alpha) + color * alpha, img) return img.astype('uint8')
[docs]def cv_merge_two_images(img1, img2, alpha=0.5, size=None): """Merge two images with OpoenCV. Parameters ---------- img1 : numpy.ndarray or mxnet.nd.NDArray Image with shape `H, W, 3`. img2 : numpy.ndarray or mxnet.nd.NDArray Image with shape `H, W, 3`. alpha : float, optional, default 0.5 Transparency of `img2` size : list, optional, default None The output size of the merged image Returns ------- numpy.ndarray The merged image """ from ..filesystem import try_import_cv2 cv2 = try_import_cv2() if isinstance(img1, mx.nd.NDArray): img1 = img1.asnumpy() if isinstance(img2, mx.nd.NDArray): img2 = img2.asnumpy() img = cv2.addWeighted(img1, 1-alpha, img2, alpha, 0) if size is not None: img = cv2.resize(img, (int(size[1]), int(size[0]))) return img