コード例 #1
0
def test_generateAffines():

    v2w = affine.compose(np.random.random(3), np.random.random(3),
                         np.random.random(3))
    shape = (10, 10, 10)
    pixdim = (1, 1, 1)

    got, isneuro = fslimage.Nifti.generateAffines(v2w, shape, pixdim)

    w2v = npla.inv(v2w)

    assert isneuro == (npla.det(v2w) > 0)

    if not isneuro:
        v2f = np.eye(4)
        f2v = np.eye(4)
        f2w = v2w
        w2f = w2v
    else:
        v2f = affine.scaleOffsetXform([-1, 1, 1], [9, 0, 0])
        f2v = npla.inv(v2f)
        f2w = affine.concat(v2w, f2v)
        w2f = affine.concat(v2f, w2v)

    assert np.all(np.isclose(v2w, got['voxel', 'world']))
    assert np.all(np.isclose(w2v, got['world', 'voxel']))
    assert np.all(np.isclose(v2f, got['voxel', 'fsl']))
    assert np.all(np.isclose(f2v, got['fsl', 'voxel']))
    assert np.all(np.isclose(f2w, got['fsl', 'world']))
    assert np.all(np.isclose(w2f, got['world', 'fsl']))
コード例 #2
0
    def __xformChanged(self, ev=None):
        """Called when any of the scale, offset, or rotate widgets are
        modified. Updates the :attr:`.NiftiOpts.displayXform` for the
        overlay currently being edited.
        """

        if self.__overlay is None:
            return

        overlay = self.__overlay
        opts = self.displayCtx.getOpts(overlay)

        if self.__extraXform is None: v2wXform = overlay.voxToWorldMat
        else: v2wXform = self.__extraXform

        xform = self.__getCurrentXform()
        xform = affine.concat(xform, v2wXform)

        self.__formatXform(xform, self.__newXform)

        # The NiftiOpts.displayXform is applied on
        # top of the image voxToWorldMat. But our
        # xform here has been constructed to replace
        # the voxToWorldMat entirely. So we include
        # a worldToVoxMat transform to trick the
        # NiftiOpts code.
        opts.displayXform = affine.concat(xform, overlay.worldToVoxMat)
