From 079ba8d17efb8bc79e41028b54f9854b6e5e78a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Haitz=20Legarreta=20Gorro=C3=B1o?= Date: Fri, 4 Aug 2023 13:17:40 -0400 Subject: [PATCH] ENH: Add a command line option to apply a transformation Add a command line option to apply a transformation to the obtained tractography data. Relevant for data where the brain size of the subject is significantly different (e.g. infant data) from an adult's brain size (used for the ORG atlas). The option allows to apply a scaling transformation so that the registration process to the ORG atlas data can work reasonably. The inverse transformation is automatically applied after the clustering process has finished in case the transformation file is provided. Document the use of the transform in documentation file. --- bin/wm_apply_ORG_atlas_to_subject.sh | 73 +++++++++++++++++-- ...ject-specific-tractography-parcellation.md | 38 ++++++++++ 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/bin/wm_apply_ORG_atlas_to_subject.sh b/bin/wm_apply_ORG_atlas_to_subject.sh index d338423c..00d4b072 100755 --- a/bin/wm_apply_ORG_atlas_to_subject.sh +++ b/bin/wm_apply_ORG_atlas_to_subject.sh @@ -11,6 +11,7 @@ Compulsory arguments: two folders named: ORG-RegAtlas-100HCP and ORG-800FC-100HCP -s: Path to 3D Slicer, e.g., under macOS, it is /Applications/Slicer.app/Contents/MacOS/Slicer Optional arguments: + -t: apply a transformation file to match the data to the adult brain size of the atlas. -r: whole brain tractography registration mode (default = 'rig') rig: rigid_affine_fast : this enables a rough tractography registration. This mode in general applicable to tractography data generated from different dMRI @@ -63,7 +64,7 @@ function reportMappingParameters { REPORTMAPPINGPARAMETERS } -while getopts ":hi:i:o:a:s:n:r:x:d:m:c:" opt; do +while getopts ":hi:i:o:a:s:n:r:t:x:d:m:c:" opt; do case $opt in h) Usage; exit 0 ;; @@ -77,6 +78,8 @@ while getopts ":hi:i:o:a:s:n:r:x:d:m:c:" opt; do ;; r) RegMode="$OPTARG" ;; + t) TfmFile="$OPTARG" + ;; n) NumThreads="$OPTARG" ;; x) VX="$OPTARG" @@ -192,15 +195,42 @@ echo " - tractography registration atlas:" $RegAtlasFolder echo " - fiber clustering atlas:" $FCAtlasFolder echo "" +# Apply transformation if provided +InTractographyDirname="$(dirname "$InputTractography")" +OutTfmTractography=$OutputCaseFolder/TransformedTracts +if [ "$TfmFile" ]; then + if [ ! -f "$TfmFile" ]; then + echo "" + echo "ERROR: Transformation file not found." + echo "" + exit + else + echo " Apply transformation with file: " "$TfmFile" + if [ $VX == 0 ]; then + wm_harden_transform.py -t "$TfmFile" \ + "$InTractographyDirname" "$OutTfmTractography" "$SlicerPath" + else + xvfb-run wm_harden_transform.py -t "$TfmFile" \ + "$InTractographyDirname" "$OutTfmTractography" "$SlicerPath" + fi + echo "" + fi +fi echo " Tractography registration with mode [" $RegMode "]" RegistrationFolder=$OutputCaseFolder/TractRegistration +if [ "$TfmFile" ]; then + TractographyData=$(find $OutTfmTractography -type f) +else + TractographyData=$InputTractography +fi + if [ "$RegMode" == "rig" ]; then RegTractography=$RegistrationFolder/${caseID}/output_tractography/${caseID}_reg.vtk if [ ! -f $RegTractography ]; then wm_register_to_atlas_new.py -mode rigid_affine_fast \ - $InputTractography $RegAtlasFolder/registration_atlas.vtk $RegistrationFolder/ + $TractographyData $RegAtlasFolder/registration_atlas.vtk $RegistrationFolder/ else echo " - registration has been done." fi @@ -209,7 +239,7 @@ elif [ "$RegMode" == "nonrig" ]; then if [ ! -f $RegTractography ]; then wm_register_to_atlas_new.py -mode affine \ - $InputTractography $RegAtlasFolder/registration_atlas.vtk $RegistrationFolder/ + $TractographyData $RegAtlasFolder/registration_atlas.vtk $RegistrationFolder/ affineRegTract=$RegistrationFolder/${caseID}/output_tractography/${caseID}_reg.vtk @@ -366,12 +396,45 @@ if [ $numfiles -lt 800 ]; then exit fi -echo " Append clusters into anatomical tracts." +# Apply the inverse transformation if provided +ClusterDirnames=($(find "$SeparatedClustersFolder" -mindepth 1 -type d | sort)) +OutInvTfmTractographyDirnameRoot=$OutputCaseFolder/InvTransformedTracts +if [ "$TfmFile" ]; then + if [ ! -f "$TfmFile" ]; then + echo "" + echo "ERROR: Transformation file not found." + echo "" + exit + else + echo " Apply inverse transformation with file: " "$TfmFile" + mkdir $OutInvTfmTractographyDirnameRoot + for ClusterDirname in "${ClusterDirnames[@]}"; do + GroupName=($(basename $ClusterDirname)) + OutInvTfmTractographyDirname=$OutInvTfmTractographyDirnameRoot/$GroupName + mkdir $OutInvTfmTractographyDirname + if [ $VX == 0 ]; then + wm_harden_transform.py -i -t "$TfmFile" \ + "$ClusterDirname" "$OutInvTfmTractographyDirname" "$SlicerPath" + else + xvfb-run wm_harden_transform.py -i -t "$TfmFile" \ + "$ClusterDirname" "$OutInvTfmTractographyDirname" "$SlicerPath" + fi + done + echo "" + fi +fi +echo " Append clusters into anatomical tracts." AnatomicalTractsFolder=$OutputCaseFolder/AnatomicalTracts +if [ "$TfmFile" ]; then + TractographyData=$OutInvTfmTractographyDirnameRoot +else + TractographyData=$SeparatedClustersFolder +fi + if [ ! -f $AnatomicalTractsFolder/T_UF_right.vtp ]; then - wm_append_clusters_to_anatomical_tracts.py $SeparatedClustersFolder/ $FCAtlasFolder $AnatomicalTractsFolder + wm_append_clusters_to_anatomical_tracts.py $TractographyData/ $FCAtlasFolder $AnatomicalTractsFolder else echo " - Appending clusters into anatomical tracts has been done." diff --git a/doc/subject-specific-tractography-parcellation.md b/doc/subject-specific-tractography-parcellation.md index 6d26bc7d..47e41046 100644 --- a/doc/subject-specific-tractography-parcellation.md +++ b/doc/subject-specific-tractography-parcellation.md @@ -78,6 +78,44 @@ This step performs QC of the input tractography data (“_example-UKF-data.vtk_ ![test image](tutorial-pics/fig_qc_input_overlap.jpg) +### 4.1. Optional: approximate brain size matching + +The ORG atlas was designed to work with adult's brain data. When working with infant data, you may need to apply a +transformation to them so that the relevant data gets scaled to approximately match an adult's brain size. The purpose +of this transformation is to ensure a good fit for the registration process. + +The transform file can be obtained using `Slicer`'s `Transform` module. The transformation used for scaling purposes +is a linear transform. The scaling factor (i.e. the diagonal components of the generated transformation matrix) is the +value that needs to be adjusted. Typically, a 1.5 value (across all three components) has been found to provide +reasonably good results. Once the `.tfm` file has been saved, it is used as the transform filename for the +`wm_harden_transform.py` script. + +A `.tfm` file containing a linear transform will look like this: +``` +#Insight Transform File V1.0 +#Transform 0 +Transform: AffineTransform_double_3_3 +Parameters: 0.6666666666666666 0 0 0 0.6666666666666666 0 0 0 0.6666666666666666 0 0 0 +FixedParameters: 0 0 0 +``` + +Whether the chosen scaling factor is a reasonably good estimate can be assessed by applying it to a diffusion scalar +map (e.g. the FA image) in `Slicer` and seeing if it provides a brain that has the approximate same size brain as the +ORG atlas FA image. + +Thus, prior to feeding the obtained tractography data to the pipeline, the transformation would be applied to the +tractography `vtk` file so that it can be scaled to approximately the size of an adult brain data. + +After obtaining the tracts and the clusters, using the same script and the transform file, the inverse transformation +must be applied to scale back the tractography data to the original size. + +In order to apply a transform file, the `-t` option followed by the filename containing the transformation must be +provided to the `wm_apply_ORG_atlas_to_subject.sh` script, e.g. + +```shell +wm_apply_ORG_atlas_to_subject.sh -i InputTractography -o OutputDirectory -a ORGAtlasFolder -s PathTo3DSlicer -t TransformFile +``` + ## 5. Tractography registration This steps registers the input tractography data to the ORG atlas tractography data.