Ejemplo n.º 1
0
def make_orimask(radians, mag=None, alpha=1.0):
    """
    Makes a colormap in HSV space where the orientation changes color and mag
    changes the saturation/value.

    Args:
        radians (ndarray): orientation in radians
        mag (ndarray): magnitude (must be normalized between 0 and 1)
        alpha (float | ndarray):
            if False or None, then the image is returned without alpha
            if a float, then mag is scaled by this and used as the alpha channel
            if an ndarray, then this is explicilty set as the alpha channel

    Returns:
        ndarray[float32]: an rgb / rgba image in 01 space

    SeeAlso:
        kwimage.overlay_alpha_images

    Example:
        >>> # xdoc: +REQUIRES(module:matplotlib)
        >>> x, y = np.meshgrid(np.arange(64), np.arange(64))
        >>> dx, dy = x - 32, y - 32
        >>> radians = np.arctan2(dx, dy)
        >>> mag = np.sqrt(dx ** 2 + dy ** 2)
        >>> orimask = make_orimask(radians, mag)
        >>> # xdoc: +REQUIRES(--show)
        >>> import kwplot
        >>> kwplot.imshow(orimask, fnum=1, doclf=True, colorspace='rgb')
        >>> kwplot.show_if_requested()
    """
    import matplotlib as mpl
    import matplotlib.cm  # NOQA
    TAU = np.pi * 2
    # Map radians to 0 to 1
    ori01 = (radians % TAU) / TAU
    cmap_ = mpl.cm.get_cmap('hsv')
    color_rgb = cmap_(ori01)[..., 0:3].astype(np.float32)
    if mag is not None:
        import kwimage
        if mag.max() > 1:
            mag = mag / mag.max()
        color_hsv = kwimage.convert_colorspace(color_rgb, 'rgb', 'hsv')
        color_hsv[..., 1:3] = mag[..., None]
        color_rgb = kwimage.convert_colorspace(color_hsv, 'hsv', 'rgb')
    else:
        mag = 1
    orimask = np.array(color_rgb, dtype=np.float32)

    if isinstance(alpha, np.ndarray):
        # Alpha specified as explicit numpy array
        orimask = kwimage.ensure_alpha_channel(orimask)
        orimask[:, :, 3] = alpha
    elif alpha is not False and alpha is not None:
        orimask = kwimage.ensure_alpha_channel(orimask)
        orimask[:, :, 3] = mag * alpha
    return orimask
Ejemplo n.º 2
0
    def _draw_batch_preds(harn, batch, outputs, lim=16):
        """
        Example:
            >>> # xdoctest: +REQUIRES(--slow)
            >>> kw = {'workers': 0, 'xpu': 'cpu', 'batch_size': 8}
            >>> harn = setup_harn(cmdline=False, **kw).initialize()
            >>> batch = harn._demo_batch(tag='train')
            >>> outputs, loss_parts = harn.run_batch(batch)
            >>> toshow = harn._draw_batch_preds(batch, outputs)
            >>> # xdoctest: +REQUIRES(--show)
            >>> import kwplot
            >>> kwplot.autompl()
            >>> kwplot.imshow(toshow)
        """
        import cv2
        im = batch['im'].data.cpu().numpy()
        class_true = batch['class_idxs'].data.cpu().numpy()
        class_pred = outputs['class_probs'].data.cpu().numpy().argmax(axis=1)

        batch_imgs = []

        for bx in range(min(len(class_true), lim)):
            orig_img = im[bx].transpose(1, 2, 0)

            out_size = class_pred[bx].shape[::-1]

            orig_img = cv2.resize(orig_img, tuple(map(int, out_size)))
            orig_img = kwimage.ensure_alpha_channel(orig_img)

            pred_heatmap = kwimage.Heatmap(
                class_idx=class_pred[bx],
                classes=harn.classes
            )
            true_heatmap = kwimage.Heatmap(
                class_idx=class_true[bx],
                classes=harn.classes
            )

            # TODO: scale up to original image size

            pred_img = pred_heatmap.draw_on(orig_img, channel='idx', with_alpha=.5)
            true_img = true_heatmap.draw_on(orig_img, channel='idx', with_alpha=.5)

            true_img = kwimage.ensure_uint255(true_img)
            pred_img = kwimage.ensure_uint255(pred_img)

            true_img = kwimage.draw_text_on_image(
                true_img, 'true', org=(0, 0), valign='top', color='blue')

            pred_img = kwimage.draw_text_on_image(
                pred_img, 'pred', org=(0, 0), valign='top', color='blue')

            item_img = kwimage.stack_images([pred_img, true_img], axis=1)
            batch_imgs.append(item_img)

        toshow = kwimage.stack_images_grid(batch_imgs, chunksize=2, overlap=-32)
        return toshow
