Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XA61A localizer crash #1392

Open
bpinsard opened this issue Nov 26, 2024 · 10 comments
Open

XA61A localizer crash #1392

bpinsard opened this issue Nov 26, 2024 · 10 comments

Comments

@bpinsard
Copy link
Contributor

I got my hands on Siemens XA61A data (Cima.X), and the localizer causes heudiconv (@yarikoptic FYI) to crash in nibabel code.

Traceback (most recent call last):                                             
  File "/home/bpinsard/.virtualenvs/heudiconv_dev/bin/heudiconv", line 8, in <module>
    sys.exit(main())                                                           
  File "/home/bpinsard/.virtualenvs/heudiconv_dev/lib/python3.10/site-packages/heudiconv/cli/run.py", line 30, in main
    workflow(**kwargs)                                                         
  File "/home/bpinsard/.virtualenvs/heudiconv_dev/lib/python3.10/site-packages/heudiconv/main.py", line 410, in workflow
    study_sessions = get_study_sessions(        
  File "/home/bpinsard/.virtualenvs/heudiconv_dev/lib/python3.10/site-packages/heudiconv/parser.py", line 221, in get_study_sessions
    seqinfo_dict = group_dicoms_into_seqinfos(
  File "/home/bpinsard/.virtualenvs/heudiconv_dev/lib/python3.10/site-packages/heudiconv/dicoms.py", line 342, in group_dicoms_into_seqinfos
    mwinfo = validate_dicom(filename, dcmfilter)                    
  File "/home/bpinsard/.virtualenvs/heudiconv_dev/lib/python3.10/site-packages/heudiconv/dicoms.py", line 179, in validate_dicom
    del mw.series_signature[sig]                                                                                                                              
  File "/usr/lib/python3.10/functools.py", line 981, in __get__
    val = self.func(instance)
  File "/home/bpinsard/.virtualenvs/heudiconv_dev/lib/python3.10/site-packages/nibabel/nicom/dicomwrappers.py", line 886, in series_signature
    signature['image_shape'] = (self.image_shape, eq)
  File "/usr/lib/python3.10/functools.py", line 981, in __get__
    val = self.func(instance)                                                  
  File "/home/bpinsard/.virtualenvs/heudiconv_dev/lib/python3.10/site-packages/nibabel/nicom/dicomwrappers.py", line 775, in image_shape
    raise WrapperError("Number of slice indices and positions don't match")
nibabel.nicom.dicomwrappers.WrapperError: Number of slice indices and positions don't match

This is a classic localizer with 3 slices in each plane, but packed into a single enhanced dicoms.
Possibly Siemens is not following some dicoms specs.

dcm2niix v1.0.20240731 (FYI @neurolabusc) is also behaving abnormally, as it stacks the 3 slices in 1 volume, instead of splitting it in separate niftis.

@bpinsard
Copy link
Contributor Author

Precision: because the crash occurs when heudiconv indexes dicoms, it is not possible to filter these with the heuristics.

@bpinsard
Copy link
Contributor Author

The issue seems to be that the FrameContentSequence.StackID is the same for the 3 orientations?
So Siemens is not adequately implementing DICOM standard.

In the meantime, nibabel seems no to want to deal with multiple stacks for now, understandably due to the complexity.

# Make sure there is only one StackID remaining
first_fcs = self.frames[0].get('FrameContentSequence', (None,))[0]
if first_fcs is not None and hasattr(first_fcs, 'StackID'):
if len({frame.FrameContentSequence[0].StackID for frame in self.frames}) > 1:
raise WrapperError('More than one StackID remains after filtering')

@bpinsard
Copy link
Contributor Author

I manually fixed the StackID to 1,2,3 and InStackPositionNumber to 1 for all slices, and nibabel is effectively able to deal with it.

@yarikoptic
Copy link
Member

The issue seems to be that the FrameContentSequence.StackID is the same for the 3 orientations?
So Siemens is not adequately implementing DICOM standard.

@neurolabusc is this something you identified/reported to Siemens too?

@neurolabusc
Copy link

@yarikoptic it would be nice to have a concrete example of this. Can you tell me if the first series loca_3plan_haste from dcm2niix issue 870 dataset phantom_check_MBfactor_CimaX_XA61.zip shows this issue? Have you tested the latest commit of the dcm2niix development branch?

@yarikoptic
Copy link
Member

@bpinsard could you please check those out?

@bpinsard
Copy link
Contributor Author

I tested dcm2niix with the latest branch, and with the localizer from ICM Paris Cima.X and it results in a single nifti files with all slices stacked.
And give the same error in nibabel when trying to get image_shape on the dicom wrapper.

These are all in the same stack, which is not following the dicom spec.

dcmdump 88972147 | grep "StackID"
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID
        (0020,9056) SH [1]                                      #   2, 1 StackID

@neurolabusc
Copy link

@bpinsard correctly detects that the slices are not aligned, and correctly ignores this if you request it ignores localizers (-i y). I agree it creates a single NIfTI if you include localizers, but it generates a clear warning. It seems to me that dcm2niix is providing the best interpretation it can given the limitations of the NIfTI format (which requires all slices are in the same plane). My sense is that dcm2niix behaves appropriately, and nibabel should be updated to deal with this situation. I agree that it would e helpful if Siemens generated a unique StackID (0020,9056) so perhaps a topic for the Siemens Research Collaboration Manager associated with your center.

Chris Rorden's dcm2niiX version v1.0.20241127  Clang16.0.0 ARM (64-bit MacOS)
Found 1 DICOM file(s)
slice orientation varies (localizer?) [0 1 0 0 0 -1] != [1 0 0 0 0 -1]
Ignoring localizer (sequence '') of series 1 /Users/chris/Downloads/XA61/20241003104114/1_loca_3plan_haste/0019_1.3.12.2.1107.5.2.63.213017.2024100310415286366400427.dcm

@bpinsard
Copy link
Contributor Author

@neurolabusc yes, as the Siemens dicoms are not compliant, I am ok with current dcm2niix behavior.
This issue was mainly opened for other encountering that issue to know the cause and potential solutions.
With heudiconv, this would require the heuristics to set a filter_dicom function to discard dicoms before they are further indexed and passed to dcm2niix.

@moloney
Copy link
Contributor

moloney commented Dec 5, 2024

In nibabel we can define a FrameFilter that would reject all frames that don't match the orientation of the first frame. Then you would just get one slice (or set of slices).

This does hint at the need for an API for getting multiple SpatialImage instances from a single file. While the localizer case isn't very motivating for me, I vaguely remember hearing some Vendors are going to stick multiple series (or entire studies) into a single multi-frame DICOM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants