Exemplo n.º 1
0
def test_MGHImage():

    testfile = op.join(datadir, 'example.mgz')

    # Load from a file
    img = fslmgh.MGHImage(testfile)
    nbimg = nib.load(testfile)
    v2s = nbimg.header.get_vox2ras_tkr()
    w2s = affine.concat(v2s, affine.invert(nbimg.affine))

    assert np.all(np.isclose(img[:], np.asanyarray(nbimg.dataobj)))
    assert np.all(np.isclose(img.voxToWorldMat, nbimg.affine))
    assert np.all(np.isclose(img.voxToSurfMat, v2s))
    assert np.all(np.isclose(img.surfToVoxMat, affine.invert(v2s)))
    assert np.all(np.isclose(img.worldToSurfMat, w2s))
    assert np.all(np.isclose(img.surfToWorldMat, affine.invert(w2s)))

    assert img.name == op.basename(testfile)
    assert img.dataSource == testfile
    assert img.mghImageFile == testfile

    # Load from an in-memory nibabel object
    img = fslmgh.MGHImage(nbimg)
    assert np.all(np.isclose(img[:], np.asanyarray(nbimg.dataobj)))
    assert np.all(np.isclose(img.voxToWorldMat, nbimg.affine))
    assert img.dataSource is None
    assert img.mghImageFile is None
Exemplo n.º 2
0
    def __init__(self, image, **kwargs):
        """Create a ``MGHImage``.

        :arg image: Name of MGH file, or a
                    ``nibabel.freesurfer.mghformat.MGHImage`` instance.

        All other arguments are passed through to :meth:`Image.__init__`
        """

        if isinstance(image, six.string_types):
            filename = op.abspath(image)
            name = op.basename(filename)
            image = nib.load(image)
        else:
            name = 'MGH image'
            filename = None

        data = np.asanyarray(image.dataobj)
        xform = image.affine
        pixdim = image.header.get_zooms()
        vox2surf = image.header.get_vox2ras_tkr()

        # the image may have an affine which
        # transforms the data into some space
        # with a scaling that is different to
        # the pixdims. So we create a header
        # object with both the affine and the
        # pixdims, so they are both preserved.
        #
        # Note that we have to set the zooms
        # after the s/qform, otherwise nibabel
        # will clobber them with zooms gleaned
        # fron the affine.
        header = nib.nifti1.Nifti1Header()
        header.set_data_shape(data.shape)
        header.set_sform(xform)
        header.set_qform(xform)
        header.set_zooms(pixdim)

        fslimage.Image.__init__(self,
                                data,
                                header=header,
                                name=name,
                                dataSource=filename,
                                **kwargs)

        if filename is not None:
            self.setMeta('mghImageFile', filename)

        self.__voxToSurfMat = vox2surf
        self.__surfToVoxMat = affine.invert(vox2surf)
        self.__surfToWorldMat = affine.concat(xform, self.__surfToVoxMat)
        self.__worldToSurfMat = affine.invert(self.__surfToWorldMat)
Exemplo n.º 3
0
def test_nonlinear_altref(seed):
    with tempdir.tempdir():

        src2ref = affine.scaleOffsetXform([1, 1, 1], [5, 5, 5])
        ref2src = affine.invert(src2ref)
        altv2w = affine.scaleOffsetXform([1, 1, 1], [10, 10, 10])

        srcdata = np.random.randint(1, 65536, (10, 10, 10))
        src = fslimage.Image(srcdata, xform=np.eye(4))
        ref = fslimage.Image(src.data, xform=src2ref)
        altref = fslimage.Image(src.data, xform=altv2w)

        field = _affine_field(src, ref, ref2src, 'world', 'world')

        src.save('src')
        ref.save('ref')
        altref.save('altref')

        x5.writeNonLinearX5('xform.x5', field)

        fsl_apply_x5.main('src xform.x5 out -r altref'.split())

        result = fslimage.Image('out')
        expect = np.zeros(srcdata.shape)
        expect[:5, :5, :5] = srcdata[5:, 5:, 5:]

        assert result.sameSpace(altref)
        assert np.all(result.data == expect)
Exemplo n.º 4
0
    def getTransform(self, from_, to):
        """Return a matrix which may be used to transform coordinates from
        ``from_`` to ``to``.

        The following values are accepted for the ``from_`` and ``to``
        parameters:

          - ``'world'``:  World coordinate system
          - ``'display'`` Display coordinate system
          - ``'mesh'``    The coordinate system of this mesh.
        """

        nfrom_ = self.normaliseSpace(from_)
        nto    = self.normaliseSpace(to)
        ref    = self.refImage

        if ref is None:
            return np.eye(4)

        opts  = self.displayCtx.getOpts(ref)
        xform = opts.getTransform(nfrom_, nto)

        if from_ == 'mesh' and self.coordSpace == 'torig':
            surfToVox = affine.invert(fslmgh.voxToSurfMat(ref))
            xform     = affine.concat(xform,
                                      ref.getAffine('voxel', 'world'),
                                      surfToVox)
        if to == 'mesh' and self.coordSpace == 'torig':
            voxToSurf = fslmgh.voxToSurfMat(ref)
            xform     = affine.concat(voxToSurf,
                                      ref.getAffine('world', 'voxel'),
                                      xform)

        return xform
