I would like to get an interpolated value at non-integer voxel coordinate.
With this program I can get the value for example at coordinate 25,50,50:
import SimpleITK as sitk
import numpy as np
# Reads the image using SimpleITK
itkimage = sitk.ReadImage('phantom.mhd')
# Convert the image to a numpy array first and then shuffle the dimensions to get axis in the order z,y,x
ct_scan = sitk.GetArrayFromImage(itkimage)
print(ct_scan[25,50,50])
But what if I need the value say at 25.1,49.9,50.0?
A new method could be added to the sitk::Image class. Perhaps something like GetInterpolatedPixel(std::vector &, InterpolatorEnum). It may need to have different return types for many of the pixel types, which adds a little complication.
For you case of interpolating along a curve, the ResampleImageFilter may be a good approach. If you consider your image as input, and the output a 3D image if Nx1x1 , where N is the number of values you want. The transform maps the outputs from the output to the input. If you can come up with this transform you can use the resample filter.
For the case of sampling along a line, a 3d rotational matrix with translation can be used to perform the transformation. With a little research you should be able to find a formula, per construct such a transform. Keep in mind the transformation maps the point from physical space to physical space ( not between index spaces! ), so the output image’s geometry is important.
Thank you.
This is what I understood, even if this is not strictly related to ITK maybe you can help me anyway:
given a line L in 3D (for example given two points in mm); first find the translation T that bring L passing through the origin, call L1 this new line passing through the origin; then find the rotation R that overlap L1 to, say, axis x; then apply T and R to my 3D image using a ResampleImageFilter with a WindowedSincInterpolateImageFunction interpolator (like in the example https://github.com/InsightSoftwareConsortium/ITK/blob/master/Examples/Filtering/ResampleImageFilter8.cxx) to get a new image img2 and finally get from img2 all the voxel which have y=0 and z=0 (that’s because I overlapped L1 to axis x which is the locus of points where y=0 and z=0).
The ITK Python wrapping can be used to directly interpolate pixel values.
For example,
import itk
image = itk.imread('ImageFile.mhd')
interpolator = itk.LinearInterpolateImageFunction.New(image)
# Interpolate at the physical space location [1.2, 3.4, 4.4]
interpolated_pixel = interpolator.Evaluate([1.2, 3.4, 4.4])
# There is also .EvaluateAtIndex() and .EvaluateAtContinuousIndex() to interpolate with pixel coordinates
Also available in the ITK Python wrapping are Path objects to help define and use paths in space.
In the meanwhile you can use a broadcasting approach to obtain the intensity value at an arbitrary set of points:
import SimpleITK as sitk
import numpy as np
img = sitk.ReadImage('training_001_ct.mha')
# generate random samples in image
num_samples = 10
physical_points = []
for pnt in zip(*[list(np.random.random(num_samples)*sz) for sz in img.GetSize()]):
physical_points.append(img.TransformContinuousIndexToPhysicalPoint(pnt))
interp_grid_img = sitk.Image((num_samples, *([1]*(img.GetDimension()-1))), sitk.sitkUInt8)
displacement_img = sitk.Image((num_samples, *([1]*(img.GetDimension()-1))), sitk.sitkVectorFloat64, img.GetDimension())
for i, pnt in enumerate(physical_points):
displacement_img[(i, *([0]*(img.GetDimension()-1)))] = np.array(pnt) - np.array(interp_grid_img.TransformIndexToPhysicalPoint((i, *([0]*(img.GetDimension()-1)))))
resampled_points = sitk.Resample(img, interp_grid_img, sitk.DisplacementFieldTransform(displacement_img), sitk.sitkLinear, 0.0, sitk.sitkFloat32)
for i in range(resampled_points.GetWidth()):
print(resampled_points[i,0,0])