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

N4biasFieldCorrection: Inputs do not occupy the same physical space! #750

Closed
gourdchen opened this issue May 16, 2019 · 37 comments
Closed

Comments

@gourdchen
Copy link

when i use the N4 Correction filter,the error will occur with some image in windows(in linux never show). Before I call the function, I print the origin、spacing of the mask and image,they are totally the same.

Even i do not write the mask image :
output = corrector.Execute(input)
some image will also return the error.
RuntimeError: Exception thrown in SimpleITK N4BiasFieldCorrectionImageFilter_Execute: c:\d\vs14-win64-pkg\simpleitk-build\itk-prefix\include\itk-4.13\itkImageToImageFilter.hxx:241:
itk::ERROR: SubtractImageFilter(00000246299BDE10): Inputs do not occupy the same physical space!
InputImage Origin: [-9.0000000e+01, 1.2600000e+02, -7.2000000e+01], InputImage_1 Origin: [-2.2625000e+01, 2.7125000e+01, -2.2625000e+01]
Tolerance: 1.0000000e-06
InputImage Spacing: [1.0000000e+00, 1.0000000e+00, 1.0000000e+00], InputImage_1 Spacing: [2.2625000e+01, 2.7125000e+01, 2.2625000e+01]
Tolerance: 1.0000000e-06

I use the filter in a loop,when I reduce the MaximumNumberOfIterations ,the error shows will delay(before reduce it occur in the second image, after it occur in the fourth image ) . I think maybe it is a memory access error in windows , my version is 1.2 , my visual studio is visual studio 2015

@blowekamp
Copy link
Member

Can you share your images, and code to reproduce the problem?

Generally, you can also relax the "GlobalDefaultCoordinateTolerance" but these values seem too significant to be a tolerance issue.

@gourdchen
Copy link
Author

sorry, I don't have permission to share the image.
The error will not occur in one image, it will occur in a loop.
my code is the same as the example of N4 filter :

for input in inputs:
    mask = sitk.OtsuThreshold( input, 0, 1, 200 )
    input = sitk.Cast( input, sitk.sitkFloat32 )
    mask = sitk.Cast( mask , sitk.sitkUInt8)
    corrector = sitk.N4BiasFieldCorrectionImageFilter()
    #corrector.SetDebug(True)
    print("input : origin:",input.GetOrigin(),"Mask : origin:",mask.GetOrigin())
    output = corrector.Execute(input)

I have attempted to set the "GlobalDefaultCoordinateTolerance" , but it is useless.
The same data in linux will be corrected, and I use the ANTs's N4 correction in windows with no error.

@blowekamp
Copy link
Member

Does this occur with the distributed Python binaries too or just you local compilation?

@blowekamp blowekamp added this to the v1.3 milestone Jun 3, 2019
@gourdchen
Copy link
Author

both error .
I try the distributed Python binary SimpleITK-1.2.0-cp36-cp36m-win_amd64.whl

@motahareaghalari
Copy link

Hello
def n4itk(x): #must input with sitk img object

img_mask = sitk.OtsuThreshold(x)
x = sitk.Cast(x, sitk.sitkFloat32)
corrector = sitk.N4BiasFieldCorrectionImageFilter()
return corrector.Execute(x, img_mask)

When I use this code for the brats2015 data set, the following error occurs for the 13th image:
Each image is in .mha format and its size (155,240,240). How can this error be resolved?
RuntimeError: Exception thrown in SimpleITK N4BiasFieldCorrectionImageFilter_Execute: c:\d\vs14-win64-pkg\simpleitk-build\itk-prefix\include\itk-4.13\itkImageToImageFilter.hxx:241:
itk::ERROR: SubtractImageFilter(000000B488140240): Inputs do not occupy the same physical space!
InputImage Origin: [0.0000000e+00, -2.3900000e+02, 0.0000000e+00], InputImage_1 Origin: [-5.9750000e+01, -5.9750000e+01, -3.8500000e+01]
Tolerance: 1.0000000e-06
InputImage Spacing: [1.0000000e+00, 1.0000000e+00, 1.0000000e+00], InputImage_1 Spacing: [5.9750000e+01, 5.9750000e+01, 3.8500000e+01]
Tolerance: 1.0000000e-06