Exemplo n.º 5
0
def test_applyDeformation_altref():
    src2ref = affine.compose(
        np.random.randint(2, 5, 3),
        np.random.randint(1, 10, 3),
        np.random.random(3))
    ref2src = affine.invert(src2ref)

    srcdata = np.random.randint(1, 65536, (10, 10, 10))
    refdata = np.random.randint(1, 65536, (10, 10, 10))

    src   = fslimage.Image(srcdata)
    ref   = fslimage.Image(refdata, xform=src2ref)
    field = _affine_field(src, ref, ref2src, 'world', 'world')

    altrefxform = affine.concat(
        src2ref,
        affine.scaleOffsetXform([1, 1, 1], [5, 0, 0]))

    altref = fslimage.Image(refdata, xform=altrefxform)

    expect, xf = resample.resampleToReference(
        src, altref, matrix=src2ref, order=1, mode='constant', cval=0)
    result = nonlinear.applyDeformation(
        src, field, ref=altref, order=1, mode='constant', cval=0)

    # boundary voxels can get truncated
    # (4 is the altref-ref overlap boundary)
    expect[4, :, :] = 0
    result[4, :, :] = 0
    expect = expect[1:-1, 1:-1, 1:-1]
    result = result[1:-1, 1:-1, 1:-1]

    assert np.all(np.isclose(expect, result))
Exemplo n.º 6
0
def test_applyDeformation_worldAligned():
    refv2w   = affine.scaleOffsetXform([1, 1, 1], [10,   10,   10])
    fieldv2w = affine.scaleOffsetXform([2, 2, 2], [10.5, 10.5, 10.5])
    src2ref  = refv2w
    ref2src  = affine.invert(src2ref)

    srcdata = np.random.randint(1, 65536, (10, 10, 10))

    src   = fslimage.Image(srcdata)
    ref   = fslimage.Image(srcdata, xform=src2ref)
    field = _affine_field(src, ref, ref2src, 'world', 'world',
                          shape=(5, 5, 5), fv2w=fieldv2w)

    field = nonlinear.DeformationField(
        nonlinear.convertDeformationType(field, 'absolute'),
        header=field.header,
        src=src,
        ref=ref,
        srcSpace='world',
        refSpace='world',
        defType='absolute')

    expect, xf = resample.resampleToReference(
        src, ref, matrix=src2ref, order=1, mode='constant', cval=0)
    result = nonlinear.applyDeformation(
        src, field, order=1, mode='constant', cval=0)

    expect = expect[1:-1, 1:-1, 1:-1]
    result = result[1:-1, 1:-1, 1:-1]

    assert np.all(np.isclose(expect, result))
Exemplo n.º 7
0
    def updateVertices(self, *a):
        """Called by :meth:`__init__`, and when certain display properties
        change. (Re-)generates the mesh vertices, indices and normals (if
        being displayed in 3D). They are stored as attributes called
        ``vertices``, ``indices``, and ``normals`` respectively.
        """

        overlay  = self.overlay
        vertices = overlay.vertices
        indices  = overlay.indices
        normals  = self.overlay.vnormals
        xform    = self.opts.getTransform('mesh', 'display')

        if not np.all(np.isclose(xform, np.eye(4))):
            vertices = affine.transform(vertices, xform)

            if self.threedee:
                nmat    = affine.invert(xform).T
                normals = affine.transform(normals, nmat, vector=True)

        self.vertices = np.asarray(vertices,          dtype=np.float32)
        self.indices  = np.asarray(indices.flatten(), dtype=np.uint32)

        self.vertices = dutils.makeWriteable(self.vertices)
        self.indices  = dutils.makeWriteable(self.indices)

        if self.threedee:
            self.normals = np.array(normals, dtype=np.float32)
Exemplo n.º 8
0
def test_nonlinear(seed):
    with tempdir.tempdir():

        src2ref = _random_affine()
        ref2src = affine.invert(src2ref)
        src = _random_image(np.eye(4))
        ref = _random_image(src2ref)
        field = _affine_field(src, ref, ref2src, 'world', 'world')

        x5.writeNonLinearX5('xform.x5', field)

        src.save('src')

        fsl_apply_x5.main('src xform.x5 out'.split())

        result = fslimage.Image('out')
        expect = resample.resampleToReference(src,
                                              ref,
                                              matrix=src2ref,
                                              smooth=False)[0]

        assert result.sameSpace(ref)

        # We might get truncation on the edges
        result = result.data[1:-1, 1:-1, 1:-1]
        expect = expect[1:-1, 1:-1, 1:-1]

        tol = dict(atol=1e-3, rtol=1e-3)
        assert np.all(np.isclose(result, expect, **tol))
