Example #1
0
def test_3D_len_one_indexing(shape=None, img=None):

    # Testing ImageWrapper for a 3D image with
    # a third dimension of length 1 - it should
    # look like a 3D image, but should still
    # accept (valid) 2D slicing.

    if shape is None: shape = (20, 20, 1)
    elif len(shape) < 3: shape = tuple(list(shape) + [1])

    if img is None:
        data = np.random.random(shape)
        nibImg = nib.Nifti1Image(data, np.eye(4))
        img = imagewrap.ImageWrapper(nibImg, loadData=True)

    test_3D_indexing(shape, img)

    assert type(img[0, 0, :]) == np.ndarray
    assert type(img[0, 0]) == np.ndarray
    assert type(img[0, 0, 0]) == np.float64

    mask = np.zeros(shape[:2], dtype=np.bool)
    mask[0, 0] = True

    assert type(img[mask]) == np.ndarray
    assert img[mask].shape == (1, )

    mask = np.zeros(shape, dtype=np.bool)
    mask[0, 0, 0] = True

    assert type(img[mask]) == np.ndarray
    assert img[mask].shape == (1, )
Example #2
0
def _test_ImageWrapper_read(niters, seed, threaded):

    for _ in range(niters):

        # Generate an image with a number of volumes
        ndims = random.choice((2, 3, 4)) - 1
        shape = np.random.randint(5, 60, size=ndims + 1)
        shape[-1] = np.random.randint(5, 15)
        nvols = shape[-1]

        data = np.zeros(shape)

        # The data range of each volume
        # increases sequentially
        data[..., 0] = np.random.randint(-5, 6, shape[:-1])
        volRanges = [(np.min(data[..., 0]), np.max(data[..., 0]))]

        for vol in range(1, nvols):
            data[..., vol] = data[..., 0] * (vol + 1)
            volRanges.append((np.min(data[..., vol]), np.max(data[..., vol])))

        img = nib.Nifti1Image(data, np.eye(4))
        wrapper = imagewrap.ImageWrapper(img,
                                         loadData=False,
                                         threaded=threaded)

        # We're going to access data volumes
        # through the image wrapper with a
        # bunch of random volume orderings.

        for _ in range(niters):

            ordering = list(range(nvols))
            random.shuffle(ordering)

            ranges = [volRanges[o] for o in ordering]

            wrapper.reset()

            assert wrapper.dataRange == (0.0, 0.0)

            for j, (vol, r) in enumerate(zip(ordering, ranges)):

                # Access the volume
                if len(data.shape) >= 3: wrapper[..., vol]
                else: wrapper[:, vol, 0]

                _ImageWraper_busy_wait(wrapper, vol)

                # The current known data range
                # should be the min/max of
                # all acccessed volumes so far
                expMin = min([r[0] for r in ranges[:j + 1]])
                expMax = max([r[1] for r in ranges[:j + 1]])

                assert wrapper.dataRange == (expMin, expMax)

                if j < nvols - 1: assert not wrapper.covered
                else: assert wrapper.covered
