• No results found

EXAMPLE GALLERY 10.1 Mlab functions gallery

10.4 Advanced visualization examples

10.4.14 Structured grid example

An example of how to generate a structured grid dataset using numpy arrays. Also shown is a way to visualize this data with the mayavi2 application.

The script can be run like so:

$ mayavi2 -x structured_grid.py

Alternatively, it can be run as: $ python structured_grid.py

Source code: structured_grid.py

# Authors: Eric Jones <eric at enthought dot com>

# Prabhu Ramachandran <prabhu at aero dot iitb dot ac dot in> # Copyright (c) 2007, Enthought, Inc.

# License: BSD style. import numpy as np

from numpy import cos, sin, pi from enthought.tvtk.api import tvtk

from enthought.mayavi.scripts import mayavi2

def generate_annulus(r=None, theta=None, z=None):

""" Generate points for structured grid for a cylindrical annular volume. This method is useful for generating a structured cylindrical mesh for VTK (and perhaps other tools).

Parameters ---

r : array : The radial values of the grid points. It defaults to linspace(1.0, 2.0, 11).

theta : array : The angular values of the x axis for the grid points. It defaults to linspace(0,2*pi,11). z: array : The values along the z axis of the grid points.

It defaults to linspace(0,0,1.0, 11).

Return ---

points : array

Nx3 array of points that make up the volume of the annulus. They are organized in planes starting with the first value of z and with the inside "ring" of the plane as the first set of points. The default point array will be 1331x3. """

# Default values for the annular grid. if r is None: r = np.linspace(1.0, 2.0, 11)

if theta is None: theta = np.linspace(0, 2*pi, 11) if z is None: z = np.linspace(0.0, 1.0, 11)

# Find the x values and y values for each plane. x_plane = (cos(theta)*r[:,None]).ravel()

y_plane = (sin(theta)*r[:,None]).ravel()

Mayavi User Guide, Release 3.3.1

# Allocate an array for all the points. We’ll have len(x_plane) # points on each plane, and we have a plane for each z value, so # we need len(x_plane)*len(z) points.

points = np.empty([len(x_plane)*len(z),3])

# Loop through the points for each plane and fill them with the # correct x,y,z values.

start = 0

for z_plane in z:

end = start + len(x_plane)

# slice out a plane of the output points and fill it # with the x,y, and z values for this plane. The x,y # values are the same for every plane. The z value # is set to the current z

plane_points = points[start:end] plane_points[:,0] = x_plane plane_points[:,1] = y_plane plane_points[:,2] = z_plane start = end return points

# Make the data. dims = (51, 25, 25)

# Note here that the ’x’ axis corresponds to ’theta’ theta = np.linspace(0, 2*np.pi, dims[0])

# ’y’ corresponds to varying ’r’ r = np.linspace(1, 10, dims[1]) z = np.linspace(0, 5, dims[2]) pts = generate_annulus(r, theta, z)

# Uncomment the following if you want to add some noise to the data. #pts += np.random.randn(dims[0]*dims[1]*dims[2], 3)*0.04

sgrid = tvtk.StructuredGrid(dimensions=dims) sgrid.points = pts

s = np.sqrt(pts[:,0]**2 + pts[:,1]**2 + pts[:,2]**2) sgrid.point_data.scalars = np.ravel(s.copy())

sgrid.point_data.scalars.name = ’scalars’

# Uncomment the next two lines to save the dataset to a VTK XML file. #w = tvtk.XMLStructuredGridWriter(input=sgrid, file_name=’sgrid.vts’) #w.write()

# View the data. @mayavi2.standalone

def view():

from enthought.mayavi.sources.vtk_data_source import VTKDataSource from enthought.mayavi.modules.api import Outline, GridPlane

mayavi.new_scene() src = VTKDataSource(data=sgrid) mayavi.add_source(src) mayavi.add_module(Outline()) g = GridPlane() g.grid_plane.axis = ’x’ mayavi.add_module(g) g = GridPlane()

g.grid_plane.axis = ’y’ mayavi.add_module(g)

Mayavi User Guide, Release 3.3.1 g = GridPlane() g.grid_plane.axis = ’z’ mayavi.add_module(g) if __name__ == ’__main__’: view()

10.4.15 Tvtk segmentation example

Using VTK to assemble a pipeline for segmenting MRI images. This example shows how to insert well-controled custom VTK filters in Mayavi.

This example downloads an MRI scan, turns it into a 3D numpy array, applies a segmentation procedure made of VTK filters to extract the gray-matter/white-matter boundary.

