Skip to content

Commit fa05777

Browse files
committed
BF+TST: Handle case with extra-spatial index that is unique per frame
Not sure if this ever actually happens in real multiframe data, but it does in non-multiframe and I can imagine if a DimensionIndexSequence element refrences a per-frame AcquisitionTime then this could happen.
1 parent 2715226 commit fa05777

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

nibabel/nicom/dicomwrappers.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -598,22 +598,35 @@ def image_shape(self):
598598
unique = np.unique(row)
599599
if len(unique) != count:
600600
raise WrapperError("Number of slice indices and positions don't match")
601+
elif count == n_frames:
602+
if shape[-1] == "remaining":
603+
raise WrapperError("At most one index have ambiguous size")
604+
shape.append("remaining")
605+
continue
601606
new_parts, leftover = divmod(curr_parts, count)
602-
allowed_val_counts = [new_parts * frames_per_part]
603-
if row_idx != slice_dim_idx:
604-
# Except for the slice dim, having a unique value for each frame is valid
605-
allowed_val_counts.append(n_frames)
607+
expected = new_parts * frames_per_part
606608
if (
607609
leftover != 0 or
608-
any(np.count_nonzero(row == val) not in allowed_val_counts for val in unique)
610+
any(np.count_nonzero(row == val) != expected for val in unique)
609611
):
610612
if row_idx == slice_dim_idx:
611613
raise WrapperError("Missing slices from multiframe")
612614
del_indices[row_idx] = count
613615
continue
616+
if shape[-1] == "remaining":
617+
shape[-1] = new_parts
618+
frames_per_part *= shape[-1]
619+
new_parts = 1
614620
frames_per_part *= count
615621
shape.append(count)
616622
curr_parts = new_parts
623+
if shape[-1] == "remaining":
624+
if curr_parts > 1:
625+
shape[-1] = curr_parts
626+
curr_parts = 1
627+
else:
628+
del_indices[len(shape)] = 1
629+
shape = shape[:-1]
617630
if del_indices:
618631
if curr_parts > 1:
619632
ns_failed = [k for k, v in del_indices.items() if v != 1]

nibabel/nicom/tests/test_dicomwrappers.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,28 @@ def test_shape(self):
623623
(1, 1, 2, 2), (1, 2, 2, 2))
624624
fake_mf.update(fake_shape_dependents(div_seq, sid_dim=0))
625625
assert MFW(fake_mf).image_shape == (32, 64, 2, 3)
626+
# Test invalid 4D indices
627+
div_seq = ((1, 1, 1), (1, 2, 1), (1, 1, 2), (1, 2, 2), (1, 1, 3), (1, 2, 4))
628+
fake_mf.update(fake_shape_dependents(div_seq, sid_dim=0))
629+
with pytest.raises(didw.WrapperError):
630+
MFW(fake_mf).image_shape
631+
div_seq = ((1, 1, 1), (1, 2, 1), (1, 1, 2), (1, 2, 2), (1, 1, 3), (1, 2, 2))
632+
fake_mf.update(fake_shape_dependents(div_seq, sid_dim=0))
633+
with pytest.raises(didw.WrapperError):
634+
MFW(fake_mf).image_shape
635+
# Time index that is unique to each frame
636+
div_seq = ((1, 1, 1), (1, 2, 2), (1, 1, 3), (1, 2, 4), (1, 1, 5), (1, 2, 6))
637+
fake_mf.update(fake_shape_dependents(div_seq, sid_dim=0))
638+
assert MFW(fake_mf).image_shape == (32, 64, 2, 3)
639+
div_seq = ((1, 1, 1, 1), (1, 2, 2, 1),
640+
(1, 1, 3, 1), (1, 2, 4, 1),
641+
(1, 1, 5, 1), (1, 2, 6, 1),
642+
(1, 1, 7, 2), (1, 2, 8, 2),
643+
(1, 1, 9, 2), (1, 2, 10, 2),
644+
(1, 1, 11, 2), (1, 2, 12, 2),
645+
)
646+
fake_mf.update(fake_shape_dependents(div_seq, sid_dim=0))
647+
assert MFW(fake_mf).image_shape == (32, 64, 2, 3, 2)
626648

627649
def test_iop(self):
628650
# Test Image orient patient for multiframe

0 commit comments

Comments
 (0)