Example #3
0
def test_4D_indexing(shape=None, img=None):

    if shape is None:
        shape = (20, 21, 22, 23)

    if img is None:

        data = np.random.random(shape)
        nibImg = nib.Nifti1Image(data, affine=np.eye(4))
        img = imagewrap.ImageWrapper(nibImg, loadData=True)

    assert tuple(img[:].shape) == tuple(shape)
    assert tuple(img[:, :].shape) == tuple(shape)
    assert tuple(img[:, :, :].shape) == tuple(shape)
    assert tuple(img[:, :, :, :].shape) == tuple(shape)

    assert tuple(img[:, 0, 0, 0].shape) == (shape[0], )
    assert tuple(img[0, :, 0, 0].shape) == (shape[1], )
    assert tuple(img[0, 0, :, 0].shape) == (shape[2], )
    assert tuple(img[0, 0, 0, :].shape) == (shape[3], )

    assert tuple(img[0, :, :, :].shape) == (shape[1], shape[2], shape[3])
    assert tuple(img[:, 0, :, :].shape) == (shape[0], shape[2], shape[3])
    assert tuple(img[:, :, 0, :].shape) == (shape[0], shape[1], shape[3])
    assert tuple(img[:, :, :, 0].shape) == (shape[0], shape[1], shape[2])

    assert type(img[0, 0, 0, 0]) == np.float64

    mask1 = np.zeros(shape, dtype=np.bool)

    mask1[0, 0, 0, 0] = True
    mask1[1, 0, 0, 0] = True

    assert tuple(img[mask1].shape) == (2, )

    img[0, 0, 0, 0] = 999

    img[:, 0, 0, 0] = [999] * shape[0]
    img[0, :, 0, 0] = [999] * shape[1]
    img[0, 0, :, 0] = [999] * shape[2]
    img[0, 0, 0, :] = [999] * shape[3]

    img[:, 0, 0, 0] = np.array([999] * shape[0])
    img[0, :, 0, 0] = np.array([999] * shape[1])
    img[0, 0, :, 0] = np.array([999] * shape[2])
    img[0, 0, 0, :] = np.array([999] * shape[3])

    img[0, :, :, :] = np.ones((shape[1], shape[2], shape[3]))
    img[:, 0, :, :] = np.ones((shape[0], shape[2], shape[3]))
    img[:, :, 0, :] = np.ones((shape[0], shape[1], shape[3]))
    img[:, :, :, 0] = np.ones((shape[0], shape[1], shape[2]))

    img[0, :, :, :] = [[[999] * shape[1]] * shape[2]] * shape[3]
    img[:, 0, :, :] = [[[999] * shape[0]] * shape[2]] * shape[3]
    img[:, :, 0, :] = [[[999] * shape[0]] * shape[1]] * shape[3]
    img[:, :, :, 0] = [[[999] * shape[0]] * shape[1]] * shape[2]
Example #4
0
def test_2D_indexing():

    # Testing ImageWrapper for a 2D image -
    # it should look just like a 3D image
    # (the same as is tested above).

    shape = (20, 20)
    data = np.random.random(shape[:2])
    nibImg = nib.Nifti1Image(data, np.eye(4))
    img = imagewrap.ImageWrapper(nibImg, loadData=True)

    test_3D_len_one_indexing(shape, img)
Example #5
0
def test_3D_indexing(shape=None, img=None):

    # Test that a 3D image looks like a 3D image

    if shape is None: shape = (21, 22, 23)
    elif len(shape) == 2: shape = tuple(list(shape) + [1])

    if img is None:
        data = np.random.random(shape)
        nibImg = nib.Nifti1Image(data, np.eye(4))
        img = imagewrap.ImageWrapper(nibImg, loadData=True)

    assert tuple(img[:].shape) == tuple(shape)
    assert tuple(img[:, :].shape) == tuple(shape)
    assert tuple(img[:, :, :].shape) == tuple(shape)
    assert tuple(img[:, 0, 0].shape) == (shape[0], )
    assert tuple(img[0, :, 0].shape) == (shape[1], )
    assert tuple(img[0, 0, :].shape) == (shape[2], )
    assert tuple(img[0, :, :].shape) == (shape[1], shape[2])
    assert tuple(img[:, 0, :].shape) == (shape[0], shape[2])
    assert tuple(img[:, :, 0].shape) == (shape[0], shape[1])

    assert type(img[0, 0, 0]) == np.float64

    mask1 = np.zeros(shape, dtype=np.bool)

    mask1[0, 0, 0] = True
    mask1[1, 0, 0] = True

    assert tuple(img[mask1].shape) == (2, )

    img[0, 0, 0] = 999
    img[:, 0, 0] = [999] * shape[0]
    img[0, :, 0] = [999] * shape[1]
    img[0, 0, :] = [999] * shape[2]
    img[:, 0, 0] = np.array([999] * shape[0])
    img[0, :, 0] = np.array([999] * shape[1])
    img[0, 0, :] = np.array([999] * shape[2])

    img[0, :, :] = np.ones((shape[1], shape[2]))
    img[:, 0, :] = np.ones((shape[0], shape[2]))
    img[:, :, 0] = np.ones((shape[0], shape[1]))

    img[0, :, :] = [[999] * shape[1]] * shape[2]
    img[:, 0, :] = [[999] * shape[0]] * shape[2]
    img[:, :, 0] = [[999] * shape[0]] * shape[1]