The segmentation algorithm used here is very naive and should, of course, not be used as an example of segmentation. Source code: tvtk_segmentation.py

### Download the data, if not already on disk ################################## import os

if not os.path.exists(’mri_data.tar.gz’): # Download the data

import urllib

print "Downloading data, Please Wait (7.8MB)" opener = urllib.urlopen(

’http://www-graphics.stanford.edu/data/voldata/MRbrain.tar.gz’)

open(’mri_data.tar.gz’, ’wb’).write(opener.read()) # Extract the data

import tarfile

tar_file = tarfile.open(’mri_data.tar.gz’) try: os.mkdir(’mri_data’) except: pass tar_file.extractall(’mri_data’) tar_file.close()

### Read the data in a numpy 3D array ########################################## import numpy as np

data = np.array([np.fromfile(os.path.join(’mri_data’, ’MRbrain.%i’ % i), dtype=’>u2’) for i in range(1, 110)]) data.shape = (109, 256, 256)

data = data.T

################################################################################ # Heuristic for finding the threshold for the brain

# Exctract the percentile 20 and 80 (without using # scipy.stats.scoreatpercentile)

sorted_data = np.sort(data.ravel()) l = len(sorted_data)

lower_thr = sorted_data[0.2*l] upper_thr = sorted_data[0.8*l]

Mayavi User Guide, Release 3.3.1

# The white matter boundary: find the densest part of the upper half # of histogram, and take a value 10% higher, to cut _in_ the white matter hist, bins = np.histogram(data[data > np.mean(data)], bins=50)

brain_thr_idx = np.argmax(hist) brain_thr = bins[brain_thr_idx + 4]

del hist, bins, brain_thr_idx

# Display the data ############################################################# from enthought.mayavi import mlab

from enthought.tvtk.api import tvtk

fig = mlab.figure(bgcolor=(0, 0, 0), size=(400, 500)) # to speed things up

fig.scene.disable_render = True

src = mlab.pipeline.scalar_field(data)

# Our data is not equally spaced in all directions: src.spacing = [1, 1, 1.5]

src.update_image_data = True

#--- # Brain extraction pipeline

# In the following, we create a Mayavi pipeline that strongly # relies on VTK filters. For this, we make heavy use of the # mlab.pipeline.user_defined function, to include VTK filters in # the Mayavi pipeline.

# Apply image-based filters to clean up noise thresh_filter = tvtk.ImageThreshold()

thresh_filter.threshold_between(lower_thr, upper_thr)

thresh = mlab.pipeline.user_defined(src, filter=thresh_filter) median_filter = tvtk.ImageMedian3D()

median_filter.set_kernel_size(3, 3, 3)

median = mlab.pipeline.user_defined(thresh, filter=median_filter) diffuse_filter = tvtk.ImageAnisotropicDiffusion3D(

diffusion_factor=1.0, diffusion_threshold=100.0, number_of_iterations=5, )

diffuse = mlab.pipeline.user_defined(median, filter=diffuse_filter) # Extract brain surface

contour = mlab.pipeline.contour(diffuse, ) contour.filter.contours = [brain_thr, ]

# Apply mesh filter to clean up the mesh (decimation and smoothing) dec = mlab.pipeline.decimate_pro(contour)

dec.filter.feature_angle = 60. dec.filter.target_reduction = 0.7 smooth_ = tvtk.SmoothPolyDataFilter(

number_of_iterations=10, relaxation_factor=0.1, feature_angle=60,

Mayavi User Guide, Release 3.3.1

feature_edge_smoothing=False, boundary_smoothing=False, convergence=0.,

)

smooth = mlab.pipeline.user_defined(dec, filter=smooth_) # Get the largest connected region

connect_ = tvtk.PolyDataConnectivityFilter(extraction_mode=4) connect = mlab.pipeline.user_defined(smooth, filter=connect_) # Compute normals for shading the surface

compute_normals = mlab.pipeline.poly_data_normals(connect) compute_normals.filter.feature_angle = 80

surf = mlab.pipeline.surface(compute_normals,

color=(0.9, 0.72, 0.62))

#--- # Display a cut plane of the raw data

ipw = mlab.pipeline.image_plane_widget(src, colormap=’bone’, plane_orientation=’z_axes’,

slice_index=55)

mlab.view(-165, 32, 350, [143, 133, 73]) mlab.roll(180)

fig.scene.disable_render = False

mlab.show()