def plot_ants_plane(off_screen=False, notebook=None): """ Demonstrate how to create a plot class to plot multiple meshes while adding scalars and text. Plot two ants and airplane """ # load and shrink airplane airplane = vtki.PolyData(planefile) airplane.points /= 10 # pts = airplane.points # gets pointer to array # pts /= 10 # shrink # rotate and translate ant so it is on the plane ant = vtki.PolyData(antfile) ant.rotate_x(90) ant.translate([90, 60, 15]) # Make a copy and add another ant ant_copy = ant.copy() ant_copy.translate([30, 0, -10]) # Create plotting object plotter = vtki.Plotter(off_screen=off_screen, notebook=notebook) plotter.add_mesh(ant, 'r') plotter.add_mesh(ant_copy, 'b') # Add airplane mesh and make the color equal to the Y position plane_scalars = airplane.points[:, 1] plotter.add_mesh(airplane, scalars=plane_scalars, stitle='Plane Y\nLocation') plotter.add_text('Ants and Plane Example') plotter.plot()
def test_invalid_file(): with pytest.raises(Exception): mesh = vtki.PolyData('file.bad') with pytest.raises(TypeError): filename = os.path.join(test_path, 'test_polydata.py') mesh = vtki.PolyData(filename)
def test_invalid_init(): with pytest.raises(ValueError): mesh = vtki.PolyData(np.array([1])) with pytest.raises(TypeError): mesh = vtki.PolyData(np.array([1]), 'woa') with pytest.raises(TypeError): mesh = vtki.PolyData('woa', 'woa') with pytest.raises(TypeError): mesh = vtki.PolyData('woa', 'woa', 'woa')
def test_init_from_arrays_triangular(): vertices = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0.5, 0.5, -1]]) # mesh faces faces = np.vstack([[3, 0, 1, 2], [3, 0, 1, 4], [3, 1, 2, 4]]) mesh = vtki.PolyData(vertices, faces) assert mesh.n_points == 5 assert mesh.n_cells == 3 mesh = vtki.PolyData(vertices, faces, deep=True) assert mesh.n_points == 5 assert mesh.n_cells == 3
def test_init_from_arrays(): vertices = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0.5, 0.5, -1]]) # mesh faces faces = np.hstack([[4, 0, 1, 2, 3], [3, 0, 1, 4], [3, 1, 2, 4]]).astype(np.int8) mesh = vtki.PolyData(vertices, faces) assert mesh.n_points == 5 assert mesh.n_cells == 3 mesh = vtki.PolyData(vertices, faces, deep=True) vertices[0] += 1 assert not np.allclose(vertices[0], mesh.points[0])
def add_border(self, color=[1, 1, 1], width=2.0): points = np.array([[1., 1., 0.], [0., 1., 0.], [0., 0., 0.], [1., 0., 0.]]) lines = np.array([[2, 0, 1], [2, 1, 2], [2, 2, 3], [2, 3, 0]]).ravel() poly = vtki.PolyData() poly.points = points poly.lines = lines coordinate = vtk.vtkCoordinate() coordinate.SetCoordinateSystemToNormalizedViewport() mapper = vtk.vtkPolyDataMapper2D() mapper.SetInputData(poly); mapper.SetTransformCoordinate(coordinate); actor = vtk.vtkActor2D() actor.SetMapper(mapper) actor.GetProperty().SetColor(parse_color(color)) actor.GetProperty().SetLineWidth(width) self.add_actor(actor)
def contour(self, surface, scalars, contours, line_width=1.0, opacity=1.0, vmin=None, vmax=None, colormap=None): from matplotlib import cm from matplotlib.colors import ListedColormap if colormap is None: cmap = cm.get_cmap('coolwarm') else: cmap = ListedColormap(colormap / 255.0) vertices = np.array(surface['rr']) triangles = np.array(surface['tris']) n_triangles = len(triangles) triangles = np.c_[np.full(n_triangles, 3), triangles] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=FutureWarning) pd = vtki.PolyData(vertices, triangles) pd.point_arrays['scalars'] = scalars self.plotter.add_mesh(pd.contour(isosurfaces=contours, rng=(vmin, vmax)), show_scalar_bar=False, line_width=line_width, cmap=cmap, opacity=opacity)
def surface(self, surface, color=None, opacity=1.0, vmin=None, vmax=None, colormap=None, scalars=None, backface_culling=False): from matplotlib import cm from matplotlib.colors import ListedColormap if colormap is None: cmap = cm.get_cmap('coolwarm') else: cmap = ListedColormap(colormap / 255.0) vertices = np.array(surface['rr']) triangles = np.array(surface['tris']) n_triangles = len(triangles) triangles = np.c_[np.full(n_triangles, 3), triangles] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=FutureWarning) pd = vtki.PolyData(vertices, triangles) if scalars is not None: pd.point_arrays['scalars'] = scalars self.plotter.add_mesh(mesh=pd, color=color, rng=[vmin, vmax], show_scalar_bar=False, opacity=opacity, cmap=cmap, backface_culling=backface_culling)
def load_texture_to_omf(filename, name, description): """Loads a PNG Image texture to an ``omf.ImageTexture`` object""" # Load a raster import gdal ds = gdal.Open(filename.replace('.png', '.tif')) # Grab the Groung Control Points points = np.array([get_point(gcp) for gcp in ds.GetGCPs()]) if points.size < 1: raise RuntimeError( 'No associated tif file to recover spatial reference.') # Now Grab the three corners of their bounding box #-- This guarantees we grab the right points bounds = vtki.PolyData(points).bounds origin = np.array([bounds[0], bounds[2], bounds[4]]) # BOTTOM LEFT CORNER point_u = np.array([bounds[1], bounds[2], bounds[4]]) # BOTTOM RIGHT CORNER point_v = np.array([bounds[0], bounds[3], bounds[4]]) # TOP LEFT CORNER axis_u = point_u - origin axis_v = point_v - origin the_texture = omf.ImageTexture( origin=origin, axis_u=axis_u, axis_v=axis_v, name=name, description=description, image=filename, ) return the_texture
def read(filename): """This will read any VTK file! It will figure out what reader to use then wrap the VTK object for use in ``vtki`` """ def legacy(filename): reader = vtk.vtkDataSetReader() reader.SetFileName(filename) reader.Update() return reader.GetOutputDataObject(0) ext = os.path.splitext(filename)[1] if ext.lower() in '.vtk': # Use a legacy reader and wrap the result return wrap(legacy(filename)) else: # From the extension, decide which reader to use if ext.lower() in '.vti': # ImageData return vtki.UniformGrid(filename) elif ext.lower() in '.vtr': # RectilinearGrid return vtki.RectilinearGrid(filename) elif ext.lower() in '.vtu': # UnstructuredGrid return vtki.UnstructuredGrid(filename) elif ext.lower() in '.ply': # PolyData return vtki.PolyData(filename) elif ext.lower() in '.vts': # UnstructuredGrid return vtki.StructuredGrid(filename) else: # Attempt to use the legacy reader... try: return wrap(legacy(filename)) except: pass raise IOError("This file was not able to be automatically read by vtki.")
def test_init_as_points(): vertices = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0.5, 0.5, -1]]) mesh = vtki.PolyData(vertices) assert mesh.n_points == vertices.shape[0] assert mesh.n_cells == vertices.shape[0]
def lines_from_points(points): """ Generates line from points. Assumes points are ordered as line segments. Parameters ---------- points : np.ndarray Points representing line segments. For example, two line segments would be represented as: np.array([[0, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 0]]) Returns ------- lines : vtki.PolyData PolyData with lines and cells. Examples -------- This example plots two line segments at right angles to each other line. >>> import vtki >>> import numpy as np >>> points = np.array([[0, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 0]]) >>> lines = vtki.lines_from_points(points) >>> lines.plot() # doctest:+SKIP """ # Assuming ordered points, create array defining line order npoints = points.shape[0] - 1 lines = np.vstack((2 * np.ones(npoints, np.int), np.arange(npoints), np.arange(1, npoints + 1))).T.ravel() return vtki.PolyData(points, lines)
def test_save(extension, binary, tmpdir): filename = str(tmpdir.mkdir("tmpdir").join('tmp.%s' % extension)) sphere.save(filename, binary) mesh = vtki.PolyData(filename) assert mesh.faces.shape == sphere.faces.shape assert mesh.points.shape == sphere.points.shape
def mesh(self, x, y, z, triangles, color, opacity=1.0, shading=False, backface_culling=False, **kwargs): vertices = np.c_[x, y, z] n_triangles = len(triangles) triangles = np.c_[np.full(n_triangles, 3), triangles] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=FutureWarning) pd = vtki.PolyData(vertices, triangles) self.plotter.add_mesh(mesh=pd, color=color, opacity=opacity, backface_culling=backface_culling)
def vector_poly_data(orig, vec): """ Creates a vtkPolyData object composed of vectors """ # shape, dimention checking if not isinstance(orig, np.ndarray): orig = np.asarray(orig) if not isinstance(vec, np.ndarray): vec = np.asarray(vec) if orig.ndim != 2: orig = orig.reshape((-1, 3)) elif orig.shape[1] != 3: raise Exception('orig array must be 3D') if vec.ndim != 2: vec = vec.reshape((-1, 3)) elif vec.shape[1] != 3: raise Exception('vec array must be 3D') # Create vtk points and cells objects vpts = vtk.vtkPoints() vpts.SetData(numpy_to_vtk(np.ascontiguousarray(orig), deep=True)) npts = orig.shape[0] cells = np.hstack((np.ones((npts, 1), 'int'), np.arange(npts).reshape( (-1, 1)))) if cells.dtype != ctypes.c_int64 or cells.flags.c_contiguous: cells = np.ascontiguousarray(cells, ctypes.c_int64) cells = np.reshape(cells, (2 * npts)) vcells = vtk.vtkCellArray() vcells.SetCells(npts, numpy_to_vtkIdTypeArray(cells, deep=True)) # Create vtkPolyData object pdata = vtk.vtkPolyData() pdata.SetPoints(vpts) pdata.SetVerts(vcells) # Add vectors to polydata name = 'vectors' vtkfloat = numpy_to_vtk(np.ascontiguousarray(vec), deep=True) vtkfloat.SetName(name) pdata.GetPointData().AddArray(vtkfloat) pdata.GetPointData().SetActiveVectors(name) # Add magnitude of vectors to polydata name = 'mag' scalars = (vec * vec).sum(1)**0.5 vtkfloat = numpy_to_vtk(np.ascontiguousarray(scalars), deep=True) vtkfloat.SetName(name) pdata.GetPointData().AddArray(vtkfloat) pdata.GetPointData().SetActiveScalars(name) return vtki.PolyData(pdata)
def test_export_verts(tmpdir): filename = str(tmpdir.mkdir("tmpdir").join('scene')) data = vtki.PolyData(np.random.rand(100, 3)) # Create the scene plotter = vtki.Plotter(off_screen=OFF_SCREEN) plotter.add_mesh(data) plotter.export_vtkjs(filename) cpos_out = plotter.show() # Export must be called before showing! plotter.close() # Now make sure the file is there assert os.path.isfile('{}.vtkjs'.format(filename))
def with_vtk(plot=True): """ Tests VTK interface and mesh repair of Stanford Bunny Mesh """ mesh = vtki.PolyData(bunny_scan) meshfix = pymeshfix.MeshFix(mesh) if plot: print('Plotting input mesh') meshfix.Plot() meshfix.Repair() if plot: print('Plotting repaired mesh') meshfix.Plot() return meshfix.mesh
def test_contour(): dataset = examples.load_uniform() iso = dataset.contour() assert iso is not None iso = dataset.contour(isosurfaces=[100, 300, 500]) assert iso is not None with pytest.raises(AssertionError): result = dataset.contour(scalars='Spatial Cell Data') with pytest.raises(RuntimeError): result = dataset.contour(isosurfaces=vtki.PolyData()) dataset = examples.load_airplane() with pytest.raises(AssertionError): result = dataset.contour()
def sphere(self, center, color, scale, opacity=1.0, resolution=8, backface_culling=False): sphere = vtk.vtkSphereSource() sphere.SetThetaResolution(resolution) sphere.SetPhiResolution(resolution) sphere.Update() geom = sphere.GetOutput() with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=FutureWarning) pd = vtki.PolyData(center) self.plotter.add_mesh(pd.glyph(orient=False, scale=False, factor=scale, geom=geom), color=color, opacity=opacity, backface_culling=backface_culling)
def test_load_and_save_file(tmpdir): meshfix = _meshfix.PyTMesh() meshfix.load_file(examples.bunny_scan) with pytest.raises(Exception): meshfix.load_file(examples.bunny_scan) v, f = meshfix.return_arrays() assert f.shape[0] == bunny.n_faces # test saving filename = str(tmpdir.mkdir("tmpdir").join('tmp.ply')) meshfix.save_file(filename) new_bunny = vtki.PolyData(filename) assert new_bunny.points.shape == v.shape
def test_repair_vtk(): meshin = vtki.PolyData(bunny_scan) meshfix = pymeshfix.MeshFix(meshin) meshfix.repair() # check arrays and output mesh assert np.any(meshfix.v) assert np.any(meshfix.f) meshout = meshfix.mesh assert meshfix.mesh.n_points # test for any holes pdata = meshout.extract_edges(non_manifold_edges=False, feature_edges=False, manifold_edges=False) assert pdata.n_points == 0
def read(filename, attrs=None): """This will read any VTK file! It will figure out what reader to use then wrap the VTK object for use in ``vtki``. Parameters ---------- attrs : dict, optional A dictionary of attributes to call on the reader. Keys of dictionary are the attribute/method names and values are the arguments passed to those calls. If you do not have any attributes to call, pass ``None`` as the value. """ filename = os.path.abspath(os.path.expanduser(filename)) ext = get_ext(filename) # From the extension, decide which reader to use if attrs is not None: reader = get_reader(filename) return standard_reader_routine(reader, filename, attrs=attrs) elif ext in '.vti': # ImageData return vtki.UniformGrid(filename) elif ext in '.vtr': # RectilinearGrid return vtki.RectilinearGrid(filename) elif ext in '.vtu': # UnstructuredGrid return vtki.UnstructuredGrid(filename) elif ext in ['.ply', '.obj', '.stl']: # PolyData return vtki.PolyData(filename) elif ext in '.vts': # StructuredGrid return vtki.StructuredGrid(filename) elif ext in ['.vtm', '.vtmb']: return vtki.MultiBlock(filename) elif ext in ['.e', '.exo']: return read_exodus(filename) elif ext in ['.vtk']: # Attempt to use the legacy reader... return read_legacy(filename) else: # Attempt find a reader in the readers mapping try: reader = get_reader(filename) return standard_reader_routine(reader, filename) except KeyError: pass raise IOError("This file was not able to be automatically read by vtki.")
def load_attach_texture(dataset, filename, name): """Loads a texture and attaches it to the dataset inplace. """ import gdal # Load a raster ds = gdal.Open(filename) texture = vtki.load_texture(filename) # Grab the Groung Control Points points = np.array([get_point(gcp) for gcp in ds.GetGCPs()]) # Now Grab the three corners of their bounding box #-- This guarantees we grab the right points bounds = vtki.PolyData(points).bounds origin = [bounds[0], bounds[2], bounds[4]] # BOTTOM LEFT CORNER point_u = [bounds[1], bounds[2], bounds[4]] # BOTTOM RIGHT CORNER point_v = [bounds[0], bounds[3], bounds[4]] # TOP LEFT CORNER dataset.texture_map_to_plane(origin, point_u, point_v, inplace=True, name=name) dataset.textures[name] = texture return None # No return because it updates input object inplace
def test_texture(): """Test adding texture coordinates""" # create a rectangle vertices vertices = np.array([ [0, 0, 0], [1, 0, 0], [1, 0.5, 0], [0, 0.5, 0], ]) # mesh faces faces = np.hstack([[3, 0, 1, 2], [3, 0, 3, 2]]).astype(np.int8) # Create simple texture coordinates t_coords = np.array([[0, 0], [1, 0], [1, 1], [0, 1]]) # Create the poly data mesh = vtki.PolyData(vertices, faces) # Attempt setting the texture coordinates mesh.t_coords = t_coords # now grab the texture coordinates foo = mesh.t_coords assert np.allclose(foo, t_coords)
def img2D(points): #三角形片面重建模型 sg.Popup('渲染正在进行中,请您耐心等候一段时间~~~', button_color=('white', 'blue'), background_color='white', keep_on_top=True) gif(gifpath2) cloud = vtki.PolyData(points) # bcloud = vtki.PolyData(blist) # roicloud = vtki.PolyData(roilist) surf = cloud.delaunay_2d(tol=1e-08, alpha=1, offset=100.0, bound=False, inplace=False) # surf1 = bcloud.delaunay_2d(tol = 1e-08,alpha = 0.3,offset = 100.0,bound = False,inplace =False ) # surf2 = roicloud.delaunay_2d(tol = 1e-08,alpha = 0.1,offset = 100.0,bound = False,inplace =False ) print(type(surf)) plotter = vtki.BackgroundPlotter() plotter.add_mesh(surf) # plotter.add_mesh(surf1) # plotter.add_mesh(surf2) plotter.show()
import vtki import numpy as np ################################################################################ # First, create some points for the surface. # Define a simple Gaussian surface xx, yy = np.meshgrid(np.linspace(-200,200,20), np.linspace(-200,200,20)) A, b = 100, 100 zz = A*np.exp(-0.5*((xx/b)**2. + (yy/b)**2.)) # Get the points as a 2D NumPy array (N by 3) points = np.c_[xx.reshape(-1), yy.reshape(-1), zz.reshape(-1)] print(points[0:5, :]) ################################################################################ # Now use those points to create a point cloud ``vtki`` data object. This will # be encompassed in a :class:`vtki.PolyData` object. # simply pass the numpy points to the PolyData constructor cloud = vtki.PolyData(points) vtki.set_plot_theme('doc') cloud.plot(point_size=15) ################################################################################ # Now that we have a ``vtki`` data structure of the points, we can perform a # triangulation to turn those boring discrete points into a connected surface. surf = cloud.delaunay_2d() surf.plot(show_edges=True)
def test_init(): mesh = vtki.PolyData() assert not mesh.n_points assert not mesh.n_cells
def test_init_from_pdata(): mesh = vtki.PolyData(sphere, deep=True) assert mesh.n_points assert mesh.n_cells mesh.points[0] += 1 assert not np.allclose(sphere.points[0], mesh.points[0])
def mesh(self): """ Return the surface mesh """ triangles = np.empty((self.f.shape[0], 4)) triangles[:, -3:] = self.f triangles[:, 0] = 3 return vtki.PolyData(self.v, triangles, deep=False)
def triangulation(pts, downsampling=(1, 1, 1), n_closings=0, single_cc=False, decimate_mesh=0, gradient_direction='descent', force_single_cc=False): """ Calculates triangulation of point cloud or dense volume using marching cubes by building dense matrix (in case of a point cloud) and applying marching cubes. Parameters ---------- pts : np.array [N, 3] or [N, M, O] (dtype: uint8, bool) downsampling : Tuple[int] Magnitude of downsampling, e.g. 1, 2, (..) which is applied to pts for each axis n_closings : int Number of closings applied before mesh generation single_cc : bool Returns mesh of biggest connected component only decimate_mesh : float Percentage of mesh size reduction, i.e. 0.1 will leave 90% of the vertices gradient_direction : str defines orientation of triangle indices. '?' is needed for KNOSSOS compatibility. TODO: check compatible index orientation, switched to `descent`, 23April2019 force_single_cc : bool If True, performans dilations until only one foreground CC is present and then erodes with the same number to maintain size. Returns ------- array, array, array indices [M, 3], vertices [N, 3], normals [N, 3] """ if boundaryDistanceTransform is None: raise ImportError( '"boundaryDistanceTransform" could not be imported from VIGRA. ' 'Please install vigra, see SyConn documentation.') assert type( downsampling) == tuple, "Downsampling has to be of type 'tuple'" assert (pts.ndim == 2 and pts.shape[1] == 3) or pts.ndim == 3, \ "Point cloud used for mesh generation has wrong shape." if pts.ndim == 2: if np.max(pts) <= 1: msg = "Currently this function only supports point " \ "clouds with coordinates >> 1." log_proc.error(msg) raise ValueError(msg) offset = np.min(pts, axis=0) pts -= offset pts = (pts / downsampling).astype(np.uint32) # add zero boundary around object margin = n_closings + 5 pts += margin bb = np.max(pts, axis=0) + margin volume = np.zeros(bb, dtype=np.float32) volume[pts[:, 0], pts[:, 1], pts[:, 2]] = 1 else: volume = pts if np.any(np.array(downsampling) != 1): ndimage.zoom(volume, downsampling, order=0) offset = np.array([0, 0, 0]) if n_closings > 0: volume = binary_closing(volume, iterations=n_closings).astype(np.float32) if force_single_cc: n_dilations = 0 while True: labeled, nb_cc = ndimage.label(volume) # log_proc.debug('Forcing single CC, additional dilations {}, num' # 'ber connected components: {}' # ''.format(n_dilations, nb_cc)) if nb_cc == 1: # does not count background break # pad volume to maintain margin at boundary and correct offset volume = np.pad(volume, [(1, 1), (1, 1), (1, 1)], mode='constant', constant_values=0) offset -= 1 volume = binary_dilation(volume, iterations=1).astype(np.float32) n_dilations += 1 else: volume = volume.astype(np.float32) if single_cc: labeled, nb_cc = ndimage.label(volume) cnt = Counter(labeled[labeled != 0]) l, occ = cnt.most_common(1)[0] volume = np.array(labeled == l, dtype=np.float32) # InterpixelBoundary, OuterBoundary, InnerBoundary dt = boundaryDistanceTransform(volume, boundary="InterpixelBoundary") dt[volume == 1] *= -1 volume = gaussianSmoothing(dt, 1) if np.sum(volume < 0) == 0 or np.sum(volume > 0) == 0: # less smoothing volume = gaussianSmoothing(dt, 0.5) try: verts, ind, norm, _ = measure.marching_cubes_lewiner( volume, 0, gradient_direction=gradient_direction) except Exception as e: raise ValueError(e) if pts.ndim == 2: # account for [5, 5, 5] offset verts -= margin verts = np.array(verts) * downsampling + offset if decimate_mesh > 0: if not __vtk_avail__: msg = "vtki not installed. Please install vtki.'" \ "pip install vtki'." log_proc.error(msg) raise ImportError(msg) # log_proc.warning("'triangulation': Currently mesh-sparsification" # " may not preserve volume.") # add number of vertices in front of every face (required by vtki) ind = np.concatenate( [np.ones((len(ind), 1)).astype(np.int64) * 3, ind], axis=1) mesh = vtki.PolyData(verts, ind.flatten()) mesh.decimate(decimate_mesh, volume_preservation=True) # remove face sizes again ind = mesh.faces.reshape((-1, 4))[:, 1:] verts = mesh.points mo = MeshObject("", ind, verts) # compute normals norm = mo.normals.reshape((-1, 3)) return np.array(ind, dtype=np.int), verts, norm