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

Segmentation disagreement between dicom2nifti and Monai when converting DICOM to NIFTI format #143

Open
staydelight opened this issue Apr 23, 2024 · 0 comments

Comments

@staydelight
Copy link

Environment

Steps to reproduce the disagreement

  • Process dicom image

    No preprocessing of the dataset is required, the input is a DICOM file with the following command:

     python -m monai.bundle run --config_file configs/inference_dicom.json
    

    The config file is referred from 'Project-MONAI/modelzoo/models/prostate_mri_anatomy/configs/inference.json' with the following changes to modify its path:

    "imports": [
        "$import pandas as pd",
+       "$import glob",
        "$import os"
    ],
-   "bundle_root": "/workspace/data/prostate_mri_anatomy",
+   "bundle_root": ".",
-   "output_dir": "$@bundle_root + '/eval'",
+   "output_dir": "$@bundle_root + '/eval_monai'",
-   "dataset_dir": "/workspace/data/prostate158/prostate158_test/",
+   "dataset_dir": "501.T2WTSEAX",
-    "datalist": "$list(@dataset_dir + pd.read_csv(@dataset_dir + 'test.csv').t2)",
+   "datalist": "$list(sorted(glob.glob(@dataset_dir)))",
  • Process nifti image

    Step 1: Convert dicom to nifti with the following command:

    dicom2nifti 501.000000-T2WTSEAX-40778/ dicom2nifti.501
    

    Step 2: Get segmentation results from Monai model:

    python -m monai.bundle run --config_file configs/inference_nifti.json
    

    The config file is referred from the same source as Monai with the following changes to modify its path:

    "imports": [
        "$import pandas as pd",
+       "$import glob",
        "$import os"
    ],
-   "bundle_root": "/workspace/data/prostate_mri_anatomy",
+   "bundle_root": ".",
-   "output_dir": "$@bundle_root + '/eval'",
+   "output_dir": "$@bundle_root + '/eval_d2n'",
-   "dataset_dir": "/workspace/data/prostate158/prostate158_test/",
+   "dataset_dir": "dicom2nifti.501",
-   "datalist": "$list(@dataset_dir + pd.read_csv(@dataset_dir + 'test.csv').t2)",
+   "datalist": "$list(sorted(glob.glob(@dataset_dir+'/*.nii.gz')))",

Expected result

The segmentation results should be the same.

My investigation

As you can see from the pictures below , two segmentation results are different:

Process dicom image Process nifti image
1 3
2 4

After digging into the code a little bit, I find that the affine matrix should play the important role in making this difference.

Finding the affine matrix

  • Process dicom image

    The affine matrix from 'monai/data/image_reader.py' is defined with:

    direction = np.asarray(direction)
    sr = min(max(direction.shape[0], 1), 3)
    affine: np.ndarray = np.eye(sr + 1)
    affine[:sr, :sr] = direction[:sr, :sr] @ np.diag(spacing[:sr])
    affine[:sr, -1] = origin[:sr]
    if lps_to_ras:
        affine = orientation_ras_lps(affine)
      
    self.logger.debug(f"Affine matrix:\n{affine}")
    
    return affine
    

    From the input that we given, we can find affine matrix with the following:

    6

  • Process nifti image

    The affine matrix from 'dicom2nifti/common.py' is defined with:

    affine = numpy.array(
            [[-image_orient1[0] * delta_c, -image_orient2[0] * delta_r, -step[0], -image_pos[0]],
            [-image_orient1[1] * delta_c, -image_orient2[1] * delta_r, -step[1], -image_pos[1]],
            [image_orient1[2] * delta_c, image_orient2[2] * delta_r, step[2], image_pos[2]],
            [0, 0, 0, 1]]
    )
      
    logger.debug(f"Affine matrix:\n{affine}")
    
    return affine, numpy.linalg.norm(step)
    

    From the input that we given, we can find affine matrix with the following:

    8

    The difference:

    Process dicom image Process nifti image
    17 18

Truncate the floating point

I added this line separately to both Monai and dicom2nifti:

affine = orientation_ras_lps(affine)

After I truncated these individual values to five decimal places, we can achieve the same affine matrix and the same segmentation results.

Process dicom image Process nifti image
11 11
13 15
14 16

It is obvious that this element, with its precise floating-point value plays a role.
Given this result, I don't know which is correct, so I am sharing them here to seek feedback.

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

1 participant