コード例 #3
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
コード例 #4
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))
コード例 #5
0
def draw2D(self, zpos, axes, xform=None, bbox=None):
    """Draws the line vectors at a plane at the specified Z location.
    Voxel coordinates are passed to the vertex shader, which calculates
    the corresponding line vertex locations.
    """

    opts = self.opts
    shader = self.shader
    v2dMat = opts.getTransform('voxel', 'display')

    voxels = self.generateVoxelCoordinates2D(zpos, axes, bbox=bbox)
    voxels = np.repeat(voxels, 2, 0)
    indices = np.arange(voxels.shape[0], dtype=np.uint32)

    if xform is None: xform = v2dMat
    else: xform = affine.concat(xform, v2dMat)

    shader.set('voxToDisplayMat', xform)
    shader.setAtt('vertexID', indices)
    shader.setAtt('voxel', voxels)
    shader.loadAtts()

    gl.glLineWidth(opts.lineWidth)
    gl.glDrawArrays(gl.GL_LINES, 0, voxels.size // 3)

    shader.unloadAtts()
コード例 #6
0
def test_convert_flirt():
    with tempdir.tempdir():
        src = random_image()
        ref = random_image()
        src.save('src')
        ref.save('ref')

        xform = affine.compose(np.random.randint(1, 10, 3),
                               np.random.randint(-100, 100, 3),
                               (np.random.random(3) - 0.5) * np.pi)

        np.savetxt('src2ref.mat', xform)

        fsl_convert_x5.main('flirt -s src -r ref '
                            'src2ref.mat src2ref.x5'.split())
        expxform = affine.concat(ref.getAffine('fsl', 'world'), xform,
                                 src.getAffine('world', 'fsl'))
        gotxform, gotsrc, gotref = x5.readLinearX5('src2ref.x5')
        assert np.all(np.isclose(gotxform, expxform))
        assert src.sameSpace(gotsrc)
        assert ref.sameSpace(gotref)

        fsl_convert_x5.main('flirt src2ref.x5 src2ref_copy.mat'.split())

        gotxform = flirt.readFlirt('src2ref_copy.mat')
        assert np.all(np.isclose(gotxform, xform))
コード例 #7
0
def test_prepareMask():

    reg = atlases.registry
    reg.rescanAtlases()

    probatlas    = reg.loadAtlas('harvardoxford-cortical')
    probsumatlas = reg.loadAtlas('harvardoxford-cortical', loadSummary=True)
    lblatlas     = reg.loadAtlas('talairach')

    for atlas in [probatlas, probsumatlas, lblatlas]:

        ashape        = list(atlas.shape[:3])
        m2shape       = [s * 1.5 for s in ashape]

        goodmask1     = fslimage.Image(
            np.array(np.random.random(ashape), dtype=np.float32),
            xform=atlas.voxToWorldMat)

        goodmask2, xf = resample.resample(goodmask1, m2shape)
        goodmask2     = fslimage.Image(goodmask2, xform=xf)

        wrongdims     = fslimage.Image(
            np.random.random(list(ashape) + [2]))
        wrongspace    = fslimage.Image(
            np.random.random((20, 20, 20)),
            xform=affine.concat(atlas.voxToWorldMat, np.diag([2, 2, 2, 1])))

        with pytest.raises(atlases.MaskError):
            atlas.prepareMask(wrongdims)
        with pytest.raises(atlases.MaskError):
            atlas.prepareMask(wrongspace)

        assert list(atlas.prepareMask(goodmask1).shape) == ashape
        assert list(atlas.prepareMask(goodmask2).shape) == ashape
コード例 #8
0
ファイル: test_affine.py プロジェクト: physimals/fslpy
def test_concat():

    testfile = op.join(datadir, 'test_transform_test_concat.txt')
    lines = readlines(testfile)

    ntests = len(lines) // 4
    tests = []

    for i in range(ntests):
        ilines = lines[i * 4:i * 4 + 4]
        data = np.genfromtxt(ilines)
        ninputs = data.shape[1] // 4 - 1

        inputs = []

        for j in range(ninputs):
            inputs.append(data[:, j * 4:j * 4 + 4])

        output = data[:, -4:]

        tests.append((inputs, output))

    for inputs, expected in tests:

        result = affine.concat(*inputs)

        assert np.all(np.isclose(result, expected))
コード例 #9
0
    def _rotateModeLeftMouseDrag(self, ev, canvas, mousePos, canvasPos):
        """Called on left mouse drag events in ``rotate`` mode.
        Modifies the canvas rotation matrix according to the X and Y
        mouse position (relative to the mouse down location).
        """

        if self.__rotateMousePos is None:
            return

        w, h = canvas.GetSize()
        x0, y0 = self.__rotateMousePos
        x1, y1 = mousePos

        # Normalise x/y mouse pos to [-fac*pi, +fac*pi]
        fac = 1
        x0 = -1 + 2 * (x0 / float(w)) * fac * np.pi
        y0 = -1 + 2 * (y0 / float(h)) * fac * np.pi
        x1 = -1 + 2 * (x1 / float(w)) * fac * np.pi
        y1 = -1 + 2 * (y1 / float(h)) * fac * np.pi

        xrot = x1 - x0
        yrot = y1 - y0

        rot = affine.axisAnglesToRotMat(yrot, 0, xrot)

        self.__lastRot = rot
        self.__rotateMousePos = mousePos

        canvas.opts.rotation = affine.concat(rot, self.__lastRot,
                                             self.__baseXform)
コード例 #10
0
def lookAt(eye, centre, up):
    """Replacement for ``gluLookAt`. Creates a transformation matrix which
    transforms the display coordinate system such that a camera at position
    (0, 0, 0), and looking towards (0, 0, -1), will see a scene as if from
    position ``eye``, oriented ``up``, and looking towards ``centre``.

    See:
    https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml
    """

    eye = np.array(eye)
    centre = np.array(centre)
    up = np.array(up)
    proj = np.eye(4)

    forward = centre - eye
    forward /= np.sqrt(np.dot(forward, forward))

    right = np.cross(forward, up)
    right /= np.sqrt(np.dot(right, right))

    up = np.cross(right, forward)
    up /= np.sqrt(np.dot(up, up))

    proj[0, :3] = right
    proj[1, :3] = up
    proj[2, :3] = -forward

    eye = affine.scaleOffsetXform(1, -eye)
    proj = affine.concat(proj, eye)

    return proj
コード例 #11
0
    def __onApply(self, ev):
        """Called when the *Apply* button is pushed. Sets the
        ``voxToWorldMat`` attribute of the :class:`.Image` instance being
        transformed.
        """

        overlay = self.__overlay

        if overlay is None:
            return

        if self.__extraXform is None: v2wXform = overlay.voxToWorldMat
        else: v2wXform = self.__extraXform

        newXform = self.__getCurrentXform()
        opts = self.displayCtx.getOpts(overlay)

        xform = affine.concat(newXform, v2wXform)

        with props.suppress(opts, 'displayXform'):
            opts.displayXform = np.eye(4)
            overlay.voxToWorldMat = xform

        # Reset the interface, and clear any
        # cached transform for this overlay
        self.__deregisterOverlay()
        self.__cachedXforms.pop(overlay, None)
        self.__selectedOverlayChanged()
コード例 #12
0
def draw2D(self, zpos, axes, xform=None, bbox=None):
    """Draws the line vertices corresponding to a 2D plane located
    at the specified Z location.
    """

    opts = self.opts
    vertices, voxCoords = self.lineVertices.getVertices2D(self,
                                                          zpos,
                                                          axes,
                                                          bbox=bbox)

    if vertices.size == 0:
        return

    self.shader.setAtt('voxCoord', voxCoords)
    self.shader.loadAtts()

    v2d = opts.getTransform('voxel', 'display')

    if xform is None: xform = v2d
    else: xform = affine.concat(xform, v2d)

    gl.glPushMatrix()
    gl.glMultMatrixf(np.array(xform, dtype=np.float32).ravel('F'))

    gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices)

    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE)
    gl.glLineWidth(opts.lineWidth)
    gl.glDrawArrays(gl.GL_LINES, 0, vertices.size // 3)

    gl.glPopMatrix()
コード例 #13
0
    def doMovieUpdate(self, overlay, opts):
        """Overrides :meth:`.CanvasPanel.doMovieUpdate`. For x/y/z axis
        movies, the scene is rotated. Otherwise (for time) the ``CanvasPanel``
        implementation is called.
        """

        if self.movieAxis >= 3:
            return canvaspanel.CanvasPanel.doMovieUpdate(self, overlay, opts)
        else:

            canvas = self.__canvas
            currot = canvas.opts.rotation
            rate = float(self.movieRate)
            rateMin = self.getAttribute('movieRate', 'minval')
            rateMax = self.getAttribute('movieRate', 'maxval')
            rate = 0.1 + 0.9 * (rate - rateMin) / (rateMax - rateMin)
            rate = rate * np.pi / 10

            rots = [0, 0, 0]
            rots[self.movieAxis] = rate

            xform = affine.axisAnglesToRotMat(*rots)
            xform = affine.concat(xform, currot)

            canvas.opts.rotation = xform
            return np.copy(xform)
コード例 #14
0
ファイル: glvolume.py プロジェクト: marcobarilari/fsleyes
    def getModulateValueXform(self):
        """Returns an affine transform to normalise alpha modulation values.

        The GL volume shaders need to normalise the modulate value by the
        modulation range to generate an opacity value. We calculate a suitable
        scale and offset by buildin an affine transform which transforms voxel
        values from the image/modulate image texture range to 0/1, where 0
        corresponds to the low modulate range bound, and 1 to the high
        modulate range bound. The resulting scale/offset can be used by the
        shader to convert a modulate value directly into an opacity value.
        """

        opts = self.opts
        if opts.modulateImage is None:
            modXform = self.imageTexture.voxValXform
        else:
            modXform = self.modulateTexture.voxValXform

        modlo, modhi = opts.modulateRange
        modrange     = modhi - modlo
        if modrange == 0:
            modXform = np.eye(4)
        else:
            modXform = affine.concat(
                affine.scaleOffsetXform(1 / modrange, -modlo / modrange),
                modXform)

        return modXform
コード例 #15
0
def _affine_field(src, ref, xform, srcSpace, refSpace, shape=None, fv2w=None):

    if shape is None: shape = ref.shape[:3]
    if fv2w is None: fv2w = ref.getAffine('voxel', 'world')

    rx, ry, rz = np.meshgrid(np.arange(shape[0]),
                             np.arange(shape[1]),
                             np.arange(shape[2]),
                             indexing='ij')

    rvoxels = np.vstack((rx.flatten(), ry.flatten(), rz.flatten())).T
    f2r = affine.concat(ref.getAffine('world', refSpace), fv2w)
    rcoords = affine.transform(rvoxels, f2r)
    scoords = affine.transform(rcoords, xform)

    field = np.zeros(list(shape[:3]) + [3])
    field[:] = (scoords - rcoords).reshape(*it.chain(shape, [3]))
    field = nonlinear.DeformationField(field,
                                       src,
                                       ref,
                                       srcSpace=srcSpace,
                                       refSpace=refSpace,
                                       xform=fv2w,
                                       header=ref.header,
                                       defType='relative')
    return field
コード例 #16
0
ファイル: glsh_funcs.py プロジェクト: marcobarilari/fsleyes
def draw2D(self, zpos, axes, xform=None, bbox=None):
    """Called by :meth:`.GLSH.draw2D`. Draws the scene. """

    opts = self.opts
    shader = self.shader
    v2dMat = opts.getTransform('voxel', 'display')

    if xform is None: xform = v2dMat
    else: xform = affine.concat(v2dMat, xform)

    voxels = self.generateVoxelCoordinates2D(zpos, axes, bbox)
    voxels, radTexShape = self.updateRadTexture(voxels)

    if len(voxels) == 0:
        return

    voxIdxs = np.arange(voxels.shape[0], dtype=np.float32)

    shader.setAtt('voxel', voxels, divisor=1)
    shader.setAtt('voxelID', voxIdxs, divisor=1)
    shader.set('voxToDisplayMat', xform)
    shader.set('radTexShape', radTexShape)
    shader.set('radXform', self.radTexture.voxValXform)

    shader.loadAtts()

    arbdi.glDrawElementsInstancedARB(gl.GL_TRIANGLES, self.nVertices,
                                     gl.GL_UNSIGNED_INT, None, len(voxels))
コード例 #17
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))
コード例 #18
0
ファイル: test_mghimage.py プロジェクト: physimals/fslpy
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
コード例 #19
0
    def draw2D(self, zpos, axes):
        """Draws this ``VoxelSelection``."""

        xax, yax     = axes[:2]
        opts         = self.__opts
        texture      = self.__texture
        shape        = self.__selection.getSelection().shape
        displayToVox = opts.getTransform('display', 'voxel')
        voxToDisplay = opts.getTransform('voxel',   'display')
        voxToTex     = opts.getTransform('voxel',   'texture')
        voxToTex     = affine.concat(texture.texCoordXform(shape), voxToTex)
        verts, voxs  = glroutines.slice2D(shape,
                                          xax,
                                          yax,
                                          zpos,
                                          voxToDisplay,
                                          displayToVox)

        texs  = affine.transform(voxs, voxToTex)[:, :texture.ndim]
        verts = np.array(verts, dtype=np.float32).ravel('C')
        texs  = np.array(texs,  dtype=np.float32).ravel('C')

        texture.bindTexture(gl.GL_TEXTURE0)
        gl.glClientActiveTexture(gl.GL_TEXTURE0)
        gl.glTexEnvf(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_MODULATE)

        with glroutines.enabled((texture.target,
                                 gl.GL_TEXTURE_COORD_ARRAY,
                                 gl.GL_VERTEX_ARRAY)):
            gl.glVertexPointer(  3,            gl.GL_FLOAT, 0, verts)
            gl.glTexCoordPointer(texture.ndim, gl.GL_FLOAT, 0, texs)
            gl.glDrawArrays(     gl.GL_TRIANGLES, 0, 6)

        texture.unbindTexture()
