Resample 3D images


(Romain Leguay) #1

Hello everyone,

I try to resample (resize) 3d images with dimensions [171, 127, 411] to [256, 256, 411].

For this, I tried to use itk::ResampleImageFilter but with no success: either I have an my previous image and some black borders (at the right and bottom) or I have a black image.

The following code show you how I (mis)used ResampleImageFilter:

typedef typename Image::SizeType SizeType;
typedef itk::IdentityTransform<double, 3> TransformType;
typedef itk::ResampleImageFilter<Image, Image> ResampleImageFilter;

typename TransformType::Pointer transform = TransformType::New();
transform->SetIdentity(); // is this useful?

SizeType newSize;
newSize[0] = 256;
newSize[1] = 256;
newSize[2] = 411;

// Compute the new spacing
SizeType inputSize = inputImage->GetLargestPossibleRegion().GetSize();
Image::SpacingType outputSpacing;
outputSpacing[0] = (intputImage->GetSpacing()[0] * inputSize[0]) / newSize[0];
outputSpacing[1] = (intputImage->GetSpacing()[1] * inputSize[1]) / newSize[1];
outputSpacing[2] = intputImage->GetSpacing()[2]; 

// Apply the resampling filter
ResampleImageFilter::Pointer resample = ResampleImageFilter::New();
resample->SetInput(inputImage);
resample->SetOutputParametersFromImage(inputImage);
resample->SetSize(newSize);
resample->SetOutputSpacing(outputSpacing);
resample->SetTransform(transform);
resample->Update();

// Get the result
return resample->GetOutput();

What did I do wrong? Thanks


(Dave Chen) #2

Is the origin of your original image not (0,0,0)? You might need to set the resample filter’s output origin to whatever the input image’s origin is.


(Romain Leguay) #3

I added the line:

resample->SetOutputOrigin(inputImage->GetOrigin());

But the result that I obtain is not good:

P006_AORTEABD_crop_image_000


(Dave Chen) #4

Slightly better, though, right? :slight_smile:

The next question is what is the “Direction” of the input image.

Similar to your last change, try adding

resample->SetOutputDirection( inputImage->GetDirection() );


(Romain Leguay) #5

You’re right: I have some pixels not black ^^.

Unfortunately, I have no difference by adding the Direction.


(Dave Chen) #6

The only other things I’ve noticed is that in computing the outputSpacing you refer to “intputImage”, where elsewhere its “inputImage”, so there’s a typo. But that ought to have tripped the compiler. Also you might want to cast the numbers to float or double when computing output spacing.

For reference, you can see the ResampleImageFilter example here:

https://itk.org/Wiki/ITK/Examples/ImageProcessing/ResampleImageFilter


(Romain Leguay) #7

I didn’t write correctly the variable name inputImage.

The cast here is not necessary because the spacing is already in floating point number (implicit cast).

I follow this example and the main difference I saw is that I have some different size in X-axis and Y-axis.

Edit:

I have some news: I practically solved my problem: I save my image first then reload it and the resampling work. So I think it’s a memory problem but I don’t quiet understand what I do wrong.

Here’s my pipeline:

-> read image (Nifty format in 3D) -> crop image (CropImageFilter) -> resize crop image (ResampleImageFilter) -> save series (ImageSeriesWriter)

To debug, I save images after each filter and I have an expected result after the crop filter.

I would like to know if I can do something like that:

using Image = itk::Image<unsigned short, 3>;

Image::Pointer applyFilter(typename Image::Pointer image)
{
   using FilterType = AnITKFilter<Image, Image>;
   FilterType::Pointer filter = FilterType::New();
   filter->SetInput(image);
   filter->Update();
   return cropFilter->GetOutput();
}

Image::Point inputImage = Image::New();
Image::Pointer output = applyFilter(inputImage);

Does this code create a new image (aka copy of all pixels, etc…)? Does it depend of the filter?
Thank you


(Bradley Lowekamp) #8

One of the properties of an image is the LargestPossibleRegion, related is the buffered region, and requested region. TheImageRegions contains a starting index and a size. When you read/write an image the starting index is [0]. There are a few filters which change the starting index, the CropImageFilter is one of them. Print the image before and after the CropFilter to observe.

So your input and output images have non-zero starting index, so when you change the spacing, the physical location of starting index of the output image changes.

I’d recommend you not use the copy of parameters SetOutputParametersFromImage method, and explicitly set all output image parameters: origin, spacing, direction, starting index, and size. Carefully think about them! I’d set the output starting index to [0], and then for the origin use inputImage-> TransformIndexToPhysicalPoint(inputImage->GetLargestPossibleRegion()->GetIndex()).