@blowekamp
Copy link
Member

That looks like an internal problem with the filter. Thank you for reference public data so the error can be reproduced. An issue will need to be create with ITK to correct the underlying issue.

The work around here is to save the spacing and the direction matrix in your function. The set the input x to have unit spacing and an identity direction matrix, then run the code you have, Most importantly, restore the spacing and direction matrix after correction. Since the filter does need to operate in physical space it it OK to do this operation.

@motahareaghalari
Copy link

Thank you for your answer
But can you explain a little bit how to make these changes in my definition function ??
If I restart my code every time and then I run my function for each image, the problem will be resolved, but is the result correct?

@blowekamp
Copy link
Member

# save physical info
spacing = x.GetSpacing()
direction = x.GetDirection()

# set physical info
x.SetSpacing([1.0]*3)
x.SetDirection([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])

...
out = ...your code...

# restore physical
x.SetSpacing(spacing)
x.SetDirection(direction)

The above should work, I just typed it and didn't run it.

@motahareaghalari
Copy link

Hello
Thank you for your help
I corrected the code.
Origin and Sepce Mask and Image are the same. But the problem remains.

###code##
sample_filter=[]
start=datetime.datetime.now()
for i in train_image:
print(i)
spacing = i.GetSpacing()
direction = i.GetDirection()
print(i.GetSpacing())
print(i.GetDirection())

# set physical info
i.SetSpacing([1.0]*3)
i.SetDirection([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])

img_mask = sitk.OtsuThreshold(i)
img_mask.SetSpacing([1.0]*3)
img_mask.SetDirection([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])
print(img_mask.GetSpacing())
print(img_mask.GetDirection())
new = sitk.Cast(i, sitk.sitkFloat32)
print(new.GetSpacing())
print(new.GetDirection())
corrector = sitk.N4BiasFieldCorrectionImageFilter()
out=corrector.Execute(new, img_mask)
print(out.GetSpacing())
print(out.GetDirection())
# restore physical
out.SetSpacing(spacing)
out.SetDirection(direction)##filter n4itk
img_arrey = sitk.GetArrayFromImage(out)##numpy_array 
sample_filter.append(img_arrey)

###########information of mask
print(img_mask)
Image (000000B106475A30)
RTTI typeinfo: class itk::Image<unsigned char,3>
Reference Count: 1
Modified Time: 4071217929
Debug: Off
Object Name:
Observers:
none
Source: (none)
Source output name: (none)
Release Data: Off
Data Released: False
Global Release Data: Off
PipelineMTime: 4071217798
UpdateMTime: 4071217927
RealTimeStamp: 0 seconds
LargestPossibleRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [240, 240, 155]
BufferedRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [240, 240, 155]
RequestedRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [240, 240, 155]
Spacing: [1, 1, 1]
Origin: [0, -239, 0]
Direction:
1 0 0
0 1 0
0 0 1

IndexToPointMatrix:
1 0 0
0 1 0
0 0 1

PointToIndexMatrix:
1 0 0
0 1 0
0 0 1

Inverse Direction:
1 0 0
0 1 0
0 0 1

PixelContainer:
ImportImageContainer (000000B109E92F20)
RTTI typeinfo: class itk::ImportImageContainer<unsigned __int64,unsigned char>
Reference Count: 1
Modified Time: 4071217917
Debug: Off
Object Name:
Observers:
none
Pointer: 000000B127D97040
Container manages memory: true
Size: 8928000
Capacity: 8928000
##########imformation of image####
print(new)
Image (000000B106476270)
RTTI typeinfo: class itk::Image<float,3>
Reference Count: 1
Modified Time: 4071217955
Debug: Off
Object Name:
Observers:
none
Source: (none)
Source output name: (none)
Release Data: Off
Data Released: False
Global Release Data: Off
PipelineMTime: 4071217946
UpdateMTime: 4071217954
RealTimeStamp: 0 seconds
LargestPossibleRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [240, 240, 155]
BufferedRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [240, 240, 155]
RequestedRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [240, 240, 155]
Spacing: [1, 1, 1]
Origin: [0, -239, 0]
Direction:
1 0 0
0 1 0
0 0 1