Exemplo n.º 9
0
def resampleToReference(image, reference, matrix=None, **kwargs):
    """Resample ``image`` into the space of the ``reference``.

    This is a wrapper around :func:`resample` - refer to its documenttion
    for details on the other arguments and the return values.

    When resampling to a reference image, resampling will only be applied
    along the spatial (first three) dimensions.

    :arg image:     :class:`.Image` to resample
    :arg reference: :class:`.Nifti` defining the space to resample ``image``
                    into
    :arg matrix:    Optional world-to-world affine alignment matrix
    """

    oldShape = list(image.shape)
    newShape = list(reference.shape[:3])

    if matrix is None:
        matrix = np.eye(4)

    # If the input image is >3D, pad the
    # new shape so that we only resample
    # along the first 3 dimensions.
    if len(newShape) < len(oldShape):
        newShape = newShape + oldShape[len(newShape):]

    # Align the two images together
    # via their vox-to-world affines,
    # and the world-to-world affine
    # if provided
    matrix = affine.concat(image.worldToVoxMat,
                           affine.invert(matrix),
                           reference.voxToWorldMat)

    # If the input image is >3D, we
    # have to adjust the resampling
    # matrix to take into account the
    # additional dimensions (see scipy.
    # ndimage.affine_transform)
    if len(newShape) > 3:
        rotmat  = matrix[:3, :3]
        offsets = matrix[:3,  3]
        matrix  = np.eye(len(newShape) + 1)
        matrix[:3, :3] = rotmat
        matrix[:3, -1] = offsets

    kwargs['mode']     = kwargs.get('mode', 'constant')
    kwargs['newShape'] = newShape
    kwargs['matrix']   = matrix

    data = resample(image, **kwargs)[0]

    # The image is now in the same space
    # as the reference, so it inherits
    # ref's voxel-to-world affine
    return data, reference.voxToWorldMat
Exemplo n.º 10
0
def draw(self,
         glType,
         vertices,
         indices=None,
         normals=None,
         vdata=None,
         mdata=None):
    """Called for 3D meshes, and :attr:`.MeshOpts.vertexData` is not
    ``None``. Loads and runs the shader program.

    :arg glType:   The OpenGL primitive type.

    :arg vertices: ``(n, 3)`` array containing the line vertices to draw.

    :arg indices:  Indices into the ``vertices`` array. If not provided,
                   ``glDrawArrays`` is used.

    :arg normals:  Vertex normals.

    :arg vdata:    ``(n, )`` array containing data for each vertex.

    :arg mdata:    ``(n, )`` array containing alpha modulation data for
                   each vertex.
    """

    shader = self.activeShader

    if normals is not None: shader.setAtt('normal',       normals)
    if vdata   is not None: shader.setAtt('vertexData',   vdata.reshape(-1, 1))
    if mdata   is not None: shader.setAtt('modulateData', mdata.reshape(-1, 1))

    if normals is not None:

        # NOTE You are assuming here that the canvas
        #      view matrix is the GL model view matrix.
        normalMatrix = self.canvas.viewMatrix
        normalMatrix = affine.invert(normalMatrix).T

        shader.setVertParam('normalMatrix', normalMatrix)

    shader.loadAtts()

    nvertices = vertices.shape[0]
    vertices  = vertices.ravel('C')

    with glroutines.enabled((gl.GL_VERTEX_ARRAY)):
        gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices)

        if indices is None:
            gl.glDrawArrays(glType, 0, nvertices)
        else:
            gl.glDrawElements(glType,
                              indices.shape[0],
                              gl.GL_UNSIGNED_INT,
                              indices.ravel('C'))
Exemplo n.º 11
0
def test_applyDeformation_premat():

    src2ref = affine.compose(
        np.random.randint(2, 5, 3),
        np.random.randint(1, 10, 3),
        [0, 0, 0])
    ref2src = affine.invert(src2ref)

    srcdata = np.random.randint(1, 65536, (10, 10, 10))
    refdata = np.random.randint(1, 65536, (10, 10, 10))

    src   = fslimage.Image(srcdata)
    ref   = fslimage.Image(refdata, xform=src2ref)
    field = _affine_field(src, ref, ref2src, 'world', 'world')

    # First try a down-sampled version
    # of the original source image
    altsrc, xf = resample.resample(src, (5, 5, 5), origin='corner')
    altsrc     = fslimage.Image(altsrc, xform=xf, header=src.header)
    expect, xf = resample.resampleToReference(
        altsrc, ref, matrix=src2ref, order=1, mode='nearest')
    premat = affine.concat(src   .getAffine('world', 'voxel'),
                           altsrc.getAffine('voxel', 'world'))
    result = nonlinear.applyDeformation(
        altsrc, field, order=1, mode='nearest', premat=premat)
    assert np.all(np.isclose(expect, result))

    # Now try a down-sampled ROI
    # of the original source image
    altsrc     = roi.roi(src, [(2, 9), (2, 9), (2, 9)])
    altsrc, xf = resample.resample(altsrc, (4, 4, 4))
    altsrc     = fslimage.Image(altsrc, xform=xf, header=src.header)
    expect, xf = resample.resampleToReference(
        altsrc, ref, matrix=src2ref, order=1, mode='nearest')
    premat = affine.concat(src   .getAffine('world', 'voxel'),
                           altsrc.getAffine('voxel', 'world'))
    result = nonlinear.applyDeformation(
        altsrc, field, order=1, mode='nearest', premat=premat)
    assert np.all(np.isclose(expect, result))

    # down-sampled and offset ROI
    # of the original source image
    altsrc     = roi.roi(src, [(-5, 8), (-5, 8), (-5, 8)])
    altsrc, xf = resample.resample(altsrc, (6, 6, 6))
    altsrc     = fslimage.Image(altsrc, xform=xf, header=src.header)
    expect, xf = resample.resampleToReference(
        altsrc, ref, matrix=src2ref, order=1, mode='nearest')
    premat = affine.concat(src   .getAffine('world', 'voxel'),
                           altsrc.getAffine('voxel', 'world'))
    result = nonlinear.applyDeformation(
        altsrc, field, order=1, mode='nearest', premat=premat)
    assert np.all(np.isclose(expect, result))
