|
12 | 12 | import pytest |
13 | 13 | from numpy.testing import assert_array_almost_equal, assert_array_equal |
14 | 14 |
|
| 15 | +from ...openers import ImageOpener |
15 | 16 | from ...tests.nibabel_data import get_nibabel_data, needs_nibabel_data |
16 | 17 | from ...volumeutils import endian_codes |
17 | 18 | from .. import dicomreaders as didr |
|
39 | 40 | 'dcm_qa_xa30', |
40 | 41 | 'In/20_DWI_dir80_AP/0001_1.3.12.2.1107.5.2.43.67093.2022071112140611403312307.dcm', |
41 | 42 | ) |
| 43 | +DATA_FILE_XA60_MULTI_ORIENT = pjoin( |
| 44 | + get_nibabel_data(), |
| 45 | + 'dcm_qa_xa60', |
| 46 | + 'In/XA60/DICOM/24100413/39280000/75739321', |
| 47 | +) |
42 | 48 |
|
43 | 49 | # This affine from our converted image was shown to match our image spatially |
44 | 50 | # with an image from SPM DICOM conversion. We checked the matching with SPM |
@@ -873,6 +879,57 @@ def test_data_trace(self): |
873 | 879 | dw = didw.wrapper_from_file(DATA_FILE_SIEMENS_TRACE) |
874 | 880 | assert dw.image_shape == (72, 72, 39) |
875 | 881 |
|
| 882 | + @dicom_test |
| 883 | + @needs_nibabel_data('dcm_qa_xa60') |
| 884 | + def test_data_multi_orient_same_stack(self): |
| 885 | + # Test that a file with 3 orientations sharing the same StackID returns |
| 886 | + # only one stack/orientation |
| 887 | + dw = didw.wrapper_from_file(DATA_FILE_XA60_MULTI_ORIENT) |
| 888 | + assert dw.image_shape == (512, 512, 7) |
| 889 | + |
| 890 | + @dicom_test |
| 891 | + @needs_nibabel_data('dcm_qa_xa60') |
| 892 | + def test_data_multi_orient_extract_all(self): |
| 893 | + with ImageOpener(DATA_FILE_XA60_MULTI_ORIENT) as fobj: |
| 894 | + dcm_data = pydicom.dcmread(fobj) |
| 895 | + for keep_group, nslices in enumerate([7, 3, 3]): |
| 896 | + dw = didw.wrapper_from_data( |
| 897 | + dcm_data, frame_filters=[didw.FilterMultiOrient(keep_group=keep_group)] |
| 898 | + ) |
| 899 | + assert dw.image_shape == (512, 512, nslices) |
| 900 | + |
| 901 | + @dicom_test |
| 902 | + def test_filter_multi_orient_unit(self): |
| 903 | + iop_a = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0] |
| 904 | + iop_b = [0.0, 1.0, 0.0, 1.0, 0.0, 0.0] |
| 905 | + |
| 906 | + class FakeFrame(pydicom.Dataset): |
| 907 | + def __init__(self, iop=None): |
| 908 | + super().__init__() |
| 909 | + if iop is not None: |
| 910 | + elem = pydicom.Dataset() |
| 911 | + elem.ImageOrientationPatient = iop |
| 912 | + self.PlaneOrientationSequence = [elem] |
| 913 | + |
| 914 | + class FakeWrp: |
| 915 | + def __init__(self, frames): |
| 916 | + self.frames = frames |
| 917 | + |
| 918 | + filt = didw.FilterMultiOrient() |
| 919 | + # Single orientation -> does not apply |
| 920 | + assert not filt.applies(FakeWrp([FakeFrame(iop_a), FakeFrame(iop_a)])) |
| 921 | + # Frame missing PlaneOrientationSequence -> does not apply |
| 922 | + assert not filt.applies(FakeWrp([FakeFrame(), FakeFrame()])) |
| 923 | + # Mixed orientations -> applies, keeps first group |
| 924 | + wrp = FakeWrp([FakeFrame(iop_a), FakeFrame(iop_b)]) |
| 925 | + with pytest.warns(UserWarning, match='Multiple frame orientations'): |
| 926 | + assert filt.applies(wrp) |
| 927 | + assert filt.keep(wrp.frames[0]) |
| 928 | + assert not filt.keep(wrp.frames[1]) |
| 929 | + # Out-of-range group index |
| 930 | + with pytest.raises(didw.WrapperError): |
| 931 | + didw.FilterMultiOrient(keep_group=5).applies(wrp) |
| 932 | + |
876 | 933 | @dicom_test |
877 | 934 | @needs_nibabel_data('nitest-dicom') |
878 | 935 | def test_data_unreadable_private_headers(self): |
|
0 commit comments