Ejemplo n.º 3
0
    def _from_elem(self, cname, chip, size=None):
        """
        Example:
            >>> # hack to allow chip to be None
            >>> chip = None
            >>> size = (32, 32)
            >>> cname = 'superstar'
            >>> self = CategoryPatterns.coerce()
            >>> self._from_elem(cname, chip, size)
        """
        elem_func = self._category_to_elemfunc[cname]

        if chip is None:
            assert size is not None
            x = max(size)
        else:
            size = tuple(map(int, chip.shape[0:2][::-1]))
            x = max(chip.shape[0:2])

        # x = int(2 ** np.floor(np.log2(x)))
        elem, kpts_yx = elem_func(x)

        if kpts_yx is not None:
            kp_catnames = list(kpts_yx.keys())
            xy = np.array([yx[::-1] for yx in kpts_yx.values()])
            kpts = kwimage.Points(xy=xy,
                                  class_idxs=np.arange(len(xy)),
                                  classes=kp_catnames)
            sf = np.array(size) / np.array(elem.shape[0:2][::-1])
            kpts = kpts.scale(sf)
        else:
            kpts = None
            # center
            kpts = kwimage.Points(xy=np.array([]))
            # kpts = kwimage.Points(xy=np.array([[.5, .5]]))
            kpts = kpts.scale(size)

        template = cv2.resize(elem, size).astype(np.float32)
        fg_intensity = np.float32(self.fg_intensity)
        fg_scale = np.float32(self.fg_scale)

        if chip is not None:
            fgdata = kwarray.standard_normal(chip.shape,
                                             std=fg_scale,
                                             mean=fg_intensity,
                                             rng=self.rng,
                                             dtype=np.float32)
            fgdata = np.clip(fgdata, 0, 1, out=fgdata)
            fga = kwimage.ensure_alpha_channel(fgdata, alpha=template)
            data = kwimage.overlay_alpha_images(fga, chip, keepalpha=False)
        else:
            data = None
        mask = (template > 0.05).astype(np.uint8)
        return data, mask, kpts
Ejemplo n.º 4
0
def overlay_colorized(colorized, orig, alpha=.6, keepcolors=False):
    """
    Overlays a color segmentation mask on an original image

    Args:
        colorized (ndarray): the color mask to be overlayed on top of the original image
        orig (ndarray): the original image to superimpose on
        alpha (float): blend level to use if colorized is not an alpha image

    """
    import kwimage
    color_mask = kwimage.ensure_alpha_channel(colorized, alpha=alpha)
    if not keepcolors:
        orig = ensure_grayscale(orig)
    color_blend = kwimage.overlay_alpha_images(color_mask, orig)
    color_blend = (color_blend * 255).astype(np.uint8)
    return color_blend
