From c7f85b729145d8b8ebf1786aa87c45398f7fbc76 Mon Sep 17 00:00:00 2001 From: Fabian Isensee Date: Wed, 27 Mar 2024 15:59:42 +0100 Subject: [PATCH] documentation: further clarify the need for consistency of axes ordering between training and inference --- nnunetv2/inference/predict_from_raw_data.py | 11 ++++++++--- nnunetv2/inference/readme.md | 17 +++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/nnunetv2/inference/predict_from_raw_data.py b/nnunetv2/inference/predict_from_raw_data.py index daeead75e..2ac6600c2 100644 --- a/nnunetv2/inference/predict_from_raw_data.py +++ b/nnunetv2/inference/predict_from_raw_data.py @@ -424,9 +424,14 @@ def predict_single_npy_array(self, input_image: np.ndarray, image_properties: di """ WARNING: SLOW. ONLY USE THIS IF YOU CANNOT GIVE NNUNET MULTIPLE IMAGES AT ONCE FOR SOME REASON. - input_image must use SimpleITK axis ordering! - (NB: if array comes from a nibabel-loaded image, you must swap the - axes of both the array *and* the spacing from [x,y,z] to [z,y,x]!) + + input_image: Make sure to load the image in the way nnU-Net expects! nnU-Net is trained on a certain axis + ordering which cannot be disturbed in inference, + otherwise you will get bad results. The easiest way to achieve that is to use the same I/O class + for loading images as was used during nnU-Net preprocessing! You can find that class in your + plans.json file under the key "image_reader_writer". If you decide to freestyle, know that the + default axis ordering for medical images is the one from SimpleITK. If you load with nibabel, + you need to transpose your axes AND your spacing from [x,y,z] to [z,y,x]! image_properties must only have a 'spacing' key! """ ppa = PreprocessAdapterFromNpy([input_image], [segmentation_previous_stage], [image_properties], diff --git a/nnunetv2/inference/readme.md b/nnunetv2/inference/readme.md index a9d6d65d8..d0acc6b2a 100644 --- a/nnunetv2/inference/readme.md +++ b/nnunetv2/inference/readme.md @@ -147,7 +147,11 @@ cons: tldr: - you give one image as npy array -- array must use [SimpleITK axis order](http://insightsoftwareconsortium.github.io/SimpleITK-Notebooks/Python_html/03_Image_Details.html#Conversion-between-numpy-and-SimpleITK) (see examples below) +- axes ordering must match the corresponding training data. The easiest way to achieve that is to use the same I/O class + for loading images as was used during nnU-Net preprocessing! You can find that class in your + plans.json file under the key "image_reader_writer". If you decide to freestyle, know that the + default axis ordering for medical images is the one from SimpleITK. If you load with nibabel, + you need to transpose your axes AND your spacing from [x,y,z] to [z,y,x]! - everything is done in the main process: preprocessing, prediction, resampling, (export) - no interlacing, slowest variant! - ONLY USE THIS IF YOU CANNOT GIVE NNUNET MULTIPLE IMAGES AT ONCE FOR SOME REASON @@ -161,12 +165,17 @@ cons: - never the right choice unless you can only give a single image at a time to nnU-Net ```python - # predict a single numpy array (SimpleITK) + # predict a single numpy array (SimpleITKIO) img, props = SimpleITKIO().read_images([join(nnUNet_raw, 'Dataset003_Liver/imagesTr/liver_63_0000.nii.gz')]) ret = predictor.predict_single_npy_array(img, props, None, None, False) - # predict a single numpy array (Nibabel with axes swapped) - img_nii = nib.load('Dataset003_Liver/imagesTr/liver_63_0000.nii.gz') + # predict a single numpy array (NibabelIO) + img, props = NibabelIO().read_images([join(nnUNet_raw, 'Dataset003_Liver/imagesTr/liver_63_0000.nii.gz')]) + ret = predictor.predict_single_npy_array(img, props, None, None, False) + + # The following IS NOT RECOMMENDED. Use nnunetv2.imageio! + # nibabel, we need to transpose axes and spacing to match the training axes ordering for the nnU-Net default: + nib.load('Dataset003_Liver/imagesTr/liver_63_0000.nii.gz') img = np.asanyarray(img_nii.dataobj).transpose([2, 1, 0]) # reverse axis order to match SITK props = {'spacing': img_nii.header.get_zooms()[::-1]} # reverse axis order to match SITK ret = predictor.predict_single_npy_array(img, props, None, None, False)