Skip to content

Commit b7d54af

Browse files
committed
Adding extra nifti test samples
1 parent 3745388 commit b7d54af

File tree

3 files changed

+53
-24
lines changed

3 files changed

+53
-24
lines changed

tests/data/nifti/anatomical.nii

66.4 KB
Binary file not shown.

tests/integration/converters/test_nifti.py

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,43 @@
77
from tiledb.bioimg.converters.nifti import NiftiConverter
88

99

10-
def compare_nifti_images(file1, file2):
10+
def compare_nifti_images(file1, file2, scaled_test):
1111
img1 = nib.load(file1)
1212
img2 = nib.load(file2)
1313

14-
# Compare the headers (metadata)
15-
if img1.header != img2.header:
16-
return False
17-
1814
# Compare the affine matrices (spatial information)
19-
if not np.array_equal(img1.affine, img2.affine):
20-
return False
15+
assert np.array_equal(img1.affine, img2.affine)
2116

2217
# Compare the image data (voxel data)
23-
data1 = img1.get_fdata()
24-
data2 = img2.get_fdata()
25-
if not np.array_equal(data1, data2):
26-
return False
27-
return True
18+
data1 = np.array(img1.dataobj, dtype=img1.get_data_dtype())
19+
data2 = np.array(img2.dataobj, dtype=img2.get_data_dtype())
20+
21+
assert np.array_equal(data1, data2)
22+
23+
# Compare the image data scaled (voxel data)
24+
if scaled_test:
25+
data_sc = img1.get_fdata()
26+
data_sc_2 = img2.get_fdata()
27+
28+
assert np.array_equal(data_sc, data_sc_2)
2829

2930

3031
@pytest.mark.parametrize(
31-
"filename", ["nifti/example4d.nii", "nifti/functional.nii", "nifti/standard.nii"]
32+
"filename",
33+
[
34+
"nifti/example4d.nii",
35+
"nifti/functional.nii",
36+
"nifti/standard.nii",
37+
"nifti/visiblehuman.nii",
38+
"nifti/anatomical.nii",
39+
],
3240
)
3341
@pytest.mark.parametrize("preserve_axes", [False, True])
3442
@pytest.mark.parametrize("chunked", [False])
3543
@pytest.mark.parametrize(
3644
"compressor, lossless",
3745
[
38-
(tiledb.ZstdFilter(level=0), True),
46+
(tiledb.ZstdFilter(level=0), False),
3947
# WEBP is not supported for Grayscale images
4048
],
4149
)
@@ -57,4 +65,9 @@ def test_nifti_converter_roundtrip(
5765
)
5866
# Store it back to PNG
5967
NiftiConverter.from_tiledb(tiledb_path, output_path)
60-
compare_nifti_images(input_path, output_path)
68+
# The dtype of this image is complex and nibabel breaks originally
69+
compare_nifti_images(
70+
input_path,
71+
output_path,
72+
scaled_test=False if filename == "nifti/visiblehuman.nii" else True,
73+
)

tiledb/bioimg/converters/nifti.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929
from .base import ImageConverterMixin
3030

3131

32+
# Function to find and return the third value based on the first value
33+
def get_dtype_from_code(dtype_code: int) -> Optional[np.dtype]:
34+
for item in _dtdefs:
35+
if item[0] == dtype_code: # Check if the first value matches the input code
36+
return item[2] # Return the third value (dtype)
37+
return None # Return None if the code is not found
38+
39+
3240
class NiftiReader:
3341
_logger: logging.Logger
3442

@@ -83,7 +91,12 @@ def logger(self) -> Optional[logging.Logger]:
8391

8492
@property
8593
def group_metadata(self) -> Dict[str, Any]:
86-
writer_kwargs = dict(metadata=self._metadata, binaryblock=self._binary_header)
94+
writer_kwargs = dict(
95+
metadata=self._metadata,
96+
binaryblock=self._binary_header,
97+
slope=self._nib_image.dataobj.slope,
98+
inter=self._nib_image.dataobj.inter,
99+
)
87100
self._logger.debug(f"Group metadata: {writer_kwargs}")
88101
return {"json_write_kwargs": json.dumps(writer_kwargs)}
89102

@@ -173,7 +186,7 @@ def level_count(self) -> int:
173186
def level_dtype(self, level: int = 0) -> np.dtype:
174187
header_dict = self.nifti1_hdr_2_dict()
175188

176-
dtype = self.get_dtype_from_code(header_dict["datatype"])
189+
dtype = get_dtype_from_code(header_dict["datatype"])
177190
if dtype == np.dtype([("R", "u1"), ("G", "u1"), ("B", "u1")]):
178191
dtype = np.uint8
179192
# TODO: Compare with the dtype of fields
@@ -218,8 +231,14 @@ def level_image(
218231
self._metadata["original_mode"] = self._mode
219232
raw_data_contiguous = np.ascontiguousarray(unscaled_img)
220233
numerical_data = np.frombuffer(raw_data_contiguous, dtype=self.level_dtype())
234+
# Account endianness
235+
numerical_data = numerical_data.view(
236+
numerical_data.dtype.newbyteorder(self._nib_image.header.endianness)
237+
)
221238
numerical_data = numerical_data.reshape(self.level_shape())
222239

240+
# Bug! data might have slope and inter and header not contain them.
241+
223242
if tile is None:
224243
return numerical_data
225244
else:
@@ -256,13 +275,6 @@ def nifti1_hdr_2_dict(self) -> Dict[str, Any]:
256275
for field in structured_header_arr.dtype.names
257276
}
258277

259-
# Function to find and return the third value based on the first value
260-
def get_dtype_from_code(self, dtype_code: int) -> np.dtype:
261-
for item in _dtdefs:
262-
if item[0] == dtype_code: # Check if the first value matches the input code
263-
return item[2] # Return the third value (dtype)
264-
return None # Return None if the code is not foun
265-
266278
@staticmethod
267279
def _serialize_header(header_dict: Mapping[str, Any]) -> Dict[str, Any]:
268280
serialized_header = {
@@ -335,6 +347,10 @@ def write_level_image(
335347
nib_image = self._writer(
336348
structured_arr, header=header, affine=header.get_best_affine()
337349
)
350+
351+
nib_image.header.set_slope_inter(
352+
self._group_metadata["slope"], self._group_metadata["inter"]
353+
)
338354
nib.save(nib_image, self._output_path)
339355

340356
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:

0 commit comments

Comments
 (0)