GUI system¶
Taichi has a built-in GUI system to help users visualize results.
Create a window¶
-
ti.
GUI
(title, res, bgcolor = 0x000000)¶ 参数: - title – (string) the window title
- res – (scalar or tuple) resolution / size of the window
- bgcolor – (optional, RGB hex) background color of the window
返回: (GUI) an object represents the window
Create a window. If
res
is scalar, then width will be equal to height.The following code creates a window of resolution
640x360
:gui = ti.GUI('Window Title', (640, 360))
-
gui.
show
(filename = None)¶ 参数: - gui – (GUI) the window object
- filename – (optional, string) see notes below
Show the window on the screen.
注解
If
filename
is specified, a screenshot will be saved to the file specified by the name. For example, the following saves frames of the window to.png
’s:for frame in range(10000): render(img) gui.set_image(img) gui.show(f'{frame:06d}.png')
Paint on a window¶
-
gui.
set_image
(img)¶ 参数: - gui – (GUI) the window object
- img – (np.array or Tensor) tensor containing the image, see notes below
Set an image to display on the window.
The image pixels are set from the values of
img[i, j]
, wherei
indicates the horizontal coordinates (from left to right) andj
the vertical coordinates (from bottom to top).If the window size is
(x, y)
, thenimg
must be one of:ti.var(shape=(x, y))
, a grey-scale imageti.var(shape=(x, y, 3))
, where 3 is for(r, g, b)
channelsti.Vector(3, shape=(x, y))
(see 向量)np.ndarray(shape=(x, y))
np.ndarray(shape=(x, y, 3))
The data type of
img
must be one of:uint8
, range[0, 255]
uint16
, range[0, 65535]
uint32
, range[0, 4294967295]
float32
, range[0, 1]
float64
, range[0, 1]
注解
When using
float32
orfloat64
as the data type,img
entries will be clipped into range[0, 1]
for display.
-
gui.
circle
(pos, color = 0xFFFFFF, radius = 1)¶ 参数: - gui – (GUI) the window object
- pos – (tuple of 2) the position of the circle
- color – (optional, RGB hex) the color to fill the circle
- radius – (optional, scalar) the radius of the circle
Draw a solid circle.
-
gui.
circles
(pos, color = 0xFFFFFF, radius = 1)¶ 参数: - gui – (GUI) the window object
- pos – (np.array) the positions of the circles
- color – (optional, RGB hex or np.array of uint32) the color(s) to fill the circles
- radius – (optional, scalar or np.array of float32) the radius (radii) of the circles
Draw solid circles.
注解
If color
is a numpy array, the circle at pos[i]
will be colored with color[i]
.
In this case, color
must have the same size as pos
.
-
gui.
line
(begin, end, color = 0xFFFFFF, radius = 1)¶ 参数: - gui – (GUI) the window object
- begin – (tuple of 2) the first end point position of line
- end – (tuple of 2) the second end point position of line
- color – (optional, RGB hex) the color of line
- radius – (optional, scalar) the width of line
Draw a line.
-
gui.
lines
(begin, end, color = 0xFFFFFF, radius = 1)¶ 参数: - gui – (GUI) the window object
- begin – (np.array) the positions of the first end point of lines
- end – (np.array) the positions of the second end point of lines
- color – (optional, RGB hex or np.array of uint32) the color(s) of lines
- radius – (optional, scalar or np.array of float32) the width(s) of the lines
Draw lines.
-
gui.
triangle
(a, b, c, color = 0xFFFFFF)¶ 参数: - gui – (GUI) the window object
- a – (tuple of 2) the first end point position of triangle
- b – (tuple of 2) the second end point position of triangle
- c – (tuple of 2) the third end point position of triangle
- color – (optional, RGB hex) the color to fill the triangle
Draw a solid triangle.
-
gui.
triangles
(a, b, c, color = 0xFFFFFF)¶ 参数: - gui – (GUI) the window object
- a – (np.array) the positions of the first end point of triangles
- b – (np.array) the positions of the second end point of triangles
- c – (np.array) the positions of the third end point of triangles
- color – (optional, RGB hex or np.array of uint32) the color(s) to fill the triangles
Draw solid triangles.
-
gui.
rect
(topleft, bottomright, radius = 1, color = 0xFFFFFF)¶ 参数: - gui – (GUI) the window object
- topleft – (tuple of 2) the top-left point position of rectangle
- bottomright – (tuple of 2) the bottom-right point position of rectangle
- color – (optional, RGB hex) the color of stroke line
- radius – (optional, scalar) the width of stroke line
Draw a hollow rectangle.
-
gui.
text
(content, pos, font_size = 15, color = 0xFFFFFF)¶ 参数: - gui – (GUI) the window object
- content – (str) the text to draw
- pos – (tuple of 2) the top-left point position of the fonts / texts
- font_size – (optional, scalar) the size of font (in height)
- color – (optional, RGB hex) the foreground color of text
Draw a line of text on screen.
-
ti.rgb_to_hex(rgb):
参数: rgb – (tuple of 3 floats) The (R, G, B) float values, in range [0, 1] 返回: (RGB hex or np.array of uint32) The converted hex value Convert a (R, G, B) tuple of floats into a single integer value. E.g.,
rgb = (0.4, 0.8, 1.0) hex = ti.rgb_to_hex(rgb) # 0x66ccff rgb = np.array([[0.4, 0.8, 1.0], [0.0, 0.5, 1.0]]) hex = ti.rgb_to_hex(rgb) # np.array([0x66ccff, 0x007fff])
The return values can be used in GUI drawing APIs.
Event processing¶
Every event have a key and type.
Event type is the type of event, for now, there are just three type of event:
ti.GUI.RELEASE # key up or mouse button up
ti.GUI.PRESS # key down or mouse button down
ti.GUI.MOTION # mouse motion or mouse wheel
Event key is the key that you pressed on keyboard or mouse, can be one of:
# for ti.GUI.PRESS and ti.GUI.RELEASE event:
ti.GUI.ESCAPE # Esc
ti.GUI.SHIFT # Shift
ti.GUI.LEFT # Left Arrow
'a' # we use lowercase for alphabet
'b'
...
ti.GUI.LMB # Left Mouse Button
ti.GUI.RMB # Right Mouse Button
# for ti.GUI.MOTION event:
ti.GUI.MOVE # Mouse Moved
ti.GUI.WHEEL # Mouse Wheel Scrolling
A event filter is a list combined of key, type and (type, key) tuple, e.g.:
# if ESC pressed or released:
gui.get_event(ti.GUI.ESCAPE)
# if any key is pressed:
gui.get_event(ti.GUI.PRESS)
# if ESC pressed or SPACE released:
gui.get_event((ti.GUI.PRESS, ti.GUI.ESCAPE), (ti.GUI.RELEASE, ti.GUI.SPACE))
-
gui.
running
¶ 参数: gui – (GUI) 返回: (bool) True
ifti.GUI.EXIT
event occurred, vice versati.GUI.EXIT
occurs when you click on the close (X) button of a window. Sogui.running
will obtainFalse
when the GUI is being closed.For example, loop until the close button is clicked:
while gui.running: render() gui.set_image(pixels) gui.show()
You can also close the window by manually setting
gui.running
toFalse
:while gui.running: if gui.get_event(ti.GUI.ESCAPE): gui.running = False render() gui.set_image(pixels) gui.show()
-
gui.
get_event
(a, ...)¶ 参数: - gui – (GUI)
- a – (optional, EventFilter) filter out matched events
返回: (bool)
False
if there is no pending event, vise versaTry to pop a event from the queue, and store it in
gui.event
.For example:
if gui.get_event(): print('Got event, key =', gui.event.key)
For example, loop until ESC is pressed:
gui = ti.GUI('Title', (640, 480)) while not gui.get_event(ti.GUI.ESCAPE): gui.set_image(img) gui.show()
-
gui.
get_events
(a, ...)¶ 参数: - gui – (GUI)
- a – (optional, EventFilter) filter out matched events
返回: (generator) a python generator, see below
Basically the same as
gui.get_event
, except for this one returns a generator of events instead of storing intogui.event
:for e in gui.get_events(): if e.key == ti.GUI.ESCAPE: exit() elif e.key == ti.GUI.SPACE: do_something() elif e.key in ['a', ti.GUI.LEFT]: ...
-
gui.
is_pressed
(key, ...)¶ 参数: - gui – (GUI)
- key – (EventKey) keys you want to detect
返回: (bool)
True
if one of the keys pressed, vice versa警告
Must be used together with
gui.get_event
, or it won’t be updated! For example:while True: gui.get_event() # must be called before is_pressed if gui.is_pressed('a', ti.GUI.LEFT): print('Go left!') elif gui.is_pressed('d', ti.GUI.RIGHT): print('Go right!')
-
gui.
get_cursor_pos
()¶ 参数: gui – (GUI) 返回: (tuple of 2) current cursor position within the window For example:
mouse_x, mouse_y = gui.get_cursor_pos()
GUI Widgets¶
Sometimes it’s more intuitive to use widgets like slider, button to control program variables instead of chaotic keyboard bindings. Taichi GUI provides a set of widgets that hopefully could make variable control more intuitive:
-
gui.
slider
(text, minimum, maximum, step=1)¶ 参数: - text – (str) the text to be displayed above this slider.
- minumum – (float) the minimum value of the slider value.
- maxumum – (float) the maximum value of the slider value.
- step – (optional, float) the step between two separate value.
返回: (WidgetValue) a value getter / setter, see
WidgetValue
.The widget will be display as:
{text}: {value:.3f}
, followed with a slider.
-
gui.
label
(text)¶ 参数: text – (str) the text to be displayed in the label. 返回: (WidgetValue) a value getter / setter, see WidgetValue
.The widget will be display as:
{text}: {value:.3f}
.
参数: - text – (str) the text to be displayed in the button.
- event_name – (optional, str) customize the event name.
返回: (EventKey) the event key for this button, see Event processing.
Image I/O¶
-
gui.
get_image
()¶ 返回: a np.ndarray
which is the current image shown on the GUI.Get the RGBA shown image from the current GUI system which has four channels.
-
ti.
imwrite
(img, filename)¶ 参数: - img – (Matrix or Expr) the image you want to export
- filename – (string) the location you want to save to
Export a
np.ndarray
or Taichi tensor (ti.Matrix
,ti.Vector
, orti.var
) to a specified locationfilename
.Same as
ti.GUI.show(filename)
, the format of the exported image is determined by the suffix offilename
as well. Nowti.imwrite
supports exporting images topng
,img
andjpg
and we recommend usingpng
.Please make sure that the input image has a valid shape. If you want to export a grayscale image, the input shape of tensor should be
(height, weight)
or(height, weight, 1)
. For example:import taichi as ti ti.init() shape = (512, 512) type = ti.u8 pixels = ti.var(dt=type, shape=shape) @ti.kernel def draw(): for i, j in pixels: pixels[i, j] = ti.random() * 255 # integars between [0, 255] for ti.u8 draw() ti.imwrite(pixels, f"export_u8.png")
Besides, for RGB or RGBA images,
ti.imwrite
needs to receive a tensor which has shape(height, width, 3)
and(height, width, 4)
individually.Generally the value of the pixels on each channel of a
png
image is an integar in [0, 255]. For this reason,ti.imwrite
will cast tensors which has different datatypes all into integars between [0, 255]. As a result,ti.imwrite
has the following requirements for different datatypes of input tensors:- For float-type (
ti.f16
,ti.f32
, etc) input tensors, the value of each pixel should be float between [0.0, 1.0]. Otherwiseti.imwrite
will first clip them into [0.0, 1.0]. Then they are multiplied by 256 and casted to integaters ranging from [0, 255]. - For int-type (
ti.u8
,ti.u16
, etc) input tensors, the value of each pixel can be any valid integer in its own bounds. These integers in this tensor will be scaled to [0, 255] by being divided over the upper bound of its basic type accordingly.
Here is another example:
import taichi as ti ti.init() shape = (512, 512) channels = 3 type = ti.f32 pixels = ti.Matrix(channels, dt=type, shape=shape) @ti.kernel def draw(): for i, j in pixels: for k in ti.static(range(channels)): pixels[i, j][k] = ti.random() # floats between [0, 1] for ti.f32 draw() ti.imwrite(pixels, f"export_f32.png")
-
ti.
imread
(filename, channels=0)¶ 参数: - filename – (string) the filename of the image to load
- channels – (optional int) the number of channels in your specified image. The default value
0
means the channels of the returned image is adaptive to the image file
返回: (np.ndarray) the image read from
filename
This function loads an image from the target filename and returns it as a
np.ndarray(dtype=np.uint8)
.Each value in this returned tensor is an integer in [0, 255].
-
ti.
imshow
(img, windname)¶ 参数: - img – (Matrix or Expr) the image to show in the GUI
- windname – (string) the name of the GUI window
This function will create an instance of
ti.GUI
and show the input image on the screen.It has the same logic as
ti.imwrite
for different datatypes.