IndexToPointMatrix:
1 0 0
0 1 0
0 0 1

PointToIndexMatrix:
1 0 0
0 1 0
0 0 1

Inverse Direction:
1 0 0
0 1 0
0 0 1

PixelContainer:
ImportImageContainer (000000B1064806B0)
RTTI typeinfo: class itk::ImportImageContainer<unsigned __int64,float>
Reference Count: 1
Modified Time: 4071217952
Debug: Off
Object Name:
Observers:
none
Pointer: 000000B13B944040
Container manages memory: true
Size: 8928000
Capacity: 8928000
########error##########
return _SimpleITK.N4BiasFieldCorrectionImageFilter_Execute(self, *args)

RuntimeError: Exception thrown in SimpleITK N4BiasFieldCorrectionImageFilter_Execute: c:\d\vs14-win64-pkg\simpleitk-build\itk-prefix\include\itk-4.13\itkImageToImageFilter.hxx:241:
itk::ERROR: SubtractImageFilter(000000B106E14420): Inputs do not occupy the same physical space!
InputImage Origin: [0.0000000e+00, -2.3900000e+02, 0.0000000e+00], InputImage_1 Origin: [-5.9750000e+01, -5.9750000e+01, -3.8500000e+01]
Tolerance: 1.0000000e-06
InputImage Spacing: [1.0000000e+00, 1.0000000e+00, 1.0000000e+00], InputImage_1 Spacing: [5.9750000e+01, 5.9750000e+01, 3.8500000e+01]
Tolerance: 1.0000000e-06

what this the InputImage_1 Origin??

@blowekamp
Copy link
Member

You can review the fundamental concepts of a ITK image here: https://simpleitk.readthedocs.io/en/master/Documentation/docs/source/fundamentalConcepts.html

It looks like you need to set the origin to 0, then restore it after the processing.

@RainyRen
Copy link

RainyRen commented Oct 23, 2019

@blowekamp
Hi, thanks for you solution. I have tried but got the same error. Below are my code.
Could you pls help to find where the error come from?

series_IDs = sitk.ImageSeriesReader.GetGDCMSeriesFileNames(str(image_path))
series_reader = sitk.ImageSeriesReader()
series_reader.SetFileNames(series_IDs)
image3D = series_reader.Execute()
image_origin = image3D.GetOrigin()
image_spacing = image3D.GetSpacing()
image_direction = image3D.GetDirection()
image3D = sitk.Cast(image3D, sitk.sitkFloat32)

maskImage = sitk.OtsuThreshold(image3D, 0, 1, 200)

image3D.SetOrigin([0] * 3)
image3D.SetSpacing([1] * 3)
image3D.SetDirection([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])
maskImage.SetOrigin([0] * 3)
maskImage.SetSpacing([1] * 3)
maskImage.SetDirection([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])

--- N4 bias correct ---

corrector = sitk.N4BiasFieldCorrectionImageFilter();
image3DPost = corrector.Execute(image3D, maskImage)

RuntimeError: Exception thrown in SimpleITK N4BiasFieldCorrectionImageFilter_Execute: d:\a\1\sitk-build\itk-prefix\include\itk-4.13\itkImageToImageFilter.hxx:241:
itk::ERROR: SubtractImageFilter(0000021ABAE2BCE0): Inputs do not occupy the same physical space!
InputImage Origin: [0.0000000e+00, 0.0000000e+00, 0.0000000e+00], InputImage_1 Origin: [-1.2775000e+02, -1.2775000e+02, -9.2500000e+00]
Tolerance: 1.0000000e-06
InputImage Spacing: [1.0000000e+00, 1.0000000e+00, 1.0000000e+00], InputImage_1 Spacing: [1.2775000e+02, 1.2775000e+02, 9.2500000e+00]
Tolerance: 1.0000000e-06

