Display a numpy image and draw pixel-coordinate overlays¶
Keywords: image · ImageCanvas · rectangle · Rectangle2D · shader · uniform · overlay · pixels
Shows a synthetic RGB gradient in an ~pytanga.viz.ImageCanvas (a
dedicated 2D scene with a y-down pixel frame, 1 unit = 1 pixel), draws a
~pytanga.geometry.Rectangle2D overlay (via
~pytanga.geometry.Rectangle2D.between) in pixel coordinates, and binds
a ctrl+left-drag handler that maps the cursor position to the image's
brightness/contrast uniforms.
The ctrl+left-drag is registered as a ~pytanga.viz.DragBinding (a
mouse-button + modifier combination) via the canvas's drag_handlers list.
Run¶
Source¶
Code¶
# SPDX-License-Identifier: Apache-2.0
# Copyright 2021 Christian Perwass
"""image_canvas.py — Display a numpy image and draw pixel-coordinate overlays.
Shows a synthetic RGB gradient in an :class:`~pytanga.viz.ImageCanvas` (a
dedicated 2D scene with a y-down pixel frame, 1 unit = 1 pixel), draws a
:class:`~pytanga.geometry.Rectangle2D` overlay (via
:meth:`~pytanga.geometry.Rectangle2D.between`) in pixel coordinates, and binds
a ctrl+left-drag handler that maps the cursor position to the image's
brightness/contrast uniforms.
The ctrl+left-drag is registered as a :class:`~pytanga.viz.DragBinding` (a
mouse-button + modifier combination) via the canvas's ``drag_handlers`` list.
Run with: uv run python py/examples/viz/image/image_canvas.py
Keywords: image, ImageCanvas, rectangle, Rectangle2D, shader, uniform, overlay, pixels
"""
import numpy as np
from pytanga.geometry import Point, Rectangle2D
from pytanga.viz import (
DragBinding,
DragEvent,
ImageCanvas,
ImageData,
ModifierKey,
MouseButton,
Visualizer,
)
def _gradient(width: int, height: int) -> np.ndarray:
"""A 3-channel RGB gradient of shape (H, W, 3), dtype uint8."""
ys, xs = np.mgrid[0:height, 0:width]
r = (xs / max(width - 1, 1) * 255).astype(np.uint8)
g = (ys / max(height - 1, 1) * 255).astype(np.uint8)
b = np.full_like(r, 128)
return np.stack([r, g, b], axis=-1)
def _rectangle(canvas: ImageCanvas, x0: int, y0: int, x1: int, y1: int) -> None:
"""Draw a rectangle outline in pixel coordinates (y down)."""
canvas.add(
Rectangle2D.between(
Point(float(x0), float(y0), 0.0),
Point(float(x1), float(y1), 0.0),
),
color="#ff4444",
)
def main() -> None:
width, height = 320, 200
viz = Visualizer(add_default_axes=False, add_default_grid=False, space_dim=2)
async def on_drag(event: DragEvent, canvas: ImageCanvas) -> bool:
# ctrl+left drag: horizontal position → contrast, vertical → brightness.
px, py = event.world_position.x, event.world_position.y
canvas.set_uniform("u_contrast", 0.5 + 1.5 * px / width)
canvas.set_uniform("u_brightness", (py / height - 0.5) * 2.0)
return True
canvas = ImageCanvas(
viz,
drag_handlers=[DragBinding(MouseButton.LEFT, on_drag, ModifierKey.CTRL)],
)
canvas.set_image(ImageData("gradient", data=_gradient(width, height)))
_rectangle(canvas, 40, 30, 160, 120)
viz.show(layout=canvas.scene_view())
viz.wait()
if __name__ == "__main__":
main()