Exemplo n.º 12
0
def test_invert():

    testfile = op.join(datadir, 'test_transform_test_invert.txt')
    testdata = np.loadtxt(testfile)

    nmatrices = testdata.shape[0] // 4

    for i in range(nmatrices):

        x = testdata[i * 4:i * 4 + 4, 0:4]
        invx = testdata[i * 4:i * 4 + 4, 4:8]
        result = affine.invert(x)

        assert np.all(np.isclose(invx, result))
Exemplo n.º 13
0
    def transformCoords(self, coords, from_, to, *args, **kwargs):
        """Transforms the given ``coords`` from ``from_`` to ``to``.

        :arg coords: Coordinates to transform.
        :arg from_:  Space that the coordinates are in
        :arg to:     Space to transform the coordinates to

        All other parameters are passed through to the
        :meth:`.NiftiOpts.transformCoords` method of the reference image
        ``DisplayOpts``.

        The following values are accepted for the ``from_`` and ``to``
        parameters:

          - ``'world'``:  World coordinate system
          - ``'display'`` Display coordinate system
          - ``'mesh'``    The coordinate system of this mesh.
          - ``'voxel'``:   The voxel coordinate system of the reference
                           image
          - ``'id'``:      Equivalent to ``'voxel'``.
        """

        nfrom_ = self.normaliseSpace(from_)
        nto = self.normaliseSpace(to)
        ref = self.refImage
        pre = None
        post = None

        if ref is None:
            return coords

        if from_ == 'mesh' and self.coordSpace == 'torig':
            pre = affine.concat(ref.getAffine('voxel', 'world'),
                                affine.invert(fslmgh.voxToSurfMat(ref)))

        if to == 'mesh' and self.coordSpace == 'torig':
            post = affine.concat(fslmgh.voxToSurfMat(ref),
                                 ref.getAffine('world', 'voxel'))

        opts = self.displayCtx.getOpts(ref)

        return opts.transformCoords(coords,
                                    nfrom_,
                                    nto,
                                    pre=pre,
                                    post=post,
                                    **kwargs)
Exemplo n.º 14
0
    def updateVertices(self, *a):
        """Called by :meth:`__init__`, and when certain display properties
        change. (Re-)generates the mesh vertices, indices and normals (if
        being displayed in 3D). They are stored as attributes called
        ``vertices``, ``indices``, and ``normals`` respectively.
        """

        overlay = self.overlay
        opts = self.opts
        threedee = self.threedee
        vertices = overlay.vertices
        indices = overlay.indices
        normals = self.overlay.vnormals
        vdata = opts.getVertexData('vertex')
        xform = opts.getTransform('mesh', 'display')

        if not np.all(np.isclose(xform, np.eye(4))):
            vertices = affine.transform(vertices, xform)

            if self.threedee:
                nmat = affine.invert(xform).T
                normals = affine.transform(normals, nmat, vector=True)

        self.origIndices = indices
        indices = np.asarray(indices.flatten(), dtype=np.uint32)

        # If flatShading is active, we cannot share
        # vertices between triangles, so we generate
        # a set of unique vertices for each triangle,
        # and then re-generate the triangle indices.
        # The original indices are saved above, as
        # they will be used by the getVertexData
        # method to duplicate the vertex data.
        if threedee and (vdata is not None) and opts.flatShading:
            self.vertices = vertices[indices].astype(np.float32)
            self.indices = np.arange(0, len(self.vertices), dtype=np.uint32)
            normals = normals[indices, :]
        else:
            self.vertices = np.asarray(vertices, dtype=np.float32)
            self.indices = indices

        self.vertices = dutils.makeWriteable(self.vertices)
        self.indices = dutils.makeWriteable(self.indices)

        if self.threedee:
            self.normals = np.array(normals, dtype=np.float32)
