Beispiel #1
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))
Beispiel #2
0
def test_linear_altsrc(seed):
    with tempdir.tempdir():

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

        x5.writeLinearX5('xform.x5', src2ref, src, ref)

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

        srclo, xf = resample.resample(src, (10, 10, 10))
        srclo = fslimage.Image(srclo, xform=xf)
        srchi, xf = resample.resample(src, (40, 40, 40))
        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 = resample.resampleToReference(src, ref, matrix=src2ref)[0]
        explo = resample.resampleToReference(srclo, ref, matrix=src2ref)[0]
        exphi = resample.resampleToReference(srchi, ref, matrix=src2ref)[0]
        expoff = resample.resampleToReference(srcoff, ref, matrix=src2ref)[0]

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

        assert np.all(np.isclose(out.data, exp))
        assert np.all(np.isclose(outlo.data, explo))
        assert np.all(np.isclose(outhi.data, exphi))
        assert np.all(np.isclose(outoff.data, expoff))
Beispiel #3
0
def test_roi():

    # inshape, bounds, expected outshape, expected affine offset
    tests = [
        # 3D image, 3D roi
        ([10, 10, 10], [(0, 10), (0, 10), (0, 10)], [10, 10, 10], [0, 0, 0]),
        ([10, 10, 10], [(1, 10), (1, 10), (1, 10)], [9, 9, 9], [1, 1, 1]),
        ([10, 10, 10], [(1, 9), (1, 9), (1, 9)], [8, 8, 8], [1, 1, 1]),
        ([10, 10, 10], [(3, 5), (3, 5), (3, 5)], [2, 2, 2], [3, 3, 3]),
        ([10, 10, 10], [(4, 5), (4, 5), (4, 5)], [1, 1, 1], [4, 4, 4]),

        # 4D image, 3D roi
        ([10, 10, 10, 10], [(0, 10), (0, 10), (0, 10)], [10, 10, 10,
                                                         10], [0, 0, 0]),
        ([10, 10, 10, 10], [(1, 10), (1, 10), (1, 10)], [9, 9, 9,
                                                         10], [1, 1, 1]),
        ([10, 10, 10, 10], [(1, 9), (1, 9), (1, 9)], [8, 8, 8, 10], [1, 1, 1]),
        ([10, 10, 10, 10], [(3, 5), (3, 5), (3, 5)], [2, 2, 2, 10], [3, 3, 3]),
        ([10, 10, 10, 10], [(4, 5), (4, 5), (4, 5)], [1, 1, 1, 10], [4, 4, 4]),

        # 4D image, 4D roi
        ([10, 10, 10, 10], [(0, 10), (0, 10), (0, 10),
                            (0, 10)], [10, 10, 10, 10], [0, 0, 0]),
        ([10, 10, 10, 10], [(1, 10), (1, 10), (1, 10),
                            (1, 10)], [9, 9, 9, 9], [1, 1, 1]),
        ([10, 10, 10, 10], [(1, 9), (1, 9), (1, 9), (1, 9)], [8, 8, 8,
                                                              8], [1, 1, 1]),
        ([10, 10, 10, 10], [(3, 5), (3, 5), (3, 5), (3, 5)], [2, 2, 2,
                                                              2], [3, 3, 3]),
        ([10, 10, 10, 10], [(4, 5), (4, 5), (4, 5), (4, 5)], [1, 1,
                                                              1], [4, 4, 4]),

        # expanding FOV
        ([10, 10, 10], [(-5, 15), (0, 10), (0, 10)], [20, 10, 10], [-5, 0, 0]),
        ([10, 10, 10], [(-5, 15), (-5, 15), (0, 10)], [20, 20,
                                                       10], [-5, -5, 0]),
        ([10, 10, 10], [(-5, 15), (-5, 10), (-5, 15)], [20, 15,
                                                        20], [-5, -5, -5]),
        ([10, 10, 10], [(-5, 15), (3, 7), (0, 10)], [20, 4, 10], [-5, 3, 0]),
    ]

    for inshape, bounds, outshape, offset in tests:
        data = np.random.randint(1, 10, inshape)
        image = fslimage.Image(data, xform=np.eye(4))

        result = roi.roi(image, bounds)

        expaff = np.eye(4)
        expaff[:3, 3] = offset

        assert np.all(list(result.shape) == list(outshape))
        assert np.all(np.isclose(result.voxToWorldMat, expaff))

        oldslc = []
        newslc = []

        for (lo, hi), oldlen in zip(bounds, inshape):
            oldslc.append(slice(max(lo, 0), min(hi, oldlen)))

        if len(oldslc) < len(inshape):
            for d in inshape[len(oldslc):]:
                oldslc.append(slice(0, d))

        for (lo, hi), slc in zip(bounds, oldslc):
            if lo < 0: newlo = -lo
            else: newlo = 0

            oldlen = slc.stop - slc.start

            newslc.append(slice(newlo, newlo + oldlen))

        if len(newslc) > len(outshape):
            newslc = newslc[:len(outshape)]

        assert np.all(data[tuple(oldslc)] == result.data[tuple(newslc)])

    # Error on:
    #  - not enough bounds
    #  - too many bounds
    #  - hi >= lo
    data = np.random.randint(1, 10, (10, 10, 10))
    image = fslimage.Image(data, xform=np.eye(4))
    with pytest.raises(ValueError):
        roi.roi(image, [(0, 10), (0, 10)])
    with pytest.raises(ValueError):
        roi.roi(image, [(0, 10), (0, 10), (0, 10), (0, 10)])
    with pytest.raises(ValueError):
        roi.roi(image, [(5, 5), (0, 10), (0, 10)])
    with pytest.raises(ValueError):
        roi.roi(image, [(6, 5), (0, 10), (0, 10)])
    with pytest.raises(ValueError):
        roi.roi(image, [(0, 10), (5, 5), (0, 10)])
    with pytest.raises(ValueError):
        roi.roi(image, [(0, 10), (6, 5), (0, 10)])
    with pytest.raises(ValueError):
        roi.roi(image, [(0, 10), (0, 10), (5, 5)])
    with pytest.raises(ValueError):
        roi.roi(image, [(0, 10), (0, 10), (6, 5)])
