def load_labelled_volume(data, vmin=0, alpha=1, **kwargs): """ Load volume image from .nrrd file. It assume that voxels with value = 0 are empty while voxels with values > 0 are labelles (e.g. to indicate the location of a brain region in a reference atlas) :param data: str, path to file with volume data or 3d numpy array :param vmin: float, values below this numner will be assigned an alpha=0 and not be visualized :param **kwargs: kwargs to pass to the Volume class from vtkplotter :param alpha: float in range [0, 1], transparency [for the part of volume with value > vmin] """ # Load/check volumetric data if isinstance(data, str): # load from file if not os.path.isfile(data): raise FileNotFoundError(f'Volume data file {data} not found') try: data = brainio.load_any(data) except: raise ValueError(f"Could not load volume data from file: {data}") elif not isinstance(data, np.ndarray): raise ValueError( f"Data should be a filepath or np array, not: {data.__type__}") # Create volume and set transparency range vol = Volume(data, alpha=alpha, **kwargs) otf = vol.GetProperty().GetScalarOpacity() otf.RemoveAllPoints() otf.AddPoint(vmin, 0) # set to transparent otf.AddPoint(vmin + .1, alpha) # set to opaque otf.AddPoint(data.max(), alpha) return vol
def add_volume(self, volume, cmap='afmhot_r', alpha=1, add_colorbar=True, **kwargs): """ Renders intensitdata from a 3D numpy array as a lego volumetric actor. :param volume: np 3D array with number of dimensions = those of the 100um reference space. :param cmap: str with name of colormap to use :param alpha: float, transparency :param add_colorbar: if True a colorbar is added to show the values of the colormap """ # Parse kwargs line_width = kwargs.pop('line_width', 1) if cmap == 'random' or not cmap or cmap is None: cmap = get_random_colormap() # Get vmin and vmax threshold for visualisation vmin = kwargs.pop('vmin', 0.000001) vmax = kwargs.pop('vmax', np.nanmax(volume)) # Check values if np.max(volume) > vmax: print( "While rendering mapped projection some of the values are above the vmax threshold." + "They will not be displayed." + f" vmax was {vmax} but found value {round(np.max(volume), 5)}." ) if vmin > vmax: raise ValueError( f'The vmin threhsold [{vmin}] cannot be larger than the vmax threshold [{vmax}' ) if vmin < 0: vmin = 0 # Get 'lego' actor vol = Volume(volume) lego = vol.legosurface(vmin=vmin, vmax=vmax, cmap=cmap) # Scale and color actor lego.alpha(alpha).lw(line_width).scale(self.voxel_size) lego.cmap = cmap # Add colorbar if add_colorbar: lego.addScalarBar(vmin=vmin, vmax=vmax, horizontal=1, c='k', pos=(0.05, 0.05), titleFontSize=40) # Add to scene actor = self.scene.add_vtkactor(lego) return actor
def load_volume_file(filepath, **kwargs): """ Load a volume file (e.g., .nii) and return vtk actor :param filepath: path to file :param **kwargs: """ from vtkplotter import Volume, load if not os.path.isfile(filepath): raise FileNotFoundError(filepath) if ".x3d" in filepath.lower(): raise ValueError( "brainrender cannot use .x3d data as they are not supported by vtkplotter" ) elif "nii" in filepath.lower() or ".label" in filepath.lower(): import nibabel as nb data = nb.load(filepath) d = data.get_fdata() act = Volume(d, **kwargs) else: act = load(filepath, **kwargs) if act is None: raise ValueError("Could not load {}".format(filepath)) return act
def load_mesh_from_file(filepath, *args, **kwargs): """ Load a a mesh or volume from files like .obj, .stl, ... :param filepath: path to file :param **kwargs: """ if not os.path.isfile(filepath): raise FileNotFoundError(filepath) try: actor = load(filepath, *args, **kwargs) except: actor = Volume(load_volume_file(filepath, *args, **kwargs)) return actor
# Create the reader for the data. reader = vtk.vtkXMLImageDataReader() reader.SetFileName(datadir+"vase.vti") reader.Update() img = reader.GetOutput() # vtkImageData object # specify the data array in the file to process # img.GetPointData().SetActiveAttribute('SLCImage', 0) # NB: all the above lines could be reduced to: #img = load(datadir+"vase.vti").imagedata() ################################# from vtkplotter import Volume, show, Text # can set colors and transparencies along the scalar range # from minimum to maximum value. In this example voxels with # the smallest value will be completely transparent (and white) # while voxels with highest value of the scalar will get alpha=0.8 # and color will be=(0,0,1) vol1 = Volume(img, mode=0, # composite rendering c=["white", "fuchsia", "dg", (0,0,1)], alpha=[0.0, 0.2, 0.3, 0.8]) # mode = 1 is maximum-projection volume rendering vol2 = load(datadir+"vase.vti").mode(1).addPos(60,0,0) # show command creates and returns an instance of class Plotter show(vol1, vol2, Text(__doc__), bg="w", axes=1)
model.add(Dense(neurons, activation="relu")) model.add(Dense(neurons, activation="relu")) model.add(Dense(1, activation="sigmoid")) model.compile(optimizer="rmsprop", loss="mse", metrics=["mae"]) model.fit(datalist, scalars, epochs=50, batch_size=64) predicted_scalars = model.predict(datalist) model.summary() idx = 0 vispred = np.zeros([n, n, n]) for i, x in enumerate(ls): for j, y in enumerate(ls): for k, z in enumerate(ls): vispred[i, j, k] = predicted_scalars[idx] idx += 1 v1 = Volume(visdata) v2 = Volume(vispred) s1 = v1.isosurface(threshold=[t for t in arange(0, 1, 0.1)]) s1.alpha(0.5) s2 = v2.isosurface(threshold=[t for t in arange(0, 1, 0.1)]) s2.alpha(0.5) show([[v1, s1], s2], N=2, axes=8)
model = Sequential() model.add(Dense(neurons, activation="relu", input_dim=3)) model.add(Dense(neurons, activation="relu")) model.add(Dense(neurons, activation="relu")) model.add(Dense(1, activation="sigmoid")) model.compile(optimizer="rmsprop", loss="mse", metrics=["mae"]) model.fit(shuffled_datalist, shuffled_scalars, epochs=epochs, batch_size=max(nx, ny, nz)) predicted_scalars = model.predict(datalist) model.summary() idx = 0 vispred = np.zeros([nx, ny, nz]) for i, x in enumerate(lsx): for j, y in enumerate(lsy): for k, z in enumerate(lsz): vispred[i, j, k] = predicted_scalars[idx] idx += 1 v1 = Volume(visdata) v2 = Volume(vispred) s1 = v1.isosurface(threshold=0).alpha(0.8) s2 = v2.isosurface(threshold=0).alpha(0.8) show(v1, v2, s1, s2, N=4, axes=8, bg="w")
iteration = 4 size = 3**iteration voxels = np.ones((size, size, size)) def iterate(length, x, y, z): nl = length // 3 if nl < 1: return margin = (nl - 1) // 2 voxels[z - margin:z + margin + 1, y - margin:y + margin + 1, :] = 0 voxels[z - margin:z + margin + 1, :, x - margin:x + margin + 1] = 0 voxels[:, y - margin:y + margin + 1, x - margin:x + margin + 1] = 0 for ix, iy, iz in np.ndindex((3, 3, 3)): if (1 if ix != 1 else 0) + (1 if iy != 1 else 0) + (1 if iz != 1 else 0) != 2: iterate(nl, x + (ix - 1) * nl, y + (iy - 1) * nl, z + (iz - 1) * nl) iterate(size, size // 2, size // 2, size // 2) print('voxels min, max =', np.min(voxels), np.max(voxels)) vol = Volume(voxels) lego = vol.legosurface(-0.1, 1.1, cmap='afmhot_r') show(vol, lego, N=2, bg='w')
scals = np.abs(coords[:, 2]) # let the scalar be the z of point itself fact = 1. / (bins - 1) # conversion factor btw the 2 ranges vp = Plotter(verbose=0) vp.ztitle = 'z == scalar value' cloud = vp.points(coords) # fill the vtkImageData object pb = ProgressBar(0, bins, c=4) for iz in pb.range(): pb.print() for iy in range(bins): for ix in range(bins): pt = vector(ix, iy, iz) * fact closestPointsIDs = cloud.closestPoint(pt, N=5, returnIds=True) num, den = 0, 0 for i in closestPointsIDs: # work out RBF manually on N points invdist = 1 / (mag2(coords[i] - pt) + 1e-06) num += scals[i] * invdist den += invdist img.SetScalarComponentFromFloat(ix, iy, iz, 0, num / den) #vp.write(img, 'imgcube.tif') # or .vti # set colors and transparencies along the scalar range vol = Volume(img, c=['r', 'g', 'b'], alphas=[0.4, 0.8]) #vtkVolume act = vp.points(coords / fact) vp.show([vol, act], viewup='z')
model = Sequential() model.add(Dense(neurons, activation="relu", input_dim=3)) model.add(Dense(neurons, activation="relu")) model.add(Dense(neurons, activation="relu")) model.add(Dense(1, activation="sigmoid")) model.compile(optimizer="rmsprop", loss="mse", metrics=["mae"]) model.fit(shuffled_datalist, shuffled_scalars, epochs=epochs, batch_size=max(nx, ny, nz)) predicted_scalars = model.predict(datalist) model.summary() idx = 0 vispred = np.zeros([nx, ny, nz]) for i, x in enumerate(lsx): for j, y in enumerate(lsy): for k, z in enumerate(lsz): vispred[i, j, k] = predicted_scalars[idx] idx += 1 v1 = Volume(visdata) v2 = Volume(vispred) s1 = isosurface(v1, threshold=0).alpha(0.8) s2 = isosurface(v2, threshold=0).alpha(0.8) show([v1, v2, s1, s2], N=4, axes=8, bg="w")
"""Create a Volume from a numpy array""" import numpy as np data_matrix = np.zeros([75, 75, 75], dtype=np.uint8) # all voxels have value zero except: data_matrix[0:35, 0:35, 0:35] = 1 data_matrix[35:55, 35:55, 35:55] = 2 data_matrix[55:74, 55:74, 55:74] = 3 from vtkplotter import Volume, Text2D, show vol = Volume(data_matrix, c=['white', 'b', 'g', 'r']) show(vol, Text2D(__doc__), axes=1)
''' Work with vtkVolume objects and surface meshes in the same rendering window. ''' from vtkplotter import loadImageData, Plotter, Volume, Sphere, Text vp = Plotter(axes=0, verbose=0, bg='w') # Load a 3D voxel dataset (returns a vtkImageData object): img = loadImageData('data/embryo.slc', spacing=[1, 1, 1]) # Build a vtkVolume object. # A set of transparency values - of any length - can be passed # to define the opacity transfer function in the range of the scalar. # E.g.: setting alphas=[0, 0, 0, 1, 0, 0, 0] would make visible # only voxels with value close to 98.5 (see print output). vol = Volume(img, c='green', alphas=[0, 0.4, 0.9, 1]) # vtkVolume # can relocate volume in space: #vol.scale(0.3).pos([10,100,0]).rotate(90, axis=[0,1,1]) sph = Sphere(pos=[100, 100, 100], r=20) # add a dummy surface doc = Text(__doc__, c='k') # show both vtkVolume and vtkActor vp.show([vol, sph, doc], zoom=1.4)
""" Generate the isosurfaces corresponding to a set of thresholds. (These surfaces are not separate meshes). """ from vtk import vtkQuadric, vtkSampleFunction # Quadric definition. This is a type of implicit function. quadric = vtkQuadric() quadric.SetCoefficients(0.5, 1, 0.2, 0, 0.1, 0, 0, 0.2, 0, 0) # the vtkSampleFunction evaluates quadric over a volume sample = vtkSampleFunction() sample.SetSampleDimensions(40, 40, 40) sample.SetImplicitFunction(quadric) sample.Update() img = sample.GetOutput() # vtkImageData print("Scalar Range", img.GetScalarRange(), "\ntry press shift-x.") ######################## from vtkplotter import show, Text, Volume # generate an isosurface the volume for each thresholds ts = [0.1, 0.25, 0.4, 0.6, 0.75, 0.9] # Use c=None to use the default vtk color map. isos is of type Actor isos = Volume(img).isosurface(threshold=ts) show(isos, Text(__doc__))
# Using normal vtk commands to load a xml vti file # then use vtkplotter to show the resulting 3d image. # import vtk # Create the reader for the data. reader = vtk.vtkXMLImageDataReader() reader.SetFileName('data/vase.vti') reader.Update() img = reader.GetOutput() # specify the data array in the file to process #img.GetPointData().SetActiveAttribute('SLCImage', 0) ################################# from vtkplotter import Volume, load, show # can set colors and transparencies along the scalar range vol = Volume(img, c=['gray', 'fuchsia', 'dg', (0, 0, 1)], alphas=[0.1, 0.2, 0.3, 0.8]) # load command returns an isosurface (vtkActor) of the 3d image iso = load('data/vase.vti', threshold=140).wire(True).alpha(0.1) # show command creates and returns an instance of class Plotter show([vol, iso], verbose=0)
""" Using normal vtk commands to load a xml vti file then use vtkplotter to show the resulting 3d image. """ import vtk from vtkplotter import datadir # Create the reader for the data. reader = vtk.vtkXMLImageDataReader() reader.SetFileName(datadir + "vase.vti") reader.Update() img = reader.GetOutput() # specify the data array in the file to process # img.GetPointData().SetActiveAttribute('SLCImage', 0) ################################# from vtkplotter import Volume, load, show, Text # can set colors and transparencies along the scalar range vol = Volume(img, c=["gray", "fuchsia", "dg", (0, 0, 1)], alpha=[0.1, 0.2, 0.3, 0.8]) # load command returns an isosurface (vtkActor) of the 3d image iso = load(datadir + "vase.vti", threshold=140).wire(True).alpha(0.1) # show command creates and returns an instance of class Plotter show(vol, iso, Text(__doc__), bg="w")
"""Create a Volume from a numpy array""" import numpy as np data_matrix = np.zeros([75, 75, 75], dtype=np.uint8) # all voxels have value zero except: data_matrix[0:35, 0:35, 0:35] = 1 data_matrix[35:55, 35:55, 35:55] = 2 data_matrix[55:74, 55:74, 55:74] = 3 from vtkplotter import Volume, show vol = Volume(data_matrix, c=['white', 'b', 'g', 'r']) vol.addScalarBar3D() show(vol, __doc__, axes=1)
def addCutterTool(actor): """Create handles to cut away parts of a mesh. .. hint:: |cutter| |cutter.py|_ """ if isinstance(actor, vtk.vtkVolume): return _addVolumeCutterTool(actor) elif isinstance(actor, vtk.vtkImageData): from vtkplotter import Volume return _addVolumeCutterTool(Volume(actor)) vp = settings.plotter_instance if not vp.renderer: save_int = vp.interactive vp.show(interactive=0) vp.interactive = save_int vp.clickedActor = actor apd = actor.polydata() planes = vtk.vtkPlanes() planes.SetBounds(apd.GetBounds()) clipper = vtk.vtkClipPolyData() clipper.GenerateClipScalarsOn() clipper.SetInputData(apd) clipper.SetClipFunction(planes) clipper.InsideOutOn() clipper.GenerateClippedOutputOn() clipper.Update() act0 = Actor(clipper.GetOutput()) # act0.mapper = actor.mapper # act0.mapper.Modified() # print(actor.mapper.GetLookupTable()) # print(actor.polydata().GetPointData().GetScalars()) # print(act0.polydata().GetCellData().GetScalars().GetRange()) # print(act0.mapper.GetScalarRange()) # act0.mapper.SetScalarRange(act0.polydata().GetCellData().GetScalars().GetRange()) # act0.cellColors('pointColors_seismic', vmin=40, vmax=130) act1Mapper = vtk.vtkPolyDataMapper() # the part which is cut away act1Mapper.SetInputConnection( clipper.GetClippedOutputPort()) # needs OutputPort?? act1 = vtk.vtkActor() act1.SetMapper(act1Mapper) act1.GetProperty().SetOpacity(0.02) act1.GetProperty().SetRepresentationToWireframe() act1.VisibilityOn() vp.renderer.AddActor(act0) vp.renderer.AddActor(act1) vp.renderer.RemoveActor(actor) def SelectPolygons(vobj, event): vobj.GetPlanes(planes) boxWidget = vtk.vtkBoxWidget() boxWidget.OutlineCursorWiresOn() boxWidget.GetSelectedOutlineProperty().SetColor(1, 0, 1) boxWidget.GetOutlineProperty().SetColor(0.1, 0.1, 0.1) boxWidget.GetOutlineProperty().SetOpacity(0.8) boxWidget.SetPlaceFactor(1.05) boxWidget.SetInteractor(vp.interactor) boxWidget.SetInputData(apd) boxWidget.PlaceWidget() boxWidget.AddObserver("InteractionEvent", SelectPolygons) boxWidget.On() vp.cutterWidget = boxWidget vp.clickedActor = act0 ia = vp.actors.index(actor) vp.actors[ia] = act0 colors.printc("Mesh Cutter Tool:", c="m", invert=1) colors.printc(" Move gray handles to cut away parts of the mesh", c="m") colors.printc(" Press X to save file to: clipped.vtk", c="m") vp.interactor.Start() boxWidget.Off() vp.widgets.append(boxWidget) vp.interactor.Start() # allow extra interaction return act0
iteration = 4 size = 3**iteration voxels = np.ones((size, size, size)) def iterate(length, x, y, z): nl = length // 3 if nl < 1: return margin = (nl - 1) // 2 voxels[z - margin:z + margin + 1, y - margin:y + margin + 1, :] = 0 voxels[z - margin:z + margin + 1, :, x - margin:x + margin + 1] = 0 voxels[:, y - margin:y + margin + 1, x - margin:x + margin + 1] = 0 for ix, iy, iz in np.ndindex((3, 3, 3)): if (1 if ix != 1 else 0) + (1 if iy != 1 else 0) + (1 if iz != 1 else 0) != 2: iterate(nl, x + (ix - 1) * nl, y + (iy - 1) * nl, z + (iz - 1) * nl) iterate(size, size // 2, size // 2, size // 2) print('voxels min, max =', np.min(voxels), np.max(voxels)) vol = Volume(voxels) lego = legosurface(vol, -0.1, 1.1, cmap='afmhot_r') show(vol, lego, N=2, bg='w')
import numpy as np data_matrix = np.zeros([75, 75, 75], dtype=np.uint8) # all voxels have value zero except: data_matrix[0:35, 0:35, 0:35] = 1 data_matrix[35:55, 35:55, 35:55] = 2 data_matrix[55:74, 55:74, 55:74] = 3 from vtkplotter import Volume vol = Volume(data_matrix, c=['white', 'b', 'g', 'r']) vol.show(axes=1)
# Perform other simple mathematical operation between 3d images. # Possible operations are: +, -, /, 1/x, sin, cos, exp, log, abs, **2, sqrt, # min, max, atan, atan2, median, mag, dot, gradient, divergence, laplacian. # Alphas defines the opacity transfer function in the scalar range. # from vtkplotter import Plotter, loadImageData from vtkplotter import imageOperation, Volume vp = Plotter(N=8, axes=4) img0 = loadImageData('data/embryo.slc') # vtkImageData object v0 = Volume(img0, c=0) # build a vtk.vtkVolume derived object vp.show(v0, at=0) img1 = imageOperation(img0, 'gradient') img1 = imageOperation(img1, '+', 92.0) v1 = Volume(img1, c=1, alphas=[0, 1, 0, 0, 0]) vp.show(v1, at=1) img2 = imageOperation(img0, 'divergence') v2 = Volume(img2, c=2) vp.show(v2, at=2) img3 = imageOperation(img0, 'laplacian') v3 = Volume(img3, c=3, alphas=[0, 1, 0, 0, 1]) vp.show(v3, at=3) img4 = imageOperation(img0, 'median') v4 = Volume(img4, c=4) vp.show(v4, at=4)
"""Modify a Volume dataset and colorize voxels individually """ from vtkplotter import Text2D, Volume, show import numpy as np vol = Volume(shape=(10,11,12), mode=0) vol.alpha(0.8).jittering(False) vol.interpolation(0) # nearest neighbour interpolation type # Overwrite the (sofar empty) voxel data with new data vol.imagedata().AllocateScalars(3, 4) # type 3 corresponds to np.uint8 arr = vol.getPointArray() arr[:] = np.random.randint(0,255, (10*11*12,4)).astype(np.uint8) # For 4 component data, the first 3 directly represent RGB, no lookup table. # (see https://vtk.org/doc/nightly/html/classvtkVolumeProperty.html): vol.GetProperty().IndependentComponentsOff() show(vol, Text2D(__doc__), axes=1)
reader.SetFileName(datadir + "vase.vti") reader.Update() img = reader.GetOutput() # vtkImageData object # NB: the above lines could be reduced to: #img = load(datadir+"vase.vti").imagedata() ################################# from vtkplotter import Volume, show, Text # can set colors and transparencies along the scalar range # from minimum to maximum value. In this example voxels with # the smallest value will be completely transparent (and white) # while voxels with highest value of the scalar will get alpha=0.8 # and color will be=(0,0,1) vol1 = Volume(img, mode=0) # composite rendering vol1.color(["white", "fuchsia", "dg", (0, 0, 1)]) #vol1.color('jet') # a matplotlib colormap name is also accepted vol1.alpha([0.0, 0.2, 0.3, 0.8]) # a transparency for the GRADIENT of the scalar can also be set: # in this case when the scalar is ~constant the gradient is ~zero # and the voxel are made transparent: vol1.alphaGradient([0.0, 0.5, 0.9]) # mode = 1 is maximum-projection volume rendering vol2 = load(datadir + "vase.vti").mode(1).addPos(60, 0, 0) # show command creates and returns an instance of class Plotter show(vol1, vol2, Text(__doc__), bg="w", axes=1)
###################################### getActors print('Test getMeshes') assert len(asse.unpack()) == 2 assert asse.unpack(0) == cone assert asse.unpack(1) == sphere assert 4.1 < asse.diagonalSize() < 4.2 ############################################################################ Volume X, Y, Z = np.mgrid[:30, :30, :30] scalar_field = ((X - 15)**2 + (Y - 15)**2 + (Z - 15)**2) / 225 print('Test Volume, scalar min, max =', np.min(scalar_field), np.max(scalar_field)) vol = Volume(scalar_field) volarr = vol.getPointArray() assert volarr.shape[0] == 27000 assert np.max(volarr) == 3 assert np.min(volarr) == 0 ###################################### isosurface print('Test isosurface') iso = vol.isosurface(threshold=1.0) print('area', iso.area()) assert 2540 < iso.area() < 3000 #lego = vol.legosurface(vmin=0.3, vmax=0.5) #show(lego) #print('lego.N()', lego.N())
"""Load and render a 3D Volume. mode=0, composite rendering mode=1, maximum-projection rendering """ import vtk from vtkplotter import datadir, load, Volume, show # Create the reader for the data. reader = vtk.vtkXMLImageDataReader() reader.SetFileName(datadir + "vase.vti") reader.Update() img = reader.GetOutput() # vtkImageData object vol1 = Volume(img, mode=0) # mode=0, composite rendering # --- NB: THE ABOVE LINES COULD BE REDUCED TO: #vol1 = load(datadir+"vase.vti") # ------------------------------------------- # can set colors and transparencies along the scalar range # from minimum to maximum value. In this example voxels with # the smallest value will be completely transparent (and white) # while voxels with highest value of the scalar will get alpha=0.8 # and color will be=(0,0,1) vol1.color(["white", "fuchsia", "dg", (0, 0, 1)]) #vol1.color('jet') # a matplotlib colormap name is also accepted vol1.alpha([0.0, 0.2, 0.3, 0.8]) # a transparency for the GRADIENT of the scalar can also be set: # in this case when the scalar is ~constant the gradient is ~zero