Exemplo n.º 15
0
def test_applyDeformation():

    src2ref = affine.compose(np.random.randint(2, 5, 3),
                             np.random.randint(1, 10, 3), np.random.random(3))
    ref2src = affine.invert(src2ref)

    srcdata = np.random.randint(1, 65536, (10, 10, 10))
    refdata = np.random.randint(1, 65536, (10, 10, 10))

    src = fslimage.Image(srcdata)
    ref = fslimage.Image(refdata, xform=src2ref)
    field = _affine_field(src, ref, ref2src, 'world', 'world')

    expect, xf = resample.resampleToReference(src,
                                              ref,
                                              matrix=src2ref,
                                              order=1,
                                              mode='nearest')
    result = nonlinear.applyDeformation(src, field, order=1, mode='nearest')

    assert np.all(np.isclose(expect, result))
Exemplo n.º 16
0
    def __setViewport(self):
        """Called by :meth:`_draw`. Configures the viewport and calculates
        the model-view trasformation matrix.

        :returns: ``True`` if the viewport was successfully configured,
                  ``False`` otherwise.
        """

        width, height = self.GetScaledSize()
        b = self.__displayCtx.bounds
        blo = [b.xlo, b.ylo, b.zlo]
        bhi = [b.xhi, b.yhi, b.zhi]
        zoom = self.opts.zoom / 100.0

        if width == 0 or height == 0:
            return False

        # We allow one dimension to be
        # flat, so we can display 2D
        # meshes (e.g. flattened surfaces)
        if np.sum(np.isclose(blo, bhi)) > 1:
            return False

        # Generate the view and projection matrices
        self.__genViewMatrix(width, height)
        projmat, viewport = glroutines.ortho(blo, bhi, width, height, zoom)
        self.__projMat = projmat
        self.__viewport = viewport
        self.__invViewProjMat = affine.concat(self.__projMat, self.__viewMat)
        self.__invViewProjMat = affine.invert(self.__invViewProjMat)

        gl.glViewport(0, 0, width, height)
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glLoadMatrixf(self.__projMat.ravel('F'))
        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glLoadIdentity()

        return True
Exemplo n.º 17
0
def test_rescale():

    with pytest.raises(ValueError):
        affine.rescale((5, 5), (10, 10, 10))

    assert np.all(affine.rescale((5, 5), (5, 5)) == np.eye(3))
    assert np.all(affine.rescale((5, 5, 5), (5, 5, 5)) == np.eye(4))
    assert np.all(affine.rescale((5, 5, 5, 5), (5, 5, 5, 5)) == np.eye(5))

    # (old shape, new shape, origin, expect)
    tests = [
        ((5, 5), (10, 10), 'centre',
         np.array([[0.5, 0, 0], [0, 0.5, 0], [0, 0, 1]])),
        ((5, 5), (10, 10), 'corner',
         np.array([[0.5, 0, -0.25], [0, 0.5, -0.25], [0, 0, 1]])),
        ((5, 5, 5), (10, 10, 10), 'centre',
         np.array([[0.5, 0, 0, 0], [0, 0.5, 0, 0], [0, 0, 0.5, 0],
                   [0, 0, 0, 1]])),
        ((5, 5, 5), (10, 10, 10), 'corner',
         np.array([[0.5, 0, 0, -0.25], [0, 0.5, 0, -0.25], [0, 0, 0.5, -0.25],
                   [0, 0, 0, 1]])),
        ((5, 5, 5, 5), (10, 10, 10, 10), 'centre',
         np.array([[0.5, 0, 0, 0, 0], [0, 0.5, 0, 0, 0], [0, 0, 0.5, 0, 0],
                   [0, 0, 0, 0.5, 0], [0, 0, 0, 0, 1]])),
        ((5, 5, 5, 5), (10, 10, 10, 10), 'corner',
         np.array([[0.5, 0, 0, 0, -0.25], [0, 0.5, 0, 0, -0.25],
                   [0, 0, 0.5, 0, -0.25], [0, 0, 0, 0.5, -0.25],
                   [0, 0, 0, 0, 1]])),
    ]

    for oldshape, newshape, origin, expect in tests:

        got = affine.rescale(oldshape, newshape, origin)
        assert np.all(np.isclose(got, expect))
        got = affine.rescale(newshape, oldshape, origin)
        assert np.all(np.isclose(got, affine.invert(expect)))
Exemplo n.º 18
0
 def invTexCoordXform(self, origShape):
     """Returns the inverse of :meth:`texCoordXform`. """
     return affine.invert(self.texCoordXform(origShape))