Beispiel #4
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))
Beispiel #5
0
def copyImage(overlayList,
              displayCtx,
              overlay,
              createMask=False,
              copy4D=True,
              copyDisplay=True,
              name=None,
              roi=None,
              channel=None,
              data=None):
    """Creates a copy of the given :class:`.Image` overlay, and inserts it
    into the :class:`.OverlayList`.

    :arg overlayList: The :class:`.OverlayList`.

    :arg displayCtx:  The :class:`.DisplayContext`.

    :arg overlay:     The :class:`.Image` to be copied.

    :arg createMask:  If ``True``, the copy will be an empty ``Image`` the
                      same shape as the ``overlay``.

    :arg copy4D:      If ``True``, and the ``overlay`` is 4D, the copy will
                      also be 4D. Otherwise, the current 3D voluem is copied.

    :arg copyDisplay: If ``True``, the copy will inherit the display settings
                      of the ``overlay``. Otherwise, the copy will be
                      initialised  with default display settings.

    :arg name:        If provided, will be used as the :attr:`.Display.name`
                      of the copy. Otherwise the copy will be given a name.

    :arg roi:         If provided, the copy will be cropped to the low/high
                      voxel bounds specified in the image. Must be a sequence
                      of tuples, containing the low/high bounds for each voxel
                      dimension. For 4D images, the bounds for the fourth
                      dimension are optional. If ``roi`` specifies more than
                      three dimensions, but ``copy4D is False``, the additional
                      dimensions are ignored.

    :arg channel:     If provided, and if the image is complex or multi-valued
                      (RGB(A)), only this channel is copied. Otherwise the
                      image and data type are copied as-is. For complex images,
                      valid values are ``'real'`` or ``'imag'``; for multi-
                      valued images, valid values are ``'R'``, ``'G'``, ``'B'``
                      or ``'A'``.

    :arg data:        If provided, is used as the image data for the new copy.
                      Must match the shape dictated by the other arguments
                      (i.e. ``copy4D`` and ``roi``). If ``data`` is provided,
                      the ``createMask`` argument is ignored.

    :returns:         The newly created :class:`.Image` object.


    Note that the ``roi`` and ``copy4D`` options do not support images with
    more than four dimensions.
    """

    ovlIdx = overlayList.index(overlay)
    opts = displayCtx.getOpts(overlay)
    is4D = len(overlay.shape) > 3
    isROI = roi is not None
    copy4D = copy4D and is4D
    createMask = createMask and (data is None)

    # Initialise the roi indices if one wasn't
    # provided - we will use the indices
    # regardless of whether an ROI was passed
    # in or not
    if roi is None:
        roi = [(0, s) for s in overlay.shape]

    # Adjust the roi to index a
    # specific volume if requested
    if not copy4D:
        roi = list(roi[:3]) + [(i, i + 1) for i in opts.index()[3:]]

    if name is None:
        name = '{}_copy'.format(overlay.name)

    # If an ROI is not specified, we slice
    # the image data, either including all
    # volumes, or the currently selected volume
    if not isROI:
        slc = tuple(slice(lo, hi) for lo, hi in roi)
        imgdata = overlay[slc]
        xform = overlay.voxToWorldMat

    # if an ROI is specified, we use the
    # fsl.utils.image.roi module to generate
    # an ROI and the adjusted voxel-to-world
    # affine
    else:
        roi = imgroi.roi(overlay, roi)
        imgdata = roi.data
        xform = roi.voxToWorldMat

    if channel is not None:
        if overlay.iscomplex:
            if channel == 'real': imgdata = imgdata.real
            elif channel == 'imag': imgdata = imgdata.imag
            else:
                raise ValueError('Invalid value for channel: '
                                 '{}'.format(channel))
        elif overlay.nvals > 1:
            if channel not in 'RGBA':
                raise ValueError('Invalid value for channel: '
                                 '{}'.format(channel))
            imgdata = imgdata[channel]

    if createMask:
        data = np.zeros(imgdata.shape, dtype=imgdata.dtype)
    elif data is None:
        data = np.copy(imgdata)

    copy = fslimage.Image(data, xform=xform, header=overlay.header, name=name)

    overlayList.insert(ovlIdx + 1, copy)

    # Copy the Display/DisplayOpts settings
    if copyDisplay:

        # Don't override the name
        # that we set above
        dispexcl = ('name', )

        # And don't clobber the transform, and related,
        # properties, as it is (typically) automatically
        # controlled via the DisplayContext.displaySpace
        optexcl = ('transform', 'bounds')

        copyDisplayProperties(displayCtx,
                              overlay,
                              copy,
                              displayExclude=dispexcl,
                              optExclude=optexcl)

    return copy