コード例 #20
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)
コード例 #21
0
    def __getMeshInfo(self, overlay, display):
        """Creates and returns an :class:`OverlayInfo` object containing
        information about the given :class:`.Mesh` overlay.

        :arg overlay: A :class:`.Mesh` instance.
        :arg display: The :class:`.Display` instance assocated with the
                      ``Mesh``.
        """

        opts = display.opts
        refImg = opts.refImage

        modelInfo = [
            ('numVertices', overlay.vertices.shape[0]),
            ('numTriangles', overlay.indices.shape[0]),
        ]

        if refImg is None:
            modelInfo.append(
                ('displaySpace', strings.labels[self, overlay, 'coordSpace',
                                                'display']))

            mesh2worldXform = np.eye(4)

        else:

            refOpts = self.displayCtx.getOpts(refImg)
            dsImg = self.displayCtx.displaySpace
            displaySpace = strings.labels[self, refImg, 'displaySpace',
                                          refOpts.transform]
            coordSpace = strings.labels[self, overlay, 'coordSpace',
                                        opts.coordSpace].format(refImg.name)
            mesh2worldXform = affine.concat(
                refOpts.getTransform('display', 'world'),
                opts.getTransform('mesh', 'display'))

            if refOpts.transform == 'reference':
                dsDisplay = self.displayCtx.getDisplay(dsImg)
                displaySpace = displaySpace.format(dsDisplay.name)

            modelInfo.append(('refImage', refImg.dataSource))
            modelInfo.append(('coordSpace', coordSpace))
            modelInfo.append(('displaySpace', displaySpace))

        bounds = affine.transform(overlay.bounds, mesh2worldXform)
        lens = bounds[1] - bounds[0]
        lens = 'X={:0.0f} mm Y={:0.0f} mm Z={:0.0f} mm'.format(*lens)

        modelInfo.append(('size', lens))

        info = OverlayInfo('{} - {}'.format(display.name,
                                            strings.labels[self, overlay]))

        info.addInfo(strings.labels[self, 'dataSource'], overlay.dataSource)

        for name, value in modelInfo:
            info.addInfo(strings.labels[self, overlay, name], value)

        return info
