Skip to content

Commit 0f45ac0

Browse files
committed
ENH: add sorted_labels function to PARRECHeader and corresponding info to PARRECArrayProxy
1 parent 23bc068 commit 0f45ac0

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

bin/parrec2nii

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import numpy as np
88
import numpy.linalg as npl
99
import sys
1010
import os
11+
import json
1112
import nibabel
1213
import nibabel.parrec as pr
1314
from nibabel.parrec import one_line
@@ -262,6 +263,18 @@ def proc_file(infile, opts):
262263
fid.write('%s ' % val)
263264
fid.write('\n')
264265

266+
opts.dim_info = True # TODO: remove hard-coded value
267+
if opts.dim_info and pr_img.dataobj._dim_4_labels is not None:
268+
if len(list(pr_img.dataobj._dim_4_labels.keys())) > 0:
269+
with open(basefilename + '.ordering.json', 'w') as fid:
270+
json.dump(pr_img.dataobj._dim_4_labels, fid, sort_keys=True,
271+
indent=4)
272+
elif opts.dim_info and pr_img.dataobj._dim_3_4_labels is not None:
273+
if len(list(pr_img.dataobj._dim_3_4_labels.keys())) > 0:
274+
with open(basefilename + '.ordering.json', 'w') as fid:
275+
json.dump(pr_img.dataobj._dim_3_4_labels, fid, sort_keys=True,
276+
indent=4)
277+
265278
# write out dwell time if requested
266279
if opts.dwell_time:
267280
try:

nibabel/parrec.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,21 @@ def __init__(self, file_like, header, mmap=True, scaling='dv'):
569569
self._slice_scaling = header.get_data_scaling(scaling)
570570
self._rec_shape = header.get_rec_shape()
571571

572+
try:
573+
# store additional slice & volume label information
574+
self._dim_4_labels = header.sorted_labels(
575+
sorted_indices=self._slice_indices,
576+
collapse_slices=True)
577+
self._dim_3_4_labels = None
578+
except:
579+
# if non-unique slice orientations or image angulations, need to
580+
# also keep labels for the 3rd (slice) dimension
581+
self._dim_4_labels = None
582+
self._dim_3_4_labels = header.sorted_labels(
583+
sorted_indices=self._slice_indices,
584+
collapse_slices=False)
585+
586+
572587
@property
573588
def shape(self):
574589
return self._shape
@@ -1114,6 +1129,75 @@ def get_sorted_slice_indices(self):
11141129
n_used = np.prod(self.get_data_shape()[2:])
11151130
return sort_order[:n_used]
11161131

1132+
def sorted_labels(self, sorted_indices=None, collapse_slices=True):
1133+
""" return a dictionary of lists of the varying values in
1134+
``self.image_defs``. This is useful for custom data sorting. only
1135+
keys that have more than 1 unique value across the dataset will exist
1136+
in the returned `sort_info` dictionary.
1137+
1138+
Parameters
1139+
----------
1140+
sorted_indices : array, optional
1141+
sorted slice indices as returned by
1142+
``self.get_sorted_slice_indices``.
1143+
collapse_slices : bool, optional
1144+
if True, only return indices corresponding to the first slice
1145+
1146+
Returns
1147+
-------
1148+
sort_info : dict
1149+
Each key corresponds to a dynamically varying sequence dimension.
1150+
The ordering of values corresponds to that in sorted_indices.
1151+
"""
1152+
1153+
# define which keys to store sorting info for
1154+
dynamic_keys = ['slice number',
1155+
'cardiac phase number',
1156+
'echo number',
1157+
'label type',
1158+
'image_type_mr',
1159+
'dynamic scan number',
1160+
'slice orientation',
1161+
'image_display_orientation', # ????
1162+
'image angulation',
1163+
'scanning sequence',
1164+
'gradient orientation number',
1165+
'diffusion b value number']
1166+
1167+
if sorted_indices is None:
1168+
sorted_indices = self.get_sorted_slice_indices()
1169+
1170+
if collapse_slices:
1171+
dynamic_keys.remove('slice number')
1172+
1173+
non_unique_keys = []
1174+
for key in dynamic_keys:
1175+
if len(np.unique(self.image_defs[key])) > 1:
1176+
non_unique_keys.append(key)
1177+
1178+
if collapse_slices:
1179+
if 'slice orientation' in non_unique_keys:
1180+
raise ValueError("for non-unique slice orientation, need "
1181+
"collapse_slice=False")
1182+
if 'image angulation' in non_unique_keys:
1183+
raise ValueError("for non-unique image angulation, need "
1184+
"collapse_slice=False")
1185+
if 'image image_display_orientation' in non_unique_keys: # ???
1186+
raise ValueError("for non-unique display orientation, need "
1187+
"collapse_slice=False")
1188+
sl1_indices = self.image_defs['slice number'][sorted_indices] == 1
1189+
1190+
sort_info = {}
1191+
for key in non_unique_keys:
1192+
if collapse_slices:
1193+
sort_info[key] = list(
1194+
self.image_defs[key][sorted_indices][sl1_indices])
1195+
else:
1196+
sort_info[key] = list(
1197+
self.image_defs[key][sorted_indices])
1198+
1199+
return sort_info
1200+
11171201

11181202
class PARRECImage(SpatialImage):
11191203
"""PAR/REC image"""

0 commit comments

Comments
 (0)