@blowekamp
Copy link
Member

I have not been able to reproduce this issue locally. Can a minimal reproducible example with data please be provided. Also what OS? and what binary are you using?

Thanks

@blowekamp
Copy link
Member

@ntustison Have you seen this error with N4?

@ntustison
Copy link

ntustison commented Oct 23, 2019

Hey @blowekamp, currently away from my desk but I’ll look later today.

@ntustison
Copy link

Okay @blowekamp , I found this issue which looks similar. Unfortunately, I don't think we ever pinpointed the source of the issue.

@philnovv
Copy link

philnovv commented Oct 24, 2019

I can confirm same issue on Windows 10. This behaviour seems somewhat random, but I'm sure to see it at some point if I use a loop of repeated calls to N4.

@blowekamp
Copy link
Member

By running it in a loop, you are calling N4 in the same process over and over again?

Can you reproduce the bug with synthetic data?

I wonder if this is a windows only bug.

@blowekamp
Copy link
Member

I think I have a candidate for the cause of the problem:

PipelineMTime: 4071217798

On windows the MTimes are only 32-bits. I think they are overflowing. This issues was only addressed recently in ITKv5. We can back port the fix for SimpleITK 1.2 and/or you can build SimpleITK against ITKv5 yourself.

@philnovv
Copy link

philnovv commented Oct 24, 2019

By running it in a loop, you are calling N4 in the same process over and over again?

Can you reproduce the bug with synthetic data?

I wonder if this is a windows only bug.

Yep, calling the same process over and over again like this:

for i in range(0,500):
    corr = sitk.N4BiasFieldCorrection(im)

Curiously, it only crashes at some seemingly random point in the loop. Here's the error:

RuntimeError: Exception thrown in SimpleITK N4BiasFieldCorrection: c:\b\3.7-64\itk-prefix\include\itk-4.13\itkImageToImageFilter.hxx:241:
itk::ERROR: SubtractImageFilter(0000026EACAA8D20): Inputs do not occupy the same physical space!
InputImage Origin: [0.0000000e+00, 0.0000000e+00], InputImage_1 Origin: [-2.7875000e+01, -2.7875000e+01]
Tolerance: 1.0000000e-06
InputImage Spacing: [1.0000000e+00, 1.0000000e+00], InputImage_1 Spacing: [2.7875000e+01, 2.7875000e+01]
Tolerance: 1.0000000e-06

@danielamg94
Copy link

Hi! I have the same problem. I run the same code over and over and sometimes it works, sometimes it doesn't.

@blowekamp
Copy link
Member

To verify the cause on the resulting images run:

re.findall("^.*Time:.*", str(img),re.MULTILINE) 

You should see the pipeline modified times hit close to 2^32 then reset.

@philnovv
Copy link

Confirmed:

[' Modified Time: 4292895946', ' PipelineMTime: 4281687443', ' UpdateMTime: 4292895945', ' Modified Time: 4292895939']

@blowekamp
Copy link
Member

blowekamp commented Oct 24, 2019

I created a simple script to test the Modified time:

import re; import SimpleITK as sitk
img = sitk.Image([512,512], sitk.sitkUInt8)
x = img
img_mask = sitk.OtsuThreshold(x)
x = sitk.Cast(x, sitk.sitkFloat32)
corrector = sitk.N4BiasFieldCorrectionImageFilter()
c=  corrector.Execute(x, img_mask)
re.findall("^.*Time:.*", str(c),re.MULTILINE)

Running N4 on a zero image, with the default parameters is non-sense but it serves the purpose.

The resulting Modified Time: 11,555,091. And if I double the size of the image to 1024x512 it goes up to 23,089,434.

Now If I use the current ITKv5 the resulting Modified Time: 1,087,445. And it the image is double it's 2,136,021 That is still doubled!

@N-Dekker has done some great work optimized N4 in ITKv5 reducing the modifications by 10x. However it appears to still be linear with the number of pixel! This really creates an excessive number of modifications! @ntustison

