File: animate_images_slice.py

package info (click to toggle)
python-vispy 0.15.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,868 kB
  • sloc: python: 59,799; javascript: 6,800; makefile: 69; sh: 6
file content (147 lines) | stat: -rw-r--r-- 4,279 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author: Irwin Zaid
# vispy: gallery 2:40:4
"""
Animate an Image
================

Use a timer to trigger updating an image.

This example demonstrates a 3D Texture. The volume contains noise that
is smoothed in the z-direction. Shown is one slice through that volume
to give the effect of "morphing" noise.
"""

import numpy as np

from vispy.util.transforms import ortho
from vispy import gloo
from vispy import app
from vispy.visuals.shaders import ModularProgram


# Shape of image to be displayed
D, H, W = 30, 60, 90

# Modulated image
img_array = np.random.uniform(0, 0.1, (D, H, W, 3)).astype(np.float32)
# Depth slices are dark->light
img_array[...] += np.linspace(0, 0.9, D)[:, np.newaxis, np.newaxis, np.newaxis]
# Make vertical direction more green moving upward
img_array[..., 1] *= np.linspace(0, 1, H)[np.newaxis, :, np.newaxis]
# Make horizontal direction more red moving rightward
img_array[..., 0] *= np.linspace(0, 1, W)[np.newaxis, np.newaxis, :]

# A simple texture quad
data = np.zeros(4, dtype=[('a_position', np.float32, 2),
                          ('a_texcoord', np.float32, 2)])
data['a_position'] = np.array([[0, 0], [W, 0], [0, H], [W, H]])
data['a_texcoord'] = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])


VERT_SHADER = """
// Uniforms
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;

// Attributes
attribute vec2 a_position;
attribute vec2 a_texcoord;

// Varyings
varying vec2 v_texcoord;

// Main
void main (void)
{
    v_texcoord = a_texcoord;
    gl_Position = u_projection * u_view * u_model * vec4(a_position,0.0,1.0);
}
"""

FRAG_SHADER = """
uniform $sampler_type u_texture;
uniform float i;
varying vec2 v_texcoord;
void main()
{
    // step through gradient with i, note that slice (depth) comes last here!
    gl_FragColor = $sample(u_texture, vec3(v_texcoord, i));
    gl_FragColor.a = 1.0;
}

"""


class Canvas(app.Canvas):

    def __init__(self, emulate3d=True):
        app.Canvas.__init__(self, keys='interactive', size=((W*5), (H*5)))

        if emulate3d:
            tex_cls = gloo.TextureEmulated3D
        else:
            tex_cls = gloo.Texture3D
        self.texture = tex_cls(img_array, interpolation='nearest',
                               wrapping='clamp_to_edge')

        self.program = ModularProgram(VERT_SHADER, FRAG_SHADER)
        self.program.frag['sampler_type'] = self.texture.glsl_sampler_type
        self.program.frag['sample'] = self.texture.glsl_sample
        self.program['u_texture'] = self.texture
        self.program['i'] = 0.0
        self.program.bind(gloo.VertexBuffer(data))

        self.view = np.eye(4, dtype=np.float32)
        self.model = np.eye(4, dtype=np.float32)
        self.projection = np.eye(4, dtype=np.float32)

        self.program['u_model'] = self.model
        self.program['u_view'] = self.view
        self.projection = ortho(0, W, 0, H, -1, 1)
        self.program['u_projection'] = self.projection

        self.i = 0

        gloo.set_clear_color('white')

        self._timer = app.Timer('auto', connect=self.on_timer, start=True)

        self.show()

    def on_resize(self, event):
        width, height = event.physical_size
        gloo.set_viewport(0, 0, width, height)
        self.projection = ortho(0, width, 0, height, -100, 100)
        self.program['u_projection'] = self.projection

        # Compute the new size of the quad
        r = width / float(height)
        R = W / float(H)
        if r < R:
            w, h = width, width / R
            x, y = 0, int((height - h) / 2)
        else:
            w, h = height * R, height
            x, y = int((width - w) / 2), 0
        data['a_position'] = np.array(
            [[x, y], [x + w, y], [x, y + h], [x + w, y + h]])
        self.program.bind(gloo.VertexBuffer(data))

    def on_timer(self, event):
        # cycle every 2 sec
        self.i = (self.i + 1./120.) % 1.0
        self.update()

    def on_draw(self, event):
        gloo.clear(color=True, depth=True)
        self.program['i'] = 1.9 * np.abs(0.5 - self.i)
        self.program.draw('triangle_strip')


if __name__ == '__main__':
    # Use emulated3d to switch from an emulated 3D texture to an actual one
    canvas = Canvas(emulate3d=True)
    app.run()