Example #6
0
def test_3D_4D_indexing():

    # Testing ImageWrapper for an image with a
    # trailing fourth dimension of length 1 -
    # it should look like a 3D image, but
    # should still accept (valid) 4D slicing.

    # __getitem__ and __setitem__ on
    #   - 3D index
    #   - 4D index
    #   - 3D boolean array
    #   - 4D boolean array
    #
    padShape = (21, 22, 23, 1)
    shape = padShape[:3]

    data = np.random.random(shape)
    nibImg = nib.Nifti1Image(data, np.eye(4))
    img = imagewrap.ImageWrapper(nibImg, loadData=True)

    test_3D_indexing(shape, img)

    assert tuple(img[:, :, :, :].shape) == tuple(shape)

    assert tuple(img[:, 0, 0, 0].shape) == (shape[0], )
    assert tuple(img[:, 0, 0, :].shape) == (shape[0], )

    assert tuple(img[:, :, 0, 0].shape) == (shape[0], shape[1])
    assert tuple(img[:, :, 0, :].shape) == (shape[0], shape[1])

    assert type(img[0, 0, 0, 0]) == np.float64
    assert type(img[0, 0, 0, :]) == np.float64

    mask = np.zeros(padShape, dtype=np.bool)
    mask[0, 0, 0, 0] = True

    assert type(img[mask]) == np.ndarray
    assert img[mask].shape == (1, )
