Drawing with the Painter

class viren2d.Painter

A Painter lets you draw on its canvas.

Typical workflow:

  1. Create a painter with an empty canvas:

    >>> import viren2d
    >>> painter = viren2d.Painter()
    
  2. Initialize its canvas:

    Note that the overloaded Painter constructors allow combining these steps:

    >>> # Set up from image data, e.g. `numpy.ndarray`:
    >>> image = np.zeros((600, 800, 3), dtype=np.uint8)
    >>> painter = viren2d.Painter(image)
    >>>
    >>> # Or create a custom, blue canvas:
    >>> painter = viren2d.Painter(
    >>>     width=1920, height=1080, color=(0.0, 0.0, 0.8))
    
  3. Draw onto the canvas via the painter’s draw_xxx(...) methods, for example:

    >>> painter.draw_arrow(...)
    >>> painter.draw_bounding_box_2d(...)
    
  4. After all objects have been drawn, retrieve the visualization via get_canvas(). For example, to get a deeply copied image as numpy.ndarray:

    >>> import numpy as np
    >>> canvas = painter.get_canvas(copy=True)
    >>> img_np = np.array(canvas, copy=False)
    

    Alternatively, if access via properties is preferred, a shared memory image buffer can also be via its canvas attribute. To obtain a deeply copied image as before, we can leverage the numpy.ndarray constructor:

    >>> img_np = np.array(painter.canvas, copy=True)
    
  5. Either continue drawing (step 3) or set up a new canvas (step 2), i.e. it is safe to reuse the same painter instance.

Methods:

__init__

Overloaded function.

draw_arc

Draws a circular arc.

draw_arrow

Draws an arrow.

draw_bounding_box_2d

Draws a single 2D bounding box.

draw_circle

Draws a circle.

draw_ellipse

Draws an ellipse.

draw_gradient

Draws a color gradient.

draw_grid

Draws a grid.

draw_horizon_line

Draws the estimated line of horizon.

draw_image

Draws an image onto the canvas.

draw_line

Draws a line.

draw_marker

Draws a single marker/keypoint.

draw_markers

Draws multiple (similarly styled) markers/keypoints.

draw_polygon

Draws a polygon.

draw_rect

Draws a rectangle.

draw_text

Draws single- or multi-line text.

draw_text_box

Draws a single- or multi-line text box.

draw_trajectories

Draws multiple (similarly styled) trajectories.

draw_trajectory

Draws a single trajectory.

draw_xyz_axes

Visualizes a coordinate system reference frame.

get_canvas

Returns the current visualization in RGBA format.

get_canvas_size

Returns the size of the canvas in pixels.

is_valid

Checks if the canvas has been set up correctly.

reset_clip

Resets the latest clip region.

save_canvas

Saves the current visualization to disk.

set_canvas_filename

Initializes the canvas from the given image file.

set_canvas_image

Initializes the canvas from the given image.

set_canvas_rgb

Initializes the canvas with the given color.

set_clip_circle

Establishes a circular clip region for the current canvas.

set_clip_rect

Establishes a rectangular clip region for the current canvas.

Attributes:

canvas

Provides a shared memory view on the painter's canvas for convenience.

height

Height in pixels of the painter's canvas (read-only).

width

Width in pixels of the painter's canvas (read-only).

__init__(*args, **kwargs)

Overloaded function.

  1. __init__(self: viren2d.Painter) -> None

    Default constructor.

    Initializes an empty canvas, i.e. is_valid() will return False until the canvas has been properly set up via set_canvas_image(), etc.

  2. __init__(self: viren2d.Painter, image: object) -> None

    Creates a painter and initializes its canvas from an image.

    Initializes the painter’s canvas with the given image. See set_canvas_image() for supported image formats and parameter types.

  3. __init__(self: viren2d.Painter, height: int, width: int, color: viren2d.Color = viren2d.Color(red=1, green=1, blue=1, alpha=1)) -> None

    Creates a painter with a customized canvas.

    Initializes the painter’s canvas and fills it with the given Color.

property canvas

Provides a shared memory view on the painter’s canvas for convenience.

See get_canvas() for details about the image format of the canvas. Can be used to convert the current visualization into a numpy.ndarray via:

>>> img_np = np.array(painter.canvas, copy=True)

Although this property is read-only (you cannot assign a newly allocated memory), it could still be used to change the individual pixels of the canvas (as these are not write-protected):

>>> img_np = np.array(painter.canvas, copy=False)
>>> img_np[:, :, :3] = 0  # Now, the canvas is black

Corresponding C++ API: viren2d::Painter::GetCanvas.

Type:

ImageBuffer