Ejemplo n.º 5
0
    def draw_on(self, image, color='blue', fill=True, border=False, alpha=1.0,
                copy=False):
        """
        Rasterizes a polygon on an image. See `draw` for a vectorized
        matplotlib version.

        Args:
            image (ndarray): image to raster polygon on.
            color (str | tuple): data coercable to a color
            fill (bool, default=True): draw the center mass of the polygon
            border (bool, default=False): draw the border of the polygon
            alpha (float, default=1.0): polygon transparency (setting alpha < 1
                makes this function much slower).
            copy (bool, default=False): if False only copies if necessary

        Example:
            >>> # xdoc: +REQUIRES(module:kwplot)
            >>> from kwimage.structs.polygon import *  # NOQA
            >>> self = Polygon.random(n_holes=1).scale(128)
            >>> image = np.zeros((128, 128), dtype=np.float32)
            >>> image = self.draw_on(image)
            >>> # xdoc: +REQUIRES(--show)
            >>> import kwplot
            >>> kwplot.autompl()
            >>> kwplot.imshow(image, fnum=1)

        Example:
            >>> import kwimage
            >>> color = 'blue'
            >>> self = kwimage.Polygon.random(n_holes=1).scale(128)
            >>> image = np.zeros((128, 128), dtype=np.float32)
            >>> # Test drawong on all channel + dtype combinations
            >>> im3 = np.random.rand(128, 128, 3)
            >>> im_chans = {
            >>>     'im3': im3,
            >>>     'im1': kwimage.convert_colorspace(im3, 'rgb', 'gray'),
            >>>     'im4': kwimage.convert_colorspace(im3, 'rgb', 'rgba'),
            >>> }
            >>> inputs = {}
            >>> for k, im in im_chans.items():
            >>>     inputs[k + '_01'] = (kwimage.ensure_float01(im.copy()), {'alpha': None})
            >>>     inputs[k + '_255'] = (kwimage.ensure_uint255(im.copy()), {'alpha': None})
            >>>     inputs[k + '_01_a'] = (kwimage.ensure_float01(im.copy()), {'alpha': 0.5})
            >>>     inputs[k + '_255_a'] = (kwimage.ensure_uint255(im.copy()), {'alpha': 0.5})
            >>> outputs = {}
            >>> for k, v in inputs.items():
            >>>     im, kw = v
            >>>     outputs[k] = self.draw_on(im, color=color, **kw)
            >>> # xdoc: +REQUIRES(--show)
            >>> import kwplot
            >>> kwplot.figure(fnum=2, doclf=True)
            >>> kwplot.autompl()
            >>> pnum_ = kwplot.PlotNums(nCols=2, nRows=len(inputs))
            >>> for k in inputs.keys():
            >>>     kwplot.imshow(inputs[k][0], fnum=2, pnum=pnum_(), title=k)
            >>>     kwplot.imshow(outputs[k], fnum=2, pnum=pnum_(), title=k)
            >>> kwplot.show_if_requested()
        """
        import kwimage
        # return shape of contours to openCV contours

        dtype_fixer = _generic._consistent_dtype_fixer(image)

        # print('--- A')
        # print('image.dtype = {!r}'.format(image.dtype))
        # print('image.max() = {!r}'.format(image.max()))

        # line_type = cv2.LINE_AA
        line_type = cv2.LINE_8

        cv_contours = self._to_cv_countours()

        if alpha is None or alpha == 1.0:
            # image = kwimage.ensure_uint255(image)
            image = kwimage.atleast_3channels(image, copy=copy)
            rgba = kwimage.Color(color)._forimage(image)
        else:
            image = kwimage.ensure_float01(image)
            image = kwimage.ensure_alpha_channel(image)
            rgba = kwimage.Color(color, alpha=alpha)._forimage(image)

        # print('--- B')
        # print('image.dtype = {!r}'.format(image.dtype))
        # print('image.max() = {!r}'.format(image.max()))
        # print('rgba = {!r}'.format(rgba))

        if fill:
            if alpha is None or alpha == 1.0:
                # Modification happens inplace
                image = cv2.fillPoly(image, cv_contours, rgba, line_type, shift=0)
            else:
                orig = image.copy()
                mask = np.zeros_like(orig)
                mask = cv2.fillPoly(mask, cv_contours, rgba, line_type, shift=0)
                # TODO: could use add weighted
                image = kwimage.overlay_alpha_images(mask, orig)
                rgba = kwimage.Color(rgba)._forimage(image)

        # print('--- C')
        # print('image.dtype = {!r}'.format(image.dtype))
        # print('image.max() = {!r}'.format(image.max()))
        # print('rgba = {!r}'.format(rgba))

        if border or True:
            thickness = 4
            contour_idx = -1
            image = cv2.drawContours(image, cv_contours, contour_idx, rgba,
                                     thickness, line_type)
        # image = kwimage.ensure_float01(image)[..., 0:3]

        # print('--- D')
        # print('image.dtype = {!r}'.format(image.dtype))
        # print('image.max() = {!r}'.format(image.max()))

        image = dtype_fixer(image, copy=False)
        return image
