Example #1
0
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
Example #2
0
    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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
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])
Example #6
0
    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)
Example #7
0
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)
Example #8
0
# 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)
Example #9
0
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)