コード例 #22
0
ファイル: glmesh.py プロジェクト: marcobarilari/fsleyes
    def drawOutline(self, zpos, axes, xform=None, bbox=None):
        """Called by :meth:`draw2D` when ``MeshOpts.outline is True or
        MeshOpts.vertexData is not None``.  Calculates the intersection of the
        mesh with the viewing plane, and renders it as a set of
        ``GL_LINES``. If ``MeshOpts.vertexData is None``, the draw is
        performed using immediate mode OpenGL.

        Otherwise, the :func:`.gl14.glmesh_funcs.draw` or
        :func:`.gl21.glmesh_funcs.draw` function is used, which performs
        shader-based rendering.
        """

        opts = self.opts

        # Makes code below a bit nicer
        if xform is None:
            xform = np.eye(4)

        vertices, faces, dists, vertXform = self.calculateIntersection(
            zpos, axes, bbox)

        if vertXform is not None:
            xform = affine.concat(xform, vertXform)

        vdata     = self.getVertexData('vertex',   faces, dists)
        mdata     = self.getVertexData('modulate', faces, dists)
        useShader = vdata is not None
        vertices  = vertices.reshape(-1, 3)
        nvertices = vertices.shape[0]

        if mdata is None:
            mdata = vdata

        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glPushMatrix()
        gl.glMultMatrixf(np.array(xform, dtype=np.float32).ravel('F'))

        gl.glLineWidth(opts.outlineWidth)

        # Constant colour
        if not useShader:
            vertices = vertices.ravel('C')
            gl.glColor(*opts.getConstantColour())
            gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
            gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices)
            gl.glDrawArrays(gl.GL_LINES, 0, nvertices)
            gl.glDisableClientState(gl.GL_VERTEX_ARRAY)

        # Coloured from vertex data
        else:
            fslgl.glmesh_funcs.draw(
                self,
                gl.GL_LINES,
                vertices,
                vdata=vdata,
                mdata=mdata)

        gl.glPopMatrix()