The solution to this issue is in ITKv5. We will see about getting a fix into SimpleITK, either with a patch to ITK upgrading to ITKv5.

In the mean time, SImpleITK can be built against ITKv5 by using the Superbuild and adding "-D ITK_GIT_TAG:STRING=master" to the CMake configuration command.

@ntustison
Copy link

Thanks @blowekamp . So does the excessive number of modifications imply that there's something in the code that needs to be fixed?

@blowekamp
Copy link
Member

@ntustison I think is falls should a little a being a full bug. But it's something that should be addressed.

  • It causes problems with long running processes even with 64-bit time will eventual be an issue.
  • It is likely a significant performance issue too.

@ntustison
Copy link

Thanks @blowekamp. Based on your judgment, I'm more than willing to try to resolve this issue although modification times gets into ITK details that are beyond my area of comfort so I'll need your help or somebody else's.

I'm not sure as to the source of the issue but my guess would be the underlying B-spline fitting class which is used to generate the estimated bias field. Specifically, the reconstruction function employs an optimization trick specific to B-splines for which I use multiple images as temporary data structures. Would that be a possible culprit?

@blowekamp
Copy link
Member

I created an ITK issue, we can continue how to address it there.

blowekamp added a commit to blowekamp/ITK that referenced this issue Oct 30, 2019
Use the VectorContainer's STL interface to avoid causing MTime to be
called too many time. This has reported to overflow the global time
stamp with it's a 32-bit integer.
SimpleITK/SimpleITK#750
closes ITK/ITK#1352
@danielamg94
Copy link

Hi @blowekamp. I noticed it was solved for ITK, is it solved for simpleITK?

@blowekamp
Copy link
Member

When SimpleITK is built against ITKv5 it is solved. PR #861 is also back porting a couple fixes to the ITKv4 branch for a SimpleITK 1.2.4 distribution.

blowekamp added a commit to SimpleITK/ITK that referenced this issue Oct 30, 2019
Use the VectorContainer's STL interface to avoid causing MTime to be
called too many time. This has reported to overflow the global time
stamp with it's a 32-bit integer.
SimpleITK/SimpleITK#750
closes ITK/ITK#1352
@danielamg94
Copy link

danielamg94 commented Nov 5, 2019

@blowekamp Thanks. Do you know when will that happen? Because I really need to use this tool... I installed ITKv5 and I tried to use N4BiasField in Python but for some reason it does not give the same results.

blowekamp added a commit to blowekamp/ITK that referenced this issue Nov 5, 2019
Use the VectorContainer's STL interface to avoid causing MTime to be
called too many time. This has reported to overflow the global time
stamp with it's a 32-bit integer.
SimpleITK/SimpleITK#750
closes ITK/ITK#1352
@blowekamp
Copy link
Member

We plan on packaging 1.2.4 this week.

blowekamp added a commit to blowekamp/ITK that referenced this issue Nov 6, 2019
Use the VectorContainer's STL interface to avoid causing MTime to be
called too many time. This has reported to overflow the global time
stamp with it's a 32-bit integer.
SimpleITK/SimpleITK#750
closes ITK/ITK#1352
@blowekamp blowekamp removed this from the v1.3 milestone Nov 13, 2019
@blowekamp
Copy link
Member

An intermediate fix in now available in the just release v1.2.4 binaries before the ITKv5 upgrade. Enjoy!

@RainyRen
Copy link

Hi @blowekamp, thank you very much for your help and update so quickly.
I have test the newest version of SimpleITK, the problem still occur

Platform

OS: window 10
python: 3.6.9
SimpleITK: 1.2.4

code

import SimpleITK as sitk
import numpy as np

Image = sitk.ReadImage('./F2.nii')

image_orgin = Image.GetOrigin()
image_spacing = Image.GetSpacing()
image_direction = Image.GetDirection()

Image = sitk.Cast(Image, sitk.sitkFloat32)
maskImage = sitk.OtsuThreshold(Image, 0, 1, 200)

Image.SetOrigin([0] * 3)
Image.SetSpacing([1] * 3)
Image.SetDirection([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])

