Skip to content

Commit

Permalink
Imporvements in philips tag handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
wtclarke committed Dec 7, 2023
1 parent 2b90b29 commit cc056a8
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 6 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
This document contains the Spec2nii release history in reverse chronological order.

0.7.2 (WIP)
---------------------------------
0.7.2 (Thursday 7th December 2023)
----------------------------------
- SpectralWidth now added to header extension automatically to match bids specification.
- NIfTI-MRS V0.8 now generated.
- Better handling of philips spar/sdat tags and singleton dimensions.

0.7.1 (Tuesday 7th November 2023)
---------------------------------
Expand Down
14 changes: 13 additions & 1 deletion spec2nii/Philips/philips.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from spec2nii.nifti_orientation import NIFTIOrient, calc_affine
from spec2nii import __version__ as spec2nii_ver

default_tag_order = ['DIM_DYN', 'DIM_EDIT', 'DIM_USER_0']


def read_sdat_spar_pair(sdat_file, spar_file, shape=None, tags=None, fileout=None, special=None):
"""Read and convert SPAR/SDAT pairs from Philips scanners
Expand Down Expand Up @@ -55,9 +57,19 @@ def read_sdat_spar_pair(sdat_file, spar_file, shape=None, tags=None, fileout=Non
meta = spar_to_nmrs_hdrext(spar_params)
meta.set_standard_def('OriginalFile', [sdat_file.name])

for idx, tag in enumerate(tags):
# Sort dimension tags
# First ensure user defined tags has length of 3.
while len(tags) < 3:
tags.append(None)

# Set user defined tags, or the default if the dimension exists
# and is larger than 1
for idx, (tag, default) in enumerate(zip(tags, default_tag_order)):
npdim = idx + 4
if tag is not None:
meta.set_dim_info(idx, tag)
elif data.ndim > npdim and data.shape[npdim] > 1:
meta.set_dim_info(idx, default)

# Orientation
if spar_params["volume_selection_enable"] == "yes":
Expand Down
6 changes: 4 additions & 2 deletions spec2nii/spec2nii.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ def add_common_parameters(subparser):
"-t", "--tags",
type=str,
nargs='+',
default=["DIM_DYN", None, None],
help="Specify NIfTI MRS tags used for higher (5th-7th) dimensions.")
default=[None, None, None],
help="Specify NIfTI MRS tags used for higher (5th-7th) dimensions. "
"Defaults to DIM_DYN if more than one spectrum is present. "
"Can be used to create singleton higher dimensions.")
parser_philips.add_argument(
"-s", "--shape",
type=int,
Expand Down
2 changes: 1 addition & 1 deletion tests/spec2nii_test_data
Submodule spec2nii_test_data updated from e0ad58 to ca9850
64 changes: 64 additions & 0 deletions tests/test_philips_sdat_spar.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@
import numpy as np

from .io_for_tests import read_nifti_mrs
from nifti_mrs.nifti_mrs import NIFTI_MRS

# Data paths
philips_path = Path(__file__).parent / 'spec2nii_test_data' / 'philips'
svs_path_sdat = philips_path / 'P1' / 'SV_PRESS_sh_6_2_raw_act.SDAT'
svs_path_spar = philips_path / 'P1' / 'SV_PRESS_sh_6_2_raw_act.SPAR'

svs_ma_path_sdat = philips_path / 'spar_multi_avg' / 'multi_avg.sdat'
svs_ma_path_spar = philips_path / 'spar_multi_avg' / 'multi_avg.spar'

svs_edit_path_sdat = philips_path / 'HERCULES_spar_sdat' / 'HERCULES_Example_noID.sdat'
svs_edit_path_spar = philips_path / 'HERCULES_spar_sdat' / 'HERCULES_Example_noID.spar'

Expand Down Expand Up @@ -50,6 +54,66 @@ def test_svs(tmp_path):
assert hdr_ext['OriginalFile'][0] == svs_path_sdat.name
assert hdr_ext['SoftwareVersions'] == '5.5.2 ; .5.2 ;'

# Check no hanging singleton dimension
nmrs_obj = NIFTI_MRS(tmp_path / 'svs.nii.gz')
assert nmrs_obj.shape == (1, 1, 1, 2048)

subprocess.check_call([
'spec2nii', 'philips',
'-t', 'DIM_DYN',
'-f', 'svs_singleton',
'-o', tmp_path,
'-j',
str(svs_path_sdat),
str(svs_path_spar)])

img_t = read_nifti_mrs(tmp_path / 'svs_singleton.nii.gz')
assert img_t.shape == (1, 1, 1, 2048)

nmrs_obj = NIFTI_MRS(tmp_path / 'svs_singleton.nii.gz')
assert nmrs_obj.shape == (1, 1, 1, 2048, 1)

hdr_ext_codes = img_t.header.extensions.get_codes()
hdr_ext = json.loads(img_t.header.extensions[hdr_ext_codes.index(44)].get_content())
assert hdr_ext['dim_5'] == 'DIM_DYN'


def test_multiavg_svs(tmp_path):

subprocess.check_call(['spec2nii', 'philips',
'-f', 'svs',
'-o', tmp_path,
'-j',
str(svs_ma_path_sdat),
str(svs_ma_path_spar)])

img_t = read_nifti_mrs(tmp_path / 'svs.nii.gz')

assert img_t.shape == (1, 1, 1, 2048, 10)
assert np.iscomplexobj(img_t.dataobj)

hdr_ext_codes = img_t.header.extensions.get_codes()
hdr_ext = json.loads(img_t.header.extensions[hdr_ext_codes.index(44)].get_content())

assert hdr_ext['dim_5'] == 'DIM_DYN'

# Check override tags
subprocess.check_call([
'spec2nii', 'philips',
'-t', 'DIM_USER_0',
'-f', 'svs_2',
'-o', tmp_path,
'-j',
str(svs_ma_path_sdat),
str(svs_ma_path_spar)])

img_t = read_nifti_mrs(tmp_path / 'svs_2.nii.gz')
assert img_t.shape == (1, 1, 1, 2048, 10)

hdr_ext_codes = img_t.header.extensions.get_codes()
hdr_ext = json.loads(img_t.header.extensions[hdr_ext_codes.index(44)].get_content())
assert hdr_ext['dim_5'] == 'DIM_USER_0'


def test_svs_edit(tmp_path):

Expand Down

0 comments on commit cc056a8

Please sign in to comment.