Search code examples
python3dvolumevispyvoxels

Transparency with voxels in VisPy


I am attempting to use python and VisPy to display 3D data from a numpy array. I looked up the example here and it was extrememly useful. I've gotten the data to display--but it doesn't look the way I want.

The way my data is displaying now I really can't see every voxel. I can see the sides of the shape, but it honestly looks like just a hollowed out cube. It looks like this. I think this is probably due to the fact that many values are negative or that most values are relatively small with a few large outliers.

Either way, I would like to be able to set the transparency of values individually--so that positive values, for instance, are 70% transparent, while values less then -2 but greater than -5 are only 30% transparent and a shade of green. I'm hoping this will allow me to see an actual "volume" as opposed to what I have now.

Here's a peek of what I have now, in case anyone would like to see (note, heavily copied and pasted from the example vispy code I linked):

# Creating volume data (returns a 100x100x100 numpy array)
volume_data = func()

# Prepare canvas
canvas = scene.SceneCanvas(keys='interactive', size=(800, 600), show=True)

# Set up a viewbox to display the image with interactive pan/zoom
view = canvas.central_widget.add_view()

# Creating and assigning camera
camera = scene.cameras.ArcballCamera(parent=view.scene, fov=60)
view.camera = camera  

# Create the volume
volume = scene.visuals.Volume(volume_data, clim=(0, 1), parent=view.scene, 
threshold=0.225,emulate_texture=False)

volume.cmap = 'blues'

if __name__ == '__main__':
    print(__doc__)
    app.run()

Solution

  • May be you can try to normalize the volume between (0., 1.) and define a colormap with multiple transparency levels. Just as an example :

    import numpy as np
    from vispy import scene, app, io
    from vispy.color import BaseColormap
    
    class MultiLevels(BaseColormap):
        """Mix of green and red."""
    
        glsl_map = """
        vec4 translucent_fire(float t) {
            if (t > .5 && t < .6) {
                return vec4(1, 0., 0., .3);
            }
            else if (t >= .6) {
                return vec4(0, 1., 0., 1.);
            }
            else {
                return vec4(0., 0., 0., 0.);
            }
        }
        """
    
    class Greens(BaseColormap):
        """Transparent green."""
    
        glsl_map = """
        vec4 translucent_fire(float t) {
            float alpha;
            if (t < .4) {
                alpha = 0.;
            }
            else if (t >= .4 && t < .5) {
                alpha = .1;
            }
            else {
                alpha = 1.;
            }
            return vec4(t, pow(t, 0.5), t*t, alpha);
        }
        """
    
    # Creating volume data (returns a 100x100x100 numpy array)
    volume_data = np.load(io.load_data_file('volume/stent.npz'))['arr_0'].astype(float)
    volume_data /= volume_data.max()  # normalize the volume between (0., 1.)
    
    # Prepare canvas
    canvas = scene.SceneCanvas(keys='interactive', size=(800, 600), show=True)
    
    # Set up a viewbox to display the image with interactive pan/zoom
    view = canvas.central_widget.add_view()
    
    # Creating and assigning camera
    camera = scene.cameras.ArcballCamera(parent=view.scene, fov=60)
    view.camera = camera
    
    # Create the volume
    method = 'translucent'  # 'mip'
    volume = scene.visuals.Volume(volume_data, parent=view.scene, method=method)
    volume.cmap = Greens()  # MultiLevels()
    
    if __name__ == '__main__':
        app.run()