pyushkevich / itksnap

ITK-SNAP medical image segmentation tool
http://www.itksnap.org
GNU General Public License v3.0
313 stars 91 forks source link

Nii segmentation z-flip in certain circumstances (4.0.0) #87

Open KrisThielemans opened 1 year ago

KrisThielemans commented 1 year ago

I have a CT in DICOM and a segmentation in Nifti (obtained by someone else in a previous version of itk-snap). When first loading the CT as main image and then the segmentation, there is a SI flip in how the segmentation is displayed. I can confirm that by loading the segmentation as additional image, which displays correctly.

DICOM with segmentation as layer image

segmentation loaded as additional image and segmentation as layer image

I have checked that if I convert the CT to Nifti using an external tool, load that as main image, and then load the segmentation, ITK-snap displays it alright.

Unfortunately I cannot share the CT, but could share the segmented nii (although that's unlikely to be any use).

(Maybe some flag that doesn't get re-initialised?)

jilei-hao commented 1 year ago

Hi Kris, thanks for reporting the issue! Can you share the segmentation nii?

I suspect it's something related to the dicom main image. Have you tried saving the main image as nii, and open the nii main image and segmentation?

KrisThielemans commented 1 year ago

here's the segmentation segmentation.nii.gz

KrisThielemans commented 1 year ago

Contrary to my expectations, exporting the DICOM to Nifti via ITKsnap, and then loading the output Nii in a new window showed the same erroneous behaviour

KrisThielemans commented 1 year ago

Here's the header output from one of our tools (from https://github.com/SyneRBI/SIRF/)

sirf_print_nifti_info.exe .\segmentation4d.nii .\CT2.nii
                  0              -3023
Printing info for 2 nifti image(s):
        analyze_75_orient: 0                  0
        analyze75_orient:  0                  0
        byteorder:         1                  1
        cal_max:           0                  0
        cal_min:           0                  0
        datatype:          16                 16
        dt:                1                  0
        du:                0                  0
        dv:                0                  0
        dw:                0                  0
        dx:                0.976562           0.976562
        dy:                0.976562           0.976562
        dz:                0.625              0.625
        ext_list:          0000000000000000   0000000000000000
        freq_dim:          0                  0
        iname_offset:      352                352
        intent_code:       0                  0
        intent_p1:         0                  0
        intent_p2:         0                  0
        intent_p3:         0                  0
        nbyper:            4                  4
        ndim:              4                  3
        nifti_type:        1                  1
        num_ext:           0                  0
        nvox:              282066944          70516736
        nx:                512                512
        ny:                512                512
        nz:                269                269
        nt:                4                  1
        nu:                1                  1
        nv:                1                  1
        nw:                1                  1
        phase_dim:         0                  0
        qfac:              1                  -1
        qform_code:        1                  1
        qoffset_x:         250                250
        qoffset_y:         250                250
        qoffset_z:         -288.75            -121.25
        quatern_b:         0                  0
        quatern_c:         0                  0
        quatern_d:         1                  1
        scl_inter:         0                  0
        scl_slope:         1                  1
        sform_code:        1                  1
        slice_code:        0                  0
        slice_dim:         0                  0
        slice_duration:    0                  0
        slice_end:         0                  0
        slice_start:       0                  0
        swapsize:          4                  4
        time_units:        0                  0
        toffset:           0                  0
        xyz_units:         2                  2
        dim[0]:            4                  3
        dim[1]:            512                512
        dim[2]:            512                512
        dim[3]:            269                269
        dim[4]:            4                  1
        dim[5]:            1                  1
        dim[6]:            1                  1
        dim[7]:            1                  1
        pixdim[0]:         0                  0
        pixdim[1]:         0.976562           0.976562
        pixdim[2]:         0.976562           0.976562
        pixdim[3]:         0.625              0.625
        pixdim[4]:         1                  0
        pixdim[5]:         0                  0
        pixdim[6]:         0                  0
        pixdim[7]:         0                  0
        qto_ijk:
                           [-1.02,0,0,256]    [-1.02,-0,0,256]
                           [0,-1.02,0,256]    [-0,-1.02,0,256]
                           [0,0,1.6,462]      [-0,-0,-1.6,-194]
                           [0,0,0,1]          [0,0,0,1]
        qto_xyz:
                           [-0.977,0,0,250]   [-0.977,0,-0,250]
                           [0,-0.977,0,250]   [0,-0.977,-0,250]
                           [0,0,0.625,-289]   [0,0,-0.625,-121]
                           [0,0,0,1]          [0,0,0,1]
        sto_ijk:
                           [-1.02,0,0,256]    [-1.02,-0,0,256]
                           [0,-1.02,0,256]    [-0,-1.02,0,256]
                           [0,0,1.6,462]      [-0,-0,-1.6,-194]
                           [0,0,0,1]          [0,0,0,1]
        sto_xyz:
                           [-0.977,0,0,250]   [-0.977,0,-0,250]
                           [0,-0.977,0,250]   [0,-0.977,-0,250]
                           [0,0,0.625,-289]   [0,0,-0.625,-121]
                           [0,0,0,1]          [0,0,0,1]
        orig_datatype:     4                  4
        min:
        max:               1                  3071
        mean:              0.25               -1296.97
        contains nans?:    0                  0

showing that the 2 files have different slice order.

Note that DICOM and exported nii and "segmentation as additional image" all look fine. It is the "segmentation as segmentation" that is displayed incorrectly as stated above

jilei-hao commented 1 year ago

Thanks for the extra info! It's very helpful.

Did the ITK-SNAP-Converted Nifti render differently than the External-Converted Nifti? Did the image orient correctly when directly loaded as DICOM?

KrisThielemans commented 1 year ago

Images all load correct and are always displayed the same. It's only the segmentation that isn't (presumably only when its slice orientation doesn't match the one of the main image)

jilei-hao commented 1 year ago

Can you open the dicom image and share what's displayed on the image info and the metadata (without any sensitive information) panel in the layer inspector?

Thanks, Jilei

On Wed, Mar 1, 2023 at 12:52 PM Kris Thielemans @.***> wrote:

Images all load correct and are always displayed the same. It's only the segmentation that isn't (presumably only when its slice orientation doesn't match the one of the main image)

— Reply to this email directly, view it on GitHub https://github.com/pyushkevich/itksnap/issues/87#issuecomment-1450594524, or unsubscribe https://github.com/notifications/unsubscribe-auth/ARDT6PQY4W4GEY7HUYEXDLLWZ6EGRANCNFSM6AAAAAAVMGX7UE . You are receiving this because you commented.Message ID: @.***>

KrisThielemans commented 1 year ago

1) first load DICOM

DICOM: image segmentation loaded as additional image image segmentation loaded as segmentation image Note that the origin z is different from the one above

2) don't load DICOM but load segmentation as main image matrix info of both "segmentation as image" and "segmentation as segmentation" is the same image

I haven't included any DICOM info as I don't know which fields you're interested in. Also, as I can reproduce the problem with the DICOM exported via itksnap as nifti, I guess the actual dicom fields don't matter too much?

KrisThielemans commented 1 year ago

This issue does not occur with ITK-snap 3.8.0. Segmentation loads fine.

KrisThielemans commented 1 year ago

screenshots with 3.8.0:

  1. DICOM image
  2. segmentation as additional image and segmentation are identical image

i see that 3.8.0 says that orientation is RAI for the DICOM but 4.0.0 RAS.

KrisThielemans commented 1 year ago

You should be able to reproduce this with the following files: segmentation.nii.gz segmentationstir.zip

load segmentationstir.nii as main image and segmentation.nii.gz as segmentation. The files are "identical" in a geometric sense, but have different slice order. Obviuosly, you might not believe me, but with 3.8.0 it works fine.

KrisThielemans commented 1 year ago

Correction. In ITKsnap 3.8.0, loading the DICOM and segmentation.nii works fine, but using segmentationstir.nii shows the flip. This exactly opposed from 4.0.0

jilei-hao commented 1 year ago

I think the root cause of this issue is in 3.8 it reads the dicom oriented in RAI, but 4.0 in RAS. And your segmentation is in RAI.

A possible work around of this issue is to save the nii in 3.8 and open it in 4.0. So the exported nii has the same orientation as the segmentation.

Do you have the same issue with other dicom series? The flip does not happen to the data I have.

Best, Jilei

On Sat, Mar 4, 2023 at 3:58 AM Kris Thielemans @.***> wrote:

Correction. In ITKsnap 3.8.0, loading the CT and segmentation.nii works fine, but using segmentationstir.nii shows the flip. This exactly opposed from 4.0.0

— Reply to this email directly, view it on GitHub https://github.com/pyushkevich/itksnap/issues/87#issuecomment-1454669389, or unsubscribe https://github.com/notifications/unsubscribe-auth/ARDT6PRL3JNHEBOFJGVJEDDW2L733ANCNFSM6AAAAAAVMGX7UE . You are receiving this because you commented.Message ID: @.***>

KrisThielemans commented 1 year ago

Hi Jilei

in my opinion, ITKsnap should either cope with different orientations or tell the user that the orientations don't match and refuse to load the segmentation. Doing the incorrect thing silently is quite dangerous. Of course, the images all load ok (when loaded as mean or additional image), so it seems that the relevant mechanism already exist somewhere in the code in ITKsnap. Therefore maybe the first option isn't too hard to implement, but I have no idea obviously. Putting a safeguard might be the easiest way out.

jilei-hao commented 1 year ago

I still need to do some investigation in the code, but I agree that having some warning is necessary if mismatch in orientation is detected. We have a lot of other cases giving users warnings about possible issues.

Thanks for contributing the issue!

On Wed, Mar 8, 2023 at 3:22 PM Kris Thielemans @.***> wrote:

Hi Jilei

in my opinion, ITKsnap should either cope with different orientations or tell the user that the orientations don't match and refuse to load the segmentation. Doing the incorrect thing silently is quite dangerous. Of course, the images all load ok (when loaded as mean or additional image), so it seems that the relevant mechanism already exist somewhere in the code in ITKsnap. Therefore maybe the first option isn't too hard to implement, but I have no idea obviously. Putting a safeguard might be the easiest way out.

— Reply to this email directly, view it on GitHub https://github.com/pyushkevich/itksnap/issues/87#issuecomment-1460815856, or unsubscribe https://github.com/notifications/unsubscribe-auth/ARDT6PWYZCCKQTHMU7HSQEDW3DTABANCNFSM6AAAAAAVMGX7UE . You are receiving this because you commented.Message ID: @.***>