def __init__(self, verts, faces, filling_factors): mesh = Mesh([verts, faces]) self.filling_factors = filling_factors self.verts = verts self.faces = faces self.all_cells = mesh.faces() self.n_cells = mesh.NCells()
def slicePlane(self, origin=(0,0,0), normal=(1,1,1)): """Extract the slice along a given plane position and normal. |slicePlane| |slicePlane.py|_ """ reslice = vtk.vtkImageReslice() reslice.SetInputData(self._data) reslice.SetOutputDimensionality(2) newaxis = utils.versor(normal) pos = np.array(origin) initaxis = (0,0,1) crossvec = np.cross(initaxis, newaxis) angle = np.arccos(np.dot(initaxis, newaxis)) T = vtk.vtkTransform() T.PostMultiply() T.RotateWXYZ(np.rad2deg(angle), crossvec) T.Translate(pos) M = T.GetMatrix() reslice.SetResliceAxes(M) reslice.SetInterpolationModeToLinear() reslice.Update() vslice = vtk.vtkImageDataGeometryFilter() vslice.SetInputData(reslice.GetOutput()) vslice.Update() msh = Mesh(vslice.GetOutput()) msh.SetOrientation(T.GetOrientation()) msh.SetPosition(pos) return msh
def show_vedo_mesh_old(verts, faces, filling_factors): start = time.time() mesh = Mesh([verts, faces]) mesh.backColor('blue').lineColor('white').lineWidth(0) # retrieve them as numpy arrays # printc('points():\n', mesh.points(), c=3) # printc('faces(): \n', mesh.faces(), c=3) # show(mesh, labs, __doc__, viewup='z', axes=1) colors = [] all_cells = mesh.faces() for i in range(mesh.NCells()): points = all_cells[i] ff_sum = 0 for p in points: ff_sum += filling_factors[p] c = int((ff_sum / 3) * 200) colors.append((c, 0, 0)) mesh.cellIndividualColors(colors) # show(mesh, __doc__, viewup='z', interactive=False, camera={'pos': (-1, -1, 2)}) # isometric: 2 2 2 plotter = Plotter(size=(1024, 1024), interactive=False) plotter += mesh plotter += __doc__ plotter.show(viewup='z', camera={'pos': (-1, -1, 2)}) screenshot() end = time.time() print(f"Calculation took {end - start} seconds.")
def isosurface(self, threshold=True): """Return a ``Mesh`` isosurface. :param float,list threshold: value or list of values to draw the isosurface(s) """ if not self._data.GetPointData().GetScalars(): self.mapCellsToPoints() scrange = self._data.GetPointData().GetScalars().GetRange() cf = vtk.vtkContourFilter() #vtk.vtkContourGrid() cf.SetInputData(self._data) if utils.isSequence(threshold): cf.SetNumberOfContours(len(threshold)) for i, t in enumerate(threshold): cf.SetValue(i, t) cf.Update() else: if threshold is True: threshold = (2 * scrange[0] + scrange[1]) / 3.0 #print('automatic threshold set to ' + utils.precision(threshold, 3), end=' ') #print('in [' + utils.precision(scrange[0], 3) + ', ' + utils.precision(scrange[1], 3)+']') cf.SetValue(0, threshold) cf.Update() clp = vtk.vtkCleanPolyData() clp.SetInputData(cf.GetOutput()) clp.Update() msh = Mesh(clp.GetOutput(), c=None).phong() msh._mapper.SetLookupTable(utils.ctf2lut(self)) return msh
def procrustesAlignment(sources, rigid=False): """ Return an ``Assembly`` of aligned source meshes with the `Procrustes` algorithm. The output ``Assembly`` is normalized in size. `Procrustes` algorithm takes N set of points and aligns them in a least-squares sense to their mutual mean. The algorithm is iterated until convergence, as the mean must be recomputed after each alignment. The set of average points generated by the algorithm can be accessed with ``algoutput.info['mean']`` as a numpy array. :param bool rigid: if `True` scaling is disabled. |align3| |align3.py|_ """ from vedo.mesh import Mesh group = vtk.vtkMultiBlockDataGroupFilter() for source in sources: if sources[0].N() != source.N(): colors.printc("Error in procrustesAlignment():", c='r') colors.printc(" sources have different nr of points", c='r') raise RuntimeError() group.AddInputData(source.polydata()) procrustes = vtk.vtkProcrustesAlignmentFilter() procrustes.StartFromCentroidOn() procrustes.SetInputConnection(group.GetOutputPort()) if rigid: procrustes.GetLandmarkTransform().SetModeToRigidBody() procrustes.Update() acts = [] for i, s in enumerate(sources): poly = procrustes.GetOutput().GetBlock(i) mesh = Mesh(poly) mesh.SetProperty(s.GetProperty()) if hasattr(s, 'name'): mesh.name = s.name mesh.flagText = s.flagText acts.append(mesh) assem = Assembly(acts) assem.transform = procrustes.GetLandmarkTransform() assem.info['mean'] = vtk_to_numpy(procrustes.GetMeanPoints().GetData()) return assem
def zSlice(self, k): """Extract the slice at index `i` of volume along z-axis.""" vslice = vtk.vtkImageDataGeometryFilter() vslice.SetInputData(self.imagedata()) nx, ny, nz = self.imagedata().GetDimensions() if k > nz - 1: k = nz - 1 vslice.SetExtent(0, nx, 0, ny, k, k) vslice.Update() return Mesh(vslice.GetOutput())
def ySlice(self, j): """Extract the slice at index `j` of volume along y-axis.""" vslice = vtk.vtkImageDataGeometryFilter() vslice.SetInputData(self.imagedata()) nx, ny, nz = self.imagedata().GetDimensions() if j > ny - 1: j = ny - 1 vslice.SetExtent(0, nx, j, j, 0, nz) vslice.Update() return Mesh(vslice.GetOutput())
def xSlice(self, i): """Extract the slice at index `i` of volume along x-axis.""" vslice = vtk.vtkImageDataGeometryFilter() vslice.SetInputData(self.imagedata()) nx, ny, nz = self.imagedata().GetDimensions() if i > nx - 1: i = nx - 1 vslice.SetExtent(i, i, 0, ny, 0, nz) vslice.Update() return Mesh(vslice.GetOutput())
def toPoints(self): """Extract all image voxels as points. This function takes an input ``Volume`` and creates an ``Mesh`` that contains the points and the point attributes. See example script: |vol2points.py|_ """ v2p = vtk.vtkImageToPoints() v2p.SetInputData(self.imagedata()) v2p.Update() mpts = Mesh(v2p.GetOutput()) return mpts
def __init__(self, *inputobj, **options): c = options.pop("c", None) alpha = options.pop("alpha", 1) exterior = options.pop("exterior", False) fast = options.pop("fast", False) computeNormals = options.pop("computeNormals", False) mesh, u = _inputsort(inputobj) if not mesh: return if exterior: import dolfin meshc = dolfin.BoundaryMesh(mesh, 'exterior') else: meshc = mesh if hasattr(mesh, "coordinates"): coords = mesh.coordinates() else: coords = mesh.geometry.points poly = utils.buildPolyData(coords, meshc.cells(), fast=fast, tetras=True) Mesh.__init__( self, poly, c=c, alpha=alpha, computeNormals=computeNormals, ) self.mesh = mesh # holds a dolfin Mesh obj self.u = u # holds a dolfin function_data # holds the actual values of u on the mesh self.u_values = _compute_uvalues(u, mesh)
def slice(self, origin=(0, 0, 0), normal=(1, 0, 0)): """Return a 2D slice of the mesh by a plane passing through origin and assigned normal.""" strn = str(normal) if strn == "x": normal = (1, 0, 0) elif strn == "y": normal = (0, 1, 0) elif strn == "z": normal = (0, 0, 1) elif strn == "-x": normal = (-1, 0, 0) elif strn == "-y": normal = (0, -1, 0) elif strn == "-z": normal = (0, 0, -1) plane = vtk.vtkPlane() plane.SetOrigin(origin) plane.SetNormal(normal) cc = vtk.vtkCutter() cc.SetInputData(self._data) cc.SetCutFunction(plane) cc.Update() msh = Mesh(cc.GetOutput()).flat().lighting('ambient') msh._mapper.SetLookupTable(utils.ctf2lut(self)) return msh
def polygonize(self, threshold=None, flip=False): """ Create a polygonal Mesh from a Picture by filling regions with pixels luminosity above a specified threshold. Parameters ---------- threshold : float, optional The default is None, e.i. 1/3 of the scalar range. Returns ------- Mesh A polygonal mesh. """ from vedo.mesh import Mesh mgf = vtk.vtkImageMagnitude() mgf.SetInputData(self._data) mgf.Update() msq = vtk.vtkMarchingSquares() msq.SetInputData(mgf.GetOutput()) if threshold is None: r0, r1 = self._data.GetScalarRange() threshold = r0 + (r1 - r0) / 3 msq.SetValue(0, threshold) msq.Update() if flip: rs = vtk.vtkReverseSense() rs.SetInputData(msq.GetOutput()) rs.ReverseCellsOn() rs.ReverseNormalsOff() rs.Update() output = rs.GetOutput() else: output = msq.GetOutput() ctr = vtk.vtkContourTriangulator() ctr.SetInputData(output) ctr.Update() return Mesh(ctr.GetOutput(), c='k').bc('t').lighting('off')
def show_vedo_mesh(self): start = time.time() # retrieve them as numpy arrays # printc('points():\n', mesh.points(), c=3) # printc('faces(): \n', mesh.faces(), c=3) # show(mesh, labs, __doc__, viewup='z', axes=1) with Pool(processes=8) as pool: colors = pool.map(self.calc_color, range(self.n_cells)) mesh = Mesh([self.verts, self.faces]) mesh.backColor('blue').lineColor('white').lineWidth(0) mesh.cellIndividualColors(colors) show(mesh, __doc__, viewup='z', interactive=False, camera={'pos': (-1, -1, 2)}) # isometric: 2 2 2 screenshot() end = time.time() print(f"Calculation took {end - start} seconds.")
def draw_scene(args): nfiles = len(args.files) if nfiles == 0: printc("No input files.", c='r') return humansort(args.files) wsize = "auto" if args.full_screen: wsize = "full" if args.ray_cast_mode: if args.background == "": args.background = "bb" if args.background == "": args.background = "white" if args.background_grad: args.background_grad = getColor(args.background_grad) if nfiles == 1 and args.files[0].endswith(".gif"): ###can be improved frames = load(args.files[0]) applications.Browser(frames).show(bg=args.background, bg2=args.background_grad) return ########################################################## if args.scrolling_mode: args.multirenderer_mode = False N = None if args.multirenderer_mode: if nfiles < 201: N = nfiles if nfiles > 200: printc("Warning: option '-n' allows a maximum of 200 files", c=1) printc(" you are trying to load ", nfiles, " files.\n", c=1) N = 200 vp = Plotter(size=wsize, N=N, bg=args.background, bg2=args.background_grad) settings.immediateRendering = False vp.axes = args.axes_type for i in range(N): vp.addHoverLegend(at=i) if args.axes_type == 4 or args.axes_type == 5: vp.axes = 0 else: N = nfiles vp = Plotter(size=wsize, bg=args.background, bg2=args.background_grad) vp.axes = args.axes_type vp.addHoverLegend() vp.sharecam = not args.no_camera_share wire = False if args.wireframe: wire = True ########################################################## # special case of SLC/TIFF volumes with -g option if args.ray_cast_mode: # print('DEBUG special case of SLC/TIFF volumes with -g option') vol = io.load(args.files[0], force=args.reload) if not isinstance(vol, Volume): printc("Type Error: expected a Volume but loaded", type(vol), 'object.', c=1) return sp = vol.spacing() vol.spacing([ sp[0] * args.x_spacing, sp[1] * args.y_spacing, sp[2] * args.z_spacing ]) vol.mode(int(args.mode)).color(args.cmap).jittering(True) # if args.lighting !='default': vol.lighting(args.lighting).jittering(True) vp = applications.RayCastPlotter(vol) vp.show(viewup="z", interactive=True) vp.sliders[0][0].SetEnabled(False) vp.sliders[1][0].SetEnabled(False) vp.sliders[2][0].SetEnabled(False) return ########################################################## # special case of SLC/TIFF/DICOM volumes with --slicer option elif args.slicer: # print('DEBUG special case of SLC/TIFF/DICOM volumes with --slicer option') useSlider3D = False if args.axes_type == 4: args.axes_type = 1 elif args.axes_type == 3: args.axes_type = 1 useSlider3D = True vol = io.load(args.files[0], force=args.reload) sp = vol.spacing() vol.spacing([ sp[0] * args.x_spacing, sp[1] * args.y_spacing, sp[2] * args.z_spacing ]) settings.plotter_instance = None # reset plt = applications.SlicerPlotter( vol, bg='white', bg2='lb', useSlider3D=useSlider3D, cmaps=[args.cmap, "Spectral_r", "hot_r", "bone_r", "gist_ncar_r"], alpha=args.alpha, axes=args.axes_type, clamp=True, size=(1000, 800), ) plt.show() return ######################################################################## elif args.edit: # print('edit mode for meshes and pointclouds') settings.plotter_instance = None # reset settings.useParallelProjection = True try: m = Mesh(args.files[0], alpha=args.alpha / 2, c=args.color) except AttributeError: printc( "In edit mode, input file must be a point cloud or polygonal mesh. Exit.", c='r') return vp = applications.FreeHandCutPlotter(m, splined=True) vp.addHoverLegend() if not args.background_grad: args.background_grad = None vp.start(axes=1, bg=args.background, bg2=args.background_grad) ######################################################################## elif args.slicer2d: # print('DEBUG special case of SLC/TIFF/DICOM volumes with --slicer2d option') vol = io.load(args.files[0], force=args.reload) if not vol: return vol.cmap('bone_r') sp = vol.spacing() vol.spacing([ sp[0] * args.x_spacing, sp[1] * args.y_spacing, sp[2] * args.z_spacing ]) settings.plotter_instance = None # reset plt = applications.Slicer2d(vol) plt.interactor.Start() return ######################################################################## # normal mode for single VOXEL file with Isosurface Slider or LEGO mode elif nfiles == 1 and (".slc" in args.files[0].lower() or ".vti" in args.files[0].lower() or ".tif" in args.files[0].lower() or ".mhd" in args.files[0].lower() or ".nrrd" in args.files[0].lower() or ".dem" in args.files[0].lower()): # print('DEBUG normal mode for single VOXEL file with Isosurface Slider or LEGO mode') vol = io.load(args.files[0], force=args.reload) sp = vol.spacing() vol.spacing([ sp[0] * args.x_spacing, sp[1] * args.y_spacing, sp[2] * args.z_spacing ]) if not args.color: args.color = 'gold' vp = applications.IsosurfaceBrowser(vol, lego=args.lego, c=args.color, cmap=args.cmap, delayed=args.lego) vp.show(zoom=args.zoom, viewup="z") return ######################################################################## # NORMAL mode for single or multiple files, or multiren mode, or numpy scene elif nfiles == 1 or (not args.scrolling_mode): # print('DEBUG NORMAL mode for single or multiple files, or multiren mode') interactor_mode = 0 if args.image: interactor_mode = 'image' ########################################################## # loading a full scene if ".npy" in args.files[0] or ".npz" in args.files[0] and nfiles == 1: objct = io.load(args.files[0], force=args.reload) if "Plotter" in str(type(objct)): # loading a full scene objct.show(mode=interactor_mode) return else: # loading a set of meshes vp.show(objct, mode=interactor_mode) return ######################################################### ds = 0 actors = [] for i in range(N): f = args.files[i] colb = args.color if args.color is None and N > 1: colb = i actor = load(f, force=args.reload) if isinstance(actor, (TetMesh, UGrid)): actor = actor.tomesh().shrink(0.975).c(colb).alpha(args.alpha) if isinstance(actor, Mesh): actors.append(actor) actor.c(colb).alpha(args.alpha).wireframe(wire).lighting( args.lighting) if args.flat: actor.flat() else: actor.phong() if i == 0 and args.texture_file: actor.texture(args.texture_file) if args.point_size > 0: try: actor.GetProperty().SetPointSize(args.point_size) actor.GetProperty().SetRepresentationToPoints() except AttributeError: pass if args.showedges: try: actor.GetProperty().SetEdgeVisibility(1) actor.GetProperty().SetLineWidth(0.1) actor.GetProperty().SetRepresentationToSurface() except AttributeError: pass else: actors.append(actor) if args.multirenderer_mode: try: ds = actor.diagonalSize() * 3 vp.camera.SetClippingRange(0, ds) vp.show(actor, at=i, interactive=False, zoom=args.zoom, mode=interactor_mode) vp.actors = actors except AttributeError: # wildcards in quotes make glob return actor as a list :( printc( "Please do not use wildcards within single or double quotes!", c='r') if args.multirenderer_mode: vp.interactor.Start() else: # scene is empty if all(a is None for a in actors): printc("..could not load file(s). Quit.", c='r') return vp.show(actors, interactive=True, zoom=args.zoom, mode=interactor_mode) return ######################################################################## # scrolling mode -s else: #print("DEBUG simple browser mode -s") if vp.axes == 4: vp.axes = 1 acts = vp.load(args.files, force=args.reload) for a in acts: if hasattr(a, 'c'): #Picture doesnt have it a.c(args.color) a.alpha(args.alpha) applications.Browser(acts) vp.show(interactive=True, zoom=args.zoom)