コード例 #23
0
ファイル: resample.py プロジェクト: physimals/fslpy
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
コード例 #24
0
def roi(image, bounds):
    """Extract an ROI from the given ``image`` according to the given
    ``bounds``.

    This function can also be used to pad, or expand the field-of-view, of an
    image, by passing in negative low bound values, or high bound values which
    are larger than the image shape. The padded region will contain zeroes.

    :arg image:  :class:`.Image` object

    :arg bounds: Must be a sequence of tuples, containing the low/high bounds
                 for each voxel dimension, where the low bound is *inclusive*,
                 and the high bound is *exclusive*. For 4D images, the bounds
                 for the fourth dimension are optional.

    :returns:    A new :class:`.Image` object containing the region specified
                 by the ``bounds``.
    """

    bounds = _normaliseBounds(image.shape, bounds)

    newshape = [hi - lo for lo, hi in bounds]
    oldslc = []
    newslc = []

    # Figure out how to slice the input image
    # data array, and the corresponding slice
    # in the output data array.
    for (lo, hi), oldlen, newlen in zip(bounds, image.shape, newshape):

        oldlo = max(lo, 0)
        oldhi = min(hi, oldlen)
        newlo = max(0, -lo)
        newhi = newlo + (oldhi - oldlo)

        oldslc.append(slice(oldlo, oldhi))
        newslc.append(slice(newlo, newhi))

    oldslc = tuple(oldslc)
    newslc = tuple(newslc)

    # Copy the ROI into the new data array
    newdata = np.zeros(newshape, dtype=image.dtype)
    newdata[newslc] = image.data[oldslc]

    # Create a new affine for the ROI,
    # with an appropriate offset along
    # each spatial dimension
    oldaff = image.voxToWorldMat
    offset = [lo for lo, hi in bounds[:3]]
    offset = affine.scaleOffsetXform([1, 1, 1], offset)
    newaff = affine.concat(oldaff, offset)

    return fslimage.Image(newdata,
                          xform=newaff,
                          header=image.header,
                          name=image.name + '_roi')
