Skip to content
Snippets Groups Projects
Commit 9a99c71d authored by Paul McCarthy's avatar Paul McCarthy
Browse files

test_image module rewritten so it generates its own data, instead of relying

on an existing data set.
parent 5d063e35
No related branches found
No related tags found
No related merge requests found
...@@ -60,24 +60,14 @@ def cleardir(dir): ...@@ -60,24 +60,14 @@ def cleardir(dir):
elif op.isdir(f): shutil.rmtree(f) elif op.isdir(f): shutil.rmtree(f)
def make_random_image(filename, dims=(10, 10, 10), affine=None): def make_random_image(filename, dims=(10, 10, 10)):
"""Creates a NIFTI image with random data, returns the hash of said data. """Creates a NIFTI1 image with random data, saves and
returns it.
""" """
if affine is None: data = np.array(np.random.random(dims) * 100, dtype=np.float32)
affine = np.eye(4) img = nib.Nifti1Image(data, np.eye(4))
data = np.random.random(dims)
img = nib.Nifti1Image(data, affine)
nib.save(img, filename) nib.save(img, filename)
return hash(data.tobytes()) return img
def check_image_hash(filename, datahash):
"""Checks that the given NIFTI image matches the given hash.
"""
img = nib.load(filename)
assert hash(img.get_data().tobytes()) == datahash
#!/usr/bin/env python #!/usr/bin/env python
# #
# test_image.py - # test_image.py - Unit tests for the fsl.data.image module.
# #
# Author: Paul McCarthy <pauldmccarthy@gmail.com> # Author: Paul McCarthy <pauldmccarthy@gmail.com>
# #
"""Unit tests for the fsl.data.image module. """
import os.path as op
import os.path as op
import itertools as it
import tempfile
import shutil
import glob
import pytest import pytest
import glob
import numpy as np import numpy as np
import numpy.linalg as npla import numpy.linalg as npla
...@@ -20,17 +25,73 @@ import fsl.data.constants as constants ...@@ -20,17 +25,73 @@ import fsl.data.constants as constants
import fsl.data.image as fslimage import fsl.data.image as fslimage
import fsl.utils.path as fslpath import fsl.utils.path as fslpath
from . import make_random_image
from . import make_dummy_file
def make_image(filename,
imgtype=1,
dims=(10, 10, 10),
pixdims=(1, 1, 1),
dtype=np.float32):
"""Convenience function which makes an image containing random data.
Saves and returns the nibabel object.
imgtype == 0: ANALYZE
imgtype == 1: NIFTI1
imgtype == 2: NIFTI2
"""
if imgtype == 0: filename = '{}.img'.format(filename)
else: filename = '{}.nii'.format(filename)
if imgtype == 0: hdr = nib.AnalyzeHeader()
elif imgtype == 1: hdr = nib.Nifti1Header()
elif imgtype == 2: hdr = nib.Nifti2Header()
pixdims = pixdims[:len(dims)]
hdr.set_data_dtype(dtype)
hdr.set_data_shape(dims)
hdr.set_zooms([abs(p) for p in pixdims])
xform = np.eye(4)
for i, p in enumerate(pixdims):
xform[i, i] = p
data = np.array(np.random.random(dims) * 100, dtype=dtype)
if imgtype == 0: img = nib.AnalyzeImage(data, xform, hdr)
elif imgtype == 1: img = nib.Nifti1Image( data, xform, hdr)
elif imgtype == 2: img = nib.Nifti2Image( data, xform, hdr)
nib.save(img, filename)
return img
# Need to test: # Need to test:
# - Create image from file name (create a temp .nii.gz)
# - Create image from existing nibabel image # - Create image from existing nibabel image
# - Create image from numpy array # - Create image from numpy array
# - calcRange # - calcRange
# - loadData # - loadData
def test_load(testdir):
assert testdir is not None def test_load():
"""Create an Image from a file name. """
# notnifti.nii.gz is just a plain text
# file, the rest are NIFTI images
toCreate = ['compressed.nii.gz',
'uncompressed.nii',
'img_hdr_pair.img',
'compressed_img_hdr_pair.img.gz',
'ambiguous.nii',
'ambiguous.img',
'ambiguous.img.gz',
'notnifti.nii.gz']
shouldPass = ['compressed', shouldPass = ['compressed',
'compressed.nii.gz', 'compressed.nii.gz',
...@@ -52,48 +113,96 @@ def test_load(testdir): ...@@ -52,48 +113,96 @@ def test_load(testdir):
('ambiguous', fslpath.PathError), ('ambiguous', fslpath.PathError),
('notnifti', ImageFileError), ('notnifti', ImageFileError),
('notnifti.nii.gz', ImageFileError)] ('notnifti.nii.gz', ImageFileError)]
# Not raising an error means the test passes
for fname in shouldPass:
fslimage.Image(op.join(testdir, 'nifti_formats', fname))
# These should raise an error testdir = tempfile.mkdtemp()
for fname, exc in shouldRaise:
with pytest.raises(exc):
fslimage.Image(op.join(testdir, 'nifti_formats', fname))
for f in toCreate:
if f.startswith('notnifti'):
make_dummy_file(op.join(testdir, f))
else:
make_random_image(op.join(testdir, f))
# Not raising an error means the test passes
try:
for fname in shouldPass:
fslimage.Image(op.join(testdir, fname))
# These should raise an error
for fname, exc in shouldRaise:
with pytest.raises(exc):
fslimage.Image(op.join(testdir, fname))
finally:
shutil.rmtree(testdir)
def test_Image_atts_analyze(): _test_Image_atts(0)
def test_Image_atts_nifti1(): _test_Image_atts(1)
def test_Image_atts_nifti2(): _test_Image_atts(2)
def _test_Image_atts(imgtype):
"""Test that basic Nifti/Image attributes are correct. """
testdir = tempfile.mkdtemp()
allowedExts = fslimage.ALLOWED_EXTENSIONS
fileGroups = fslimage.FILE_GROUPS
# (file, dims, pixdims, dtype)
dtypes = [np.uint8, np.int16, np.int32, np.float32, np.double]
dims = [(10, 1, 1),
(1, 10, 1),
(1, 1, 10),
(10, 10, 1),
(10, 1, 10),
(1, 10, 10),
(10, 10, 10),
(1, 1, 1, 5),
(10, 10, 1, 5),
(10, 1, 10, 5),
(1, 10, 10, 5),
(10, 10, 10, 5)]
pixdims = [(0.5, 0.5, 0.5, 2),
(1.0, 1.0, 1.0, 2),
(2.0, 2.0, 2.0, 2),
(1.0, 5.0, 1.0, 3)]
tests = list(it.product(dims, pixdims, dtypes))
paths = ['test{:03d}'.format(i) for i in range(len(tests))]
for path, (dims, pixdims, dtype) in zip(paths, tests):
ndims = len(dims)
pixdims = pixdims[:ndims]
def test_Image_atts(testdir): path = op.abspath(op.join(testdir, path))
make_image(path, imgtype, dims, pixdims, dtype)
allowedExts = fslimage.ALLOWED_EXTENSIONS try:
# (file, dims, pixdims) for path, (dims, pixdims, dtype) in zip(paths, tests):
tests = [
('MNI152_T1_0.5mm', (364, 436, 364), (0.5, 0.5, 0.5), np.uint8),
('MNI152_T1_1mm', (182, 218, 182), (1.0, 1.0, 1.0), np.int16),
('MNI152_T1_2mm', (91, 109, 91), (2.0, 2.0, 2.0), np.int16),
('MNI152_T1_2mm_4D', (91, 109, 91, 5), (2.0, 2.0, 2.0, 1.0), np.int16),
(op.join('nifti2D', 'MNI152_T1_2mm_sliceXY'), (91, 109, 1), (2.0, 2.0, 2.0), np.int16),
(op.join('nifti2D', 'MNI152_T1_2mm_sliceXZ'), (91, 1, 91), (2.0, 2.0, 2.0), np.int16),
(op.join('nifti2D', 'MNI152_T1_2mm_sliceYZ'), (1, 109, 91), (2.0, 2.0, 2.0), np.int16)]
for path, dims, pixdims, dtype in tests: ndims = len(dims)
pixdims = pixdims[:ndims]
path = op.abspath(op.join(testdir, path)) path = op.abspath(op.join(testdir, path))
i = fslimage.Image(path) i = fslimage.Image(path)
assert tuple(i.shape) == tuple(dims) assert tuple(i.shape) == tuple(dims)
assert tuple(i.pixdim) == tuple(pixdims) assert tuple(i.pixdim) == tuple(pixdims)
assert tuple(i.nibImage.shape) == tuple(dims) assert tuple(i.nibImage.shape) == tuple(dims)
assert tuple(i.nibImage.header.get_zooms()) == tuple(pixdims) assert tuple(i.nibImage.header.get_zooms()) == tuple(pixdims)
assert i.dtype == dtype assert i.dtype == dtype
assert i.name == op.basename(path) assert i.name == op.basename(path)
assert i.dataSource == fslpath.addExt(path, allowedExts, mustExist=True) assert i.dataSource == fslpath.addExt(path,
allowedExts=allowedExts,
mustExist=True,
fileGroups=fileGroups)
finally:
shutil.rmtree(testdir)
def test_looksLikeImage(): def test_looksLikeImage():
"""Test the looksLikeImage function. """
# (file, expected) # (file, expected)
tests = [ tests = [
...@@ -111,9 +220,22 @@ def test_looksLikeImage(): ...@@ -111,9 +220,22 @@ def test_looksLikeImage():
assert fslimage.looksLikeImage(path) == expected assert fslimage.looksLikeImage(path) == expected
def test_addExt(testdir): def test_addExt():
"""Test the addExt function. """
default = fslimage.defaultExt() default = fslimage.defaultExt()
testdir = tempfile.mkdtemp()
toCreate = [
'compressed.nii.gz',
'uncompressed.nii',
'img_hdr_pair.img',
'compressed_img_hdr_pair.img.gz',
'ambiguous.nii',
'ambiguous.nii.gz',
'ambiguous.img',
'ambiguous.img.gz'
]
# (file, mustExist, expected) # (file, mustExist, expected)
tests = [ tests = [
...@@ -141,85 +263,170 @@ def test_addExt(testdir): ...@@ -141,85 +263,170 @@ def test_addExt(testdir):
('ambiguous.img.gz', True, 'ambiguous.img.gz'), ('ambiguous.img.gz', True, 'ambiguous.img.gz'),
('ambiguous.hdr.gz', True, 'ambiguous.hdr.gz')] ('ambiguous.hdr.gz', True, 'ambiguous.hdr.gz')]
for path, mustExist, expected in tests: for path in toCreate:
if mustExist: path = op.abspath(op.join(testdir, path))
path = op.join(testdir, 'nifti_formats', path) make_random_image(path)
expected = op.join(testdir, 'nifti_formats', expected)
try:
assert fslimage.addExt(path, mustExist) == expected for path, mustExist, expected in tests:
with pytest.raises(fslimage.PathError): path = op.abspath(op.join(testdir, path))
path = op.join(testdir, 'nifti_formats', 'ambiguous') expected = op.abspath(op.join(testdir, expected))
fslimage.addExt(path, mustExist=True)
assert fslimage.addExt(path, mustExist) == expected
def test_Image_orientation(testdir): # Make sure that an ambiguous path fails
with pytest.raises(fslimage.PathError):
neuro = op.join(testdir, 'dtifit', 'neuro', 'dti_FA') path = op.join(testdir, 'ambiguous')
radio = op.join(testdir, 'dtifit', 'radio', 'dti_FA') fslimage.addExt(path, mustExist=True)
finally:
neuro = fslimage.Image(neuro) shutil.rmtree(testdir)
radio = fslimage.Image(radio)
def test_Image_orientation_analyze_neuro(): _test_Image_orientation(0, 'neuro')
assert neuro.isNeurological() def test_Image_orientation_analyze_radio(): _test_Image_orientation(0, 'radio')
assert not radio.isNeurological() def test_Image_orientation_nifti1_neuro(): _test_Image_orientation(1, 'neuro')
def test_Image_orientation_nifti1_radio(): _test_Image_orientation(1, 'radio')
def test_Image_orientation_nifti2_neuro(): _test_Image_orientation(2, 'neuro')
def test_Image_orientation_nifti2_radio(): _test_Image_orientation(2, 'radio')
def _test_Image_orientation(imgtype, voxorient):
"""Test the Nifti.isNeurological and Nifti.getOrientation methods. """
testdir = tempfile.mkdtemp()
imagefile = op.join(testdir, 'image')
# an image with RAS voxel storage order
# (affine has a positive determinant)
# is said to be "neurological", whereas
# an image with LAS voxel storage order
# (negative determinant - x axis must
# be flipped to bring it into RAS nifti
# world coordinates)) is said to be
# "radiological". The make_image function
# forms the affine from these pixdims.
if voxorient == 'neuro': pixdims = ( 1, 1, 1)
elif voxorient == 'radio': pixdims = (-1, 1, 1)
make_image(imagefile, imgtype, (10, 10, 10), pixdims, np.float32)
image = fslimage.Image(imagefile)
# analyze images are always assumed to be
# stored in radiological (LAS) orientation
if imgtype == 0:
expectNeuroTest = False
expectvox0Orientation = constants.ORIENT_R2L
expectvox1Orientation = constants.ORIENT_P2A
expectvox2Orientation = constants.ORIENT_I2S
elif voxorient == 'neuro':
expectNeuroTest = True
expectvox0Orientation = constants.ORIENT_L2R
expectvox1Orientation = constants.ORIENT_P2A
expectvox2Orientation = constants.ORIENT_I2S
else:
expectNeuroTest = False
expectvox0Orientation = constants.ORIENT_R2L
expectvox1Orientation = constants.ORIENT_P2A
expectvox2Orientation = constants.ORIENT_I2S
try:
assert image.isNeurological() == expectNeuroTest
# All images should have the
# same orientation in the
# world coordinate system
assert image.getOrientation(0, np.eye(4)) == constants.ORIENT_L2R
assert image.getOrientation(1, np.eye(4)) == constants.ORIENT_P2A
assert image.getOrientation(2, np.eye(4)) == constants.ORIENT_I2S
# But the voxel orientation
# is dependent on the affine
affine = image.voxToWorldMat
assert image.getOrientation(0, affine) == expectvox0Orientation
assert image.getOrientation(1, affine) == expectvox1Orientation
assert image.getOrientation(2, affine) == expectvox2Orientation
finally:
shutil.rmtree(testdir)
def test_Image_sqforms_nifti1_normal(): _test_Image_sqforms(1, 1, 1)
def test_Image_sqforms_nifti1_nosform(): _test_Image_sqforms(1, 0, 1)
def test_Image_sqforms_nifti1_noqform(): _test_Image_sqforms(1, 1, 0)
def test_Image_sqforms_nifti1_nosqform(): _test_Image_sqforms(1, 1, 0)
def test_Image_sqforms_nifti2_normal(): _test_Image_sqforms(2, 1, 1)
def test_Image_sqforms_nifti2_nosform(): _test_Image_sqforms(2, 0, 1)
def test_Image_sqforms_nifti2_noqform(): _test_Image_sqforms(2, 1, 0)
def test_Image_sqforms_nifti2_nosqform(): _test_Image_sqforms(2, 1, 0)
def _test_Image_sqforms(imgtype, sformcode, qformcode):
"""Test the Nifti.getXFormCode method, and the voxToWorldMat/worldToVoxMat
attributes for NIFTI images with the given sform/qform code combination.
"""
testdir = tempfile.mkdtemp()
imagefile = op.abspath(op.join(testdir, 'image.nii.gz'))
# For an image with no s/q form, we expect the
# fallback affine - a simple scaling matrix.
# We add some offsets to the actual affine so
# we can distinguish it from the fallback affine.
scaleMat = np.diag([2, 2, 2, 1])
invScaleMat = np.diag([0.5, 0.5, 0.5, 1])
affine = np.array(scaleMat)
affine[:3, 3] = [25, 20, 20]
invAffine = npla.inv(affine)
image = make_image(imagefile, imgtype, (10, 10, 10), (2, 2, 2), np.float32)
image.set_sform(affine, sformcode)
image.set_qform(affine, qformcode)
image.update_header()
nib.save(image, imagefile)
# No s or qform - we expect the fallback affine
if sformcode == 0 and qformcode == 0:
expAffine = scaleMat
invExpAffine = invScaleMat
expCode = constants.NIFTI_XFORM_UNKNOWN
# No sform, but valid qform - expect the affine
elif sformcode == 0 and qformcode > 0:
expAffine = affine
invExpAffine = invAffine
expCode = qformcode
# Valid sform (qform irrelevant) - expect the affine
elif sformcode > 0:
expAffine = affine
invExpAffine = invAffine
expCode = sformcode
image = fslimage.Image(imagefile)
try:
assert np.all(np.isclose(image.voxToWorldMat, expAffine))
assert np.all(np.isclose(image.worldToVoxMat, invExpAffine))
# Both images should have the assert image.getXFormCode() == expCode
# same orientation in the assert image.getXFormCode('sform') == sformcode
# world coordinate system assert image.getXFormCode('qform') == qformcode
assert neuro.getOrientation(0, np.eye(4)) == constants.ORIENT_L2R finally:
assert neuro.getOrientation(1, np.eye(4)) == constants.ORIENT_P2A shutil.rmtree(testdir)
assert neuro.getOrientation(2, np.eye(4)) == constants.ORIENT_I2S
assert radio.getOrientation(0, np.eye(4)) == constants.ORIENT_L2R
assert radio.getOrientation(1, np.eye(4)) == constants.ORIENT_P2A
assert radio.getOrientation(2, np.eye(4)) == constants.ORIENT_I2S
# The radio image should be
# l/r flipped in the voxel
# coordinate system
assert neuro.getOrientation(0, neuro.voxToWorldMat) == constants.ORIENT_L2R
assert neuro.getOrientation(1, neuro.voxToWorldMat) == constants.ORIENT_P2A
assert neuro.getOrientation(2, neuro.voxToWorldMat) == constants.ORIENT_I2S
assert radio.getOrientation(0, radio.voxToWorldMat) == constants.ORIENT_R2L
assert radio.getOrientation(1, radio.voxToWorldMat) == constants.ORIENT_P2A
assert radio.getOrientation(2, radio.voxToWorldMat) == constants.ORIENT_I2S
def test_Image_changeXform_analyze(): _test_Image_changeXform(0)
def test_Image_changeXform_nifti1(): _test_Image_changeXform(1)
def test_Image_changeXform_nifti2(): _test_Image_changeXform(2)
def _test_Image_changeXform(imgtype):
"""Test changing the Nifti.voxToWorldMat attribute. """
def test_Image_sqforms(testdir): testdir = tempfile.mkdtemp()
imagefile = op.join(testdir, 'image')
benchmark = fslimage.Image(op.join(testdir, 'MNI152_T1_2mm.nii.gz')) make_image(imagefile, imgtype)
nosform = fslimage.Image(op.join(testdir, 'MNI152_T1_2mm_nosform.nii.gz'))
noqform = fslimage.Image(op.join(testdir, 'MNI152_T1_2mm_noqform.nii.gz'))
nosqform = fslimage.Image(op.join(testdir, 'MNI152_T1_2mm_nosqform.nii.gz'))
scalemat = np.diag([2, 2, 2, 1])
invScalemat = np.diag([0.5, 0.5, 0.5, 1])
assert np.all(np.isclose(nosform.voxToWorldMat, benchmark.voxToWorldMat))
assert np.all(np.isclose(nosform.worldToVoxMat, benchmark.worldToVoxMat))
assert np.all(np.isclose(noqform.voxToWorldMat, benchmark.voxToWorldMat))
assert np.all(np.isclose(noqform.worldToVoxMat, benchmark.worldToVoxMat))
assert np.all(np.isclose(nosqform.voxToWorldMat, scalemat))
assert np.all(np.isclose(nosqform.worldToVoxMat, invScalemat))
assert benchmark.getXFormCode() == constants.NIFTI_XFORM_MNI_152
assert benchmark.getXFormCode('sform') == constants.NIFTI_XFORM_MNI_152
assert benchmark.getXFormCode('qform') == constants.NIFTI_XFORM_MNI_152
assert nosform .getXFormCode() == constants.NIFTI_XFORM_MNI_152
assert nosform .getXFormCode('sform') == constants.NIFTI_XFORM_UNKNOWN
assert nosform .getXFormCode('qform') == constants.NIFTI_XFORM_MNI_152
assert noqform .getXFormCode() == constants.NIFTI_XFORM_MNI_152
assert noqform .getXFormCode('sform') == constants.NIFTI_XFORM_MNI_152
assert noqform .getXFormCode('qform') == constants.NIFTI_XFORM_UNKNOWN
assert nosqform .getXFormCode() == constants.NIFTI_XFORM_UNKNOWN
assert nosqform .getXFormCode('sform') == constants.NIFTI_XFORM_UNKNOWN
assert nosqform .getXFormCode('qform') == constants.NIFTI_XFORM_UNKNOWN
def test_Image_changeXform(testdir):
img = fslimage.Image(op.join(testdir, 'MNI152_T1_2mm.nii.gz'))
notified = {} notified = {}
...@@ -227,30 +434,59 @@ def test_Image_changeXform(testdir): ...@@ -227,30 +434,59 @@ def test_Image_changeXform(testdir):
notified['xform'] = True notified['xform'] = True
def onSave(*a): def onSave(*a):
notified['save'] = True notified['save'] = True
img = fslimage.Image(imagefile)
img.register('name1', onXform, 'transform') img.register('name1', onXform, 'transform')
img.register('name2', onSave, 'saveState') img.register('name2', onSave, 'saveState')
newXform = np.array([[5, 0, 0, 10], [0, 2, 0, 23], [0, 0, 14, 5], [0, 0, 0, 1]]) newXform = np.array([[5, 0, 0, 10],
[0, 2, 0, 23],
[0, 0, 14, 5],
[0, 0, 0, 1]])
assert img.saveState try:
img.voxToWorldMat = newXform # Image state should initially be saved
assert img.saveState
invx = npla.inv(newXform) if imgtype == 0:
# ANALYZE affine is not editable
with pytest.raises(Exception):
img.voxToWorldMat = newXform
return
assert notified.get('xform', False) img.voxToWorldMat = newXform
assert notified.get('save', False)
assert not img.saveState invx = npla.inv(newXform)
assert np.all(np.isclose(img.voxToWorldMat, newXform)) # Did we get notified?
assert np.all(np.isclose(img.worldToVoxMat, invx)) assert notified.get('xform', False)
assert notified.get('save', False)
assert not img.saveState
# Did the affine get updated?
assert np.all(np.isclose(img.voxToWorldMat, newXform))
assert np.all(np.isclose(img.worldToVoxMat, invx))
finally:
shutil.rmtree(testdir)
def test_Image_changeData(testdir):
img = fslimage.Image(op.join(testdir, 'dtypes', 'MNI152_T1_1mm_float.nii.gz')) def test_Image_changeData_analyze(seed): _test_Image_changeData(0)
def test_Image_changeData_nifti1(seed): _test_Image_changeData(1)
def test_Image_changeData_nifti2(seed): _test_Image_changeData(2)
def _test_Image_changeData(imgtype):
"""Test that changing image data triggers notification, and also causes
the dataRange attribute to be updated.
"""
testdir = tempfile.mkdtemp()
imagefile = op.join(testdir, 'image')
make_image(imagefile, imgtype)
img = fslimage.Image(imagefile)
notified = {} notified = {}
...@@ -258,7 +494,6 @@ def test_Image_changeData(testdir): ...@@ -258,7 +494,6 @@ def test_Image_changeData(testdir):
return (np.random.randint(0, img.shape[0]), return (np.random.randint(0, img.shape[0]),
np.random.randint(0, img.shape[1]), np.random.randint(0, img.shape[1]),
np.random.randint(0, img.shape[2])) np.random.randint(0, img.shape[2]))
def onData(*a): def onData(*a):
notified['data'] = True notified['data'] = True
...@@ -273,71 +508,100 @@ def test_Image_changeData(testdir): ...@@ -273,71 +508,100 @@ def test_Image_changeData(testdir):
img.register('name2', onSaveState, 'saveState') img.register('name2', onSaveState, 'saveState')
img.register('name3', onDataRange, 'dataRange') img.register('name3', onDataRange, 'dataRange')
# Calculate the actual data range
data = img.nibImage.get_data() data = img.nibImage.get_data()
dmin = data.min() dmin = data.min()
dmax = data.max() dmax = data.max()
drange = dmax - dmin drange = dmax - dmin
assert img.saveState try:
assert np.all(np.isclose(img.dataRange, (dmin, dmax)))
randval = dmin + np.random.random() * drange assert img.saveState
rx, ry, rz = randvox() assert np.all(np.isclose(img.dataRange, (dmin, dmax)))
img[rx, ry, rz] = randval randval = dmin + np.random.random() * drange
rx, ry, rz = randvox()
assert np.isclose(img[rx, ry, rz], randval) img[rx, ry, rz] = randval
assert notified.get('data', False)
assert notified.get('save', False)
assert not img.saveState
notified.pop('data') assert np.isclose(img[rx, ry, rz], randval)
assert notified.get('data', False)
assert notified.get('save', False)
assert not img.saveState
newdmin = dmin - 100 notified.pop('data')
newdmax = dmax + 100
rx, ry, rz = randvox() newdmin = dmin - 100
img[rx, ry, rz] = newdmin newdmax = dmax + 100
assert notified.get('data', False) rx, ry, rz = randvox()
assert notified.get('dataRange', False) img[rx, ry, rz] = newdmin
assert np.isclose(img[rx, ry, rz], newdmin)
assert np.all(np.isclose(img.dataRange, (newdmin, dmax)))
notified.pop('data') assert notified.get('data', False)
notified.pop('dataRange') assert notified.get('dataRange', False)
assert np.isclose(img[rx, ry, rz], newdmin)
assert np.all(np.isclose(img.dataRange, (newdmin, dmax)))
rx, ry, rz = randvox() notified.pop('data')
img[rx, ry, rz] = newdmax notified.pop('dataRange')
assert notified.get('data', False) rx, ry, rz = randvox()
assert notified.get('dataRange', False) img[rx, ry, rz] = newdmax
assert np.isclose(img[rx, ry, rz], newdmax)
assert np.all(np.isclose(img.dataRange, (newdmin, newdmax)))
def test_2D_images(testdir): assert notified.get('data', False)
assert notified.get('dataRange', False)
assert np.isclose(img[rx, ry, rz], newdmax)
assert np.all(np.isclose(img.dataRange, (newdmin, newdmax)))
tests = [('MNI152_T1_2mm_sliceXY.nii.gz', (91, 109, 1), (2.0, 2.0, 2.0)), finally:
('MNI152_T1_2mm_sliceXZ.nii.gz', (91, 1, 91), (2.0, 2.0, 2.0)), shutil.rmtree(testdir)
('MNI152_T1_2mm_sliceYZ.nii.gz', (1, 109, 91), (2.0, 2.0, 2.0)),
('MNI152_T1_2mm_sliceXY_4D.nii.gz', (91, 109, 1, 5), (2.0, 2.0, 2.0, 1.0)),
# When you create an XY slice with
# fslroi, it sets nifti/dim0 to 2.
# This should still be read in as
# a 3D image.
('MNI152_T1_2mm_sliceXY_bad_dim0.nii.gz', (91, 109, 1), (2.0, 2.0, 2.0))]
for fname, shape, pixdim in tests: def test_Image_2D_analyze(): _test_Image_2D(0)
def test_Image_2D_nifti1(): _test_Image_2D(1)
def test_Image_2D_nifti2(): _test_Image_2D(2)
def _test_Image_2D(imgtype):
fname = op.join(testdir, 'nifti2D', fname) testdir = tempfile.mkdtemp()
image = fslimage.Image(fname)
# The first shape tests when the
assert len(shape) == len(image .shape) # nifti dim0 field is set to 2,
assert len(shape) == len(image[:].shape) # which happens when you create
assert len(pixdim) == len(image .pixdim) # an XY slice with fslroi. This
# should still be read in as a
# 3D image.
testdims = [(10, 20),
(10, 20, 1),
(10, 1, 20),
(1, 10, 20),
(10, 20, 1, 5),
(10, 1, 20, 5),
(1, 10, 20, 5)]
try:
for shape in testdims:
pixdim = [2] * len(shape)
imagefile = op.join(testdir, 'image')
make_image(imagefile, imgtype, shape, pixdim)
image = fslimage.Image(imagefile)
# 2D should appear as 3D
if len(shape) == 2:
shape = list(shape) + [1]
pixdim = list(pixdim) + [1]
assert len(shape) == len(image .shape)
assert len(shape) == len(image[:].shape)
assert len(pixdim) == len(image .pixdim)
assert tuple(map(float, shape)) == tuple(map(float, image .shape))
assert tuple(map(float, shape)) == tuple(map(float, image[:].shape))
assert tuple(map(float, pixdim)) == tuple(map(float, image .pixdim))
assert tuple(map(float, shape)) == tuple(map(float, image .shape)) finally:
assert tuple(map(float, shape)) == tuple(map(float, image[:].shape)) shutil.rmtree(testdir)
assert tuple(map(float, pixdim)) == tuple(map(float, image .pixdim))
...@@ -31,11 +31,22 @@ import fsl.data.image as fslimage ...@@ -31,11 +31,22 @@ import fsl.data.image as fslimage
from . import make_random_image from . import make_random_image
from . import make_dummy_file from . import make_dummy_file
from . import check_image_hash
from . import looks_like_image from . import looks_like_image
from . import cleardir from . import cleardir
def makeImage(filename):
return hash(make_random_image(filename).get_data().tobytes())
def checkImageHash(filename, datahash):
"""Checks that the given NIFTI image matches the given hash.
"""
img = nib.load(filename)
assert hash(img.get_data().tobytes()) == datahash
def checkFilesToExpect(files, outdir, outputType, datahashes): def checkFilesToExpect(files, outdir, outputType, datahashes):
exts = { exts = {
...@@ -91,7 +102,7 @@ def checkFilesToExpect(files, outdir, outputType, datahashes): ...@@ -91,7 +102,7 @@ def checkFilesToExpect(files, outdir, outputType, datahashes):
else: else:
h = datahashes[op.basename(f)] h = datahashes[op.basename(f)]
check_image_hash(f, h) checkImageHash(f, h)
def test_imcp_script_shouldPass(move=False): def test_imcp_script_shouldPass(move=False):
...@@ -308,7 +319,7 @@ def test_imcp_script_shouldPass(move=False): ...@@ -308,7 +319,7 @@ def test_imcp_script_shouldPass(move=False):
print('files_to_expect: ', files_to_expect) print('files_to_expect: ', files_to_expect)
for i, fname in enumerate(files_to_create.split()): for i, fname in enumerate(files_to_create.split()):
imageHashes.append(make_random_image(op.join(indir, fname))) imageHashes.append(makeImage(op.join(indir, fname)))
imcp_args = imcp_args.split() imcp_args = imcp_args.split()
...@@ -413,7 +424,7 @@ def test_imcp_script_shouldFail(move=False): ...@@ -413,7 +424,7 @@ def test_imcp_script_shouldFail(move=False):
imcp_args = imcp_args .split() imcp_args = imcp_args .split()
for fname in files_to_create: for fname in files_to_create:
make_random_image(op.join(indir, fname)) makeImage(op.join(indir, fname))
imcp_args[:-1] = [op.join(indir, a) for a in imcp_args[:-1]] imcp_args[:-1] = [op.join(indir, a) for a in imcp_args[:-1]]
imcp_args[ -1] = op.join(outdir, imcp_args[-1]) imcp_args[ -1] = op.join(outdir, imcp_args[-1])
...@@ -609,7 +620,7 @@ def test_imcp_shouldPass(move=False): ...@@ -609,7 +620,7 @@ def test_imcp_shouldPass(move=False):
hashes = {} hashes = {}
for fn in files_to_create: for fn in files_to_create:
if looks_like_image(fn): if looks_like_image(fn):
hashes[fn] = make_random_image(op.join(indir, fn)) hashes[fn] = makeImage(op.join(indir, fn))
else: else:
hashes[fn] = make_dummy_file(op.join(indir, fn)) hashes[fn] = make_dummy_file(op.join(indir, fn))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment