Skip to content

Commit 2fa9872

Browse files
mgxdeffigies
authored andcommitted
enh+wip: support for philips dcm w/ derived volume
* if DICOM has MR Diffusion Sequence (0018, 9117), discard any derived frames * out correct final shape * TODO: fix get_data() repr
1 parent 4fb633f commit 2fa9872

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

nibabel/nicom/dicomwrappers.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from .dwiparams import B2q, nearest_pos_semi_def, q2bg
2222
from ..openers import ImageOpener
2323
from ..onetime import setattr_on_read as one_time
24-
from ..pydicom_compat import tag_for_keyword
24+
from ..pydicom_compat import tag_for_keyword, Sequence
2525

2626

2727
class WrapperError(Exception):
@@ -461,10 +461,19 @@ def __init__(self, dcm_data):
461461
Wrapper.__init__(self, dcm_data)
462462
self.dcm_data = dcm_data
463463
self.frames = dcm_data.get('PerFrameFunctionalGroupsSequence')
464+
self._nframes = self.get('NumberOfFrames')
464465
try:
465466
self.frames[0]
466467
except TypeError:
467468
raise WrapperError("PerFrameFunctionalGroupsSequence is empty.")
469+
# DWI image where derived isotropic, ADC or trace volume was appended to the series
470+
if self.frames[0].get([0x18, 0x9117]):
471+
self.frames = Sequence(
472+
frame for frame in self.frames if
473+
frame.get([0x18, 0x9117])[0].get([0x18, 0x9075]).value
474+
!= 'ISOTROPIC'
475+
)
476+
self._nframes = len(self.frames)
468477
try:
469478
self.shared = dcm_data.get('SharedFunctionalGroupsSequence')[0]
470479
except TypeError:
@@ -503,8 +512,7 @@ def image_shape(self):
503512
if None in (rows, cols):
504513
raise WrapperError("Rows and/or Columns are empty.")
505514
# Check number of frames
506-
n_frames = self.get('NumberOfFrames')
507-
assert len(self.frames) == n_frames
515+
assert len(self.frames) == self._nframes
508516
frame_indices = np.array(
509517
[frame.FrameContentSequence[0].DimensionIndexValues
510518
for frame in self.frames])
@@ -528,12 +536,15 @@ def image_shape(self):
528536
# Store frame indices
529537
self._frame_indices = frame_indices
530538
if n_dim < 4: # 3D volume
531-
return rows, cols, n_frames
539+
return rows, cols, self._nframes
532540
# More than 3 dimensions
533541
ns_unique = [len(np.unique(row)) for row in self._frame_indices.T]
542+
if len(ns_unique) == 3:
543+
# derived volume is included
544+
ns_unique.pop(1)
534545
shape = (rows, cols) + tuple(ns_unique)
535546
n_vols = np.prod(shape[3:])
536-
if n_frames != n_vols * shape[2]:
547+
if self._nframes != n_vols * shape[2]:
537548
raise WrapperError("Calculated shape does not match number of "
538549
"frames.")
539550
return tuple(shape)

nibabel/nicom/tests/test_dicomwrappers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
DATA_FILE_DEC_RSCL = pjoin(IO_DATA_PATH, 'decimal_rescale.dcm')
3737
DATA_FILE_4D = pjoin(IO_DATA_PATH, '4d_multiframe_test.dcm')
3838
DATA_FILE_EMPTY_ST = pjoin(IO_DATA_PATH, 'slicethickness_empty_string.dcm')
39+
DATA_FILE_4D_DERIVED = pjoin(IO_DATA_PATH, '4d_multiframe_with_derived.dcm')
3940

4041
# This affine from our converted image was shown to match our image spatially
4142
# with an image from SPM DICOM conversion. We checked the matching with SPM
@@ -622,6 +623,13 @@ def test_slicethickness_fallback(self):
622623
dw = didw.wrapper_from_file(DATA_FILE_EMPTY_ST)
623624
assert_equal(dw.voxel_sizes[2], 1.0)
624625

626+
@dicom_test
627+
def test_data_derived_shape(self):
628+
# Test 4D diffusion data with an additional trace volume included
629+
# Excludes the trace volume and generates the correct shape
630+
dw = didw.wrapper_from_file(DATA_FILE_4D_DERIVED)
631+
assert_equal(dw.image_shape, (96, 96, 60, 33))
632+
625633
@dicom_test
626634
def test_data_fake(self):
627635
# Test algorithm for get_data

nibabel/pydicom_compat.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
read_file = pydicom.read_file
4141

4242
if have_dicom:
43+
from pydicom.sequence import Sequence
4344
try:
4445
# Versions >= 1.0
4546
tag_for_keyword = pydicom.datadict.tag_for_keyword

0 commit comments

Comments
 (0)