def test_calculate_normals(): import visvis as vv pp = vv.Pointset(3) pp.append((1, 2, 3)) pp.append((3, 1, 5)) pp.append((4, 4, 7)) pp.append((6, 7, 9)) m = vv.BaseMesh(pp, faces=[0, 1, 2, 0, 2, 3]) assert m._normals is None vv.processing.calculateNormals(m) normals1 = m._normals assert m._normals is not None assert m._normals.shape == (4, 3) vv.processing.calculateFlatNormals(m) normals2 = m._normals assert m._normals is not None assert m._normals.shape == (6, 3) assert normals1 is not normals2 assert normals1.shape != normals2.shape # because faces have been unwound
def read(cls, fname, check=False): """ read(fname, check=False) This classmethod is the entry point for reading STL files. Parameters ---------- fname : string The name of the file to read. check : bool If check is True and the file is in ascii, some checks to the integrity of the file are done (which is a bit slower). """ # Open file f = open(fname, 'rb') try: # Read whitespace while not f.read(1).strip(): pass # Go one back f.seek(-1, 1) # Determine ascii or binary data = f.read(5).decode('ascii', 'ignore') if data == 'solid': # Pop rest of line (i.e. the name) and get reader object f.readline() reader = StlAsciiReader(f) else: # Pop rest if header (header has 80 chars) and get reader object f.read(75) reader = StlBinReader(f) # Read all vertices = vv.Pointset(3) while True: reader.readFace(vertices, check) except EOFError: pass finally: f.close() # Done return vv.BaseMesh(vertices)
def test_combine_meshes(): import visvis as vv pp = vv.Pointset(3) pp.append((1, 2, 3)) pp.append((3, 1, 5)) pp.append((4, 4, 7)) pp.append((6, 7, 9)) m = vv.BaseMesh(pp, faces=[0, 1, 2, 0, 2, 3]) assert m._vertices.shape == (4, 3) m2 = vv.processing.combineMeshes([m, m, m]) assert m2 is not m assert m2._vertices.shape == (12, 3)
def ssdfRead(fname, check=False): """ Simple function that reads a mesh in the ssdf file format. """ # Read structure s = vv.ssdf.load(fname) # Check if 'vertices' not in s: raise RuntimeError('This ssdf file does not contain mesh data.') if 'normals' not in s: s.normals = None if 'values' not in s: s.values = None if 'faces' not in s: s.faces = None if 'verticesPerFace' not in s: s.verticesPerFace = 3 # Return mesh object return vv.BaseMesh(s.vertices, s.faces, s.normals, s.values, s.verticesPerFace)
def test_unwindfaces(): import visvis as vv pp = vv.Pointset(3) pp.append((1, 2, 3)) pp.append((3, 1, 5)) pp.append((4, 4, 7)) pp.append((6, 7, 9)) m = vv.BaseMesh(pp, faces=[0, 1, 2, 0, 2, 3]) assert m._faces is not None assert m._vertices.shape == (4, 3) vv.processing.unwindFaces(m) assert m._faces is None assert m._vertices.shape == (6, 3) assert tuple(m._vertices[0]) == tuple(pp[0]) assert tuple(m._vertices[1]) == tuple(pp[1]) assert tuple(m._vertices[2]) == tuple(pp[2]) assert tuple(m._vertices[3]) == tuple(pp[0]) assert tuple(m._vertices[4]) == tuple(pp[2]) assert tuple(m._vertices[5]) == tuple(pp[3])
def finish(self): """ Converts gathere lists to numpy arrays and creates BaseMesh instance. """ if True: self._vertices = np.array(self._vertices, 'float32') if self._normals: self._normals = np.array(self._normals, 'float32') else: self._normals = None if self._texcords: self._texcords = np.array(self._texcords, 'float32') else: self._texcords = None if self._faces: self._faces = np.array(self._faces, 'uint32') else: # Use vertices only self._vertices = np.array(self._v, 'float32') self._faces = None return vv.BaseMesh(self._vertices, self._faces, self._normals, self._texcords)
def isosurface(im, isovalue=None, step=1, useClassic=False, useValues=False): """ isosurface(vol, isovalue=None, step=1, useClassic=False, useValues=False) Uses scikit-image to calculate the isosurface for the given 3D image. Returns a vv.BaseMesh object. Parameters ---------- vol : 3D numpy array The volume for which to calculate the isosurface. isovalue : float The value at which the surface should be created. If not given or None, the average of the min and max of vol is used. step : int The stepsize for stepping through the volume. Larger steps yield faster but coarser results. The result shall always be topologically correct though. useClassic : bool If True, uses the classic marching cubes by Lorensen (1987) is used. This algorithm has many ambiguities and is not guaranteed to produce a topologically correct result. useValues : bool If True, the returned BaseMesh object will also have a value for each vertex, which is related to the maximum value in a local region near the isosurface. """ # Check image if not isinstance(im, np.ndarray) or (im.ndim != 3): raise ValueError('vol should be a 3D numpy array.') # Get isovalue if isovalue is None: isovalue = 0.5 * (im.min() + im.max()) isovalue = float( isovalue) # Will raise error if not float-like value given # Check steps step = int(step) if step < 1: raise ValueError('step must be at least one.') # Deal with Aarray if hasattr(im, 'sampling'): sampling = im.sampling[0], im.sampling[1], im.sampling[2] else: sampling = (1, 1, 1) # Call into skimage algorithm xx = marching_cubes_lewiner(im, isovalue, spacing=sampling, step_size=step, use_classic=useClassic) vertices, faces, normals, values = xx # Transform the data to how Visvis likes it vertices = np.fliplr(vertices) # Check if not len(vertices): raise RuntimeError('No surface found at the given iso value.') # Done if useValues: return vv.BaseMesh(vertices, faces, normals, values) else: return vv.BaseMesh(vertices, faces, normals)
# Load vessel centerline (excel terarecon) (is very fast) centerline = PointSet( np.column_stack( load_excel_centerline(basedirCenterline, vol1, ptcode, ctcode1, filename=None))) ## Setup visualization # Show ctvolume, vessel mesh, ring model - this uses figure 1 and clears it axes1, cbars = showModelsStatic( ptcode, ctcode1, [vol1], [s1], [modelmesh1], [vv.BaseMesh(*vesselMesh.get_vertices_and_faces())], showVol, clim, isoTh, clim2, clim2D, drawRingMesh, ringMeshDisplacement, drawModelLines, showvol2D, showAxis, drawVessel, vesselType=1, climEditor=True, removeStent=removeStent, meshColor=meshColor)
def isosurface(im, isovalue=None, step=1, useClassic=False, useValues=False): """ isosurface(vol, isovalue=None, step=1, useClassic=False, useValues=False) Calculate the isosurface for the given 3D image. Returns a vv.BaseMesh object. Parameters ---------- vol : 3D numpy array The volume for which to calculate the isosurface. isovalue : float The value at which the surface should be created. If not given or None, the average of the min and max of vol is used. step : int The stepsize for stepping through the volume. Larger steps yield faster but coarser results. The result shall always be topologically correct though. useClassic : bool If True, uses the classic marching cubes by Lorensen (1987) is used. This algorithm has many ambiguities and is not guaranteed to produce a topologically correct result. useValues : bool If True, the returned BaseMesh object will also have a value for each vertex, which is related to the maximum value in a local region near the isosurface. Notes about the algorithm ------------------------- This is an implementation of: Efficient implementation of Marching Cubes' cases with topological guarantees. Thomas Lewiner, Helio Lopes, Antonio Wilson Vieira and Geovan Tavares. Journal of Graphics Tools 8(2): pp. 1-15 (december 2003) The algorithm is an improved version of Chernyaev's Marching Cubes 33 algorithm, originally written in C++. It is an efficient algorithm that relies on heavy use of lookup tables to handle the many different cases. This keeps the algorithm relatively easy. The current algorithm is a port of Lewiner's algorithm and written in Cython. Although a lot of care was taken to reduce the risk of introducing errors during the porting process, this code should be taken as is and in no event shall any of its authors be liable for any damage (see also the visvis license). """ # Check image if not isinstance(im, np.ndarray) or (im.ndim != 3): raise ValueError('vol should be a 3D numpy array.') # Make sure its 32 bit float if im.dtype != np.float32: im = im.astype('float32') # Get isovalue if isovalue is None: isovalue = 0.5 * (im.min() + im.max()) isovalue = float(isovalue) # Will raise error if not float-like value given # Check steps step = int(step) if step < 1: raise ValueError('step must be at least one.') # Remaining args useClassic = bool(useClassic) useValues = bool(useValues) # Get LutProvider class (reuse if possible) L = _getMCLuts() # Apply algorithm vertices, faces , normals, values = marchingcubes_.marching_cubes(im, isovalue, L, step, useClassic) # Check if not len(vertices): raise RuntimeError('No surface found at the given iso value.') # Done if useValues: return vv.BaseMesh(vertices, faces, normals, values) else: return vv.BaseMesh(vertices, faces, normals)