コード例 #25
0
def swapdim(infile):
    basename = fslimage.removeExt(op.basename(infile))
    outfile = '{}_swapdim.nii.gz'.format(basename)
    img = fslimage.Image(infile)

    data = img.data
    xform = img.voxToWorldMat

    data = data.transpose((2, 0, 1))
    rot = affine.rotMatToAffine(
        affine.concat(affine.axisAnglesToRotMat(np.pi / 2, 0, 0),
                      affine.axisAnglesToRotMat(0, 0, 3 * np.pi / 2)))
    xform = affine.concat(xform, affine.scaleOffsetXform((1, -1, -1),
                                                         (0, 0, 0)), rot)

    fslimage.Image(data, xform=xform, header=img.header).save(outfile)

    return outfile
コード例 #26
0
ファイル: niftiopts.py プロジェクト: marcobarilari/fsleyes
    def transformCoords(self,
                        coords,
                        from_,
                        to_,
                        vround=False,
                        vector=False,
                        pre=None,
                        post=None):
        """Transforms the given coordinates from ``from_`` to ``to_``.

        The ``from_`` and ``to_`` parameters must be those accepted by the
        :meth:`getTransform` method.

        :arg coords: Coordinates to transform
        :arg from_:  Space to transform from
        :arg to_:    Space to transform to
        :arg vround: If ``True``, and ``to_ in ('voxel', 'id)``, the
                     transformed coordinates are rounded to the nearest
                     integer.
        :arg vector: Defaults to ``False``. If ``True``, the coordinates
                     are treated as vectors.
        :arg pre:    Transformation to apply before the ``from_``-to-``to``
                     transformation.
        :arg post:   Transformation to apply after the ``from_``-to-``to``
                     transformation.
        """

        if not self.__child:
            raise RuntimeError('transformCoords cannot be called on '
                               'a parent NiftiOpts instance')

        xform = self.getTransform(from_, to_)

        if pre is not None: xform = affine.concat(xform, pre)
        if post is not None: xform = affine.concat(post, xform)

        coords = np.array(coords)
        coords = affine.transform(coords, xform, vector=vector)

        # Round to integer voxel coordinates?
        if to_ in ('voxel', 'id') and vround:
            coords = self.roundVoxels(coords)

        return coords
