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
resis 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
filenameis 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], whereiindicates the horizontal coordinates (from left to right) andjthe vertical coordinates (from bottom to top).If the window size is
(x, y), thenimgmust 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
imgmust 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
float32orfloat64as the data type,imgentries 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) Trueifti.GUI.EXITevent occurred, vice versati.GUI.EXIToccurs when you click on the close (X) button of a window. Sogui.runningwill obtainFalsewhen 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.runningtoFalse: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)
Falseif 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)
Trueif 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.ndarraywhich 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.ndarrayor 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 offilenameas well. Nowti.imwritesupports exporting images topng,imgandjpgand 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.imwriteneeds 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
pngimage is an integar in [0, 255]. For this reason,ti.imwritewill cast tensors which has different datatypes all into integars between [0, 255]. As a result,ti.imwritehas 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.imwritewill 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
0means the channels of the returned image is adaptive to the image file
返回: (np.ndarray) the image read from
filenameThis 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.GUIand show the input image on the screen.It has the same logic as
ti.imwritefor different datatypes.