Analysis: Find a way to apply motion and recover the applied motion (systematically)
LalithShiyam opened this issue ยท 11 comments
To prove falcon actually works it is crucial to show that the artificially applied motion (via simpleITK) can be recovered as well. I think the motion parameters will not be the same if the rotation/translation is applied together. Might be wise to just validate both the aspects individually. Further analysis needed!
Imposed motion can actually be recovered as long as the radians imposed are less than 0.1 in all three axes.
Workflow:
- Apply translation and rotational parameters using simpleITK
import SimpleITK as sitk
image = sitk.ReadImage('./Flipped-Zubal-028.nii')
transform = sitk.Euler3DTransform()
transform.SetCenter(image.TransformContinuousIndexToPhysicalPoint([(sz-1)/2 for sz in image.GetSize()]))
transform.SetTranslation([10,5,8]) # in mm, can go till 20.
transform.SetRotation(0.09,0.08,0.08); # make sure they don't exceed 0.1
resampled_image = sitk.Resample(image, transform)
sitk.WriteImage(resampled_image, './transformed_image_028.nii')
- Once the motion is imposed, get rigid.mat after registration.
- When we use itksnap registration GUI and load the rigid.mat along with the moving image, we can clearly see the motion parameters recovered almost accurately. However, this is not practical, since we need to do this manually for each frame. A better way would be to figure out stuff automatically. Also we have some cool information here: https://github.com/pyushkevich/itksnap/blob/2da5b3560f92e9887ecf5398e71dcb0719bb3143/GUI/Model/RegistrationModel.cxx (under // Compute the translation vector)
c3d_affine_tool rigid.mat -info-full
gives the right rotation, but the translation parameters are off. We need to figure out, how this can be rectified. I have posted the question to Paul: https://groups.google.com/g/itksnap-users/c/UXzh2x7x7sU/m/5X7tr6u4AAAJ.
In the meantime, I will pass this on to @Keyn34!
In case, we cannot make a script to decompose the matrix accurately or if paul doesn't respond in a day or two. I would suggest doing the analysis manually using itksnap GUI. I understand it is boring, but if we put our heads together, we should be able to get it done in 3 days max. We need to get this manuscript out. @DariaFerrara @josefyu would you guys help @Keyn34?
@Keyn34 found a way to make the imposed motion (via simpleITK) and recovered motion (rigid.mat after registration) comparable.
[1] Apply transform
import SimpleITK as sitk
image = sitk.ReadImage('./Flipped-Zubal-028.nii')
transform = sitk.Euler3DTransform()
transform.SetCenter(image.TransformContinuousIndexToPhysicalPoint([(sz-1)/2 for sz in image.GetSize()]))
transform.SetTranslation([10,5,8]) # mm
transform.SetRotation(0.09,0.08,0.08); # 1.145916,0.5729578,1.718873 in deg
resampled_image = sitk.Resample(image, transform)
sitk.WriteImage(resampled_image, './transformed_image_028.nii')
# [2] Write the inverse transform
sitk.WriteTransform(transform.GetInverse(),'sitk_inv_tfm.mat')
# [3] Run registration
# [4] Use c3d_affine_tool to convert the spit out 'rigid.mat' to itk format.
cmd_to_run = 'c3d_affine_tool rigid.mat -oitk greedy_tfm.mat'
os.system(cmd_to_run)
# [5] Use c3d_affine to load the sitk_inv_tfm.mat and convert it to 'greedy' based 'itk' format
cmd_to_run = 'c3d_affine_tool -itk sitk_inv_tfm.mat -oitk sitk_inv_tfm.mat'
os.system(cmd_to_run)
# [6] load both the transforms
greedy_tfm = sitk.ReadTransform('greedy_tfm.mat')
sitk_tfm = sitk.ReadTransform('sitk_inv_tfm.mat')
# [7] Use get parameters to look at the transformation matrix (last three translation, the remaining rotation matrix)
greedy_tfm.GetParameters()
sitk_tfm.GetParameters()
I wrote a script to parse the rotation and translation parameters directly from the transform.txt
file
# Get the simpleITK transform parameters
cmd_to_run = 'c3d_affine_tool -itk sit_inv_tfm.mat -info-full > sitk_inv_tfm.txt'
os.system(cmd_to_run)
# Get the registration transform parameters
cmd_to_run = 'c3d_affine_tool -itk greedy_tfm.mat -info-full > greedy_tfm.txt'
os.system(cmd_to_run)
# function for getting motion parameters from transform.txt file
import re
def get_motion_parameters(path_transform_txt: str):
transform_file = open(path_transform_txt, "r")
content = transform_file.read()
content_list = content.split("\n")
parameters_txt = str(content_list[9])
parameters = re.findall("[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?",parameters_txt)
translation = parameters[0:3]
rotation = parameters[3:6]
return translation, rotation
# load translation, rotation parameters for each of the transform files
trans_greedy, rotation_greedy = get_motion_parameters('/greedy_tfm.txt')
trans_sitk, rotation_sitk = get_motion_parameters('/sitk_inv_tfm.txt')
@josefyu @DariaFerrara I don't think we need your help with this task now ;)! Everything should be automated. @Keyn34 when you create your evaluation scripts. Kindly add them to a folder called ./FALCON/eval.
Currently doing a test run.
Additional tasks:
- Calculate mean values between iterations
- Output transformed files for visual inspection
- Add absolute values for metrics
Can we close this? @Keyn34 n
Yep!
Reopened issue for keeping track of manual motion extraction via ITK-Snap
Data extracted and send to Otto. Closing it again!