Skip to content

Commit 310a242

Browse files
committed
TEST: Test nib-roi and helpers
1 parent ab96044 commit 310a242

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

nibabel/cmdline/tests/test_roi.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import os
2+
import numpy as np
3+
import nibabel as nb
4+
from nibabel.cmdline.roi import lossless_slice, parse_slice, main
5+
from nibabel.testing import data_path
6+
7+
import unittest
8+
import pytest
9+
10+
11+
def test_parse_slice():
12+
assert parse_slice(None) == slice(None)
13+
assert parse_slice("1:5") == slice(1, 5)
14+
assert parse_slice("1:") == slice(1, None)
15+
assert parse_slice(":5") == slice(None, 5)
16+
assert parse_slice(":-1") == slice(None, -1)
17+
assert parse_slice("-5:-1") == slice(-5, -1)
18+
assert parse_slice("1:5:") == slice(1, 5, None)
19+
assert parse_slice("1::") == slice(1, None, None)
20+
assert parse_slice(":5:") == slice(None, 5, None)
21+
assert parse_slice(":-1:") == slice(None, -1, None)
22+
assert parse_slice("-5:-1:") == slice(-5, -1, None)
23+
assert parse_slice("1:5:1") == slice(1, 5, 1)
24+
assert parse_slice("1::1") == slice(1, None, 1)
25+
assert parse_slice(":5:1") == slice(None, 5, 1)
26+
assert parse_slice(":-1:1") == slice(None, -1, 1)
27+
assert parse_slice("-5:-1:1") == slice(-5, -1, 1)
28+
assert parse_slice("5:1:-1") == slice(5, 1, -1)
29+
assert parse_slice(":1:-1") == slice(None, 1, -1)
30+
assert parse_slice("5::-1") == slice(5, None, -1)
31+
assert parse_slice("-1::-1") == slice(-1, None, -1)
32+
assert parse_slice("-1:-5:-1") == slice(-1, -5, -1)
33+
34+
# Max of start:stop:step
35+
with pytest.raises(ValueError):
36+
parse_slice("1:2:3:4")
37+
# Integers only
38+
with pytest.raises(ValueError):
39+
parse_slice("abc:2:3")
40+
with pytest.raises(ValueError):
41+
parse_slice("1.2:2:3")
42+
# Unit steps only
43+
with pytest.raises(ValueError):
44+
parse_slice("1:5:2")
45+
46+
47+
def test_parse_slice_disallow_step():
48+
# Permit steps of 1
49+
assert parse_slice("1:5", False) == slice(1, 5)
50+
assert parse_slice("1:5:", False) == slice(1, 5)
51+
assert parse_slice("1:5:1", False) == slice(1, 5, 1)
52+
# Disable other steps
53+
with pytest.raises(ValueError):
54+
parse_slice("1:5:-1", False)
55+
with pytest.raises(ValueError):
56+
parse_slice("1:5:-2", False)
57+
58+
59+
def test_lossless_slice_unknown_axes():
60+
img = nb.load(os.path.join(data_path, 'minc1_4d.mnc'))
61+
with pytest.raises(ValueError):
62+
lossless_slice(img, (slice(None), slice(None), slice(None)))
63+
64+
65+
def test_lossless_slice_scaling(tmp_path):
66+
fname = tmp_path / 'image.nii'
67+
img = nb.Nifti1Image(np.random.uniform(-20000, 20000, (5, 5, 5, 5)), affine=np.eye(4))
68+
img.header.set_data_dtype("int16")
69+
img.to_filename(fname)
70+
img1 = nb.load(fname)
71+
sliced_fname = tmp_path / 'sliced.nii'
72+
lossless_slice(img1, (slice(None), slice(None), slice(2, 4))).to_filename(sliced_fname)
73+
img2 = nb.load(sliced_fname)
74+
75+
assert np.array_equal(img1.get_fdata()[:, :, 2:4], img2.get_fdata())
76+
assert np.array_equal(img1.dataobj.get_unscaled()[:, :, 2:4], img2.dataobj.get_unscaled())
77+
assert img1.dataobj.slope == img2.dataobj.slope
78+
assert img1.dataobj.inter == img2.dataobj.inter
79+
80+
81+
@pytest.mark.parametrize("inplace", (True, False))
82+
def test_nib_roi(tmp_path, inplace):
83+
in_file = os.path.join(data_path, 'functional.nii')
84+
out_file = str(tmp_path / 'sliced.nii')
85+
in_img = nb.load(in_file)
86+
87+
if inplace:
88+
in_img.to_filename(out_file)
89+
in_file = out_file
90+
91+
retval = main([in_file, out_file, '-i', '1:-1', '-j', '-1:1:-1', '-k', '::', '-t', ':5'])
92+
assert retval == 0
93+
94+
out_img = nb.load(out_file)
95+
in_data = in_img.dataobj[:]
96+
in_sliced = in_img.slicer[1:-1, -1:1:-1, :, :5]
97+
assert out_img.shape == in_sliced.shape
98+
assert np.array_equal(in_data[1:-1, -1:1:-1, :, :5], out_img.dataobj)
99+
assert np.allclose(in_sliced.dataobj, out_img.dataobj)
100+
assert np.allclose(in_sliced.affine, out_img.affine)
101+
102+
103+
@pytest.mark.parametrize("args, errmsg", (
104+
(("-i", "1:1"), "Cannot take zero-length slice"),
105+
(("-j", "1::2"), "Downsampling is not supported"),
106+
(("-t", "5::-1"), "Step entry not permitted"),
107+
))
108+
def test_nib_roi_bad_slices(capsys, args, errmsg):
109+
in_file = os.path.join(data_path, 'functional.nii')
110+
111+
retval = main([in_file, '/dev/null', *args])
112+
assert retval != 0
113+
captured = capsys.readouterr()
114+
assert errmsg in captured.out
115+

0 commit comments

Comments
 (0)