I have tried importing the transform in slicer and transforming the moving image and it helps. Is there a way to specify the fixed image in the resampling (harden transform) process (I looked in the GUI and python api). I assume this means slicer is resampling on to the moving image grid. So if I need the image/labels on the fixed image grid I would need to resample again?
Meanwhile I have implemented a poor mans alternative using SimpleITK.
- convert bspline to displacement transform
- pad displacement field with a linear ramp (zero at border)
def bspline_to_displacement_field_transform(
initial_bspline_tx: sitk.BSplineTransform,
grid_spacing: float = 1.0,
variance_update_field: float = 1.75,
variance_total_field: float = 0.5,
) -> sitk.DisplacementFieldTransform:
physical_size = initial_bspline_tx.GetTransformDomainPhysicalDimensions()
# The deformation field spacing affects the accuracy of the transform approximation,
output_spacing = [grid_spacing] * initial_bspline_tx.GetDimension()
output_size = [
int(phys_sz / spc + 1) for phys_sz, spc in zip(physical_size, output_spacing)
]
displacement_field_transform = sitk.DisplacementFieldTransform(
sitk.TransformToDisplacementField(
initial_bspline_tx,
outputPixelType=sitk.sitkVectorFloat64,
size=output_size,
outputOrigin=initial_bspline_tx.GetTransformDomainOrigin(),
outputSpacing=output_spacing,
outputDirection=initial_bspline_tx.GetTransformDomainDirection(),
)
)
displacement_field_transform.SetSmoothingGaussianOnUpdate(
variance_update_field, variance_total_field
)
return displacement_field_transform
def zero_padding(transform: sitk.DisplacementFieldTransform, pad: int = 4):
"""Pad displacement field with a linear ramp reaching zero at border"""
field = transform.GetDisplacementField()
field_np = sitk.GetArrayFromImage(field)
field_np_pad = np.pad(field_np, pad_width=((pad, pad), (pad, pad), (pad, pad), (0, 0)), mode="constant")
for k in range(3):
component_np_pad = np.pad(field_np[..., k], pad_width=pad, mode="linear_ramp")
field_np_pad[..., k] = component_np_pad
displacement_field2 = sitk.GetImageFromArray(field_np_pad, isVector=True)
# helper to for padded origin etc, needed for CopyInformation below
dummy_np = np.ones_like(field_np[..., 0], dtype=np.uint8)
dummy = sitk.GetImageFromArray(dummy_np)
dummy.CopyInformation(field)
displacement_field2.CopyInformation(sitk.ConstantPad(dummy, [pad] * 3, [pad] * 3))
transform2 = sitk.DisplacementFieldTransform(3)
transform2.SetDisplacementField(displacement_field2)
return transform2
Green is using the unmodified bspline transform:
Purple is using the padded displacement transform: