Skip to content

Commit 019f448

Browse files
moloneyeffigies
authored andcommitted
BF+TST: Fix 2D plus time case
Explicitly use `InStackPositionNumber` to identify the slice dim, produce correct output for 2D + time data.
1 parent 14c24ef commit 019f448

File tree

2 files changed

+19
-7
lines changed

2 files changed

+19
-7
lines changed

nibabel/nicom/dicomwrappers.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -470,10 +470,10 @@ def __init__(self, dcm_data):
470470
# Try to determine slice order and minimal image position patient
471471
self._frame_slc_ord = self._ipp = None
472472
try:
473-
frame_ipps = [self.shared.PlanePositionSequence[0].ImagePositionPatient]
473+
frame_ipps = [f.PlanePositionSequence[0].ImagePositionPatient for f in self.frames]
474474
except AttributeError:
475475
try:
476-
frame_ipps = [f.PlanePositionSequence[0].ImagePositionPatient for f in self.frames]
476+
frame_ipps = [self.shared.PlanePositionSequence[0].ImagePositionPatient]
477477
except AttributeError:
478478
frame_ipps = None
479479
if frame_ipps is not None and all(ipp is not None for ipp in frame_ipps):
@@ -575,33 +575,38 @@ def image_shape(self):
575575
raise WrapperError('Missing information, cannot remove indices with confidence.')
576576
derived_dim_idx = dim_seq.index(derived_tag)
577577
frame_indices = np.delete(frame_indices, derived_dim_idx, axis=1)
578+
dim_seq.pop(derived_dim_idx)
578579
# Determine the shape and which indices to use
579580
shape = [rows, cols]
580581
curr_parts = n_frames
581582
frames_per_part = 1
582583
del_indices = {}
584+
stackpos_tag = pydicom.datadict.tag_for_keyword('InStackPositionNumber')
585+
slice_dim_idx = dim_seq.index(stackpos_tag)
583586
for row_idx, row in enumerate(frame_indices.T):
584587
unique = np.unique(row)
585588
count = len(unique)
586-
if count == 1 or curr_parts == 1:
589+
if curr_parts == 1 or (count == 1 and row_idx != slice_dim_idx):
587590
del_indices[row_idx] = count
588591
continue
589592
# Replace slice indices with order determined from slice positions along normal
590-
if len(shape) == 2:
593+
if row_idx == slice_dim_idx:
594+
if len(shape) > 2:
595+
raise WrapperError('Non-singular index precedes the slice index')
591596
row = self._frame_slc_ord
592597
frame_indices.T[row_idx, :] = row
593598
unique = np.unique(row)
594599
if len(unique) != count:
595600
raise WrapperError("Number of slice indices and positions don't match")
596601
new_parts, leftover = divmod(curr_parts, count)
597602
allowed_val_counts = [new_parts * frames_per_part]
598-
if len(shape) > 2:
603+
if row_idx != slice_dim_idx:
599604
# Except for the slice dim, having a unique value for each frame is valid
600605
allowed_val_counts.append(n_frames)
601606
if leftover != 0 or any(
602607
np.count_nonzero(row == val) not in allowed_val_counts for val in unique
603608
):
604-
if len(shape) == 2:
609+
if row_idx == slice_dim_idx:
605610
raise WrapperError('Missing slices from multiframe')
606611
del_indices[row_idx] = count
607612
continue

nibabel/nicom/tests/test_dicomwrappers.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,10 +488,13 @@ def __init__(self, div, sid, ipp, iop):
488488
assert len(ipp_seq) == num_of_frames
489489
# create the DimensionIndexSequence
490490
dim_idx_seq = [DimIdxSeqElem()] * n_indices
491+
# Add entry for InStackPositionNumber to DimensionIndexSequence
492+
fcs_tag = pydicom.datadict.tag_for_keyword('FrameContentSequence')
493+
isp_tag = pydicom.datadict.tag_for_keyword('InStackPositionNumber')
494+
dim_idx_seq[slice_dim] = DimIdxSeqElem(isp_tag, fcs_tag)
491495
# add an entry for StackID into the DimensionIndexSequence
492496
if sid_dim is not None:
493497
sid_tag = pydicom.datadict.tag_for_keyword('StackID')
494-
fcs_tag = pydicom.datadict.tag_for_keyword('FrameContentSequence')
495498
dim_idx_seq[sid_dim] = DimIdxSeqElem(sid_tag, fcs_tag)
496499
# create the PerFrameFunctionalGroupsSequence
497500
frames = [
@@ -546,6 +549,10 @@ def test_shape(self):
546549
div_seq = ((1, 1, 2),)
547550
fake_mf.update(fake_shape_dependents(div_seq, sid_dim=0))
548551
assert MFW(fake_mf).image_shape == (32, 64)
552+
# Check 2D plus time
553+
div_seq = ((1, 1, 1), (1, 1, 2), (1, 1, 3))
554+
fake_mf.update(fake_shape_dependents(div_seq, sid_dim=0))
555+
assert MFW(fake_mf).image_shape == (32, 64, 1, 3)
549556
# Check 3D shape when StackID index is 0
550557
div_seq = ((1, 1), (1, 2), (1, 3), (1, 4))
551558
fake_mf.update(fake_shape_dependents(div_seq, sid_dim=0))

0 commit comments

Comments
 (0)