Ejemplo n.º 6
0
def draw_vector_field(image,
                      dx,
                      dy,
                      stride=0.02,
                      thresh=0.0,
                      scale=1.0,
                      alpha=1.0,
                      color='red',
                      thickness=1,
                      tipLength=0.1,
                      line_type='aa'):
    """
    Create an image representing a 2D vector field.

    Args:
        image (ndarray): image to draw on
        dx (ndarray): grid of vector x components
        dy (ndarray): grid of vector y components
        stride (int | float): sparsity of vectors, int specifies stride step in
            pixels, a float specifies it as a percentage.
        thresh (float): only plot vectors with magnitude greater than thres
        scale (float): multiply magnitude for easier visualization
        alpha (float): alpha value for vectors. Non-vector regions receive 0
            alpha (if False, no alpha channel is used)
        color (str | tuple | kwimage.Color): RGB color of the vectors
        thickness (int, default=1): thickness of arrows
        tipLength (float, default=0.1): fraction of line length
        line_type (int): either cv2.LINE_4, cv2.LINE_8, or cv2.LINE_AA

    Returns:
        ndarray[float32]: The image with vectors overlaid. If image=None, then an
            rgb/a image is created and returned.

    Example:
        >>> import kwimage
        >>> width, height = 512, 512
        >>> image = kwimage.grab_test_image(dsize=(width, height))
        >>> x, y = np.meshgrid(np.arange(height), np.arange(width))
        >>> dx, dy = x - width / 2, y - height / 2
        >>> radians = np.arctan2(dx, dy)
        >>> mag = np.sqrt(dx ** 2 + dy ** 2) + 1e-3
        >>> dx, dy = dx / mag, dy / mag
        >>> img = kwimage.draw_vector_field(image, dx, dy, scale=10, alpha=False)
        >>> # xdoctest: +REQUIRES(--show)
        >>> import kwplot
        >>> kwplot.autompl()
        >>> kwplot.imshow(img)
        >>> kwplot.show_if_requested()
    """
    import cv2
    import kwimage

    if image is None:
        # Create a default image
        image = np.zeros(dx.shape + (3, ), dtype=np.uint8)
        # image = kwimage.atleast_3channels(image)

    color = kwimage.Color(color)._forimage(image)

    line_type_lookup = {'aa': cv2.LINE_AA}
    line_type = line_type_lookup.get(line_type, line_type)

    height, width = dx.shape[0:2]

    x_grid = np.arange(0, width, 1)
    y_grid = np.arange(0, height, 1)
    # Vector locations and directions
    X, Y = np.meshgrid(x_grid, y_grid)
    U, V = dx, dy

    XYUV = [X, Y, U, V]

    if isinstance(stride, float):
        if stride < 0 or stride > 1:
            raise ValueError('Floating point strides must be between 0 and 1')
        stride = int(np.ceil(stride * min(width, height)))

    # stride the points
    if stride is not None and stride > 1:
        XYUV = [a[::stride, ::stride] for a in XYUV]

    # flatten the points
    XYUV = [a.ravel() for a in XYUV]

    # Filter out points with low magnitudes
    if thresh is not None and thresh > 0:
        M = np.sqrt((XYUV[2]**2) + (XYUV[3]**2)).ravel()
        XYUV = np.array(XYUV)
        flags = M > thresh
        XYUV = [a[flags] for a in XYUV]

    # Adjust vector magnitude for visibility
    if scale is not None:
        XYUV[2] *= scale
        XYUV[3] *= scale

    if alpha is not None and alpha is not False and alpha != 1:
        raise NotImplementedError

    for (x, y, u, v) in zip(*XYUV):
        pt1 = (int(x), int(y))
        pt2 = tuple(map(int, map(np.round, (x + u, y + v))))
        cv2.arrowedLine(image,
                        pt1,
                        pt2,
                        color=color,
                        thickness=thickness,
                        tipLength=tipLength,
                        line_type=line_type)

    if isinstance(alpha, np.ndarray):
        # Alpha specified as explicit numpy array
        image = kwimage.ensure_float01(image)
        image = kwimage.ensure_alpha_channel(image)
        image[:, :, 3] = alpha
    elif alpha is not False and alpha is not None:
        # Alpha specified as a scale factor
        image = kwimage.ensure_float01(image)
        image = kwimage.ensure_alpha_channel(image)
        # image[:, :, 3] = (image[:, :, 0:3].sum(axis=2) > 0) * alpha
        image[:, :, 3] = image[:, :, 0:3].sum(axis=2) * alpha
    return image