コード例 #27
0
ファイル: mghimage.py プロジェクト: physimals/fslpy
    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)
コード例 #28
0
def draw3D(self, xform=None, bbox=None):
    """Draws the image in 3D on the canvas.

    :arg self:    The :class:`.GLVolume` object which is managing the image
                  to be drawn.

    :arg xform:   A 4*4 transformation matrix to be applied to the vertex
                  data.

    :arg bbox:    An optional bounding box.
    """

    opts = self.opts
    canvas = self.canvas
    copts = canvas.opts
    tex = self.renderTexture1
    proj = self.canvas.projectionMatrix
    vertices, voxCoords, texCoords = self.generateVertices3D(bbox)
    rayStep, texform = opts.calculateRayCastSettings(xform, proj)

    rayStep = affine.transformNormal(
        rayStep, self.imageTexture.texCoordXform(self.overlay.shape))
    texform = affine.concat(
        texform, self.imageTexture.invTexCoordXform(self.overlay.shape))

    # If lighting is enabled, we specify the light
    # position in image texture coordinates, to make
    # life easier for the shader
    if copts.light:
        lxform = opts.getTransform('display', 'texture')
        lightPos = affine.transform(canvas.lightPos, lxform)
    else:
        lightPos = [0, 0, 0]

    if xform is not None:
        vertices = affine.transform(vertices, xform)

    self.shader.set('lighting', copts.light)
    self.shader.set('tex2ScreenXform', texform)
    self.shader.set('rayStep', rayStep)
    self.shader.set('lightPos', lightPos)
    self.shader.setAtt('vertex', vertices)
    self.shader.setAtt('texCoord', texCoords)

    self.shader.loadAtts()

    tex.bindAsRenderTarget()
    gl.glDrawArrays(gl.GL_TRIANGLES, 0, 36)
    tex.unbindAsRenderTarget()

    self.shader.unloadAtts()
    self.shader.unload()
コード例 #29
0
ファイル: glvolume.py プロジェクト: marcobarilari/fsleyes
    def getAuxTextureXform(self, which):
        """Calculates a transformation matrix which will transform from the
        image coordinate system into the :attr:`.VolumeOpts.clipImage` or
        :attr:`.VolumeOpts.modulateImage` coordinate system. If the property
        is ``None``, it will be an identity transform.

        This transform is used by shader programs to find the auxillary image
        coordinates that correspond with specific image coordinates.
        """
        return affine.concat(
            self.auxmgr.textureXform(which),
            # to support 2D image textures
            self.imageTexture.invTexCoordXform(self.overlay.shape))
コード例 #30
0
def translate(infile, x, y, z):
    basename = fslimage.removeExt(op.basename(infile))
    outfile = '{}_translated_{}_{}_{}.nii.gz'.format(basename, x, y, z)
    img = fslimage.Image(infile)
    xform = img.voxToWorldMat

    shift = affine.scaleOffsetXform(1, (x, y, z))
    xform = affine.concat(shift, xform)
    img.voxToWorldMat = xform

    img.save(outfile)

    return outfile