Exemplo n.º 19
0
    def draw3D(self, *args, **kwargs):
        """Calls the version dependent ``draw3D`` function. """

        opts = self.opts
        w, h = self.canvas.GetScaledSize()
        res  = self.opts.resolution / 100.0
        sw   = int(np.ceil(w * res))
        sh   = int(np.ceil(h * res))

        # Initialise and resize
        # the offscreen textures
        for rt in [self.renderTexture1, self.renderTexture2]:
            if rt.shape != (sw, sh):
                rt.shape = sw, sh

            with rt.target():
                gl.glClearColor(0, 0, 0, 0)
                gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

        if opts.resolution != 100:
            gl.glViewport(0, 0, sw, sh)

        # Do the render. Even though we're
        # drawing off-screen,  we need to
        # enable depth-testing, otherwise
        # depth values will not get written
        # to the depth buffer!
        #
        # The glvolume_funcs.draw3D function
        # will put the final render into
        # renderTexture1
        with glroutines.enabled((gl.GL_DEPTH_TEST, gl.GL_CULL_FACE)):
            gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL)
            gl.glFrontFace(gl.GL_CCW)
            gl.glCullFace(gl.GL_BACK)
            fslgl.glvolume_funcs.draw3D(self, *args, **kwargs)

        # Apply smoothing if needed. If smoothing
        # is enabled, the final final render will
        # be in renderTexture2
        if opts.smoothing > 0:
            self.smoothFilter.set(offsets=[1.0 / sw, 1.0 / sh])
            self.smoothFilter.osApply(self.renderTexture1,
                                      self.renderTexture2)

        # We now have the final result
        # - draw it to the screen.
        verts = np.array([[-1, -1, 0],
                          [-1,  1, 0],
                          [ 1, -1, 0],
                          [ 1, -1, 0],
                          [-1,  1, 0],
                          [ 1,  1, 0]], dtype=np.float32)

        invproj = affine.invert(self.canvas.projectionMatrix)
        verts   = affine.transform(verts, invproj)

        if opts.resolution != 100:
            gl.glViewport(0, 0, w, h)

        with glroutines.enabled(gl.GL_DEPTH_TEST):

            # If smoothing was not applied, rt1
            # contains the final render. Otherwise,
            # rt2 contains the final render, but rt1
            # contains the depth information. So we
            # need to # temporarily replace rt2.depth
            # with rt1.depth.
            if opts.smoothing > 0:
                src    = self.renderTexture2
                olddep = self.renderTexture2.depthTexture
                dep    = self.renderTexture1.depthTexture
            else:
                src    = self.renderTexture1
                olddep = self.renderTexture1.depthTexture
                dep    = olddep

            src.depthTexture = dep
            src.draw(verts, useDepth=True)
            src.depthTexture = olddep