maskImage.SetOrigin([0] * 3)
maskImage.SetSpacing([1] * 3)
maskImage.SetDirection([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])

corrector = sitk.N4BiasFieldCorrectionImageFilter()
imagePost = corrector.Execute(Image, maskImage)

error output:


RuntimeError Traceback (most recent call last)
in
----> 1 imagePost = corrector.Execute(Image, maskImage)

d:\workstation\pyenv\sci\lib\site-packages\SimpleITK\SimpleITK.py in Execute(self, *args)
51745
51746 """

51747 return _SimpleITK.N4BiasFieldCorrectionImageFilter_Execute(self, *args)
51748
51749 N4BiasFieldCorrectionImageFilter_swigregister = _SimpleITK.N4BiasFieldCorrectionImageFilter_swigregister

RuntimeError: Exception thrown in SimpleITK N4BiasFieldCorrectionImageFilter_Execute: d:\a\1\sitk-build\itk-prefix\include\itk-4.13\itkImageToImageFilter.hxx:241:
itk::ERROR: SubtractImageFilter(000001F9AF254FF0): Inputs do not occupy the same physical space!
InputImage Origin: [0.0000000e+00, 0.0000000e+00, 0.0000000e+00], InputImage_1 Origin: [-1.2775000e+02, -1.2775000e+02, -2.6750000e+01]
Tolerance: 1.0000000e-06
InputImage Spacing: [1.0000000e+00, 1.0000000e+00, 1.0000000e+00], InputImage_1 Spacing: [1.2775000e+02, 1.2775000e+02, 2.6750000e+01]
Tolerance: 1.0000000e-06


I have attached the testing image file, please unzip it to use.

I also tried another image, download from http://slicer.kitware.com/midas3/download/item/292312/RegLib_C01_1.nrrd
this example is fine.

Please check this example, thanks for your help
F2.zip

@blowekamp
Copy link
Member

Thank you for the test image! Running N4 with the default [50,50,50,50] max iterations resulted in an extremely long running process on OSX. These default parameters are likely now useful and need tweaking.

I ran N4 with the provided image with just [2,2,2,2] max iterations. On 1.2.3 the of the output was ~875 million, on 1.2.4 is was 506 million, while when the SimpleITK was compiled against ITKv5 master the MTime of the output was only 34,000.

We will be creating a SimpleITK 1.4 alpha binary release compiled against ITKv5 shortly.

@RainyRen
Copy link

Thanks for your feedback.
I modified the code at your suggestion, add:

corrector.SetMaximumNumberOfIterations([2, 2, 2, 2])

most image can work now, but still some occur the same error!
Testing image attached below, hope this can make more help!
PS: Due to github upload size limit, I made sub-volume. Pls rename M10.z01.zip to M10.z01, the same with z02, then unzip.
Thanks!

M10.z01.zip
M10.z02.zip
M10.zip

@blowekamp
Copy link
Member

There are now "latest" SimpleITK binaries available build against ITKv4 available on the Github release tab. It can be downloaded with:

pip install --pre SimpleITK --find-links https://github.com/SimpleITK/SimpleITK/releases/tag/latest

@rosella1234
Copy link

Hi
I encounter the same issue while processing some subject in a for loop
the commands I give are:

 mrtransform 3dT1_${S}_corr_brainmask.nii.gz -replace 3dT1_${S}_normalized.nii.gz 3dT1_${S}_corr_brainmask_corr.nii.gz 
  N4BiasFieldCorrection -d 3 -i 3dT1_${S}_normalized.nii.gz -x 3dT1_${S}_corr_brainmask_corr.nii.gz -o [3dT1_${S}_correct_corr.nii.gz,3dT1_${S}_corr_bias.nii.gz] -c [50x50x50,0.001] -s 2 -b [100,3] -t [0.15,0.01,200] -v 1

I cannot understand how to solve the issue: inputs do not occupy the same physical space, since I believed I forced them to be in the same physical space with mrtransform command!
best,
Rosella

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

No branches or pull requests

8 participants