:py:mod:`kwimage.im_draw` ========================= .. py:module:: kwimage.im_draw Module Contents --------------- Functions ~~~~~~~~~ .. autoapisummary:: kwimage.im_draw.draw_text_on_image kwimage.im_draw.draw_clf_on_image kwimage.im_draw.draw_boxes_on_image kwimage.im_draw.draw_line_segments_on_image kwimage.im_draw._broadcast_colors kwimage.im_draw.make_heatmask kwimage.im_draw.make_orimask kwimage.im_draw.make_vector_field kwimage.im_draw.draw_vector_field .. py:function:: draw_text_on_image(img, text, org, return_info=False, **kwargs) Draws multiline text on an image using opencv :Parameters: * **img** (*ndarray | None | dict*) -- Generally a numpy image to draw on (inplace). Otherwise a canvas will be constructed such that the text will fit. The user may specify a dictionary with keys width and height to have more control over the constructed canvas. * **text** (*str*) -- text to draw * **org** (*Tuple[int, int]*) -- The x, y location of the text string "anchor" in the image as specified by halign and valign. For instance, If valign='bottom', halign='left', this is the bottom left corner. * **return_info** (*bool, default=False*) -- if True, also returns information about the positions the text was drawn on. * **\*\*kwargs** -- color (tuple): default blue thickness (int): defaults to 2 fontFace (int): defaults to cv2.FONT_HERSHEY_SIMPLEX fontScale (float): defaults to 1.0 valign (str, default='bottom'): either top, center, or bottom. NOTE: this default may change to "top" in the future. halign (str, default='left'): either left, center, or right border (dict | int): If specified as an integer, draws a black border with that given thickness. If specified as a dictionary, draws a border with color specified parameters. "color": border color, defaults to "black". "thickness": border thickness, defaults to 1. :returns: the image that was drawn on :rtype: ndarray .. note:: The image is modified inplace. If the image is non-contiguous then this returns a UMat instead of a ndarray, so be carefull with that. .. rubric:: References https://stackoverflow.com/questions/27647424/ https://stackoverflow.com/questions/51285616/opencvs-gettextsize-and-puttext-return-wrong-size-and-chop-letters-with-low .. rubric:: Example >>> import kwimage >>> img = kwimage.grab_test_image(space='rgb') >>> img2 = kwimage.draw_text_on_image(img.copy(), 'FOOBAR', org=(0, 0), valign='top') >>> assert img2.shape == img.shape >>> assert np.any(img2 != img) >>> # xdoc: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(img2) >>> kwplot.show_if_requested() .. rubric:: Example >>> import kwimage >>> # Test valign >>> img = kwimage.grab_test_image(space='rgb', dsize=(500, 500)) >>> img2 = kwimage.draw_text_on_image(img, 'FOOBAR\nbazbiz\nspam', org=(0, 0), valign='top', border=2) >>> img2 = kwimage.draw_text_on_image(img, 'FOOBAR\nbazbiz\nspam', org=(150, 0), valign='center', border=2) >>> img2 = kwimage.draw_text_on_image(img, 'FOOBAR\nbazbiz\nspam', org=(300, 0), valign='bottom', border=2) >>> # Test halign >>> img2 = kwimage.draw_text_on_image(img, 'FOOBAR\nbazbiz\nspam', org=(250, 100), halign='right', border=2) >>> img2 = kwimage.draw_text_on_image(img, 'FOOBAR\nbazbiz\nspam', org=(250, 250), halign='center', border=2) >>> img2 = kwimage.draw_text_on_image(img, 'FOOBAR\nbazbiz\nspam', org=(250, 400), halign='left', border=2) >>> # xdoc: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(img2) >>> kwplot.show_if_requested() .. rubric:: Example >>> # Ensure the function works with float01 or uint255 images >>> import kwimage >>> img = kwimage.grab_test_image(space='rgb') >>> img = kwimage.ensure_float01(img) >>> img2 = kwimage.draw_text_on_image(img, 'FOOBAR\nbazbiz\nspam', org=(0, 0), valign='top', border=2) .. rubric:: Example >>> # Test dictionary border >>> import kwimage >>> img = kwimage.draw_text_on_image(None, 'hello\neveryone', org=(100, 100), valign='top', halign='center', border={'color': 'green', 'thickness': 9}) >>> #img = kwimage.draw_text_on_image(None, 'hello\neveryone', org=(0, 0), valign='top') >>> #img = kwimage.draw_text_on_image(None, 'hello', org=(0, 60), valign='top', halign='center', border=0) >>> # xdoc: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(img) >>> kwplot.show_if_requested() .. rubric:: Example >>> # Test dictionary image >>> import kwimage >>> img = kwimage.draw_text_on_image({'width': 300}, 'good\nPropogate', org=(150, 0), valign='top', halign='center', border={'color': 'green', 'thickness': 0}) >>> print('img.shape = {!r}'.format(img.shape)) >>> # xdoc: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(img) >>> kwplot.show_if_requested() .. py:function:: draw_clf_on_image(im, classes, tcx=None, probs=None, pcx=None, border=1) Draws classification label on an image. Works best with image chips sized between 200x200 and 500x500 :Parameters: * **im** (*ndarray*) -- the image * **classes** (*Sequence | CategoryTree*) -- list of class names * **tcx** (*int, default=None*) -- true class index if known * **probs** (*ndarray*) -- predicted class probs for each class * **pcx** (*int, default=None*) -- predicted class index. (if None but probs is specified uses argmax of probs) .. rubric:: Example >>> # xdoctest: +REQUIRES(module:torch) >>> import torch >>> import kwarray >>> import kwimage >>> rng = kwarray.ensure_rng(0) >>> im = (rng.rand(300, 300) * 255).astype(np.uint8) >>> classes = ['cls_a', 'cls_b', 'cls_c'] >>> tcx = 1 >>> probs = rng.rand(len(classes)) >>> probs[tcx] = 0 >>> probs = torch.FloatTensor(probs).softmax(dim=0).numpy() >>> im1_ = kwimage.draw_clf_on_image(im, classes, tcx, probs) >>> probs[tcx] = .9 >>> probs = torch.FloatTensor(probs).softmax(dim=0).numpy() >>> im2_ = kwimage.draw_clf_on_image(im, classes, tcx, probs) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(im1_, colorspace='rgb', pnum=(1, 2, 1), fnum=1, doclf=True) >>> kwplot.imshow(im2_, colorspace='rgb', pnum=(1, 2, 2), fnum=1) >>> kwplot.show_if_requested() .. py:function:: draw_boxes_on_image(img, boxes, color='blue', thickness=1, box_format=None, colorspace='rgb') Draws boxes on an image. :Parameters: * **img** (*ndarray*) -- image to copy and draw on * **boxes** (*nh.util.Boxes*) -- boxes to draw * **colorspace** (*str*) -- string code of the input image colorspace .. rubric:: Example >>> import kwimage >>> import numpy as np >>> img = np.zeros((10, 10, 3), dtype=np.uint8) >>> color = 'dodgerblue' >>> thickness = 1 >>> boxes = kwimage.Boxes([[1, 1, 8, 8]], 'ltrb') >>> img2 = draw_boxes_on_image(img, boxes, color, thickness) >>> assert tuple(img2[1, 1]) == (30, 144, 255) >>> # xdoc: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() # xdoc: +SKIP >>> kwplot.figure(doclf=True, fnum=1) >>> kwplot.imshow(img2) .. py:function:: draw_line_segments_on_image(img, pts1, pts2, color='blue', colorspace='rgb', thickness=1, **kwargs) Draw line segments between pts1 and pts2 on an image. :Parameters: * **pts1** (*ndarray*) -- xy coordinates of starting points * **pts2** (*ndarray*) -- corresponding xy coordinates of ending points * **color** (*str | List*) -- color code or a list of colors for each line segment * **colorspace** (*str, default='rgb'*) -- colorspace of image * **thickness** (*int, default=1*) * **lineType** (*int, default=cv2.LINE_AA*) :returns: the modified image (inplace if possible) :rtype: ndarray .. rubric:: Example >>> from kwimage.im_draw import * # NOQA >>> pts1 = np.array([[2, 0], [2, 20], [2.5, 30]]) >>> pts2 = np.array([[10, 5], [30, 28], [100, 50]]) >>> img = np.ones((100, 100, 3), dtype=np.uint8) * 255 >>> color = 'blue' >>> colorspace = 'rgb' >>> img2 = draw_line_segments_on_image(img, pts1, pts2, thickness=2) >>> # xdoc: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() # xdoc: +SKIP >>> kwplot.figure(doclf=True, fnum=1) >>> kwplot.imshow(img2) .. rubric:: Example >>> import kwimage >>> pts1 = kwimage.Points.random(10).scale(512).xy >>> pts2 = kwimage.Points.random(10).scale(512).xy >>> img = np.ones((512, 512, 3), dtype=np.uint8) * 255 >>> color = kwimage.Color.distinct(10) >>> img2 = kwimage.draw_line_segments_on_image(img, pts1, pts2, color=color) >>> # xdoc: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() # xdoc: +SKIP >>> kwplot.figure(doclf=True, fnum=1) >>> kwplot.imshow(img2) .. py:function:: _broadcast_colors(color, num, img, colorspace) Determine if color applies a single color to all ``num`` items, or if it is a list of colors for each item. Return as a list of colors for each item. .. todo:: - [ ] add as classmethod of kwimage.Color .. rubric:: Example >>> img = (np.random.rand(512, 512, 3) * 255).astype(np.uint8) >>> colorspace = 'rgb' >>> color = color_str_list = ['red', 'green', 'blue'] >>> color_str = 'red' >>> num = 3 >>> print(_broadcast_colors(color_str_list, num, img, colorspace)) >>> print(_broadcast_colors(color_str, num, img, colorspace)) >>> colors_tuple_list = _broadcast_colors(color_str_list, num, img, colorspace) >>> print(_broadcast_colors(colors_tuple_list, num, img, colorspace)) >>> # >>> # FIXME: This case seems broken >>> colors_ndarray_list = np.array(_broadcast_colors(color_str_list, num, img, colorspace)) >>> print(_broadcast_colors(colors_ndarray_list, num, img, colorspace)) .. py:function:: make_heatmask(probs, cmap='plasma', with_alpha=1.0, space='rgb', dsize=None) Colorizes a single-channel intensity mask (with an alpha channel) :Parameters: * **probs** (*ndarray*) -- 2D probability map with values between 0 and 1 * **cmap** (*str*) -- mpl colormap * **with_alpha** (*float*) -- between 0 and 1, uses probs as the alpha multipled by this number. * **space** (*str*) -- output colorspace * **dsize** (*tuple*) -- if not None, then output is resized to W,H=dsize SeeAlso: kwimage.overlay_alpha_images .. rubric:: Example >>> # xdoc: +REQUIRES(module:matplotlib) >>> probs = np.tile(np.linspace(0, 1, 10), (10, 1)) >>> heatmask = make_heatmask(probs, with_alpha=0.8, dsize=(100, 100)) >>> # xdoc: +REQUIRES(--show) >>> import kwplot >>> kwplot.imshow(heatmask, fnum=1, doclf=True, colorspace='rgb') >>> kwplot.show_if_requested() .. py:function:: 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. :Parameters: * **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: an rgb / rgba image in 01 space :rtype: ndarray[float32] SeeAlso: kwimage.overlay_alpha_images .. rubric:: 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() .. py:function:: 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. :Parameters: * **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: vec_img: an rgb/rgba image in 0-1 space :rtype: ndarray[float32] SeeAlso: kwimage.overlay_alpha_images DEPRECATED USE: draw_vector_field instead .. rubric:: 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() .. py:function:: 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. :Parameters: * **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: The image with vectors overlaid. If image=None, then an rgb/a image is created and returned. :rtype: ndarray[float32] .. rubric:: 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()