Exemplo n.º 20
0
    def __setupTransforms(self):
        """Calculates transformation matrices between all of the possible
        spaces in which the overlay may be displayed.

        These matrices are accessible via the :meth:`getTransform` method.
        """

        image = self.overlay
        shape = np.array(image.shape[:3])

        voxToIdMat = np.eye(4)
        voxToPixdimMat = np.diag(list(image.pixdim[:3]) + [1.0])
        voxToPixFlipMat = image.voxToScaledVoxMat
        voxToWorldMat = image.voxToWorldMat
        voxToWorldMat = affine.concat(self.displayXform, voxToWorldMat)
        ds = self.displayCtx.displaySpace

        # The reference transforms depend
        # on the value of displaySpace
        if ds == 'world':
            voxToRefMat = voxToWorldMat
        elif ds is self.overlay:
            voxToRefMat = voxToPixFlipMat
        else:
            voxToRefMat = affine.concat(ds.voxToScaledVoxMat, ds.worldToVoxMat,
                                        voxToWorldMat)

        # When going from voxels to textures,
        # we add 0.5 to centre the voxel (see
        # the note on coordinate systems at
        # the top of this file).
        voxToTexMat = affine.scaleOffsetXform(tuple(1.0 / shape),
                                              tuple(0.5 / shape))

        idToVoxMat = affine.invert(voxToIdMat)
        idToPixdimMat = affine.concat(voxToPixdimMat, idToVoxMat)
        idToPixFlipMat = affine.concat(voxToPixFlipMat, idToVoxMat)
        idToWorldMat = affine.concat(voxToWorldMat, idToVoxMat)
        idToRefMat = affine.concat(voxToRefMat, idToVoxMat)
        idToTexMat = affine.concat(voxToTexMat, idToVoxMat)

        pixdimToVoxMat = affine.invert(voxToPixdimMat)
        pixdimToIdMat = affine.concat(voxToIdMat, pixdimToVoxMat)
        pixdimToPixFlipMat = affine.concat(voxToPixFlipMat, pixdimToVoxMat)
        pixdimToWorldMat = affine.concat(voxToWorldMat, pixdimToVoxMat)
        pixdimToRefMat = affine.concat(voxToRefMat, pixdimToVoxMat)
        pixdimToTexMat = affine.concat(voxToTexMat, pixdimToVoxMat)

        pixFlipToVoxMat = affine.invert(voxToPixFlipMat)
        pixFlipToIdMat = affine.concat(voxToIdMat, pixFlipToVoxMat)
        pixFlipToPixdimMat = affine.concat(voxToPixdimMat, pixFlipToVoxMat)
        pixFlipToWorldMat = affine.concat(voxToWorldMat, pixFlipToVoxMat)
        pixFlipToRefMat = affine.concat(voxToRefMat, pixFlipToVoxMat)
        pixFlipToTexMat = affine.concat(voxToTexMat, pixFlipToVoxMat)

        worldToVoxMat = affine.invert(voxToWorldMat)
        worldToIdMat = affine.concat(voxToIdMat, worldToVoxMat)
        worldToPixdimMat = affine.concat(voxToPixdimMat, worldToVoxMat)
        worldToPixFlipMat = affine.concat(voxToPixFlipMat, worldToVoxMat)
        worldToRefMat = affine.concat(voxToRefMat, worldToVoxMat)
        worldToTexMat = affine.concat(voxToTexMat, worldToVoxMat)

        refToVoxMat = affine.invert(voxToRefMat)
        refToIdMat = affine.concat(voxToIdMat, refToVoxMat)
        refToPixdimMat = affine.concat(voxToPixdimMat, refToVoxMat)
        refToPixFlipMat = affine.concat(voxToPixFlipMat, refToVoxMat)
        refToWorldMat = affine.concat(voxToWorldMat, refToVoxMat)
        refToTexMat = affine.concat(voxToTexMat, refToVoxMat)

        texToVoxMat = affine.invert(voxToTexMat)
        texToIdMat = affine.concat(voxToIdMat, texToVoxMat)
        texToPixdimMat = affine.concat(voxToPixdimMat, texToVoxMat)
        texToPixFlipMat = affine.concat(voxToPixFlipMat, texToVoxMat)
        texToWorldMat = affine.concat(voxToWorldMat, texToVoxMat)
        texToRefMat = affine.concat(voxToRefMat, texToVoxMat)

        self.__xforms['id', 'id'] = np.eye(4)
        self.__xforms['id', 'pixdim'] = idToPixdimMat
        self.__xforms['id', 'pixdim-flip'] = idToPixFlipMat
        self.__xforms['id', 'affine'] = idToWorldMat
        self.__xforms['id', 'reference'] = idToRefMat
        self.__xforms['id', 'texture'] = idToTexMat

        self.__xforms['pixdim', 'pixdim'] = np.eye(4)
        self.__xforms['pixdim', 'id'] = pixdimToIdMat
        self.__xforms['pixdim', 'pixdim-flip'] = pixdimToPixFlipMat
        self.__xforms['pixdim', 'affine'] = pixdimToWorldMat
        self.__xforms['pixdim', 'reference'] = pixdimToRefMat
        self.__xforms['pixdim', 'texture'] = pixdimToTexMat

        self.__xforms['pixdim-flip', 'pixdim-flip'] = np.eye(4)
        self.__xforms['pixdim-flip', 'id'] = pixFlipToIdMat
        self.__xforms['pixdim-flip', 'pixdim'] = pixFlipToPixdimMat
        self.__xforms['pixdim-flip', 'affine'] = pixFlipToWorldMat
        self.__xforms['pixdim-flip', 'reference'] = pixFlipToRefMat
        self.__xforms['pixdim-flip', 'texture'] = pixFlipToTexMat

        self.__xforms['affine', 'affine'] = np.eye(4)
        self.__xforms['affine', 'id'] = worldToIdMat
        self.__xforms['affine', 'pixdim'] = worldToPixdimMat
        self.__xforms['affine', 'pixdim-flip'] = worldToPixFlipMat
        self.__xforms['affine', 'reference'] = worldToRefMat
        self.__xforms['affine', 'texture'] = worldToTexMat

        self.__xforms['reference', 'reference'] = np.eye(4)
        self.__xforms['reference', 'id'] = refToIdMat
        self.__xforms['reference', 'pixdim'] = refToPixdimMat
        self.__xforms['reference', 'pixdim-flip'] = refToPixFlipMat
        self.__xforms['reference', 'affine'] = refToWorldMat
        self.__xforms['reference', 'texture'] = refToTexMat

        self.__xforms['texture', 'texture'] = np.eye(4)
        self.__xforms['texture', 'id'] = texToIdMat
        self.__xforms['texture', 'pixdim'] = texToPixdimMat
        self.__xforms['texture', 'pixdim-flip'] = texToPixFlipMat
        self.__xforms['texture', 'affine'] = texToWorldMat
        self.__xforms['texture', 'reference'] = texToRefMat
