Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • paulmc/fslpy
  • ndcn0236/fslpy
  • seanf/fslpy
3 results
Show changes
Showing
with 770 additions and 135 deletions
#!/usr/bin/env python
#
# test_imln.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import os
import os.path as op
from unittest import mock
import pytest
from fsl.utils.tempdir import tempdir
import fsl.utils.path as fslpath
import fsl.scripts.imln as imln
from fsl.tests import touch
def test_usage():
assert imln.main([]) != 0
with mock.patch('sys.argv', []):
assert imln.main() != 0
def test_imln():
# (files, command, expected links)
tests = [
('a.nii', 'a.nii link.nii', 'link.nii'),
('a.nii', 'a link', 'link.nii'),
('a.nii', 'a.nii link', 'link.nii'),
('a.nii', 'a link.nii', 'link.nii'),
('a.nii', 'a link.nii.gz', 'link.nii'),
('a.nii.gz', 'a.nii.gz link.nii.gz', 'link.nii.gz'),
('a.nii.gz', 'a link', 'link.nii.gz'),
('a.nii.gz', 'a.nii.gz link', 'link.nii.gz'),
('a.nii.gz', 'a link.nii.gz', 'link.nii.gz'),
('a.nii.gz', 'a link.nii', 'link.nii.gz'),
('a.img a.hdr', 'a link', 'link.img link.hdr'),
('a.img a.hdr', 'a link.img', 'link.img link.hdr'),
('a.img a.hdr', 'a link.hdr', 'link.img link.hdr'),
('a.img a.hdr', 'a.img link', 'link.img link.hdr'),
('a.img a.hdr', 'a.hdr link', 'link.img link.hdr'),
('a.img a.hdr', 'a.img link.img', 'link.img link.hdr'),
('a.img a.hdr', 'a.hdr link.hdr', 'link.img link.hdr'),
('a.img a.hdr', 'a.img link.hdr', 'link.img link.hdr'),
('a.img a.hdr', 'a.hdr link.img', 'link.img link.hdr'),
]
for files, command, explinks in tests:
with tempdir():
files = files.split()
command = command.split()
explinks = explinks.split()
for f in files:
touch(f)
assert imln.main(command) == 0
assert sorted(os.listdir('.')) == sorted(files + explinks)
for f, l in zip(sorted(files), sorted(explinks)):
assert op.islink(l)
assert op.isfile(f) and not op.islink(f)
assert op.realpath(l) == op.abspath(f)
# subdirs - imln currently only
# works with absolute paths (we
# make all paths absolute below)
tests = [
('dir/a.nii', 'dir/a dir/link', 'dir/link.nii'),
('dir/a.img dir/a.hdr', 'dir/a dir/link', 'dir/link.img dir/link.hdr'),
('dir/a.nii', 'dir/a link', 'link.nii'),
('dir/a.img dir/a.hdr', 'dir/a link', 'link.img link.hdr'),
('a.nii', 'a dir/link', 'dir/link.nii'),
('a.img a.hdr', 'a dir/link', 'dir/link.img dir/link.hdr'),
]
for files, command, explinks in tests:
with tempdir():
files = files.split()
command = [op.abspath(c) for c in command.split()]
explinks = explinks.split()
os.mkdir('dir')
for f in files:
touch(f)
assert imln.main(command) == 0
for f, l in zip(sorted(files), sorted(explinks)):
assert op.islink(l)
assert op.isfile(f) and not op.islink(f)
assert op.realpath(l) == op.abspath(f)
# error cases
# (files, commnad)
tests = [
('a.img', 'a link'),
('a.nii a.img a.hdr', 'a link'),
]
for files, command in tests:
with tempdir():
files = files.split()
command = command.split()
for f in files:
touch(f)
assert imln.main(command) != 0
assert sorted(os.listdir('.')) == sorted(files)
......@@ -6,9 +6,13 @@ import os.path as op
import itertools as it
import subprocess as sp
import os
import glob
import gzip
import shutil
import tempfile
from unittest import mock
import pytest
import numpy as np
......@@ -17,18 +21,10 @@ import nibabel as nib
from fsl.utils.tempdir import tempdir
import fsl.scripts.imcp as imcp_script
import fsl.scripts.immv as immv_script
import fsl.data.image as fslimage
from .. import cleardir
from ..test_immv_imcp import makeImage, checkImageHash, checkFilesToExpect
real_print = print
def print(*args, **kwargs):
pass
from fsl.tests import cleardir
from fsl.tests.test_immv_imcp import makeImage, checkImageHash, checkFilesToExpect
def test_imcp_script_shouldPass(move=False):
......@@ -234,80 +230,67 @@ def test_imcp_script_shouldPass(move=False):
for outputType, reldir in it.product(outputTypes, reldirs):
os.environ['FSLOUTPUTTYPE'] = outputType
with mock.patch.dict(os.environ, {'FSLOUTPUTTYPE' : outputType}):
for files_to_create, imcp_args, files_to_expect in tests:
for files_to_create, imcp_args, files_to_expect in tests:
imageHashes = []
imageHashes = []
print()
print('files_to_create: ', files_to_create)
print('imcp_args: ', imcp_args)
print('files_to_expect: ', files_to_expect)
for i, fname in enumerate(files_to_create.split()):
imageHashes.append(makeImage(op.join(indir, fname)))
for i, fname in enumerate(files_to_create.split()):
imageHashes.append(makeImage(op.join(indir, fname)))
imcp_args = imcp_args.split()
imcp_args = imcp_args.split()
tindir = indir
toutdir = outdir
tindir = indir
toutdir = outdir
if reldir == 'neutral': reldir = startdir
elif reldir == 'indir': reldir = tindir
elif reldir == 'outdir': reldir = toutdir
elif reldir == 'samedir':
reldir = tindir
toutdir = tindir
if reldir == 'neutral': reldir = startdir
elif reldir == 'indir': reldir = tindir
elif reldir == 'outdir': reldir = toutdir
elif reldir == 'samedir':
reldir = tindir
toutdir = tindir
if not move:
if not move:
infiles = os.listdir(tindir)
infiles = os.listdir(tindir)
files_to_expect = files_to_expect + ' ' + \
' '.join(infiles)
for inf in infiles:
img = nib.load(op.join(tindir, inf),
mmap=False)
imghash = hash(np.asanyarray(img.dataobj).tobytes())
img = None
imageHashes.append(imghash)
files_to_expect = files_to_expect + ' ' + \
' '.join(infiles)
print('adj files_to_expect: ', files_to_expect)
for inf in infiles:
img = nib.load(op.join(tindir, inf),
mmap=False)
imghash = hash(np.asanyarray(img.dataobj).tobytes())
img = None
imageHashes.append(imghash)
os.chdir(reldir)
os.chdir(reldir)
imcp_args[:-1] = [op.join(tindir, a) for a in imcp_args[:-1]]
imcp_args[ -1] = op.join(toutdir, imcp_args[-1])
imcp_args[:-1] = [op.join(tindir, a) for a in imcp_args[:-1]]
imcp_args[ -1] = op.join(toutdir, imcp_args[-1])
for i, a in enumerate(imcp_args):
if op.splitdrive(a)[0] == op.splitdrive(reldir)[0]:
imcp_args[i] = op.relpath(a, reldir)
for i, a in enumerate(imcp_args):
if op.splitdrive(a)[0] == op.splitdrive(reldir)[0]:
imcp_args[i] = op.relpath(a, reldir)
print('indir before: ', os.listdir(tindir))
print('outdir before: ', os.listdir(toutdir))
if move: result = immv_script.main(imcp_args)
else: result = imcp_script.main(imcp_args)
if move: result = immv_script.main(imcp_args)
else: result = imcp_script.main(imcp_args)
assert result == 0
print('indir after: ', os.listdir(tindir))
print('outdir after: ', os.listdir(toutdir))
checkFilesToExpect(
files_to_expect, toutdir, outputType, imageHashes)
assert result == 0
checkFilesToExpect(
files_to_expect, toutdir, outputType, imageHashes)
# too hard if indir == outdir
if move and tindir != toutdir:
infiles = os.listdir(tindir)
infiles = [f for f in infiles if op.isfile(f)]
infiles = [f for f in infiles if op.isfile(f)]
assert len(infiles) == 0
# too hard if indir == outdir
if move and tindir != toutdir:
infiles = os.listdir(tindir)
infiles = [f for f in infiles if op.isfile(f)]
infiles = [f for f in infiles if op.isfile(f)]
assert len(infiles) == 0
cleardir(indir)
cleardir(outdir)
cleardir(indir)
cleardir(outdir)
finally:
os.chdir(startdir)
......@@ -397,18 +380,9 @@ def test_imcp_script_shouldFail(move=False):
cmd = cmd.replace('indir', indir).replace('outdir', outdir)
sp.call(cmd.split())
print('calling {} {}'.format('immv' if move else 'imcp',
' '.join(imcp_args)))
print('indir before: {}'.format(os.listdir(indir)))
print('out dir before: {}'.format(os.listdir(outdir)))
if move: result = immv_script.main(imcp_args)
else: result = imcp_script.main(imcp_args)
print('indir after: {}'.format(os.listdir(indir)))
print('out dir after: {}'.format(os.listdir(outdir)))
assert result != 0
sp.call('chmod u+rwx {}'.format(indir) .split())
......@@ -430,7 +404,6 @@ def test_imcp_script_shouldFail(move=False):
else: assert imcp_script.main(['wa']) != 0
def test_immv_script_shouldPass():
test_imcp_script_shouldPass(move=True)
......@@ -440,27 +413,123 @@ def test_immv_script_shouldFail():
test_imcp_script_shouldFail(move=True)
def test_imcp_badExt():
with tempdir():
with open('file.nii.gz', 'wt') as f:
f.write('1')
ihash = makeImage('file.nii.gz')
result = imcp_script.main(['file.nii', 'dest'])
assert result == 0
assert op.exists('dest.nii.gz')
checkImageHash('dest.nii.gz', ihash)
def test_immv_badExt():
with tempdir():
with open('file.nii.gz', 'wt') as f:
f.write('1')
ihash = makeImage('file.nii.gz')
result = immv_script.main(['file.nii', 'dest'])
assert result == 0
assert op.exists('dest.nii.gz')
checkImageHash('dest.nii.gz', ihash)
def _make_file(prefix, ftype, dtype):
mapping = {
fslimage.FileType.NIFTI : (nib.Nifti1Image, 'nii'),
fslimage.FileType.NIFTI2 : (nib.Nifti2Image, 'nii'),
fslimage.FileType.ANALYZE : (nib.AnalyzeImage, 'img'),
fslimage.FileType.NIFTI_PAIR : (nib.Nifti1Pair, 'img'),
fslimage.FileType.NIFTI2_PAIR : (nib.Nifti2Pair, 'img'),
fslimage.FileType.ANALYZE_GZ : (nib.AnalyzeImage, 'img.gz'),
fslimage.FileType.NIFTI_GZ : (nib.Nifti1Image, 'nii.gz'),
fslimage.FileType.NIFTI2_GZ : (nib.Nifti2Image, 'nii.gz'),
fslimage.FileType.NIFTI_PAIR_GZ : (nib.Nifti1Pair, 'img.gz'),
fslimage.FileType.NIFTI2_PAIR_GZ : (nib.Nifti2Pair, 'img.gz'),
}
if np.issubdtype(dtype, np.complex64):
data = np.random.random((20, 20, 20)).astype(np.float32) + \
np.random.random((20, 20, 20)).astype(np.float32) * 1j
else:
data = np.random.random((20, 20, 20)).astype(dtype)
cls, suffix = mapping[ftype]
filename = f'{prefix}.{suffix}'
cls(data, None).to_filename(filename)
return filename
def _is_gzip(filename):
try:
with gzip.GzipFile(filename, 'rb') as f:
f.read()
return True
except Exception:
return False
def _is_pair(imgfile):
prefix, suffix = fslimage.splitExt(imgfile)
hdrfile = imgfile
if suffix == '.hdr': imgfile = f'{prefix}.img'
elif suffix == '.hdr.gz': imgfile = f'{prefix}.img.gz'
elif suffix == '.img': hdrfile = f'{prefix}.hdr'
elif suffix == '.img.gz': hdrfile = f'{prefix}.hdr.gz'
return op.exists(imgfile) and op.exists(hdrfile)
def _is_analyze(filename):
img = nib.load(filename)
return _is_pair(filename) and \
isinstance(img, (nib.AnalyzeImage, nib.AnalyzeHeader)) and \
not isinstance(img, (nib.Nifti1Image, nib.Nifti1Header, nib.Nifti1Pair))
def _is_nifti1(filename):
img = nib.load(filename)
return isinstance(img, (nib.Nifti1Image, nib.Nifti1Header, nib.Nifti1Pair)) and \
not isinstance(img, (nib.Nifti2Image, nib.Nifti2Header, nib.Nifti2Pair))
def _is_nifti2(filename):
img = nib.load(filename)
return isinstance(img, (nib.Nifti2Image, nib.Nifti2Header, nib.Nifti2Pair))
def _check_file(prefix, expftype, dtype):
filename = fslimage.addExt(prefix)
if 'NIFTI2' in expftype.name: assert _is_nifti2( filename)
elif 'NIFTI' in expftype.name: assert _is_nifti1( filename)
elif 'ANALYZE' in expftype.name: assert _is_analyze(filename)
if 'GZ' in expftype.name: assert _is_gzip( filename)
if 'PAIR' in expftype.name: assert _is_pair( filename)
img = nib.load(filename)
assert np.issubdtype(img.get_data_dtype(), dtype)
def test_imcp_script_correct_output_type(move=False):
# only testing dtypes supported by ANALYZE
dtypes = [np.uint8, np.int16, np.float32, np.float64, np.complex64]
# from, to
for from_, to_, dtype in it.product(fslimage.FileType, fslimage.FileType, dtypes):
with tempdir():
fname = f'f{from_.name}'
tname = f't{to_.name}'
_make_file(fname, from_, dtype)
with mock.patch.dict(os.environ, {'FSLOUTPUTTYPE' : to_.name}):
if move: immv_script.main([fname, tname])
else: imcp_script.main([fname, tname])
_check_file(tname, to_, dtype)
#!/usr/bin/env python
#
# test_imrm.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import os
from fsl.utils.tempdir import tempdir
import fsl.scripts.imrm as imrm
from fsl.tests import touch
def test_imrm_usage():
assert imrm.main([]) != 0
def test_imrm():
# (files present, command, expected)
tests = [
('a.nii', 'a', ''),
('a.nii.gz', 'a', ''),
('a.img a.hdr', 'a', ''),
('a.img', 'a', ''),
('a.hdr', 'a', ''),
('a.nii b.nii', 'a', 'b.nii'),
('a.nii b.nii', 'a b', ''),
('a.nii b.nii', 'a b.nii', ''),
# suffix doesn't have to be correct
('a.nii.gz', 'a.nii', ''),
# files don't exist -> no problem
('a.nii', 'b', 'a.nii'),
# wildcards
('img_a.nii img_b.nii', 'img_?', ''),
('img_a.nii img_b.nii', 'img_?.nii', ''),
('img_a.nii img_b.nii', 'img_*', ''),
('img_a.nii img_b.nii', 'img_*.nii', ''),
('img_a.nii img_b.nii img_cc.nii', 'img_?', 'img_cc.nii'),
('img_a.nii img_b.nii img_cc.nii', 'img_?.nii', 'img_cc.nii'),
('img_a.nii img_b.nii img_cc.nii', 'img_*', ''),
('img_a.nii img_b.nii img_cc.nii', 'img_*.nii', ''),
]
for files, command, expected in tests:
with tempdir():
for f in files.split():
touch(f)
print('files', files)
print('command', command)
print('expected', expected)
ret = imrm.main(('imrm ' + command).split())
assert ret == 0
assert sorted(os.listdir()) == sorted(expected.split())
#!/usr/bin/env python
#
# test_imtest.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import os
import os.path as op
import fsl.utils.path as fslpath
from fsl.utils.tempdir import tempdir
import fsl.scripts.imtest as imtest
from fsl.tests import CaptureStdout, touch
def test_wrongargs():
cap = CaptureStdout()
with cap:
assert imtest.main([]) == 0
assert cap.stdout.strip() == '0'
def test_imtest():
# (files, input, expected)
tests = [
('a.nii', 'a', '1'),
('a.nii', 'a.nii', '1'),
('a.nii', 'a.nii.gz', '1'), # imtest is suffix-agnostic
('a.img a.hdr', 'a', '1'),
('a.img a.hdr', 'a.img', '1'),
('a.img a.hdr', 'a.hdr', '1'),
('a.img', 'a', '0'),
('a.img', 'a.img', '0'),
('a.img', 'a.hdr', '0'),
('a.hdr', 'a', '0'),
('a.hdr', 'a.img', '0'),
('a.hdr', 'a.hdr', '0'),
('dir/a.nii', 'dir/a', '1'),
('dir/a.img dir/a.hdr', 'dir/a', '1'),
]
for files, input, expected in tests:
with tempdir():
for f in files.split():
dirname = op.dirname(f)
if dirname != '':
os.makedirs(dirname, exist_ok=True)
touch(f)
cap = CaptureStdout()
with cap:
assert imtest.main([input]) == 0
assert cap.stdout.strip() == expected
# test that sym-links are
# followed correctly
with tempdir():
touch('image.nii.gz')
os.symlink('image.nii.gz', 'link.nii.gz')
cap = CaptureStdout()
with cap:
assert imtest.main(['link']) == 0
assert cap.stdout.strip() == '1'
# sym-links in sub-directories
# (old imtest would not work
# in this scenario)
with tempdir():
os.mkdir('subdir')
impath = op.join('subdir', 'image.nii.gz')
lnpath = op.join('subdir', 'link.nii.gz')
touch(impath)
os.symlink('image.nii.gz', lnpath)
cap = CaptureStdout()
with cap:
assert imtest.main([lnpath]) == 0
assert cap.stdout.strip() == '1'
#!/usr/bin/env python
#
# test_remove_ext.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import fsl.scripts.remove_ext as remove_ext
from fsl.tests import CaptureStdout
def test_usage():
assert remove_ext.main([]) != 0
def test_remove_ext():
# (input, expected output)
tests = [
('a', 'a'),
('a.nii', 'a'),
('a.nii.gz', 'a'),
('a.txt', 'a.txt'),
('a.nii b.img c.hdr', 'a b c'),
('a.nii b.img b.hdr', 'a b b'),
('a b.img c.txt', 'a b c.txt'),
('a.nii.gz b c.mnc', 'a b c'),
]
for input, expected in tests:
cap = CaptureStdout()
with cap:
ret = remove_ext.main(input.split())
assert ret == 0
got = cap.stdout.split()
assert sorted(got) == sorted(expected.split())
......@@ -8,11 +8,11 @@ import pytest
import fsl.scripts.resample_image as resample_image
import fsl.utils.transform as transform
import fsl.transform.affine as affine
from fsl.utils.tempdir import tempdir
from fsl.data.image import Image
from .. import make_random_image
from fsl.tests import make_random_image
......@@ -22,22 +22,22 @@ def test_resample_image_shape():
resample_image.main('image resampled -s 20,20,20'.split())
res = Image('resampled')
expv2w = transform.concat(
expv2w = affine.concat(
img.voxToWorldMat,
transform.scaleOffsetXform([0.5, 0.5, 0.5], 0))
affine.scaleOffsetXform([0.5, 0.5, 0.5], 0))
assert np.all(np.isclose(res.shape, (20, 20, 20)))
assert np.all(np.isclose(res.pixdim, (0.5, 0.5, 0.5)))
assert np.all(np.isclose(res.voxToWorldMat, expv2w))
assert np.all(np.isclose(
np.array(transform.axisBounds(res.shape, res.voxToWorldMat)) - 0.25,
transform.axisBounds(img.shape, img.voxToWorldMat)))
np.array(affine.axisBounds(res.shape, res.voxToWorldMat)) - 0.25,
affine.axisBounds(img.shape, img.voxToWorldMat)))
resample_image.main('image resampled -s 20,20,20 -o corner'.split())
res = Image('resampled')
assert np.all(np.isclose(
transform.axisBounds(res.shape, res.voxToWorldMat),
transform.axisBounds(img.shape, img.voxToWorldMat)))
affine.axisBounds(res.shape, res.voxToWorldMat),
affine.axisBounds(img.shape, img.voxToWorldMat)))
def test_resample_image_shape_4D():
......@@ -65,9 +65,9 @@ def test_resample_image_dim():
resample_image.main('image resampled -d 0.5,0.5,0.5'.split())
res = Image('resampled')
expv2w = transform.concat(
expv2w = affine.concat(
img.voxToWorldMat,
transform.scaleOffsetXform([0.5, 0.5, 0.5], 0))
affine.scaleOffsetXform([0.5, 0.5, 0.5], 0))
assert np.all(np.isclose(res.shape, (20, 20, 20)))
assert np.all(np.isclose(res.pixdim, (0.5, 0.5, 0.5)))
......
#!/usr/bin/env python
#
# test_vest2text.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import textwrap as tw
import numpy as np
import fsl.data.vest as fslvest
import fsl.scripts.Text2Vest as Text2Vest
import fsl.scripts.Vest2Text as Vest2Text
from fsl.tests import tempdir
def test_usage():
assert Vest2Text.main([]) == 0
assert Text2Vest.main([]) == 0
def test_Vest2Text():
with tempdir():
data = np.random.random((20, 10))
vest = fslvest.generateVest(data)
with open('data.vest', 'wt') as f:
f.write(vest)
assert Vest2Text.main(['data.vest', 'data.txt']) == 0
got = np.loadtxt('data.txt')
assert np.all(np.isclose(data, got))
def test_Text2Vest():
with tempdir():
data = np.random.random((20, 10))
np.savetxt('data.txt', data)
assert Text2Vest.main(['data.txt', 'data.vest']) == 0
got = fslvest.loadVestFile('data.vest', ignoreHeader=False)
assert np.all(np.isclose(data, got))
# make sure that 1D files are treated correctly (fsl/fslpy!387)
with open('colvec.txt', 'wt') as f:
f.write('1\n2\n3\n')
with open('rowvec.txt', 'wt') as f:
f.write('1 2 3\n')
colexp = tw.dedent("""
/NumWaves 1
/NumPoints 3
/Matrix
1.000000000000
2.000000000000
3.000000000000
""").strip()
rowexp = tw.dedent("""
/NumWaves 3
/NumPoints 1
/Matrix
1.000000000000 2.000000000000 3.000000000000
""").strip()
assert Text2Vest.main(['colvec.txt', 'colvec.vest']) == 0
assert Text2Vest.main(['rowvec.txt', 'rowvec.vest']) == 0
assert open('colvec.vest', 'rt').read().strip() == colexp
assert open('rowvec.vest', 'rt').read().strip() == rowexp
......@@ -12,16 +12,11 @@ import pickle
import textwrap
import tempfile
# python 3
try:
import unittest.mock as mock
# python 2
except:
import mock
import unittest.mock as mock
import pytest
import tests
import fsl.tests as tests
import fsl.utils.settings as settings
import fsl.utils.tempdir as tempdir
......
......@@ -6,6 +6,7 @@
#
import glob
import os
import os.path as op
......@@ -53,13 +54,27 @@ def test_tempdir_changeto():
assert op.realpath(os.getcwd()) == cwd
def test_tempdir_prefix():
with tempdir.tempdir(prefix='mytempdirtest') as tdir:
assert op.basename(tdir).startswith('mytempdirtest')
with tempdir.tempdir() as parent:
with tempdir.tempdir(prefix='mytempdirtest', root='.') as tdir:
assert list(glob.glob(op.join(parent, 'mytempdirtest*'))) == [tdir]
def test_tempdir_override():
with tempdir.tempdir() as parent:
override = op.abspath((op.join('override', 'directory')))
os.makedirs(override)
# tempdir should not create/change to
# a new temp directory, but should
# stay in the override directory
with tempdir.tempdir(override=parent):
assert op.realpath(os.getcwd()) == op.realpath(parent)
with tempdir.tempdir(override=override):
assert op.realpath(os.getcwd()) == op.realpath(override)
# override should not be deleted
assert op.exists(parent)
assert op.exists(override)
# and we should be moved back into the original cwd
assert op.realpath(os.getcwd()) == op.realpath(parent)
......@@ -6,8 +6,6 @@
#
from __future__ import division
import random
import glob
import os.path as op
......@@ -15,8 +13,6 @@ import itertools as it
import numpy as np
import numpy.linalg as npla
import six
import pytest
import fsl.transform.affine as affine
......@@ -39,8 +35,7 @@ def readlines(filename):
#
# Pass it [bytes, bytes, ...], and it works
# fine.
if six.PY3:
lines = [l.encode('ascii') for l in lines]
lines = [l.encode('ascii') for l in lines]
return lines
......@@ -94,7 +89,7 @@ def test_concat():
def test_veclength(seed):
def l(v):
v = np.array(v, copy=False).reshape((-1, 3))
v = np.asarray(v).reshape((-1, 3))
x = v[:, 0]
y = v[:, 1]
z = v[:, 2]
......@@ -152,6 +147,24 @@ def test_normalise(seed):
assert np.all(pars)
def test_flip():
shape = [5, 5, 5]
xform = np.diag([2, 2, 2, 1])
xform[:3, 3] = [-4.5, -4.5, -4.5]
allaxes = list(it.chain(
it.combinations([0, 1, 2], 1),
it.combinations([0, 1, 2], 2),
it.combinations([0, 1, 2], 3)))
for axes in allaxes:
flipped = affine.flip(shape, xform, *axes)
flo, fhi = affine.axisBounds(shape, flipped, boundary=None)
assert np.all(np.isclose(flo, [-5, -5, -5]))
assert np.all(np.isclose(fhi, [ 5, 5, 5]))
def test_scaleOffsetXform():
# Test numerically
......@@ -214,6 +227,17 @@ def test_scaleOffsetXform():
result = affine.scaleOffsetXform(1, offset)
assert np.all(np.isclose(result, expected))
# both args are optional
assert np.all(np.isclose(
affine.scaleOffsetXform(), np.eye(4)))
assert np.all(np.isclose(
affine.scaleOffsetXform([1, 2, 3]), np.diag([1, 2, 3, 1])))
exp = np.eye(4)
exp[:3, 3] = [1, 2, 3]
assert np.all(np.isclose(
affine.scaleOffsetXform(None, [1, 2, 3]), exp))
def test_compose_and_decompose():
......@@ -226,8 +250,10 @@ def test_compose_and_decompose():
xform = lines[i * 4: i * 4 + 4]
xform = np.genfromtxt(xform)
scales, offsets, rotations = affine.decompose(xform)
result = affine.compose(scales, offsets, rotations)
scales, offsets, rotations, shears = affine.decompose(
xform, shears=True)
result = affine.compose(scales, offsets, rotations, shears=shears)
assert np.all(np.isclose(xform, result, atol=1e-5))
......@@ -235,8 +261,10 @@ def test_compose_and_decompose():
# different rotation origin, but we test
# explicitly passing the origin for
# completeness
scales, offsets, rotations = affine.decompose(xform)
result = affine.compose(scales, offsets, rotations, [0, 0, 0])
scales, offsets, rotations, shears = affine.decompose(
xform, shears=True)
result = affine.compose(
scales, offsets, rotations, origin=[0, 0, 0], shears=shears)
assert np.all(np.isclose(xform, result, atol=1e-5))
......@@ -277,6 +305,16 @@ def test_compose_and_decompose():
assert np.all(np.isclose(rot, rots))
def test_compose_scaleAtOrigin():
for _ in range(100):
origin = np.random.randint(-50, 50, 3)
rots = -np.pi + 2 * np.pi * np.random.random(3)
scales = -10 + 20 * np.random.random(3)
xform = affine.compose(scales, [0, 0, 0], rots, origin=origin,
scaleAtOrigin=True)
assert np.all(np.isclose(affine.transform(origin, xform), origin))
def test_rotMatToAxisAngles(seed):
......@@ -381,6 +419,23 @@ def test_axisBounds():
affine.axisBounds(shape, xform, origin=origin, boundary='Blufu')
def test_mergeBounds():
bounds = [[[ 0, 0, 0], [10, 10, 10]],
[[ 0, -2, 5], [11, 8, 7]],
[[ 4, 6, 3], [12, 9, 8]],
[[-1, 3, 2], [ 9, 11, 21]]]
expect = ((-1, -2, 0), (12, 11, 21))
assert affine.mergeBounds(*bounds) == expect
bounds = [[[ 0, 10], [ 0, 10], [0, 10]],
[[ 0, 11], [-2, 8], [5, 7]],
[[ 4, 12], [ 6, 9], [3, 8]],
[[-1, 9], [ 3, 11], [2, 21]]]
expect = ((-1, 12), (-2, 11), (0, 21))
assert affine.mergeBounds(*bounds) == expect
def test_transform():
def is_orthogonal(xform):
......@@ -391,7 +446,7 @@ def test_transform():
mask = np.array([[1, 0, 0, 1],
[0, 1, 0, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]], dtype=np.bool)
[0, 0, 0, 1]], dtype=bool)
return np.all((xform != 0) == mask)
......
......@@ -15,9 +15,9 @@ import fsl.transform.flirt as flirt
import fsl.transform.affine as affine
import fsl.utils.tempdir as tempdir
from .test_affine import readlines
from fsl.tests.test_transform.test_affine import readlines
from .. import make_random_image
from fsl.tests import make_random_image
datadir = op.join(op.dirname(__file__), 'testdata')
......
......@@ -9,15 +9,18 @@ import os.path as op
import itertools as it
import numpy as np
import nibabel as nib
import pytest
import fsl.data.image as fslimage
import fsl.utils.tempdir as tempdir
import fsl.data.constants as constants
import fsl.transform.affine as affine
import fsl.transform.nonlinear as nonlinear
import fsl.transform.fnirt as fnirt
from .test_nonlinear import _random_affine_field
from fsl.tests.test_transform.test_nonlinear import _random_affine_field
datadir = op.join(op.dirname(__file__), 'testdata', 'nonlinear')
......@@ -51,6 +54,39 @@ def test_readFnirt():
assert disp.refSpace == 'fsl'
def test_readFnirt_defType_intent():
src = op.join(datadir, 'src.nii.gz')
ref = op.join(datadir, 'ref.nii.gz')
coef = op.join(datadir, 'coefficientfield.nii.gz')
disp = op.join(datadir, 'displacementfield.nii.gz')
src = fslimage.Image(src)
ref = fslimage.Image(ref)
field = fnirt.readFnirt(disp, src, ref, defType='absolute')
assert field.deformationType == 'absolute'
field = fnirt.readFnirt(disp, src, ref, defType='relative')
assert field.deformationType == 'relative'
img = nib.load(coef)
img.header['intent_code'] = 0
with tempdir.tempdir():
img.to_filename('field.nii.gz')
with pytest.raises(ValueError):
fnirt.readFnirt('field', src, ref)
field = fnirt.readFnirt(
'field', src, ref,
intent=constants.FSL_CUBIC_SPLINE_COEFFICIENTS)
assert isinstance(field, nonlinear.CoefficientField)
field = fnirt.readFnirt(
'field', src, ref,
intent=constants.FSL_FNIRT_DISPLACEMENT_FIELD)
assert isinstance(field, nonlinear.DeformationField)
def test_toFnirt():
def check(got, exp):
......
......@@ -84,7 +84,7 @@ def _random_affine_field():
np.arange(ref.shape[2]), indexing='ij')
rvoxels = np.vstack((rx.flatten(), ry.flatten(), rz.flatten())).T
rcoords = affine.transform(rvoxels, ref.voxToScaledVoxMat)
rcoords = affine.transform(rvoxels, ref.getAffine('voxel', 'fsl'))
scoords = affine.transform(rcoords, xform)
field = np.zeros(list(ref.shape[:3]) + [3])
......@@ -161,8 +161,8 @@ def test_convertDeformationSpace():
refcoords = [np.random.randint(0, basefield.shape[0], 5),
np.random.randint(0, basefield.shape[1], 5),
np.random.randint(0, basefield.shape[2], 5)]
refcoords = np.array(refcoords, dtype=np.int).T
refcoords = affine.transform(refcoords, ref.voxToScaledVoxMat)
refcoords = np.array(refcoords, dtype=int).T
refcoords = affine.transform(refcoords, ref.getAffine('voxel', 'fsl'))
srccoords = basefield.transform(refcoords)
field = nonlinear.convertDeformationSpace(basefield, from_, to)
......@@ -190,9 +190,9 @@ def test_DeformationField_transform():
np.arange(ref.shape[1]),
np.arange(ref.shape[2]), indexing='ij')
rvoxels = np.vstack((rx.flatten(), ry.flatten(), rz.flatten())).T
rcoords = affine.transform(rvoxels, ref.voxToScaledVoxMat)
rcoords = affine.transform(rvoxels, ref.getAffine('voxel', 'fsl'))
scoords = affine.transform(rcoords, xform)
svoxels = affine.transform(scoords, src.scaledVoxToVoxMat)
svoxels = affine.transform(scoords, src.getAffine('fsl', 'voxel'))
absfield = np.zeros(list(ref.shape[:3]) + [3])
absfield[:] = scoords.reshape(*it.chain(ref.shape, [3]))
......@@ -205,6 +205,10 @@ def test_DeformationField_transform():
got = absfield.transform(rcoords)
assert np.all(np.isclose(got, scoords))
# test single set of coords
got = absfield.transform(rcoords[0])
assert np.all(np.isclose(got, scoords[0]))
got = relfield.transform(rvoxels, from_='voxel', to='voxel')
assert np.all(np.isclose(got, svoxels))
got = absfield.transform(rvoxels, from_='voxel', to='voxel')
......@@ -213,9 +217,9 @@ def test_DeformationField_transform():
# test out of bounds are returned as nan
rvoxels = np.array([[-1, -1, -1],
[ 0, 0, 0]])
rcoords = affine.transform(rvoxels, ref.voxToScaledVoxMat)
rcoords = affine.transform(rvoxels, ref.getAffine('voxel', 'fsl'))
scoords = affine.transform(rcoords, xform)
svoxels = affine.transform(scoords, src.scaledVoxToVoxMat)
svoxels = affine.transform(scoords, src.getAffine('fsl', 'voxel'))
got = relfield.transform(rcoords)
assert np.all(np.isnan(got[0, :]))
......@@ -307,6 +311,38 @@ def test_CoefficientField_transform():
assert np.all(np.isclose(gotnp, srccoordsnp[srcspace], **tol))
def test_coefficientField_transform_altref():
# test coordinates (manually determined).
# original ref image is 2mm isotropic,
# resampled is 1mm. Each tuple contains:
#
# (src, ref2mm, ref1mm)
coords = [
((18.414, 26.579, 25.599), (11, 19, 11), (22, 38, 22)),
((14.727, 22.480, 20.340), ( 8, 17, 8), (16, 34, 16)),
((19.932, 75.616, 27.747), (11, 45, 5), (22, 90, 10))
]
nldir = op.join(datadir, 'nonlinear')
src = op.join(nldir, 'src.nii.gz')
ref = op.join(nldir, 'ref.nii.gz')
cf = op.join(nldir, 'coefficientfield.nii.gz')
src = fslimage.Image(src)
ref2mm = fslimage.Image(ref)
ref1mm = ref2mm.adjust((1, 1, 1))
cfref2mm = fnirt.readFnirt(cf, src, ref2mm)
cfref1mm = fnirt.readFnirt(cf, src, ref1mm)
for srcc, ref2mmc, ref1mmc in coords:
ref2mmc = cfref2mm.transform(ref2mmc, 'voxel', 'voxel')
ref1mmc = cfref1mm.transform(ref1mmc, 'voxel', 'voxel')
assert np.all(np.isclose(ref2mmc, srcc, 1e-4))
assert np.all(np.isclose(ref1mmc, srcc, 1e-4))
def test_coefficientFieldToDeformationField():
nldir = op.join(datadir, 'nonlinear')
......@@ -348,8 +384,8 @@ def test_applyDeformation():
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))
srcdata = np.random.randint(1, 65536, (10, 10, 10), dtype=np.int32)
refdata = np.random.randint(1, 65536, (10, 10, 10), dtype=np.int32)
src = fslimage.Image(srcdata)
ref = fslimage.Image(refdata, xform=src2ref)
......@@ -371,8 +407,8 @@ def test_applyDeformation_altsrc():
[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))
srcdata = np.random.randint(1, 65536, (10, 10, 10), dtype=np.int32)
refdata = np.random.randint(1, 65536, (10, 10, 10), dtype=np.int32)
src = fslimage.Image(srcdata)
ref = fslimage.Image(refdata, xform=src2ref)
......@@ -411,6 +447,60 @@ def test_applyDeformation_altsrc():
assert np.all(np.isclose(expect, result))
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), dtype=np.int32)
refdata = np.random.randint(1, 65536, (10, 10, 10), dtype=np.int32)
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))
def test_applyDeformation_altref():
src2ref = affine.compose(
np.random.randint(2, 5, 3),
......@@ -418,8 +508,8 @@ def test_applyDeformation_altref():
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))
srcdata = np.random.randint(1, 65536, (10, 10, 10), dtype=np.int32)
refdata = np.random.randint(1, 65536, (10, 10, 10), dtype=np.int32)
src = fslimage.Image(srcdata)
ref = fslimage.Image(refdata, xform=src2ref)
......@@ -454,7 +544,7 @@ def test_applyDeformation_worldAligned():
src2ref = refv2w
ref2src = affine.invert(src2ref)
srcdata = np.random.randint(1, 65536, (10, 10, 10))
srcdata = np.random.randint(1, 65536, (10, 10, 10), dtype=np.int32)
src = fslimage.Image(srcdata)
ref = fslimage.Image(srcdata, xform=src2ref)
......
......@@ -20,7 +20,7 @@ import fsl.transform.fnirt as fnirt
import fsl.transform.nonlinear as nonlinear
import fsl.transform.x5 as x5
from .. import make_random_image
from fsl.tests import make_random_image
def _check_metadata(group):
......