Example #7
0
def _test_ImageWrapper_write_different_volume(niters, seed, threaded):

    for _ in range(niters):

        # Generate an image with several volumes.
        ndims = random.choice((2, 3, 4)) - 1
        nvols = np.random.randint(10, 40)
        shape = np.random.randint(5, 60, size=ndims + 1)
        shape[-1] = nvols

        data = np.zeros(shape)

        # The data range of each volume
        # increases sequentially
        data[..., 0] = np.random.randint(-5, 6, shape[:-1])
        for vol in range(1, nvols):
            data[..., vol] = data[..., 0] * (vol + 1)

        # Generate a random coverage
        fullcov = random_coverage(shape)
        cov = np.copy(fullcov)

        # Choose some consecutive volumes
        # to limit that coverage to.
        while True:
            covvlo = np.random.randint(0, nvols - 1)
            covvhi = np.random.randint(covvlo + 1, nvols + 1)

            # Only include up to 4
            # volumes in the coverage
            if covvhi - covvlo <= 3:
                break

        for v in range(nvols):
            if v < covvlo or v >= covvhi:
                cov[..., v] = np.nan

        covlo, covhi = coverageDataRange(data, cov)

        print('Coverage: {} [{} - {}]'.format(
            [(lo, hi) for lo, hi in cov[:, :, covvlo].T], covvlo, covvhi))

        # Now, we'll simulate some writes
        # on volumes that are not in the
        # coverage
        for _ in range(niters):

            # Generate a slice, making
            # sure that the slice covers
            # at least one element
            while True:
                slices = random_slices(fullcov, shape,
                                       random.choice(('out', 'in', 'overlap')))

                # print(slices)

                # Clobber the slice volume range
                # so it does not overlap with the
                # coverage volume range
                while True:
                    vlo = np.random.randint(0, nvols)
                    vhi = np.random.randint(vlo + 1, nvols + 1)

                    if vhi < covvlo or vlo > covvhi:
                        break

                slices[-1] = vlo, vhi

                sliceshape = [hi - lo for lo, hi in slices]

                if np.prod(sliceshape) == 0:
                    continue

                sliceobjs = imagewrap.sliceTupleToSliceObj(slices)
                break

            # Calculate what we expect the
            # coverage to be after the write
            expCov = np.copy(cov)
            for vol in range(slices[-1][0], slices[-1][1]):
                expCov[...,
                       vol] = imagewrap.adjustCoverage(expCov[..., vol],
                                                       slices)

            # Test all data range possibilities:
            #  - inside the existing range       (clo < rlo < rhi < chi)
            #  - encompassing the existing range (rlo < clo < chi < rhi)
            #  - Overlapping the existing range  (rlo < clo < rhi < chi)
            #                                    (clo < rlo < chi < rhi)
            #  - Outside of the existing range   (clo < chi < rlo < rhi)
            #                                    (rlo < rhi < clo < chi)

            loRanges = [
                rfloat(covlo, covhi),
                rfloat(covlo - 100, covlo),
                rfloat(covlo - 100, covlo),
                rfloat(covlo, covhi),
                rfloat(covhi, covhi + 100),
                rfloat(covlo - 100, covlo)
            ]

            hiRanges = [
                rfloat(loRanges[0], covhi),
                rfloat(covhi, covhi + 100),
                rfloat(covlo, covhi),
                rfloat(covhi, covhi + 100),
                rfloat(loRanges[4], covhi + 100),
                rfloat(loRanges[5], covlo)
            ]

            # What we expect the range to
            # be after the data write
            expected = [(covlo, covhi), (loRanges[1], hiRanges[1]),
                        (loRanges[2], covhi), (covlo, hiRanges[3]),
                        (covlo, hiRanges[4]), (loRanges[5], covhi)]

            for rlo, rhi, (elo, ehi) in zip(loRanges, hiRanges, expected):

                img = nib.Nifti1Image(np.copy(data), np.eye(4))
                wrapper = imagewrap.ImageWrapper(img, threaded=threaded)
                applyCoverage(wrapper, cov)

                oldLo, oldHi = wrapper.dataRange

                newData = np.linspace(rlo, rhi, np.prod(sliceshape))
                newData = newData.reshape(sliceshape)

                if np.prod(sliceshape) == 1:
                    ehi = max(newData.max(), oldHi)

                wrapper[tuple(sliceobjs)] = newData
                _ImageWraper_busy_wait(wrapper)

                newLo, newHi = wrapper.dataRange

                for vol in range(nvols):
                    np.all(wrapper.coverage(vol) == expCov[..., vol])

                print('Old range:      {} - {}'.format(oldLo, oldHi))
                print('Newdata range:  {} - {}'.format(newData.min(),
                                                       newData.max()))
                print('Expected range: {} - {}'.format(elo, ehi))
                print('New range:      {} - {}'.format(newLo, newHi))

                assert np.isclose(newLo, elo)
                assert np.isclose(newHi, ehi)