Exemplo n.º 21
0
    def calculateRayCastSettings(self, view=None, proj=None):
        """Calculates various parameters required for 3D ray-cast rendering
        (see the :class:`.GLVolume` class).


        :arg view: Transformation matrix which transforms from model
                   coordinates to view coordinates (i.e. the GL view matrix).


        :arg proj: Transformation matrix which transforms from view coordinates
                   to normalised device coordinates (i.e. the GL projection
                   matrix).

        Returns a tuple containing:

          - A vector defining the amount by which to move along a ray in a
            single iteration of the ray-casting algorithm. This can be added
            directly to the volume texture coordinates.

          - A transformation matrix which transforms from image texture
            coordinates into the display coordinate system.

        .. note:: This method will raise an error if called on a
                  ``GLImageObject`` which is managing an overlay that is not
                  associated with a :class:`.Volume3DOpts` instance.
        """

        if view is None: view = np.eye(4)
        if proj is None: proj = np.eye(4)

        # In GL, the camera position
        # is initially pointing in
        # the -z direction.
        eye    = [0, 0, -1]
        target = [0, 0,  1]

        # We take this initial camera
        # configuration, and transform
        # it by the inverse modelview
        # matrix
        t2dmat = self.getTransform('texture', 'display')
        xform  = affine.concat(view, t2dmat)
        ixform = affine.invert(xform)

        eye    = affine.transform(eye,    ixform, vector=True)
        target = affine.transform(target, ixform, vector=True)

        # Direction that the 'camera' is
        # pointing, normalied to unit length
        cdir = affine.normalise(eye - target)

        # Calculate the length of one step
        # along the camera direction in a
        # single iteration of the ray-cast
        # loop. Multiply by sqrt(3) so that
        # the maximum number of steps will
        # be reached across the longest axis
        # of the image texture cube.
        rayStep = np.sqrt(3) * cdir / self.getNumSteps()

        # A transformation matrix which can
        # transform image texture coordinates
        # into the corresponding screen
        # (normalised device) coordinates.
        # This allows the fragment shader to
        # convert an image texture coordinate
        # into a relative depth value.
        #
        # The projection matrix puts depth into
        # [-1, 1], but we want it in [0, 1]
        zscale = affine.scaleOffsetXform([1, 1, 0.5], [0, 0, 0.5])
        xform  = affine.concat(zscale, proj, xform)

        return rayStep, xform
Exemplo n.º 22
0
def test_nonlinear_altsrc(seed):
    with tempdir.tempdir():

        src2ref = _random_affine()
        ref2src = affine.invert(src2ref)
        src = _random_image(np.eye(4), (20, 20, 20))
        ref = _random_image(src2ref, (20, 20, 20))

        field = _affine_field(src, ref, ref2src, 'world', 'world')

        x5.writeNonLinearX5('xform.x5', field)

        src.save('src')
        ref.save('ref')

        # use origin=corner so that the
        # resampled variants are exactly
        # aligned in the world coordinate
        # system
        srclo, xf = resample.resample(src, (10, 10, 10),
                                      origin='corner',
                                      smooth=False)
        srclo = fslimage.Image(srclo, xform=xf)
        srchi, xf = resample.resample(src, (40, 40, 40),
                                      origin='corner',
                                      smooth=False)
        srchi = fslimage.Image(srchi, xform=xf)

        srcoff = roi.roi(src, [(-10, 10), (-10, 10), (-10, 10)])

        srclo.save('srclo')
        srchi.save('srchi')
        srcoff.save('srcoff')

        fsl_apply_x5.main('src    xform.x5 out'.split())
        fsl_apply_x5.main('srclo  xform.x5 outlo'.split())
        fsl_apply_x5.main('srchi  xform.x5 outhi'.split())
        fsl_apply_x5.main('srcoff xform.x5 outoff'.split())

        out = fslimage.Image('out')
        outlo = fslimage.Image('outlo')
        outhi = fslimage.Image('outhi')
        outoff = fslimage.Image('outoff')

        exp, x1 = resample.resampleToReference(src,
                                               ref,
                                               matrix=src2ref,
                                               mode='constant',
                                               smooth=False)
        explo, x2 = resample.resampleToReference(srclo,
                                                 ref,
                                                 matrix=src2ref,
                                                 mode='constant',
                                                 smooth=False)
        exphi, x3 = resample.resampleToReference(srchi,
                                                 ref,
                                                 matrix=src2ref,
                                                 mode='constant',
                                                 smooth=False)
        expoff, x4 = resample.resampleToReference(srcoff,
                                                  ref,
                                                  matrix=src2ref,
                                                  mode='constant',
                                                  smooth=False)

        assert out.sameSpace(ref)
        assert outlo.sameSpace(ref)
        assert outhi.sameSpace(ref)
        assert outoff.sameSpace(ref)

        # We get boundary cropping,
        # so ignore edge slices
        out = out.data[1:-1, 1:-1, 1:-1]
        outlo = outlo.data[1:-1, 1:-1, 1:-1]
        outhi = outhi.data[1:-1, 1:-1, 1:-1]
        outoff = outoff.data[:9, :9, :9]
        exp = exp[1:-1, 1:-1, 1:-1]
        explo = explo[1:-1, 1:-1, 1:-1]
        exphi = exphi[1:-1, 1:-1, 1:-1]
        expoff = expoff[:9, :9, :9]

        tol = dict(atol=1e-3, rtol=1e-3)

        assert np.all(np.isclose(out, exp, **tol))
        assert np.all(np.isclose(outlo, explo, **tol))
        assert np.all(np.isclose(outhi, exphi, **tol))
        assert np.all(np.isclose(outoff, expoff, **tol))