draw_arc(self: viren2d.Painter, center: viren2d.Vec2d, radius: float, angle_from: float, angle_to: float, line_style: viren2d.LineStyle = <LineStyle(2.0px, #007fff, solid)>, include_center: bool = True, fill_color: viren2d.Color = viren2d.Color.Invalid) bool

Draws a circular arc.

Corresponding C++ API: viren2d::Painter::DrawArc.

Parameters:
  • center – Center position as Vec2d.

  • radius – Radius of the arc in pixels as float.

  • angle_from – The arc will be drawn from angle_from to angle_to in clockwise direction. Both angles are specified in degrees as float, where 0 degrees points in the direction of increasing \(x\) coordinates.

  • angle_to – See angle_from.

  • line_style

    A LineStyle specifying how to draw the arc’s outline.

    If you pass LineStyle.Invalid, the contour will not be drawn - then, you must provide a valid fill_color.

  • include_center – If True (default), the center point will be included when drawing the outline and filling.

  • fill_color – If you provide a valid Color, the arc will be filled.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> line_style = viren2d.LineStyle(
>>>     width=5, color='maroon',
>>>     dash_pattern=[], dash_offset=0.0,
>>>     cap='round', join='miter')
>>> painter.draw_arc(
>>>     center=(50, 50), radius=20, angle_from=30, angle_to=330,
>>>     line_style=line_style, include_center=True,
>>>     fill_color='same!30')
draw_arrow(self: viren2d.Painter, pt1: viren2d.Vec2d, pt2: viren2d.Vec2d, arrow_style: viren2d.ArrowStyle = <ArrowStyle(lw=2.0, tip=0.2, angle=20.0°, open, #007fff, solid)>) bool

Draws an arrow.

Corresponding C++ API: viren2d::Painter::DrawArrow.

Parameters:
  • pt1 – Start of the arrow shaft as Vec2d.

  • pt2 – End of the arrow shaft (i.e. the pointy end) as Vec2d.

  • arrow_style – An ArrowStyle specifying how to draw the arrow.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> arrow_style = viren2d.ArrowStyle(
>>>     width=3, color='black',
>>>     tip_length=0.3, tip_angle=20,
>>>     tip_closed=True, double_headed=False,
>>>     dash_pattern=[], dash_offset=0.0,
>>>     cap='round', join='miter')
>>> painter.draw_arrow(
>>>     pt1=(10, 10), pt2=(42, 42), arrow_style=arrow_style)

Note

Arrows should always be drawn fully opaque. Otherwise, you’ll experience visible blending in the crossing path segments (i.e. at the tip).

Style cheat sheet for arrows

draw_bounding_box_2d(self: viren2d.Painter, rect: viren2d.Rect, box_style: viren2d.BoundingBox2DStyle = <BoundingBox2DStyle(LineStyle(2.0px, #007fff, solid), TextStyle("monospace", 16px, ls=1.2, left, top, #000000), box fill=Color::Same(a=0.10), text fill=Color::Same(a=0.50), clipped)>, label_top: List[str] = [], label_bottom: List[str] = [], label_left: List[str] = [], left_t2b: bool = False, label_right: List[str] = [], right_t2b: bool = True) bool

Draws a single 2D bounding box.

Corresponding C++ API: viren2d::Painter::DrawBoundingBox2D.

Parameters:
  • rect – The box as Rect.

  • box_style – A BoundingBox2DStyle specifying how to draw this bounding box.

  • label_top – Label text to display at the top of the bounding box, given as list of str (supporting multi-line labels).

  • label_bottom – Label text to display at the bottom edge.

  • label_left – Label text to display along the left edge.

  • left_t2b – If True, the label text will be oriented from top-to-bottom.

  • label_right – Label text to display along the right edge.

  • right_t2b – If True, the label text will be oriented from top-to-bottom.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> line_style = viren2d.LineStyle(
>>>   width=7, color='navy-blue',
>>>   dash_pattern=[], dash_offset=0.0,
>>>   cap='round', join='miter')
>>> text_style = viren2d.TextStyle(
>>>   family='monospace', size=18,
>>>   color='navy-blue', bold=True,
>>>   italic=False, line_spacing=1.1,
>>>   halign='center', valign='top')
>>> box_style = viren2d.BoundingBox2DStyle(
>>>   line_style=line_style, text_style=text_style,
>>>   box_fill_color='same!20', text_fill_color='white!60',
>>>   clip_label=True)
>>> painter.draw_bounding_box_2d(
>>>   rect=viren2d.Rect.from_ltwh(20, 42, 200, 400, radius=0.2),
>>>   box_style=box_style,
>>>   label_top=['Multi-Line Label', '(... at the top)'],
>>>   label_bottom=['Bottom Edge'], label_left=['Left Edge'],
>>>   left_t2b=True, label_right=[], right_t2b=False)

Tracking-by-Detection Example

The code listing to create this visualization is shown in the RTD tutorial section on tracking-by-detection.

draw_circle(self: viren2d.Painter, center: viren2d.Vec2d, radius: float, line_style: viren2d.LineStyle = <LineStyle(2.0px, #007fff, solid)>, fill_color: viren2d.Color = viren2d.Color.Invalid) bool

Draws a circle.

Corresponding C++ API: viren2d::Painter::DrawCircle.

Parameters:
  • center – Center position as Vec2d.

  • radius – Radius of the circle in pixels as float.

  • line_style

    A LineStyle specifying how to draw the circle’s outline.

    If you pass LineStyle.Invalid, the contour will not be drawn - then, you must provide a valid fill_color.

  • fill_color – If you provide a valid Color, the circle will be filled.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> line_style = viren2d.LineStyle(
>>>     width=5, color='maroon',
>>>     dash_pattern=[], dash_offset=0.0,
>>>     cap='round', join='miter')
>>> painter.draw_circle(
>>>     center=(50, 50), radius=30,
>>>     line_style=line_style, fill_color='same!30')
draw_ellipse(self: viren2d.Painter, ellipse: viren2d.Ellipse, line_style: viren2d.LineStyle = <LineStyle(2.0px, #007fff, solid)>, fill_color: viren2d.Color = viren2d.Color.Invalid) bool

Draws an ellipse.

Corresponding C++ API: viren2d::Painter::DrawEllipse.

Parameters:
  • ellipse – The Ellipse, which should be drawn.

  • line_style

    A LineStyle specifying how to draw the ellipse’s outline.

    If you pass LineStyle.Invalid, the contour will not be drawn - then, you must provide a valid fill_color.

  • fill_color – If you provide a valid Color, the ellipse will be filled.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> line_style = viren2d.LineStyle(
>>>     width=3, color='forest-green',
>>>     dash_pattern=[], dash_offset=0.0,
>>>     cap='round', join='miter')
>>> ellipse = viren2d.Ellipse(
>>>     center=(100, 60), axes=(180, 50), rotation=60)
>>> painter.draw_ellipse(ellipse, line_style, 'same!20')
>>> # Or via named arguments:
>>> painter.draw_ellipse(
>>>     ellipse=ellipse, line_style=line_style,
>>>     fill_color='same!20')

Exemplary ellipses

The code listing to create this visualization is shown in the RTD tutorial section on ellipses.

draw_gradient(self: viren2d.Painter, gradient: viren2d::ColorGradient) bool

Draws a color gradient.

Corresponding C++ API: viren2d::Painter::DrawGradient.

Parameters:

gradient – The ColorGradient to draw.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> grad = viren2d.LinearColorGradient((0, 0), (200, 200))
>>> grad.add_color_stop(0.1, 'crimson')
>>> grad.add_color_stop(0.5, 'teal-green')
>>> grad.add_color_stop(0.9, 'navy-blue')
>>> painter.draw_gradient(grad)

Note

This method will render the gradient across the full canvas. If this is not wanted, a clip region must be set up before via set_clip_rect() or set_clip_circle().

draw_grid(self: viren2d.Painter, spacing_x: float, spacing_y: float, line_style: viren2d.LineStyle = <LineStyle(2.0px, #007fff, solid)>, top_left: viren2d.Vec2d = viren2d.Vec2d(0, 0), bottom_right: viren2d.Vec2d = viren2d.Vec2d(0, 0)) bool

Draws a grid.

Corresponding C++ API: viren2d::Painter::DrawGrid.

Parameters:
  • spacing_x – Width of each grid cell as float.

  • spacing_y – Height of each grid cell as float.

  • line_style – A LineStyle specifying how to render the grid lines.

  • top_left – Top-left corner as Vec2d. If provided and top_left != `bottom_right, the grid will only be drawn within this rectangular region. Otherwise, the grid will span the whole canvas.

  • bottom_right – Bottom-right corner as Vec2d. See top_left.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> line_style = viren2d.LineStyle(width=1, color='light-gray!80')
>>> painter.draw_grid(
>>>     spacing_x=50, spacing_y=50, line_style=line_style,
>>>     top_left=(50, 50), bottom_right=(150, 150))
draw_horizon_line(self: viren2d.Painter, K: numpy.ndarray[numpy.float64[3, 3]], R: numpy.ndarray[numpy.float64[3, 3]], t: viren2d.Vec3d, line_style: viren2d.LineStyle = <LineStyle(5.0px, #1670b7, dashed)>) viren2d.Line2d

Draws the estimated line of horizon.

TODO explain approximation/estimation. Or adjust it in wkz!

Corresponding C++ API: viren2d::Painter::DrawHorizonLine.

Parameters:
  • K – The \(3 \times 3\) camera matrix as numpy.ndarray of type numpy.float64, which holds the intrinsic parameters.

  • R – The \(3 \times 3\) extrinsic rotation matrix, again as numpy.ndarray of type numpy.float64.

  • t – The 3d extrinsic translation vector as Vec3d.

  • line_style – The LineStyle specifying how the horizon line should be drawn.

Returns:

The line of horizon as Line2d. Use its is_valid() method to check whether the line could be drawn. If not, it is either not visible or you provided invalid inputs. The latter will be indicated by an error message in the log.

Example

>>> K = np.array(
>>>     [[523.2, 0.0, 341.0],
>>>      [0.0, 523.2, 256.0],
>>>      [0.0, 0.0, 1.0]], dtype=np.float64)
>>> R = np.array(
>>>     [[ 0.99013141,  0.14006482, -0.00465153],
>>>      [ 0.05439048, -0.41465762, -0.90835056],
>>>      [-0.12915675,  0.89913342, -0.41818372]], dtype=np.float64)
>>> t = np.array([-51.8, 17.3, 82.5], dtype=np.float64)
>>> line_style =
>>> TODO
draw_image(self: viren2d.Painter, image: object, position: viren2d.Vec2d, anchor: viren2d.Anchor = viren2d.Anchor('top-left'), alpha: float = 1.0, scale_x: float = 1.0, scale_y: float = 1.0, rotation: float = 0.0, clip_factor: float = 0.0, line_style: viren2d.LineStyle = <LineStyle::Invalid>) bool

Draws an image onto the canvas.

Corresponding C++ API: viren2d::Painter::DrawImage.

Parameters:
  • image – The image as ImageBuffer, which can also be implicitly created by passing a numpy.ndarray.

  • position – The position of the reference point where to anchor the image as Vec2d.

  • anchor – How to orient the text with respect to position. Valid inputs are Anchor values and their string representations. For details, refer to the anchor parameter of draw_text().

  • alpha – Opacity as float \(\in [0,1]\), where 1 is fully opaque and 0 is fully transparent.

  • scale_x – Horizontal scaling factor as float.

  • scale_y – Vertical scaling factor as float.

  • rotation – Clockwise rotation in degrees as float.

  • clip_factor – If greater than 0, the corners will be clipped. In particular, \(0 < \text{clip} \leq 0.5\) will result in a rounded rectangle, where the corner radius will be clip_factor times \(\min(\text{width}, \text{height})\). If \(\text{clip} > 0.5\), the clip region will be an ellipse, where major/minor axis length equal the width/height of the image.

  • line_style – A LineStyle specifying how to draw the contour. If set to LineStyle.Invalid, the contour will not be drawn.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> painter.draw_image(
>>>     image=img, position=(10, 20), anchor='top-left',
>>>     alpha=0.8, scale_x=1.0, scale_y=1.0, rotation=0,
>>>     clip_factor=0.3, line_style=viren2d.LineStyle.Invalid)
draw_line(self: viren2d.Painter, pt1: viren2d.Vec2d, pt2: viren2d.Vec2d, line_style: viren2d.LineStyle = <LineStyle(2.0px, #007fff, solid)>) bool

Draws a line.

Corresponding C++ API: viren2d::Painter::DrawLine.

Parameters:
  • pt1 – Start position as Vec2d.

  • pt2 – End position as Vec2d.

  • line_style – A LineStyle specifying how to draw the line.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> line_style = viren2d.LineStyle(
>>>     width=7, color='crimson!80',
>>>     dash_pattern=[20, 10], dash_offset=0.0,
>>>     cap='round', join='miter')
>>> painter.draw_line(
>>>     pt1=(42, 42), pt2=(86, 86), line_style=line_style)
draw_marker(self: viren2d.Painter, position: viren2d.Vec2d, marker_style: viren2d.MarkerStyle = <MarkerStyle('o', sz=10.0, t=3.0, #007fff)>) bool

Draws a single marker/keypoint.

Corresponding C++ API: viren2d::Painter::DrawMarker.

Parameters:
  • position – Position as Vec2d.

  • marker_style – A MarkerStyle specifying how to draw the marker.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> marker_style = viren2d.MarkerStyle(
>>>     marker='7', size=20, color='navy-blue!80',
>>>     thickness=1, filled=True,
>>>     cap='round', join='miter')
>>> painter.draw_marker(position=(42, 70), marker_style=marker_style)

Available Marker Shapes

draw_markers(self: viren2d.Painter, markers: List[Tuple[viren2d.Vec2d, viren2d.Color]], marker_style: viren2d.MarkerStyle = <MarkerStyle('o', sz=10.0, t=3.0, #007fff)>) bool

Draws multiple (similarly styled) markers/keypoints.

Corresponding C++ API: viren2d::Painter::DrawMarkers.

Parameters:
  • markers – Holds the position and color of each marker. Should be provided as a list of tuples, where each tuple holds the position and color of a marker as (Vec2d, Color). If a marker’s color is invalid, it will be drawn using marker_style’s color specification instead.

  • marker_style – A MarkerStyle specifying how to draw the markers (except for the color).

Returns:

True if drawing completed successfully for all markers. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> marker_style = viren2d.MarkerStyle(color='crimson')
>>> markers = [
>>>     ((10, 10), 'blue'),
>>>     ((20, 10), (0.5, 0, 0.5)),
>>>     ((30, 10), viren2d.RGBa(200, 0, 180)),
>>>     ((40, 10), 'invalid'),   # Will use marker_style.color
>>>     ((50, 34), (-1, -1, -1)) # This one too
>>> ]
>>> painter.draw_markers(markers, marker_style)

Available Marker Shapes

draw_polygon(self: viren2d.Painter, polygon: List[viren2d.Vec2d], line_style: viren2d.LineStyle = <LineStyle(2.0px, #007fff, solid)>, fill_color: viren2d.Color = viren2d.Color.Invalid) bool

Draws a polygon.

Corresponding C++ API: viren2d::Painter::DrawPolygon.

Parameters:
  • polygon – Points of the polygon as list of Vec2d.

  • line_style

    A LineStyle specifying how to draw the polygon’s outline.

    If you pass Invalid, the contour will not be drawn - then, you must provide a valid fill_color.

  • fill_color – If you provide a valid Color, the polygon will be filled.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> points = [(0, 0), (10, 20), (42, 30), ...]
>>> line_style = viren2d.LineStyle(
>>>     width=5, color='forest-green',
>>>     dash_pattern=[], dash_offset=0.0,
>>>     cap='round', join='round')
>>> painter.draw_polygon(
>>>     polygon=points, line_style=line_style,
>>>     fill_color='same!40')
draw_rect(self: viren2d.Painter, rect: viren2d.Rect, line_style: viren2d.LineStyle = <LineStyle(2.0px, #007fff, solid)>, fill_color: viren2d.Color = viren2d.Color.Invalid) bool

Draws a rectangle.

Corresponding C++ API: viren2d::Painter::DrawRect.

Parameters:
  • rect – The Rect which should be drawn.

  • line_style

    A LineStyle specifying how to draw the rectangle’s outline.

    If you pass viren2d.LineStyle.Invalid, the contour will not be drawn - then, you must provide a valid fill_color.

  • fill_color – If you provide a valid Color, the rectangle will be filled.

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> line_style = viren2d.LineStyle()
>>> painter.draw_rect(
>>>   rect=rect, line_style=line_style, fill_color='same!20')

Exemplary Rectangles

The code listing to create this visualization is shown in the RTD tutorial section on rectangles.

draw_text(self: viren2d.Painter, text: List[str], position: viren2d.Vec2d, anchor: viren2d.Anchor = viren2d.Anchor('bottom-left'), text_style: viren2d.TextStyle = <TextStyle("monospace", 16px, ls=1.2, left, top, #000000)>, padding: viren2d.Vec2d = viren2d.Vec2d(0, 0), rotation: float = 0.0) viren2d.Rect

Draws single- or multi-line text.

Corresponding C++ API: viren2d::Painter::DrawText.

Parameters:
  • text – A list of str to be drawn. For a single line, simply pass a list which holds only a single str.

  • position – Position of the reference point where to anchor the text as Vec2d.

  • anchor

    How to orient the text with respect to the position. Valid inputs are Anchor values and their string representations.

    A string must correspond either to a position specification - i.e. center, top, top-right, right, bottom-right, bottom, bottom-left, left, or top-left - or one of the 8 compass directions - i.e. north, north-east, east, south-east, south, south-west, west, or north-west.

    Before parsing, the input string will be converted to lowercase and any whitespaces, dashes & underscores will be removed.

  • text_style – A TextStyle, specifying how to render the text.

  • padding – Optional distance between the closest glyph and the position. Specified in pixels as Vec2d.

  • rotation – Rotation angle (clockwise around position) in degrees as float.

Returns:

The bounding box of the drawn text as Rect. Check if drawing completed successfully via is_valid().

Example

>>> text_style = viren2d.TextStyle(
>>>     family='sans-serif', size=15, color='#1a1c1d', bold=True)
>>> bbox = painter.draw_text(
>>>     text=['Hello World!'], position=(200, 50), anchor='center',
>>>     text_style=text_style, padding=(5, 5), rotation=0)
draw_text_box(self: viren2d.Painter, text: List[str], position: viren2d.Vec2d, anchor: viren2d.Anchor = viren2d.Anchor('bottom-left'), text_style: viren2d.TextStyle = <TextStyle("monospace", 16px, ls=1.2, left, top, #000000)>, padding: viren2d.Vec2d = viren2d.Vec2d(6, 6), rotation: float = 0.0, line_style: viren2d.LineStyle = <LineStyle::Invalid>, fill_color: viren2d.Color = viren2d.Color(red=1, green=1, blue=1, alpha=0.6), radius: float = 0.2, fixed_size: viren2d.Vec2d = viren2d.Vec2d(-1, -1)) viren2d.Rect

Draws a single- or multi-line text box.

Corresponding C++ API: viren2d::Painter::DrawTextBox.

Parameters:
  • text – A list of str to be drawn. For a single line, simply pass a list which holds a single str.

  • position – Position of the reference point where to anchor the text as Vec2d.

  • anchor – How to orient the text with respect to position. Valid inputs are Anchor values and their string representations. For details, refer to the anchor parameter of draw_text().

  • text_style – A TextStyle, specifying how to render the text.

  • padding – Optional padding between text and the edges of the box. Specified in pixels as Vec2d.

  • rotation – Rotation angle (clockwise around position) in degrees as float.

  • line_style – A LineStyle, specifying how to render the border of the text box.

  • fill_color – If you provide a valid Color, the box will be filled.

  • radius – Corner radius of the box. Refer to radius for details on valid value ranges.

  • fixed_size – Forces the box to be of the specified size as Vec2d. If the size is smaller than the text extent, the text will overflow the box.

Returns:

The bounding box of the drawn text as Rect. Check if drawing completed successfully via is_valid().

Example

>>> text_style = viren2d.TextStyle(
>>>     family='sans-serif', size=15, color='#1a1c1d', bold=True)
>>> line_style = viren2d.LineStyle(
>>>     width=3, color='#1a1c1d')
>>> bbox = painter.draw_text_box(
>>>     text=['Hello World!'], position=(200, 50), anchor='center',
>>>     text_style=text_style, padding=(5, 5), rotation=0,
>>>     line_style=line_style, fill_color='#c0bab1', radius=0.2)
draw_trajectories(self: viren2d.Painter, trajectories: List[Tuple[List[viren2d.Vec2d], viren2d.Color]], line_style: viren2d.LineStyle = <LineStyle(5.0px, #007fff, solid)>, fade_out_color: viren2d.Color = viren2d.Color(red=0.78, green=0.78, blue=0.78, alpha=0.6), tail_first: bool = True, smoothing_window: int = 0, fading_factor: Callable[[float], float] = <built-in method  of PyCapsule object at 0x7f0f96b10ba0>) bool

Draws multiple (similarly styled) trajectories.

Corresponding C++ API: viren2d::Painter::DrawTrajectories.

Allows rendering multiple trajectories with a common LineStyle.

Parameters:
  • trajectories

    A list of tuple, where each tuple holds (trajectory, color):

    • trajectory is a list of Vec, i.e. the coordinates.

    • color is the corresponding Color. If Color.Invalid or Color.Same, the color of the line_style parameter will be used instead.

  • others – For details on all other parameters, refer to the documentation of draw_trajectory().

Returns:

True if drawing all trajectories completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> points1 = [(20,  0), (10, 20), (42, 30), ...]
>>> points2 = [(70, 70), (50, 20), (23, 30), ...]
>>> trajs = [(points1, 'maroon'), (points2, 'invalid')]
>>>
>>> line_style = viren2d.LineStyle(
>>>     width=5, color='navy-blue',
>>>     cap=viren2d.LineCap.Round,
>>>     join=viren2d.LineJoin.Round)
>>>
>>> painter.draw_trajectories(
>>>     trajectories=trajs, line_style=line_style,
>>>     fade_out_color=(0.8, 0.8, 0.8, 0.4),
>>>     smoothing_window=5, tail_first=True,
>>>     fading_factor=viren2d.fade_out_linear)

Tracking-by-Detection Example

The code listing to create this visualization is shown in the RTD tutorial section on tracking-by-detection.

draw_trajectory(self: viren2d.Painter, trajectory: List[viren2d.Vec2d], line_style: viren2d.LineStyle = <LineStyle(5.0px, #007fff, solid)>, fade_out_color: viren2d.Color = viren2d.Color(red=0.78, green=0.78, blue=0.78, alpha=0.6), tail_first: bool = True, smoothing_window: int = 0, fading_factor: Callable[[float], float] = <built-in method  of PyCapsule object at 0x7f0f96b10b10>) bool

Draws a single trajectory.

Corresponding C++ API: viren2d::Painter::DrawTrajectory.

Can be used to either draw a fixed-color path (if fade_out_color is invalid), or a path which gradually changes its color from line_style.color to fade_out_color. In the latter case, the color transition can be controlled by fading_factor.

Parameters:
  • trajectory – A list of Vec2d which specifies the trajectory’s coordinates.

  • line_style – A LineStyle specifying how to draw the trajectory (except for the color gradient).

  • fade_out_color – If this is a valid Color, the trajectory’s tail will be drawn with this color.

  • tail_first – Set to True if the first point, i.e. points[0], is the oldest point, i.e. the trajectory’s tail. Otherwise, it is assumed to be the most recent point.

  • smoothing_window – Specifies the window size to optionally smooth the trajectory via moving average. Disable smoothing by passing a value <= 0.

  • fading_factor

    A function handle which will be invoked for each segment of the trajectory to compute the mixing ratios for the color gradient.

    Its single input is a float \(\in [0,1]\), which denotes the drawing progress along the trajectory, from head (i.e. \(0\)) to tail. Its return value must also be a float \(\in [0,1]\), which specifies the amount of the fade_out_color to be applied for this drawing progress.

    For example, to get a linear color transition between head and tail, we simply use the identity function. For convenience, viren2d already provides fade_out_linear(), fade_out_quadratic(), and fade_out_logarithmic(). The default fading_factor function is fade_out_quadratic().

Returns:

True if drawing completed successfully. Otherwise, check the log messages. Drawing errors are most likely caused by invalid inputs.

Example

>>> points = [(0, 0), (10, 20), (42, 30), ...]
>>> line_style = viren2d.LineStyle(
>>>     width=5, color='navy-blue',
>>>     cap=viren2d.LineCap.Round,
>>>     join=viren2d.LineJoin.Round)
>>>
>>> painter.draw_trajectory(
>>>     trajectory=points, line_style=line_style,
>>>     fade_out_color=(0.8, 0.8, 0.8, 0.4),
>>>     smoothing_window=5, tail_first=True,
>>>     fading_factor=viren2d.fade_out_linear)

Note

If a valid fade_out_color is provided, the trajectory has to be drawn via separate line segments. This means that the join setting of line_style parameter will have no effect. Additionally, if transparent colors are used, the individual segment endpoints will be visible.

To avoid this behavior, the trajectory needs to be drawn with a single color, i.e. pass Color.Invalid as fade_out_color.

Tracking-by-Detection Example

The code listing to create this visualization is shown in the RTD tutorial section on tracking-by-detection.

draw_xyz_axes(self: viren2d.Painter, K: numpy.ndarray[numpy.float64[3, 3]], R: numpy.ndarray[numpy.float64[3, 3]], t: viren2d.Vec3d, origin: viren2d.Vec3d = viren2d.Vec3d(0, 0, 0), lengths: viren2d.Vec3d = viren2d.Vec3d(1000, 1000, 1000), arrow_style: viren2d.ArrowStyle = <ArrowStyle(lw=2.0, tip=0.2, angle=20.0°, open, #007fff, solid)>, color_x: viren2d.Color = viren2d.Color(red=0.94, green=0.13, blue=0.15, alpha=1), color_y: viren2d.Color = viren2d.Color(red=0.19, green=0.63, blue=0.3, alpha=1), color_z: viren2d.Color = viren2d.Color(red=0.09, green=0.44, blue=0.72, alpha=1)) Tuple[bool, viren2d.Vec2d, viren2d.Vec2d, viren2d.Vec2d, viren2d.Vec2d]

Visualizes a coordinate system reference frame.

Draws three arrows showing the orientation of the x, y, and z axes at a given position. Note that the default parameter settings assume that the metric camera calibration is given in millimeters.

Corresponding C++ API: viren2d::Painter::DrawXYZAxes.

Parameters:
  • K – The \(3 \times 3\) camera matrix as numpy.ndarray which holds the intrinsic parameters. Inputs will be converted to type numpy.float64.

  • R – The \(3 \times 3\) extrinsic rotation matrix, as numpy.ndarray. Inputs will be converted to type numpy.float64.

  • t – The 3d extrinsic translation vector as Vec3d.

  • origin – Center of the world coordinate system as Vec3d.

  • lengths – A Vec3d specifying how far to shift the arrow tips from the origin. Each axis tip will be computed as \(\text{tip}_{\text{axis}} = \text{origin} + \mathbf{e}_{\text{axis}} * \text{lengths}[\text{axis}]\), where \(\mathbf{e}_{\text{axis}}\) is the unit vector for the corresponding axis. The default value assumes that the calibration is given in millimeters and will result in 1 meter long arrows.

  • arrow_style – The ArrowStyle specifying how the axis arrows should be drawn. Note that it’s color attribute will be ignored.

  • color_xColor of the \(x\) axis arrow. Default reddish.

  • color_yColor of the \(y\) axis arrow. Default greenish.

  • color_zColor of the \(z\) axis arrow. Default bluish.

Returns:

A tuple(visible, origin, tip_x, tip_y, tip_z), where visible is True if drawing completed successfully and at least one point (axis arrow tip or the origin) is visible within the camera’s field-of-view. Drawing errors (such as caused by invalid inputs) will be indicated by log messages. The other result variables are of type Vec2d and hold the image coordinates of the origin, as well as the tips (i.e. end points) of the arrows.

Example

>>> K = np.array(
>>>     [[523.2, 0.0, 341.0],
>>>      [0.0, 523.2, 256.0],
>>>      [0.0, 0.0, 1.0]], dtype=np.float64)
>>> R = np.array(
>>>     [[ 0.99013141,  0.14006482, -0.00465153],
>>>      [ 0.05439048, -0.41465762, -0.90835056],
>>>      [-0.12915675,  0.89913342, -0.41818372]], dtype=np.float64)
>>> t = np.array([-51.8, 17.3, 82.5], dtype=np.float64)
>>> arrow_style = viren2d.ArrowStyle(
>>>     width=3, tip_length=0.3, tip_angle=20,
>>>     tip_closed=True, double_headed=False,
>>>     dash_pattern=[], dash_offset=0.0,
>>>     cap='round', join='miter')
>>> # This examplary calibration uses millimeters, thus the lengths
>>> # parameter corresponds to 1m along each axis.
>>> painter.draw_xyz_axes(
>>>     K=K, R=R, t=t, origin=(0, 0, 0),
>>>     lengths=(1e3, 1e3, 1e3), arrow_style=arrow_style,
>>>     color_x='red', color_y='green', color_z='blue')
get_canvas(self: viren2d.Painter, copy: bool = True) viren2d.ImageBuffer

Returns the current visualization in RGBA format.

Returns an ImageBuffer, which implements the Python buffer protocol. This means, it can be easily converted to other buffer types, such as numpy.ndarray, see the examples below.

Corresponding C++ API: viren2d::Painter::GetCanvas.

Parameters:

copy

If you want a deep copy, set copy = True. Otherwise, the buffer will just provide a shared view on the painter’s canvas.

Be aware that if you keep on drawing after obtaining a shared view, this view will also change. You could even externally modify the canvas pixels.

Returns:

The current visualization as a 4-channel, uint8 ImageBuffer with pixel format RGBA.

Examples

Get canvas as numpy.ndarray, where the memory is shared with the painter:

>>> img_np = np.array(p.get_canvas(copy=False), copy=False)

Retrieve a deep copy of the canvas as numpy.ndarray, i.e. future painter.draw_... calls will not affect this retrieved copy:

>>> img_np = np.array(p.get_canvas(copy=True), copy=False)

If we need a 3-channel image, we can leverage the to_channels() method of the buffer:

>>> # We only need a shared view on the canvas...
>>> img_buf = p.get_canvas(copy=False)
>>> # ... because the following performs a deep copy:
>>> img_np = img_buf.to_channels(3)

Tip

If you can ensure that the painter is not destroyed while you display/process the visualization, use the shared view (i.e. copy = False) on its canvas to avoid unnecessary memory allocation.

get_canvas_size(self: viren2d.Painter) tuple

Returns the size of the canvas in pixels.

Corresponding C++ API: viren2d::Painter::GetCanvasSize.

Returns:

The canvas width & height as the tuple (W, H), where W and H denote pixels (type int).

property height

Height in pixels of the painter’s canvas (read-only).

Corresponding C++ API: viren2d::Painter::GetCanvasSize.

Type:

int

is_valid(self: viren2d.Painter) bool

Checks if the canvas has been set up correctly.

Corresponding C++ API: viren2d::Painter::IsValid.

reset_clip(self: viren2d.Painter) bool

Resets the latest clip region.

Note that for each previously set clip region, a separate call to reset_clip() is needed.

Corresponding C++ API: viren2d::Painter::ResetClipRegion.

save_canvas(self: viren2d.Painter, filename: object) None

Saves the current visualization to disk.

This method is provided only for convenience and simply calls get_canvas() and save_image_uint8(). Check their documentation to be aware about the shortcomings (since viren2d is not an image I/O library).

No corresponding C++ API: Use viren2d::Painter::GetCanvas and viren2d::Painter::SaveImageUInt8 (or preferably a proper image I/O library) instead.

Parameters:

filename – The output filename as str or pathlib.Path. The calling code must ensure that the directory hierarchy exists.

Example

>>> output_folder = pathlib.Path(...)
>>> painter.save_canvas(output_folder / 'visualization.jpg')
set_canvas_filename(self: viren2d.Painter, image_filename: object) None

Initializes the canvas from the given image file.

This functionality uses the stb library to load the image file. Supported formats are:

JPEG, PNG, TGA, BMP, PSD, GIF, HDR, PIC, PNM

Corresponding C++ API: viren2d::Painter::SetCanvas.

set_canvas_image(self: viren2d.Painter, image: object) None

Initializes the canvas from the given image.

Corresponding C++ API: viren2d::Painter::SetCanvas.

Parameters:

img_np – Image as either a numpy.ndarray (currently, only numpy.uint8 is supported) or an ImageBuffer. The image can either be grayscale, RGB or RGBA.

Example

>>> img_np = np.zeros((480, 640, 3), dtype=np.uint8)
>>> painter.set_canvas_image(img_np)
set_canvas_rgb(self: viren2d.Painter, height: int, width: int, color: viren2d.Color = viren2d.Color(red=1, green=1, blue=1, alpha=1)) None

Initializes the canvas with the given color.

Corresponding C++ API: viren2d::Painter::SetCanvas.

Parameters:
  • width – Canvas width in pixels.

  • height – Canvas height in pixels.

  • color – Background Color.

Examples

>>> painter = viren2d.Painter()
>>> painter.set_canvas_rgb(height=600, width=800)
>>> painter.set_canvas_rgb(width=800, height=600, color='crimson')
>>> painter.set_canvas_rgb(width=800, height=600, color=(0.5, 0.3, 0.9))
set_clip_circle(self: viren2d.Painter, center: viren2d.Vec2d, radius: float) bool

Establishes a circular clip region for the current canvas.

After setting the clip region, any drawing operations outside the clip region are effectively masked out. Note that this does not change the canvas transformation, i.e. coordinates for subsequent drawing operations need to be provided in the global/previous canvas coordinate frame. Also note that the clip region will be reset automatically whenever a new canvas is set. To reset the clip region, use reset_clip().

Corresponding C++ API: viren2d::Painter::SetClipRegion.

Parameters:
  • center – Center of the circle as Vec2d.

  • radius – Radius of the circle.

Returns:

True if the given clip region is valid, False otherwise which will be indicated by log messages.

Example

>>> # Circular clip region and radial gradient for 3D impression:
>>> grad = viren2d.RadialColorGradient((90, 90), 10, (90, 90), 90);
>>> grad.add_color_stop(0.0, 'white')
>>> grad.add_color_stop(1.0, 'light-gray')
>>> painter.set_clip_circle((60, 60), 40)
>>> painter.draw_gradient(grad)
set_clip_rect(self: viren2d.Painter, rect: viren2d.Rect) bool

Establishes a rectangular clip region for the current canvas.

After setting the clip region, any drawing operations outside the clip region are effectively masked out. Note that this does not change the canvas transformation, i.e. coordinates for subsequent drawing operations need to be provided in the global/previous canvas coordinate frame. Also note that the clip region will be reset automatically whenever a new canvas is set. To reset the clip region, use reset_clip().

Corresponding C++ API: viren2d::Painter::SetClipRegion.

Parameters:

rect – A Rect defining the rectangular clipping region, optionally rotated and with rounded corners).

Returns:

True if the given clip region is valid, False otherwise which will be indicated by log messages.

Example

>>> TODO
property width

Width in pixels of the painter’s canvas (read-only).

Corresponding C++ API: viren2d::Painter::GetCanvasSize.

Type:

int