Ejemplo n.º 7
0
def make_vector_field(dx,
                      dy,
                      stride=0.02,
                      thresh=0.0,
                      scale=1.0,
                      alpha=1.0,
                      color='red',
                      thickness=1,
                      tipLength=0.1,
                      line_type='aa'):
    """
    Create an image representing a 2D vector field.

    Args:
        dx (ndarray): grid of vector x components
        dy (ndarray): grid of vector y components
        stride (int | float): sparsity of vectors, int specifies stride step in
            pixels, a float specifies it as a percentage.
        thresh (float): only plot vectors with magnitude greater than thres
        scale (float): multiply magnitude for easier visualization
        alpha (float): alpha value for vectors. Non-vector regions receive 0
            alpha (if False, no alpha channel is used)
        color (str | tuple | kwimage.Color): RGB color of the vectors
        thickness (int, default=1): thickness of arrows
        tipLength (float, default=0.1): fraction of line length
        line_type (int): either cv2.LINE_4, cv2.LINE_8, or cv2.LINE_AA

    Returns:
        ndarray[float32]: vec_img: an rgb/rgba image in 0-1 space

    SeeAlso:
        kwimage.overlay_alpha_images

    DEPRECATED USE: draw_vector_field instead

    Example:
        >>> x, y = np.meshgrid(np.arange(512), np.arange(512))
        >>> dx, dy = x - 256.01, y - 256.01
        >>> radians = np.arctan2(dx, dy)
        >>> mag = np.sqrt(dx ** 2 + dy ** 2)
        >>> dx, dy = dx / mag, dy / mag
        >>> img = make_vector_field(dx, dy, scale=10, alpha=False)
        >>> # xdoctest: +REQUIRES(--show)
        >>> import kwplot
        >>> kwplot.autompl()
        >>> kwplot.imshow(img)
        >>> kwplot.show_if_requested()
    """
    import warnings
    warnings.warn('Deprecated, use draw_vector_field instead',
                  DeprecationWarning)
    import cv2
    import kwimage
    color = kwimage.Color(color).as255('rgb')
    vecmask = np.zeros(dx.shape + (3, ), dtype=np.uint8)

    line_type_lookup = {'aa': cv2.LINE_AA}
    line_type = line_type_lookup.get(line_type, line_type)

    width = dx.shape[1]
    height = dy.shape[0]

    x_grid = np.arange(0, width, 1)
    y_grid = np.arange(0, height, 1)
    # Vector locations and directions
    X, Y = np.meshgrid(x_grid, y_grid)
    U, V = dx, dy

    XYUV = [X, Y, U, V]

    if isinstance(stride, float):
        if stride < 0 or stride > 1:
            raise ValueError('Floating point strides must be between 0 and 1')
        stride = int(np.ceil(stride * min(width, height)))

    # stride the points
    if stride is not None and stride > 1:
        XYUV = [a[::stride, ::stride] for a in XYUV]

    # flatten the points
    XYUV = [a.ravel() for a in XYUV]

    # Filter out points with low magnitudes
    if thresh is not None and thresh > 0:
        M = np.sqrt((XYUV[2]**2) + (XYUV[3]**2)).ravel()
        XYUV = np.array(XYUV)
        flags = M > thresh
        XYUV = [a[flags] for a in XYUV]

    # Adjust vector magnitude for visibility
    if scale is not None:
        XYUV[2] *= scale
        XYUV[3] *= scale

    for (x, y, u, v) in zip(*XYUV):
        pt1 = (int(x), int(y))
        pt2 = tuple(map(int, map(np.round, (x + u, y + v))))
        cv2.arrowedLine(vecmask,
                        pt1,
                        pt2,
                        color=color,
                        thickness=thickness,
                        tipLength=tipLength,
                        line_type=line_type)

    vecmask = kwimage.ensure_float01(vecmask)
    if isinstance(alpha, np.ndarray):
        # Alpha specified as explicit numpy array
        vecmask = kwimage.ensure_alpha_channel(vecmask)
        vecmask[:, :, 3] = alpha
    elif alpha is not False and alpha is not None:
        # Alpha specified as a scale factor
        vecmask = kwimage.ensure_alpha_channel(vecmask)
        # vecmask[:, :, 3] = (vecmask[:, :, 0:3].sum(axis=2) > 0) * alpha
        vecmask[:, :, 3] = vecmask[:, :, 0:3].sum(axis=2) * alpha
    return vecmask