wtclarke / spec2nii

Multi-format in vivo MR spectroscopy conversion to NIFTI
Other
26 stars 23 forks source link

Conversion failure on GE data #123

Open mcraig-ibme opened 11 months ago

mcraig-ibme commented 11 months ago

I am getting a conversion failure on GE MRS data - the command line and backtrace are below, however the root cause seems to be zeros in one column of the affine matrix. If I print out the calculated affine I get:

[[-22.80869862   0.          -3.10708493 -31.39293289]
 [ 11.13030002   0.          22.59598556  53.63864517]
 [ 15.99623983   0.         -20.15277751  29.13773346]
 [  0.           0.           0.           1.        ]]

Any ideas what might be going wrong, and whether there's any way to work around this? Many thanks, Martin

spec2nii ge -o mrs_mask -f mrs_data -j P03072.7

/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py:1088: RuntimeWarning: invalid value encountered in divide
  R = RZS / zooms
/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/numpy/linalg/linalg.py:2180: RuntimeWarning: invalid value encountered in det
  r = _umath_linalg.det(a, signature=signature)
Traceback (most recent call last):
  File "/home/bbzmsc/.conda/envs/brightmind/bin/spec2nii", line 10, in <module>
    sys.exit(main())
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/spec2nii.py", line 679, in main
    spec2nii(*args)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/spec2nii.py", line 290, in __init__
    args.func(args)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/spec2nii.py", line 628, in ge
    self.imageOut, self.fileoutNames = read_pfile(args.file, args.fileout)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/GE/ge_pfile.py", line 71, in read_pfile
    data, fname_suffix = _process_svs_pfile(pfile)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/spec2nii/GE/ge_pfile.py", line 113, in _process_svs_pfile
    out_nmrs.append(gen_nifti_mrs_hdr_ext(dd, dwelltime, mm, orientation.Q44, no_conj=True))
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nifti_mrs/create_nmrs.py", line 128, in gen_nifti_mrs_hdr_ext
    tmp_img = nib.nifti2.Nifti2Image(
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 1848, in __init__
    super().__init__(dataobj, affine, header, extra, file_map, dtype)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/analyze.py", line 909, in __init__
    super().__init__(dataobj, affine, header, extra, file_map)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/spatialimages.py", line 531, in __init__
    self.update_header()
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 2273, in update_header
    super().update_header()
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 1884, in update_header
    super().update_header()
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/spatialimages.py", line 565, in update_header
    self._affine2header()
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 1894, in _affine2header
    hdr.set_qform(self._affine, code='unknown')
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/nibabel/nifti1.py", line 1100, in set_qform
    P, S, Qs = npl.svd(R)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/numpy/linalg/linalg.py", line 1681, in svd
    u, s, vh = gufunc(a, signature=signature, extobj=extobj)
  File "/home/bbzmsc/.conda/envs/brightmind/lib/python3.10/site-packages/numpy/linalg/linalg.py", line 121, in _raise_linalgerror_svd_nonconvergence
    raise LinAlgError("SVD did not converge")
numpy.linalg.LinAlgError: SVD did not converge
wtclarke commented 11 months ago

Hi Martin,

What's the data specifically? SVS/MRSI? What particular sequence? Orientation etc?

GE is definitely the vendor I have least experience with and least test data currently, so there is likely stuff I get not entirely right. Are you able to share the data?

mcraig-ibme commented 11 months ago

Hi, thanks for the response, still waiting to find out if I'm allowed to share the data, it's MRS but I don't know more details of the sequence, sorry, it's not my area of expertise! I will get back to you if I can find out some more details.

wtclarke commented 11 months ago

If it turns out you can't share it we can do some digging here.

You could:

  1. Stick a breakpoint here and inspect the value of psd, which will give us a good idea of the sequence.
  2. Then the place where the NIfTI orientation is calculated is in this _calculate_affine function. From the backtrace it looks like there is a zero somewhere there shouldn't be. What do voxel_size and dcos evaluate to in that function?
JonteP commented 10 months ago

I have the exact same issue with GE data. Interestingly, we run the same sequence with same voxel dimensions in three different locations and only one of them behaves like this.

psd=probe-p dcos=[[-0.84649784 0.15044474 -0.51069346] [-0.24917919 0.73573466 0.62976525] [-0.47047969 -0.66034907 0.5853101 ]] voxel_size=[25. 30. 0.]

hacking ge_pfile.py to force voxel_size to the expected dimensions [25,30,20] makes everything run fine and the stored voxel placement looks correct.

Comparing the three voxels, the other two are placed close to the midline with mainly rotations around the x-axis (dorsal ACC and V1), while this one that causes trouble is placed at the dorsolateral PFC with much more rotations applied. Can that make a difference?

wtclarke commented 10 months ago

Hi @JonteP , do you have access to the GE distributed pfile reading software? If so can you tell me if that also reads the wrong voxel sizes?

I believe the sizes should be in: rhi_user8 rhi_user9 rhi_user10

What version of scanner software are you on?

JonteP commented 10 months ago

Hi @JonteP , do you have access to the GE distributed pfile reading software? If so can you tell me if that also reads the wrong voxel sizes?

I believe the sizes should be in: rhi_user8 rhi_user9 rhi_user10

What version of scanner software are you on?

I don't believe I have access to that software. I tried running Osprey's CoRegister function on the p-file with a t1 and it seems to read the voxel placement and dimensions fine.

The software version listed in json sidecars from other sequences that were converted with dcm2niix is "27\LX\MR Software release:MP26.0_R02_1941.a".

Hope that helps!

wtclarke commented 10 months ago

Great, are you able to share the data?

JonteP commented 10 months ago

I'm sorry, I do not own the data. Maybe it helps to look at Osprey's GELoad.m?

It identifies the version as 26.002 so the magic happens under case {'26.002','27','27.001','28.002','28.003','30'}

hdr.geometry.size will be set to [25 20 30].

wtclarke commented 7 months ago

@mcraig-ibme and @JonteP I have a proposed fix, but without any test data and a matching image of what the voxel orientation should look like I don't know whether its right. Would you be so kind as to test the 123-conversion-failure-on-ge-data-1 branch on your data?

@mcraig-ibme Your example data now generates a valid file, but I can't tell if the orientation information is correct.

JonteP commented 7 months ago

I just tried that branch and while it now converts without any issue, the voxel placement still seems problematic. We have 3 voxel placements, 2 of which are in the dorsal ACC and medial occipital cortex. These are basically only rotated within a sagittal plane and both are oriented correctly after spec2nii conversion. The third voxel placement is within the dorsolateral PFC, and rotated in all three dimensions. These were problematic to convert before, and now appear to be oriented the wrong way. Note how it is elongated in the z-direction rather than y: image

wtclarke commented 7 months ago

Ok, it might be that I need a larger test set to resolve, but I will also contact GE to see if they can help.

Sent from Outlook for Androidhttps://aka.ms/AAb9ysg


From: JonteP @.> Sent: Thursday, March 21, 2024 10:30:18 AM To: wtclarke/spec2nii @.> Cc: William Clarke @.>; Comment @.> Subject: Re: [wtclarke/spec2nii] Conversion failure on GE data (Issue #123)

I just tried that branch and while it now converts without any issue, the voxel placement still seems problematic. We have 3 voxel placements, 2 of which are in the dorsal ACC and medial occipital cortex. These are basically only rotated within a sagittal plane and both are oriented correctly after spec2nii conversion. The third voxel placement is within the dorsolateral PFC, and rotated in all three dimensions. These were problematic to convert before, and now appear to be oriented the wrong way. Note how it is elongated in the z-direction rather than y: image.png (view on web)https://github.com/wtclarke/spec2nii/assets/40265580/2db4b5f0-80f0-45e5-871c-360976b21d56

— Reply to this email directly, view it on GitHubhttps://github.com/wtclarke/spec2nii/issues/123#issuecomment-2011871267, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AFJJTTTIWS6CVQPJILJTGS3YZKZDVAVCNFSM6AAAAABAROFFBSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMJRHA3TCMRWG4. You are receiving this because you commented.Message ID: @.***>

JonteP commented 7 months ago

Again, Osprey handles this correctly if I load the P-file directly (looks more or less like a 90 degree rotation is needed in each dimension): image

wtclarke commented 7 months ago

Ok, but I can't reverse engineer their entire code, especially without test data. I've just pushed another update to the same branch. It has similar logic now to osprey, but I don't know the exact ordering of the dimensions that will be needed. As such I've put some debug statements in which will tell me what is happening in your case. Would you be so kind as to run your three examples again an report back whether their orientations are correct and what the printed outputs are?

JonteP commented 7 months ago

Took a while, but I tested the latest code now and the voxel placement matches Osprey and looks correct. This is the debug output: 25.0 20.0 30.0 1 [25. 30. 20.]

wtclarke commented 7 months ago

Great, and thanks for coming back to me. Do the other cases still match?

JonteP commented 7 months ago

Yes, they look ok. The debug output for those that already worked previously is: 25.0 30.0 20.0 2 [25. 30. 20.]

wtclarke commented 7 months ago

Thanks. @markmikkelsen is collecting me some data to validate this on, at which point I'll get this included in the main release.

miltoncamachocamacho commented 1 month ago

Hi @wtclarke,

Are there any plans to support the new GE format ScanArchives.h5?

Thanks.