Example #8
0
def _test_ImageWrapper_write_in_overlap(niters, seed, threaded):

    # Generate a bunch of random coverages
    for _ in range(niters):

        # Generate an image with just two volumes. We're only
        # testing within-volume modifications here.
        ndims = random.choice((2, 3, 4)) - 1
        shape = np.random.randint(5, 60, size=ndims + 1)
        shape[-1] = np.random.randint(2, 3)
        nvols = shape[-1]

        data = np.zeros(shape)

        # The data range of each volume
        # increases sequentially
        data[..., 0] = np.random.randint(-5, 6, shape[:-1])
        for vol in range(1, nvols):
            data[..., vol] = data[..., 0] * (vol + 1)

        # Generate a random coverage
        cov = random_coverage(shape, vol_limit=1)

        print('Shape:    {}'.format(shape))
        print('Coverage: {}'.format(cov))
        print('Data:     {}'.format(data))

        # Now, we'll simulate some writes
        # which are contained within, or
        # overlap with, the initial coverage
        for _ in range(niters):

            # Generate some slices outside
            # of the coverage area, making
            # sure that the slice covers
            # at least one element
            while True:
                slices = random_slices(cov, shape,
                                       random.choice(('in', 'overlap')))
                slices[-1] = [0, 1]
                sliceshape = [hi - lo for lo, hi in slices]

                if np.prod(sliceshape) == 0:
                    continue

                sliceobjs = imagewrap.sliceTupleToSliceObj(slices)
                sliceobjs = tuple(list(sliceobjs[:-1]) + [0])
                sliceshape = sliceshape[:-1]
                break

            # Expected wrapper coverage after the
            # write is the union of the original
            # coverage and the write slice.
            expCov = imagewrap.adjustCoverage(cov[..., 0], slices)

            for _ in range(10):

                rlo = rfloat(data.min() - 100, data.max() + 100)
                rhi = rfloat(rlo, data.max() + 100)

                if np.prod(sliceshape) == 1:
                    rhi = rlo

                img = nib.Nifti1Image(np.copy(data), np.eye(4))
                wrapper = imagewrap.ImageWrapper(img, threaded=threaded)
                applyCoverage(wrapper, cov)

                newData = np.linspace(rlo, rhi, np.prod(sliceshape))
                newData = newData.reshape(sliceshape)

                print('Old coverage:      {}'.format(cov[..., 0]))
                print('Slice:             {}'.format(sliceobjs[:-1]))
                print('Expected coverage: {}'.format(expCov))
                print('Old range:         {} - {}'.format(*wrapper.dataRange))
                print('New data range:    {} - {}'.format(
                    newData.min(), newData.max()))

                # We figure out the expected data
                # range by creating a copy of the
                # data, and doing the same write
                expData = np.copy(data[..., 0])
                expData[sliceobjs[:-1]] = newData

                # Then calcultaing the min/max
                # on this copy
                expCovSlice = [slice(int(lo), int(hi)) for lo, hi in expCov.T]

                expLo = expData[expCovSlice].min()
                expHi = expData[expCovSlice].max()

                wrapper[tuple(sliceobjs)] = newData
                _ImageWraper_busy_wait(wrapper)

                newCov = wrapper.coverage(0)
                newLo, newHi = wrapper.dataRange

                print('Expected range:    {} - {}'.format(expLo, expHi))
                print('New range:         {} - {}'.format(newLo, newHi))
                print('Slice min/max:     {} - {}'.format(
                    img.get_data()[tuple(sliceobjs)].min(),
                    img.get_data()[tuple(sliceobjs)].max()))
                print('Data min/max:      {} - {}'.format(
                    img.get_data().min(),
                    img.get_data().max()))

                assert np.all(newCov == expCov)

                assert np.isclose(newLo, expLo)
                assert np.isclose(newHi, expHi)
Example #9
0
def _test_ImageWrapper_write_out(niters, seed, threaded):
    # This is HORRIBLE

    loop = 0

    # Generate a bunch of random coverages
    for _ in range(niters):

        # Generate an image with just two volumes. We're only
        # testing within-volume modifications here.
        ndims = random.choice((2, 3, 4)) - 1
        shape = np.random.randint(5, 60, size=ndims + 1)
        shape[-1] = np.random.randint(2, 3)
        nvols = shape[-1]

        data = np.zeros(shape)

        # The data range of each volume
        # increases sequentially
        data[..., 0] = np.random.randint(-5, 6, shape[:-1])
        for vol in range(1, nvols):
            data[..., vol] = data[..., 0] * (vol + 1)

        # Generate a random coverage
        cov = random_coverage(shape, vol_limit=1)

        img = nib.Nifti1Image(data, np.eye(4))
        wrapper = imagewrap.ImageWrapper(img, threaded=threaded)
        applyCoverage(wrapper, cov)
        clo, chi = wrapper.dataRange

        loop += 1

        # Now, we'll simulate some writes
        # outside of the coverage area.
        for _ in range(niters):

            # Generate some slices outside
            # of the coverage area, making
            # sure that the slice covers
            # at least one element
            while True:
                slices = random_slices(cov, shape, 'out')
                slices[-1] = [0, 1]
                sliceshape = [hi - lo for lo, hi in slices]

                if np.prod(sliceshape) == 0:
                    continue

                sliceobjs = imagewrap.sliceTupleToSliceObj(slices)
                sliceobjs = tuple(list(sliceobjs[:-1]) + [0])
                sliceshape = sliceshape[:-1]
                break

            # print('---------------')
            # print('Slice {}'.format(slices))

            # Expected wrapper coverage after the write
            expCov = imagewrap.adjustCoverage(cov[..., 0], slices)

            # Figure out the data range of the
            # expanded coverage (the original
            # coverage expanded to include this
            # slice).
            elo, ehi = coverageDataRange(data, cov, slices)

            # Test all data range possibilities:
            #  - inside the existing range       (clo < rlo < rhi < chi)
            #  - encompassing the existing range (rlo < clo < chi < rhi)
            #  - Overlapping the existing range  (rlo < clo < rhi < chi)
            #                                    (clo < rlo < chi < rhi)
            #  - Outside of the existing range   (clo < chi < rlo < rhi)
            #                                    (rlo < rhi < clo < chi)
            loRanges = [
                rfloat(clo, chi),
                rfloat(elo - 100, elo),
                rfloat(elo - 100, elo),
                rfloat(clo, chi),
                rfloat(ehi, ehi + 100),
                rfloat(elo - 100, elo)
            ]

            hiRanges = [
                rfloat(loRanges[0], chi),
                rfloat(ehi, ehi + 100),
                rfloat(clo, chi),
                rfloat(ehi, ehi + 100),
                rfloat(loRanges[4], ehi + 100),
                rfloat(loRanges[5], elo)
            ]

            for rlo, rhi in zip(loRanges, hiRanges):

                img = nib.Nifti1Image(np.copy(data), np.eye(4))
                wrapper = imagewrap.ImageWrapper(img)
                applyCoverage(wrapper, cov)

                # print('ndims', ndims)
                # print('sliceshape', sliceshape)
                # print('sliceobjs', sliceobjs)

                newData = np.linspace(rlo, rhi, np.prod(sliceshape))
                newData = newData.reshape(sliceshape)

                # Make sure that the expected low/high values
                # are present in the data being written

                # print('Writing data (shape: {})'.format(newData.shape))

                oldCov = wrapper.coverage(0)

                wrapper[tuple(sliceobjs)] = newData
                _ImageWraper_busy_wait(wrapper)

                expLo, expHi = coverageDataRange(img.get_data(), cov, slices)
                newLo, newHi = wrapper.dataRange

                # print('Old    range: {} - {}'.format(clo,   chi))
                # print('Sim    range: {} - {}'.format(rlo,   rhi))
                # print('Exp    range: {} - {}'.format(expLo, expHi))
                # print('NewDat range: {} - {}'.format(newData.min(), newData.max()))
                # print('Data   range: {} - {}'.format(data.min(),   data.max()))
                # print('Expand range: {} - {}'.format(elo, ehi))
                # print('New    range: {} - {}'.format(newLo, newHi))

                newCov = wrapper.coverage(0)
                # print('Old coverage:      {}'.format(oldCov))
                # print('New coverage:      {}'.format(newCov))
                # print('Expected coverage: {}'.format(expCov))
                # print()
                # print()

                assert np.all(newCov == expCov)

                assert np.isclose(newLo, expLo)
                assert np.isclose(newHi, expHi)