purple-mri 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.1
2
+ Name: purple_mri
3
+ Version: 0.0.1
4
+ Summary: purple_mri: Penn Utilities for Registration and ParcelLation of Ex vivo MRI
5
+ Author-email: Pulkit Khandelwal <kpulkit95@gmail.com>
6
+ Project-URL: Homepage, https://github.com/Pulkit-Khandelwal/purple_mri
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy
9
+ Requires-Dist: torch
10
+ Requires-Dist: pykeops
11
+ Requires-Dist: pymeshlab
12
+ Requires-Dist: vtk
13
+ Requires-Dist: SimpleITK
14
+ Requires-Dist: geomloss
15
+
16
+ # purple-mri: **P**enn **U**tilities for **R**egistration and **P**arcel**L**ation of **E**x vivo **MRI**
17
+
18
+ We provide a set of tools packaged as `purple-mri` for segmentation, parcellation and registration of ultra high-resolution (< 300 microns) postmortem human brain hemisphere at 7 tesla t2w MRI at native subject-space resolution. This pipeline leverages advances in both deep learning and classical surface-based modeling techniques to produce parcellations in any atlas used in neuroimaging. The developed method allows us to perform vertex-wise analysis in the template space and thereby link morphometry measures with pathology measurements derived from histology.
19
+
20
+ Check out the [project page](https://pulkit-khandelwal.github.io/exvivo-brain-upenn/) and our latest papers [here](https://direct.mit.edu/imag/article/doi/10.1162/imag_a_00171/120741) and [here](https://arxiv.org/abs/2403.19497).
21
+
22
+ In particular, `purple-mri` allows you to do the following:
23
+ + obtain an initial 10 label segmentation: cortical GM, normal appearing WM, WMH, medial temporal lobe, corpus callosum, ventricles, caudate, putamen, globus pallidus and thalamus
24
+ + obtain surface-based native subject-space parcellation based on different brain atlases such as: DKT, Economo, Schaeffer etc
25
+ + create population specific volumetric and surface-based templates
26
+ + perform exvivo to invivo registration in volumetric intensity space
27
+ + perform surface-to-surface registration between exvivo or invivo
28
+ + perform intensity-based registration between 9.4 tesla MTL to 7 tesla whole hemsiphere registration
29
+ + perform vertex-wise and group-wise generalized linear modeling analysis for exvivo subject population for morphometry and histology
30
+
31
+ ## Steps (for segmentation and parcellation)
32
+ `purple-mri` follows a series of steps making use of bash scripts and Docker.
33
+
34
+ ### Pre-processing
35
+ Perform bias correction and image normalization/standardization. We use `N4BiasFieldCorrection` as part of the CLI tool [ANTs](https://github.com/ANTsX/ANTs) and [`c3d`](http://www.itksnap.org/pmwiki/pmwiki.php?n=Convert3D.Convert3D). We highly recommend using the option of an input mask in `N4BiasFieldCorrection` which can be obtained via corase threhsolding.
36
+ [Here](https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/tree/main/misc_scripts/perform_bias_correction.sh) is a sample script.
37
+
38
+ ### Deep learning-based initial labeling and CRUISE-based post-hoc topology correction
39
+ Currently, we have two Docker images. The first image provides the segmentation and the second employs [Nighres/CRUISE](https://nighres.readthedocs.io/en/latest/installation.html) for post-hoc topology correction.
40
+ Please follow the [link]([https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/blob/main/exvivo-segm-demo-docker.md](https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/docker/exvivo_docker.md) for detailed instructions on how to use Docker to get the segmentations. Some key commands are emphasized here:
41
+
42
+ Place the pre-processed image(s) (with a suffix _0000.nii.gz to your filenames) in a folder named `data_for_inference` within your working directory is `/your/working/directory`.
43
+ ```
44
+ docker pull pulks/docker_hippogang_exvivo_segm:v${LATEST_TAG}
45
+
46
+ docker run --gpus all --privileged -v /your/working/directory/:/data/exvivo/ -it pulks/docker_hippogang_exvivo_segm:v${LATEST_TAG} /bin/bash -c "bash /src/commands_nnunet_inference.sh ${OPTION}" >> logs.txt
47
+ ```
48
+ You will see the output in `/your/working/directory/data_for_inference/output_from_nnunet_inference`.
49
+
50
+ Next, correct for topology so that adjoining gyri and sulci are clearly separated. Copy the segmentations from `output_from_nnunet_inference` to a folder `data_for_topology_correction` in your wokring directory.
51
+ ```
52
+ docker pull pulks/docker_nighres:v1.0.0
53
+
54
+ docker run -v /your/working/directory/:/data/cruise_files/ -it pulks/docker_nighres:v1.0.0 /bin/bash -c "bash /data/prepare_cruise_files.sh"
55
+
56
+ # Locally run the file to get the final combined label file. See instructions [here](https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/blob/main/exvivo-segm-demo-docker.md) and links referenced therein.
57
+ bash clean_labels_final.sh
58
+ ```
59
+
60
+ ### Surface-based modeling to obtain whole-hemisphere parcellations
61
+ Once, you have obtained an initial 10-label topology corrected volumetric segmentation, you can proceed to the surface-based pipeline to obtain parcellations based on your favorite atlas. This step will be on your local machine. No GPUs required. To do this, you should have FreeSurfer installed locally. We have used FreeSurfer version 7.4.0 on linux obtained from [here](https://surfer.nmr.mgh.harvard.edu/fswiki/DownloadAndInstall). Moreover, there are some Python dependencies which can be found in the `dependencies.txt` file and installed using `pip`.
62
+
63
+ Run the following file which calls in several bash scripts which prepares the data, computes appropriate transformations and re-orients the images, corrects surface topology, and perform the parcellation into Desikan-Killiany-Tourville (DKT), Schaefer, Glasser and the Von Economo-Koskinos atlases.
64
+
65
+ For the surface-based modeling step, we assume that all the hemishpehrs are right hemispheres. So, we suggest flipping the left t2w MRI and its corresponding segmentation to left using the following `c3d` command: `c3d image_left.nii.gz -flip y image_right_flipped.nii.gz`
66
+
67
+ Clone the current repository and the run the following script `run_surface_pipeline.sh` from within the `purple_mri` folder which takes the following mandatory arguments:
68
+ `freesurfer_path`: path to the FreeSurfer installtion
69
+ `working_dir`: directory which will have the outputs for each subject stored
70
+ `mri_path`: mri images path
71
+ `segm_path`: 10-label segmentation path
72
+ `external_atlases_path`: directory with files for other atlases
73
+ `num_threads`: number of threads
74
+
75
+ Place your t2w MRI in a folder `mri_path` and the intial deep learning-based segmentations in `segm_path`.
76
+ Make sure your mri images and segmentation files have the same names ending with `.nii.gz`.
77
+ Place the `fsaverage` in the `working_dir` folder.
78
+
79
+ ```
80
+ cd purple_mri
81
+
82
+ bash run_surface_pipeline.sh freesurfer_path working_dir mri_path segm_path external_atlases_path num_threads
83
+ ```
84
+
85
+ ## Other scripts
86
+ ### Intensity-based volumetric template building
87
+ We build intensity-based volumetric templates using the [greedy](https://sites.google.com/view/greedyreg/about?authuser=0) tool. The required binaries (for Linux) and the scripts are located in the the `intensity_template` within the `scripts` directory. Follow the instructions [here](https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/scripts/intensity_template/README.md).
88
+
89
+
90
+ ### Ex vivo and in vivo registration
91
+ Script `exvivo_invivo_greedy_registration.sh` to register in vivo (t1w) and ex vivo (t2w) MRI is located in the folder `scripts`. We use [greedy](https://sites.google.com/view/greedyreg/about?authuser=0) to register the segmentations of in vivo aseg+aparc labels derived from FreeSurfer and 10-label initial deep learning segmentation of postmortem MRI. The warps are then used to regsiter the MRIs.
92
+
93
+ ### Perform GLM analyses
94
+ We perform vertex-wise analysis in `fsaverage` space to fit a generalized linear model (GLM) between cortical thickness (mm) and with global ratings of amyloid-β, Braak staging, CERAD, and semiquantitative ratings of the medial temporal lobe (MTL) neuronal loss and tau pathology, with age, sex and postmortem interval (PMI) as covariates. You can follow the steps detailed [here](https://github.com/Pulkit-Khandelwal/purple-mri/tree/main/glm).
95
+
96
+ ## Notes
97
+ + Our method has been developed to work on a single exvivo hemisphere.
98
+ + The deep learning-based segmentation was primarily trained on 7T t2w MRI. We have tested the model on t2* flash as well and it works pretty well but, if need be, we recommend re-training the model with some manual labels obtained on t2* flash MRI.
99
+
100
+ ## pip package
101
+
102
+ ## Introductory video
103
+ <div align="center">
104
+ <a href="https://youtu.be/0BOeUtlWlYw?si=7NeNDsoePOW3_J4Y">
105
+ <img src="https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/images/thumbnail.png" style="width:75%;">
106
+ </a>
107
+ </div>
108
+
109
+ ## Citations
110
+ + Khandelwal, P., Duong, M. T., Sadaghiani, S., Lim, S., Denning, A. E., Chung, E., ... & Yushkevich, P. A. (2024). Automated deep learning segmentation of high-resolution 7 tesla postmortem MRI for quantitative analysis of structure-pathology correlations in neurodegenerative diseases. Imaging Neuroscience, 2, 1-30.
111
+ + Khandelwal, P., Duong, M. T., Fuentes, C., Denning, A., Trotman, W., Ittyerah, R., ... & Yushkevich, P. A. (2024). Surface-based parcellation and vertex-wise analysis of ultra high-resolution ex vivo 7 tesla MRI in neurodegenerative diseases. arXiv preprint arXiv:2403.19497.
112
+
@@ -0,0 +1,97 @@
1
+ # purple-mri: **P**enn **U**tilities for **R**egistration and **P**arcel**L**ation of **E**x vivo **MRI**
2
+
3
+ We provide a set of tools packaged as `purple-mri` for segmentation, parcellation and registration of ultra high-resolution (< 300 microns) postmortem human brain hemisphere at 7 tesla t2w MRI at native subject-space resolution. This pipeline leverages advances in both deep learning and classical surface-based modeling techniques to produce parcellations in any atlas used in neuroimaging. The developed method allows us to perform vertex-wise analysis in the template space and thereby link morphometry measures with pathology measurements derived from histology.
4
+
5
+ Check out the [project page](https://pulkit-khandelwal.github.io/exvivo-brain-upenn/) and our latest papers [here](https://direct.mit.edu/imag/article/doi/10.1162/imag_a_00171/120741) and [here](https://arxiv.org/abs/2403.19497).
6
+
7
+ In particular, `purple-mri` allows you to do the following:
8
+ + obtain an initial 10 label segmentation: cortical GM, normal appearing WM, WMH, medial temporal lobe, corpus callosum, ventricles, caudate, putamen, globus pallidus and thalamus
9
+ + obtain surface-based native subject-space parcellation based on different brain atlases such as: DKT, Economo, Schaeffer etc
10
+ + create population specific volumetric and surface-based templates
11
+ + perform exvivo to invivo registration in volumetric intensity space
12
+ + perform surface-to-surface registration between exvivo or invivo
13
+ + perform intensity-based registration between 9.4 tesla MTL to 7 tesla whole hemsiphere registration
14
+ + perform vertex-wise and group-wise generalized linear modeling analysis for exvivo subject population for morphometry and histology
15
+
16
+ ## Steps (for segmentation and parcellation)
17
+ `purple-mri` follows a series of steps making use of bash scripts and Docker.
18
+
19
+ ### Pre-processing
20
+ Perform bias correction and image normalization/standardization. We use `N4BiasFieldCorrection` as part of the CLI tool [ANTs](https://github.com/ANTsX/ANTs) and [`c3d`](http://www.itksnap.org/pmwiki/pmwiki.php?n=Convert3D.Convert3D). We highly recommend using the option of an input mask in `N4BiasFieldCorrection` which can be obtained via corase threhsolding.
21
+ [Here](https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/tree/main/misc_scripts/perform_bias_correction.sh) is a sample script.
22
+
23
+ ### Deep learning-based initial labeling and CRUISE-based post-hoc topology correction
24
+ Currently, we have two Docker images. The first image provides the segmentation and the second employs [Nighres/CRUISE](https://nighres.readthedocs.io/en/latest/installation.html) for post-hoc topology correction.
25
+ Please follow the [link]([https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/blob/main/exvivo-segm-demo-docker.md](https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/docker/exvivo_docker.md) for detailed instructions on how to use Docker to get the segmentations. Some key commands are emphasized here:
26
+
27
+ Place the pre-processed image(s) (with a suffix _0000.nii.gz to your filenames) in a folder named `data_for_inference` within your working directory is `/your/working/directory`.
28
+ ```
29
+ docker pull pulks/docker_hippogang_exvivo_segm:v${LATEST_TAG}
30
+
31
+ docker run --gpus all --privileged -v /your/working/directory/:/data/exvivo/ -it pulks/docker_hippogang_exvivo_segm:v${LATEST_TAG} /bin/bash -c "bash /src/commands_nnunet_inference.sh ${OPTION}" >> logs.txt
32
+ ```
33
+ You will see the output in `/your/working/directory/data_for_inference/output_from_nnunet_inference`.
34
+
35
+ Next, correct for topology so that adjoining gyri and sulci are clearly separated. Copy the segmentations from `output_from_nnunet_inference` to a folder `data_for_topology_correction` in your wokring directory.
36
+ ```
37
+ docker pull pulks/docker_nighres:v1.0.0
38
+
39
+ docker run -v /your/working/directory/:/data/cruise_files/ -it pulks/docker_nighres:v1.0.0 /bin/bash -c "bash /data/prepare_cruise_files.sh"
40
+
41
+ # Locally run the file to get the final combined label file. See instructions [here](https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/blob/main/exvivo-segm-demo-docker.md) and links referenced therein.
42
+ bash clean_labels_final.sh
43
+ ```
44
+
45
+ ### Surface-based modeling to obtain whole-hemisphere parcellations
46
+ Once, you have obtained an initial 10-label topology corrected volumetric segmentation, you can proceed to the surface-based pipeline to obtain parcellations based on your favorite atlas. This step will be on your local machine. No GPUs required. To do this, you should have FreeSurfer installed locally. We have used FreeSurfer version 7.4.0 on linux obtained from [here](https://surfer.nmr.mgh.harvard.edu/fswiki/DownloadAndInstall). Moreover, there are some Python dependencies which can be found in the `dependencies.txt` file and installed using `pip`.
47
+
48
+ Run the following file which calls in several bash scripts which prepares the data, computes appropriate transformations and re-orients the images, corrects surface topology, and perform the parcellation into Desikan-Killiany-Tourville (DKT), Schaefer, Glasser and the Von Economo-Koskinos atlases.
49
+
50
+ For the surface-based modeling step, we assume that all the hemishpehrs are right hemispheres. So, we suggest flipping the left t2w MRI and its corresponding segmentation to left using the following `c3d` command: `c3d image_left.nii.gz -flip y image_right_flipped.nii.gz`
51
+
52
+ Clone the current repository and the run the following script `run_surface_pipeline.sh` from within the `purple_mri` folder which takes the following mandatory arguments:
53
+ `freesurfer_path`: path to the FreeSurfer installtion
54
+ `working_dir`: directory which will have the outputs for each subject stored
55
+ `mri_path`: mri images path
56
+ `segm_path`: 10-label segmentation path
57
+ `external_atlases_path`: directory with files for other atlases
58
+ `num_threads`: number of threads
59
+
60
+ Place your t2w MRI in a folder `mri_path` and the intial deep learning-based segmentations in `segm_path`.
61
+ Make sure your mri images and segmentation files have the same names ending with `.nii.gz`.
62
+ Place the `fsaverage` in the `working_dir` folder.
63
+
64
+ ```
65
+ cd purple_mri
66
+
67
+ bash run_surface_pipeline.sh freesurfer_path working_dir mri_path segm_path external_atlases_path num_threads
68
+ ```
69
+
70
+ ## Other scripts
71
+ ### Intensity-based volumetric template building
72
+ We build intensity-based volumetric templates using the [greedy](https://sites.google.com/view/greedyreg/about?authuser=0) tool. The required binaries (for Linux) and the scripts are located in the the `intensity_template` within the `scripts` directory. Follow the instructions [here](https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/scripts/intensity_template/README.md).
73
+
74
+
75
+ ### Ex vivo and in vivo registration
76
+ Script `exvivo_invivo_greedy_registration.sh` to register in vivo (t1w) and ex vivo (t2w) MRI is located in the folder `scripts`. We use [greedy](https://sites.google.com/view/greedyreg/about?authuser=0) to register the segmentations of in vivo aseg+aparc labels derived from FreeSurfer and 10-label initial deep learning segmentation of postmortem MRI. The warps are then used to regsiter the MRIs.
77
+
78
+ ### Perform GLM analyses
79
+ We perform vertex-wise analysis in `fsaverage` space to fit a generalized linear model (GLM) between cortical thickness (mm) and with global ratings of amyloid-β, Braak staging, CERAD, and semiquantitative ratings of the medial temporal lobe (MTL) neuronal loss and tau pathology, with age, sex and postmortem interval (PMI) as covariates. You can follow the steps detailed [here](https://github.com/Pulkit-Khandelwal/purple-mri/tree/main/glm).
80
+
81
+ ## Notes
82
+ + Our method has been developed to work on a single exvivo hemisphere.
83
+ + The deep learning-based segmentation was primarily trained on 7T t2w MRI. We have tested the model on t2* flash as well and it works pretty well but, if need be, we recommend re-training the model with some manual labels obtained on t2* flash MRI.
84
+
85
+ ## pip package
86
+
87
+ ## Introductory video
88
+ <div align="center">
89
+ <a href="https://youtu.be/0BOeUtlWlYw?si=7NeNDsoePOW3_J4Y">
90
+ <img src="https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/images/thumbnail.png" style="width:75%;">
91
+ </a>
92
+ </div>
93
+
94
+ ## Citations
95
+ + Khandelwal, P., Duong, M. T., Sadaghiani, S., Lim, S., Denning, A. E., Chung, E., ... & Yushkevich, P. A. (2024). Automated deep learning segmentation of high-resolution 7 tesla postmortem MRI for quantitative analysis of structure-pathology correlations in neurodegenerative diseases. Imaging Neuroscience, 2, 1-30.
96
+ + Khandelwal, P., Duong, M. T., Fuentes, C., Denning, A., Trotman, W., Ittyerah, R., ... & Yushkevich, P. A. (2024). Surface-based parcellation and vertex-wise analysis of ultra high-resolution ex vivo 7 tesla MRI in neurodegenerative diseases. arXiv preprint arXiv:2403.19497.
97
+
File without changes
@@ -0,0 +1,13 @@
1
+ import sys
2
+ import subprocess
3
+
4
+ arg1 = sys.argv[1]
5
+ arg2 = sys.argv[2]
6
+ arg3 = sys.argv[3]
7
+ arg4 = sys.argv[4]
8
+ arg5 = sys.argv[5]
9
+ arg6 = int(sys.argv[6])
10
+ arg7 = sys.argv[7]
11
+
12
+ subprocess.run("bash run_surface_pipeline.sh %s %s %s %s %s %s %s" \
13
+ % (arg1, arg2, arg3, arg4, arg5, arg6, arg7), shell=True)
@@ -0,0 +1,25 @@
1
+ working_dir=$1
2
+ tgt_dir_FS_mesh=$2
3
+ tgt_dir_FS_mesh_decimated=$3
4
+ str_split=$4
5
+ for i in $str_split; do subjects+=($i) ; done
6
+
7
+ hemis=rh
8
+ for subj in "${subjects[@]}"
9
+ do
10
+ echo ${subj}
11
+ SUBJECTS_DIR=${working_dir}/${subj}
12
+
13
+ mri_pretess ${SUBJECTS_DIR}/mri/filled.mgz 1 ${SUBJECTS_DIR}/mri/mri.mgz ${tgt_dir_FS_mesh}/${subj}_pretess.mgz
14
+ mri_tessellate ${tgt_dir_FS_mesh}/${subj}_pretess.mgz 1 ${tgt_dir_FS_mesh}/${subj}.orig.nofix
15
+ mris_convert ${tgt_dir_FS_mesh}/${subj}.orig.nofix ${tgt_dir_FS_mesh}/${subj}.orig.nofix.vtk
16
+
17
+ # decimate the vtk file
18
+ python3 -m purple_mri.scripts.decimate_mesh ${tgt_dir_FS_mesh} ${tgt_dir_FS_mesh_decimated} ${subj}.orig.nofix.vtk ${subj}.decimated.orig.nofix.vtk
19
+
20
+ # convert back to FreeSurfer format and this will act as the input to the topology correction step
21
+ mris_convert ${tgt_dir_FS_mesh_decimated}/${subj}.decimated.orig.nofix.vtk ${tgt_dir_FS_mesh_decimated}/${subj}.decimated.orig.nofix
22
+
23
+ cp ${tgt_dir_FS_mesh_decimated}/${subj}.decimated.orig.nofix ${working_dir}/${subj}/surf/${hemis}.orig.nofix
24
+
25
+ done;
@@ -0,0 +1,296 @@
1
+ import os
2
+ import sys
3
+ import numpy as np
4
+ import torch
5
+ from torch.autograd import grad
6
+ import vtk
7
+ from vtk.util.numpy_support import vtk_to_numpy, numpy_to_vtk
8
+ import pymeshlab
9
+ import pandas as pd
10
+ from pykeops.torch import Vi, Vj
11
+
12
+ # torch type and device
13
+ use_cuda = torch.cuda.is_available()
14
+ torchdeviceId = torch.device("cuda:0") if use_cuda else "cpu"
15
+ torchdtype = torch.float32
16
+
17
+ # PyKeOps counterpart
18
+ KeOpsdeviceId = torchdeviceId.index # id of Gpu device (in case GPU is used)
19
+ KeOpsdtype = torchdtype.__str__().split(".")[1] # 'float32'
20
+
21
+ use_cuda = torch.cuda.is_available()
22
+ torchdeviceId = torch.device("cuda:0") if use_cuda else "cpu"
23
+
24
+ # Read VTK mesh
25
+ def load_vtk(filename):
26
+ rd = vtk.vtkPolyDataReader()
27
+ rd.SetFileName(filename)
28
+ rd.Update()
29
+ return rd.GetOutput()
30
+
31
+ # Read points from the polydata
32
+ def vtk_get_points(pd):
33
+ return vtk_to_numpy(pd.GetPoints().GetData())
34
+
35
+ # Read the faces from the polydata
36
+ def vtk_get_triangles(pd):
37
+ return vtk_to_numpy(pd.GetPolys().GetData()).reshape(-1,4)[:,1:]
38
+
39
+ # Map all point arrays to cell arrays
40
+ def vtk_all_point_arrays_to_cell_arrays(pd):
41
+ flt = vtk.vtkPointDataToCellData()
42
+ flt.SetInputData(pd)
43
+ flt.Update()
44
+ return flt.GetOutput()
45
+
46
+ # Read a point array
47
+ def vtk_get_point_array(pd, name):
48
+ a = pd.GetPointData().GetArray(name)
49
+ return vtk_to_numpy(a) if a is not None else None
50
+
51
+ # Add a cell array to a mesh
52
+ def vtk_set_point_array(pd, name, array, array_type=vtk.VTK_FLOAT):
53
+ a = numpy_to_vtk(array, array_type=array_type)
54
+ a.SetName(name)
55
+ pd.GetPointData().AddArray(a)
56
+
57
+ # Read a cell array
58
+ def vtk_get_cell_array(pd, name):
59
+ a = pd.GetCellData().GetArray(name)
60
+ return vtk_to_numpy(a) if a is not None else None
61
+
62
+ # Add a cell array to a mesh
63
+ def vtk_set_cell_array(pd, name, array):
64
+ a = numpy_to_vtk(array)
65
+ a.SetName(name)
66
+ pd.GetCellData().AddArray(a)
67
+
68
+ # Make a VTK polydata from vertices and triangles
69
+ def vtk_make_pd(v, f):
70
+ pd = vtk.vtkPolyData()
71
+ pts = vtk.vtkPoints()
72
+ pts.SetData(numpy_to_vtk(v))
73
+ pd.SetPoints(pts)
74
+ ca = vtk.vtkCellArray()
75
+ ca.SetCells(f.shape[0], numpy_to_vtk(np.insert(f, 0, 3, axis=1).ravel(), array_type=vtk.VTK_ID_TYPE))
76
+ pd.SetPolys(ca)
77
+ return pd
78
+
79
+ # Save VTK polydata
80
+ def save_vtk(pd, filename, binary = False):
81
+ wr=vtk.vtkPolyDataWriter()
82
+ wr.SetFileName(filename)
83
+ wr.SetInputData(pd)
84
+ #wr.SetFileVersion(1)
85
+ wr.SetFileVersion(42)
86
+ #wr.SetFileFormat(1,2)
87
+ if binary:
88
+ wr.SetFileTypeToBinary()
89
+ wr.Update()
90
+
91
+ # Reduction using pymeshlab
92
+ def decimate(v, f, target_faces):
93
+ ms = pymeshlab.MeshSet()
94
+ ms.add_mesh(pymeshlab.Mesh(vertex_matrix=v, face_matrix=f))
95
+ ms.meshing_decimation_quadric_edge_collapse(targetfacenum=target_faces,
96
+ preserveboundary=True,
97
+ preservenormal=True,
98
+ preservetopology=True,
99
+ planarquadric=True)
100
+ m0 = ms.mesh(0)
101
+ return m0.vertex_matrix(), m0.face_matrix()
102
+
103
+
104
+ # For LDDMM
105
+ def GaussKernel(sigma):
106
+ x, y, b = Vi(0, 3), Vj(1, 3), Vj(2, 3)
107
+ gamma = 1 / (sigma * sigma)
108
+ D2 = x.sqdist(y)
109
+ K = (-D2 * gamma).exp()
110
+ return (K * b).sum_reduction(axis=1)
111
+
112
+ # For Varifold
113
+ def GaussLinKernel(sigma):
114
+ x, y, u, v, b = Vi(0, 3), Vj(1, 3), Vi(2, 3), Vj(3, 3), Vj(4, 1)
115
+ gamma = 1 / (sigma * sigma)
116
+ D2 = x.sqdist(y)
117
+ K = (-D2 * gamma).exp() * (u * v).sum() ** 2
118
+ return (K * b).sum_reduction(axis=1)
119
+
120
+ # For Currents
121
+ def GaussLinCurrentsKernel(sigma):
122
+ x, y, u, v = Vi(0, 3), Vj(1, 3), Vi(2, 3), Vj(3, 3)
123
+ gamma = 1 / (sigma * sigma)
124
+ D2 = x.sqdist(y)
125
+ K = (-D2 * gamma).exp() * (u * v).sum()
126
+ return K.sum_reduction(axis=1)
127
+
128
+ # For Currents
129
+ def GaussLinCurrentsKernel(sigma):
130
+ x, y, u, v = Vi(0, 3), Vj(1, 3), Vi(2, 3), Vj(3, 3)
131
+ gamma = 1 / (sigma * sigma)
132
+ D2 = x.sqdist(y)
133
+ K = (-D2 * gamma).exp() * (u * v).sum()
134
+ return K.sum_reduction(axis=1)
135
+
136
+ # For Currents to match C++ code
137
+ def GaussLinCurrentsKernelC(sigma):
138
+ x, y, u, v = Vi(0, 3), Vj(1, 3), Vi(2, 3), Vj(3, 3)
139
+ gamma = 1 / (2 * sigma * sigma)
140
+ D2 = x.sqdist(y)
141
+ K = (-D2 * gamma).exp() * (u * v).sum() * 0.5
142
+ return K.sum_reduction(axis=1)
143
+
144
+
145
+ # Forward integration
146
+ def RalstonIntegrator():
147
+ def f(ODESystem, x0, nt, deltat=1.0):
148
+ x = tuple(map(lambda x: x.clone(), x0))
149
+ dt = deltat / nt
150
+ l = [x]
151
+ for i in range(nt):
152
+ xdot = ODESystem(*x)
153
+ xi = tuple(map(lambda x, xdot: x + (2 * dt / 3) * xdot, x, xdot))
154
+ xdoti = ODESystem(*xi)
155
+ x = tuple(
156
+ map(
157
+ lambda x, xdot, xdoti: x + (0.25 * dt) * (xdot + 3 * xdoti),
158
+ x,
159
+ xdot,
160
+ xdoti,
161
+ )
162
+ )
163
+ l.append(x)
164
+ return l
165
+
166
+ return f
167
+
168
+ # LDDMM definitions
169
+
170
+ def Hamiltonian(K):
171
+ def H(p, q):
172
+ return 0.5 * (p * K(q, q, p)).sum()
173
+
174
+ return H
175
+
176
+
177
+ def HamiltonianSystem(K):
178
+ H = Hamiltonian(K)
179
+
180
+ def HS(p, q):
181
+ Gp, Gq = grad(H(p, q), (p, q), create_graph=True)
182
+ return -Gq, Gp
183
+
184
+ return HS
185
+
186
+ def Shooting(p0, q0, K, nt=10, Integrator=RalstonIntegrator()):
187
+ return Integrator(HamiltonianSystem(K), (p0, q0), nt)
188
+
189
+
190
+ def Flow(x0, p0, q0, K, deltat=1.0, Integrator=RalstonIntegrator()):
191
+ HS = HamiltonianSystem(K)
192
+
193
+ def FlowEq(x, p, q):
194
+ return (K(x, q, p),) + HS(p, q)
195
+
196
+ return Integrator(FlowEq, (x0, p0, q0), deltat)[0]
197
+
198
+
199
+ def LDDMMloss(K, dataloss, gamma=0):
200
+ def loss(p0, q0):
201
+ p, q = Shooting(p0, q0, K)[-1]
202
+ return gamma * Hamiltonian(K)(p0, q0) + dataloss(q)
203
+
204
+ return loss
205
+
206
+ # Basic Varifold loss
207
+ # VT: vertices coordinates of target surface,
208
+ # FS,FT : Face connectivity of source and target surfaces
209
+ # K kernel
210
+ def lossVarifoldSurf(FS, VT, FT, K):
211
+ def get_center_length_normal(F, V):
212
+ V0, V1, V2 = (
213
+ V.index_select(0, F[:, 0]),
214
+ V.index_select(0, F[:, 1]),
215
+ V.index_select(0, F[:, 2]),
216
+ )
217
+ centers, normals = (V0 + V1 + V2) / 3, 0.5 * torch.cross(V1 - V0, V2 - V0)
218
+ length = (normals**2).sum(dim=1)[:, None].sqrt()
219
+ return centers, length, normals / length
220
+
221
+ CT, LT, NTn = get_center_length_normal(FT, VT)
222
+ cst = (LT * K(CT, CT, NTn, NTn, LT)).sum()
223
+
224
+ def loss(VS):
225
+ CS, LS, NSn = get_center_length_normal(FS, VS)
226
+ return (
227
+ cst
228
+ + (LS * K(CS, CS, NSn, NSn, LS)).sum()
229
+ - 2 * (LS * K(CS, CT, NSn, NTn, LT)).sum()
230
+ )
231
+
232
+ return loss
233
+
234
+
235
+ # Also implement a basic currents loss
236
+ def lossCurrentsSurf(FS, VT, FT, K):
237
+ def get_center_length_normal(F, V):
238
+ V0, V1, V2 = (
239
+ V.index_select(0, F[:, 0]),
240
+ V.index_select(0, F[:, 1]),
241
+ V.index_select(0, F[:, 2]),
242
+ )
243
+ centers, normals = (V0 + V1 + V2) / 3, 0.5 * torch.cross(V1 - V0, V2 - V0)
244
+ return centers, normals
245
+
246
+ CT, NT = get_center_length_normal(FT, VT)
247
+ cst = K(CT, CT, NT, NT).sum()
248
+
249
+ def loss(VS):
250
+ CS, NS = get_center_length_normal(FS, VS)
251
+ tt,ss,st = cst, K(CS, CS, NS, NS).sum(), 2 * K(CS, CT, NS, NT).sum()
252
+ print(f'tt: {tt}, ss: {ss}, st: {st}')
253
+ return (
254
+ cst
255
+ + K(CS, CS, NS, NS).sum()
256
+ - 2 * K(CS, CT, NS, NT).sum()
257
+ )
258
+
259
+ return loss
260
+
261
+ # This function loads a mesh and extracts derived objects/tensors
262
+ def load_mesh(fn, target_faces=None):
263
+ pd = vtk_all_point_arrays_to_cell_arrays(load_vtk(fn))
264
+ v, f = vtk_get_points(pd), vtk_get_triangles(pd)
265
+ if target_faces:
266
+ v, f = decimate(v, f, target_faces)
267
+ #lp = mesh_label_prob_maps(pd)
268
+ return {
269
+ 'fn': fn,
270
+ 'pd': pd,
271
+ 'v': v,
272
+ 'f': f,
273
+ #'lp': lp,
274
+ 'vt': torch.tensor(v, dtype=torchdtype, device=torchdeviceId).contiguous(),
275
+ 'ft': torch.tensor(f, dtype=torch.long, device=torchdeviceId).contiguous()
276
+ #'lpt': torch.tensor(lp, dtype=torchdtype, device=torchdeviceId).contiguous()
277
+ }
278
+
279
+
280
+ def closure():
281
+ optimizer.zero_grad()
282
+ L = loss(p0, q0)
283
+ print("loss", L.detach().cpu().numpy())
284
+ L.backward()
285
+ return L
286
+
287
+ print("decimating the mesh............")
288
+ src_path=str(sys.argv[1])
289
+ tgt_path=str(sys.argv[2])
290
+
291
+ md_src = load_mesh(os.path.join(src_path, sys.argv[3]))
292
+ print(md_src.keys(), len(md_src['f']), len(md_src['v']))
293
+
294
+ v_dec, f_dec = decimate(md_src['v'], md_src['f'], 300000)
295
+ print(len(v_dec), len(f_dec))
296
+ save_vtk(vtk_make_pd(v_dec, f_dec), os.path.join(tgt_path, sys.argv[4]))
@@ -0,0 +1,32 @@
1
+ freesurfer_path=$1
2
+ working_dir=$2
3
+ str_split=$3
4
+ hemis=rh
5
+ for i in $str_split; do subjects+=($i) ; done
6
+
7
+ for subj in "${subjects[@]}"
8
+ do
9
+
10
+ echo ${subj}
11
+ SUBJECTS_DIR=${working_dir}/${subj}
12
+
13
+ mri_convert ${SUBJECTS_DIR}/mri/rawavg.mgz ${SUBJECTS_DIR}/mri/orig_conform.mgz --conform
14
+
15
+ tkregister2 --mov ${SUBJECTS_DIR}/mri/rawavg.mgz --targ ${SUBJECTS_DIR}/mri/orig_conform.mgz \
16
+ --reg ${SUBJECTS_DIR}/mri/transforms/register.native.dat --regheader-center \
17
+ --noedit --ltaout ${SUBJECTS_DIR}/mri/transforms/init_for_mris_register.lta
18
+
19
+ mri_add_xform_to_header -c ${SUBJECTS_DIR}/mri/transforms/talairach.xfm ${SUBJECTS_DIR}/mri/orig_conform.mgz ${SUBJECTS_DIR}/mri/orig_conform.mgz
20
+
21
+ mri_info ${SUBJECTS_DIR}/mri/orig_conform.mgz
22
+
23
+ ${freesurfer_path}/bin/talairach_avi --i ${SUBJECTS_DIR}/mri/orig_conform.mgz --xfm ${SUBJECTS_DIR}/mri/transforms/talairach.auto.xfm
24
+
25
+ cp ${SUBJECTS_DIR}/mri/transforms/talairach.auto.xfm ${SUBJECTS_DIR}/mri/transforms/talairach.xfm
26
+
27
+ lta_convert --src ${SUBJECTS_DIR}/mri/orig_conform.mgz --trg /data/pulkit/exvivo_reg_reconstruct/freesurfer_installation/freesurfer/average/mni305.cor.mgz \
28
+ --inxfm ${SUBJECTS_DIR}/mri/transforms/talairach.xfm --outlta ${SUBJECTS_DIR}/mri/transforms/talairach.xfm.lta --subject fsaverage --ltavox2vox
29
+
30
+ mri_add_xform_to_header -c ${SUBJECTS_DIR}/mri/transforms/talairach.xfm ${SUBJECTS_DIR}/mri/orig_conform.mgz ${SUBJECTS_DIR}/mri/orig_conform.mgz
31
+
32
+ done;
@@ -0,0 +1,43 @@
1
+ working_dir=$1
2
+ generated_files_folder=$2
3
+ mri_dir=$3
4
+ str_split=$4
5
+ for i in $str_split; do subjects+=($i) ; done
6
+
7
+ hemis=rh
8
+ for subj in "${subjects[@]}"
9
+ do
10
+ echo ${subj}
11
+
12
+ SUBJECTS_DIR=${working_dir}/${subj}
13
+ mkdir -p ${SUBJECTS_DIR}
14
+
15
+ mkdir -p ${SUBJECTS_DIR}/mri \
16
+ ${SUBJECTS_DIR}/surf \
17
+ ${SUBJECTS_DIR}/scripts \
18
+ ${SUBJECTS_DIR}/label \
19
+ ${SUBJECTS_DIR}/stats \
20
+ ${SUBJECTS_DIR}/mri/transforms
21
+
22
+ mri_convert ${mri_dir}/${subj}.nii.gz ${SUBJECTS_DIR}/mri/${subj}.mgz
23
+
24
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/mri.mgz
25
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/brain.mgz
26
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/brainmask.mgz
27
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/brain.finalsurfs.mgz
28
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/rawavg.mgz
29
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/norm.mgz
30
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/nu.mgz
31
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/orig.mgz
32
+ cp ${SUBJECTS_DIR}/mri/${subj}.mgz ${SUBJECTS_DIR}/mri/T1.mgz
33
+
34
+ cp ${generated_files_folder}/${subj}_filled.mgz ${SUBJECTS_DIR}/mri/filled.mgz
35
+ cp ${generated_files_folder}/${subj}_wm.mgz ${SUBJECTS_DIR}/mri/wm.mgz
36
+
37
+ cp ${generated_files_folder}/${subj}_aseg.presurf.mgz ${SUBJECTS_DIR}/mri/aseg.presurf.mgz
38
+ cp ${generated_files_folder}/${subj}_aseg.presurf_100.mgz ${SUBJECTS_DIR}/mri/aseg.presurf_100.mgz
39
+ cp ${generated_files_folder}/${subj}_aseg.mgz ${SUBJECTS_DIR}/mri/aseg.mgz
40
+ cp ${generated_files_folder}/${subj}_rh.ribbon.mgz ${SUBJECTS_DIR}/mri/${hemis}.ribbon.mgz
41
+ cp ${generated_files_folder}/${subj}.ribbon.mgz ${SUBJECTS_DIR}/mri/ribbon.mgz
42
+
43
+ done;
@@ -0,0 +1,236 @@
1
+ working_dir=$1
2
+ str_split=$2
3
+ freesurfer_path=$3
4
+ num_threads=$4
5
+ external_atlases_path=$5
6
+ autodet_stats_dat=$6
7
+ for i in $str_split; do subjects+=($i) ; done
8
+
9
+ hemis=rh
10
+ hemis_other=lh
11
+ for subj in "${subjects[@]}"
12
+ do
13
+ echo ${subj}
14
+ start=$SECONDS
15
+
16
+ SUBJECTS_DIR=${working_dir}
17
+
18
+ ######### segm_parc file
19
+ mris_place_surface --adgws-in ${autodet_stats_dat} \
20
+ --wm ${SUBJECTS_DIR}/${subj}/mri/wm.mgz --threads ${num_threads} --invol ${SUBJECTS_DIR}/${subj}/mri/aseg.presurf_100.mgz --${hemis} \
21
+ --i ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig \
22
+ --o ${SUBJECTS_DIR}/${subj}/surf/${hemis}.white.preaparc --white --seg ${SUBJECTS_DIR}/${subj}/mri/aseg.presurf.mgz
23
+
24
+ mri_label2label --label-cortex ${SUBJECTS_DIR}/${subj}/surf/${hemis}.white.preaparc ${SUBJECTS_DIR}/${subj}/mri/aseg.presurf.mgz 0 ${SUBJECTS_DIR}/${subj}/label/${hemis}.cortex.label
25
+
26
+ mris_smooth -n 3 -nw ${SUBJECTS_DIR}/${subj}/surf/${hemis}.white.preaparc ${SUBJECTS_DIR}/${subj}/surf/${hemis}.smoothwm
27
+ mris_inflate ${SUBJECTS_DIR}/${subj}/surf/${hemis}.smoothwm ${SUBJECTS_DIR}/${subj}/surf/${hemis}.inflated
28
+
29
+ mris_curvature -w ${SUBJECTS_DIR}/${subj}/surf/${hemis}.white.preaparc
30
+ mris_curvature -thresh .999 -n -a 5 -w -distances 10 10 ${SUBJECTS_DIR}/${subj}/surf/${hemis}.inflated
31
+
32
+ mris_sphere ${SUBJECTS_DIR}/${subj}/surf/${hemis}.inflated ${SUBJECTS_DIR}/${subj}/surf/${hemis}.sphere
33
+
34
+ mris_register -curv -threads ${num_threads} -inflated -init \
35
+ -reg ${SUBJECTS_DIR}/${subj}/mri/transforms/init_for_mris_register.lta \
36
+ ${SUBJECTS_DIR}/${subj}/surf/${hemis}.sphere ${freesurfer_path}/average/${hemis}.folding.atlas.acfb40.noaparc.i12.2016-08-02.tif ${SUBJECTS_DIR}/${subj}/surf/${hemis}.sphere.reg
37
+
38
+ ln -sf ${hemis}.sphere.reg ${hemis}.fsaverage.sphere.reg
39
+
40
+ mris_jacobian ${SUBJECTS_DIR}/${subj}/surf/${hemis}.white.preaparc ${SUBJECTS_DIR}/${subj}/surf/${hemis}.sphere.reg ${SUBJECTS_DIR}/${subj}/surf/${hemis}.jacobian_white
41
+ mrisp_paint -a 5 ${freesurfer_path}/average/${hemis}.folding.atlas.acfb40.noaparc.i12.2016-08-02.tif#6 ${SUBJECTS_DIR}/${subj}/surf/${hemis}.sphere.reg ${SUBJECTS_DIR}/${subj}/surf/${hemis}.avg_curv
42
+
43
+ mris_ca_label -l ${SUBJECTS_DIR}/${subj}/label/${hemis}.cortex.label -aseg ${SUBJECTS_DIR}/${subj}/mri/aseg.presurf.mgz ${subj} ${hemis} ${SUBJECTS_DIR}/${subj}/surf/${hemis}.sphere.reg ${freesurfer_path}/average/${hemis}.DKaparc.atlas.acfb40.noaparc.i12.2016-08-02.gcs ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.annot
44
+
45
+ SUBJECTS_DIR=${working_dir}
46
+
47
+ cd ${SUBJECTS_DIR}/${subj}/mri
48
+ mris_place_surface --adgws-in ${autodet_stats_dat} \
49
+ --seg aseg.presurf.mgz --threads ${num_threads} --wm wm.mgz --invol aseg.presurf_100.mgz --${hemis} --i ../surf/${hemis}.white.preaparc --o ../surf/${hemis}.white --white --nsmooth 0 \
50
+ --rip-label ../label/${hemis}.cortex.label --rip-bg --rip-surf ../surf/${hemis}.white.preaparc --aparc ../label/${hemis}.aparc.annot
51
+
52
+ cd ${SUBJECTS_DIR}/${subj}/mri
53
+ mris_place_surface --adgws-in ${autodet_stats_dat} \
54
+ --seg aseg.presurf.mgz --threads ${num_threads} --wm wm.mgz \
55
+ --invol aseg.presurf_100.mgz --${hemis} --i ../surf/${hemis}.white --o ../surf/${hemis}.pial.T1 --pial --nsmooth 0 \
56
+ --pin-medial-wall ../label/${hemis}.cortex.label --aparc ../label/${hemis}.aparc.annot \
57
+ --repulse-surf ../surf/${hemis}.white --white-surf ../surf/${hemis}.white \
58
+ --no-rip --intensity 10.00 --curv 10.00
59
+
60
+ cp ${SUBJECTS_DIR}/${subj}/surf/${hemis}.pial.T1 ${SUBJECTS_DIR}/${subj}/surf/${hemis}.pial
61
+
62
+ ######## white curv
63
+ cd ${SUBJECTS_DIR}/${subj}/mri
64
+ mris_place_surface --curv-map ../surf/${hemis}.white 2 10 ../surf/${hemis}.curv
65
+
66
+ ######## white area
67
+ cd ${SUBJECTS_DIR}/${subj}/mri
68
+ mris_place_surface --area-map ../surf/${hemis}.white ../surf/${hemis}.area
69
+
70
+ ######## pial curv
71
+ cd ${SUBJECTS_DIR}/${subj}/mri
72
+ mris_place_surface --curv-map ../surf/${hemis}.pial 2 10 ../surf/${hemis}.curv.pial
73
+
74
+ ######## pial area
75
+ cd ${SUBJECTS_DIR}/${subj}/mri
76
+ mris_place_surface --area-map ../surf/${hemis}.pial ../surf/${hemis}.area.pial
77
+
78
+ ######## thickness
79
+ cd ${SUBJECTS_DIR}/${subj}/mri
80
+ mris_place_surface --thickness ../surf/${hemis}.white ../surf/${hemis}.pial 20 5 ../surf/${hemis}.thickness
81
+
82
+ ######## area and vertex vol
83
+ cd ${SUBJECTS_DIR}/${subj}/mri
84
+ mris_place_surface --thickness ../surf/${hemis}.white ../surf/${hemis}.pial 20 5 ../surf/${hemis}.thickness
85
+
86
+ mris_curvature_stats -m --writeCurvatureFiles -G -o ${SUBJECTS_DIR}/${subj}/stats/${hemis}.curv.stats -F smoothwm ${subj} ${hemis} curv sulc
87
+
88
+ ######## Cortical Parc 2
89
+ cd ${SUBJECTS_DIR}/${subj}/mri
90
+ mris_ca_label -l ../label/${hemis}.cortex.label -aseg ../mri/aseg.presurf.mgz ${subj} ${hemis} ../surf/${hemis}.sphere.reg ${freesurfer_path}/average/${hemis}.CDaparc.atlas.acfb40.noaparc.i12.2016-08-02.gcs ../label/${hemis}.aparc.a2009s.annot
91
+
92
+ ######## Cortical Parc 3
93
+ cd ${SUBJECTS_DIR}/${subj}/mri
94
+ mris_ca_label -l ../label/${hemis}.cortex.label -aseg ../mri/aseg.presurf.mgz ${subj} ${hemis} ../surf/${hemis}.sphere.reg ${freesurfer_path}/average/${hemis}.DKTaparc.atlas.acfb40.noaparc.i12.2016-08-02.gcs ../label/${hemis}.aparc.DKTatlas.annot
95
+
96
+ ln -sf ${hemis}.sphere.reg ${hemis}.fsaverage.sphere.reg
97
+
98
+ SUBJECTS_DIR=${working_dir}
99
+
100
+ ##### Cortical Parc Schaefer atlas: 7 and 17 networks
101
+ cd ${SUBJECTS_DIR}/${subj}/mri
102
+ mri_surf2surf --hemi ${hemis} \
103
+ --srcsubject fsaverage \
104
+ --trgsubject ${subj} \
105
+ --sval-annot ${external_atlases_path}/schaefer/${hemis}.Schaefer2018_400Parcels_17Networks_order.annot \
106
+ --tval ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.Schaefer2018_400Parcels_17Networks.annot
107
+
108
+ ##### Economo-Koskinos atlas
109
+ cd ${SUBJECTS_DIR}/${subj}/mri
110
+ mris_ca_label -t ${external_atlases_path}/economo/${hemis}.colortable.txt ${subj} ${hemis} ../surf/${hemis}.sphere.reg ${external_atlases_path}/economo/${hemis}.economo.gcs \
111
+ ${SUBJECTS_DIR}/${subj}/label/${hemis}.economo.annot
112
+
113
+ ##### Glasser atlas
114
+ cd ${SUBJECTS_DIR}/${subj}/mri
115
+ mri_surf2surf --hemi ${hemis} \
116
+ --srcsubject fsaverage \
117
+ --trgsubject ${subj} \
118
+ --sval-annot ${external_atlases_path}/glasser/${hemis}.HCP-MMP1.annot \
119
+ --tval ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.HCP-MMP1.glasser.annot
120
+
121
+ SUBJECTS_DIR=${working_dir}
122
+
123
+ ######## dummy left hemis needed for stats computation
124
+ cp ${SUBJECTS_DIR}/${subj}/surf/${hemis}.white ${SUBJECTS_DIR}/${subj}/surf/${hemis_other}.white
125
+ cp ${SUBJECTS_DIR}/${subj}/surf/${hemis}.pial ${SUBJECTS_DIR}/${subj}/surf/${hemis_other}.pial
126
+ cp ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.nofix ${SUBJECTS_DIR}/${subj}/surf/${hemis_other}.orig.nofix
127
+ cp ${SUBJECTS_DIR}/${subj}/label/${hemis}.cortex.label ${SUBJECTS_DIR}/${subj}/label/${hemis_other}.cortex.label
128
+ cp ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.annot ${SUBJECTS_DIR}/${subj}/label/${hemis_other}.aparc.annot
129
+ cp ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.DKTatlas.annot ${SUBJECTS_DIR}/${subj}/label/${hemis_other}.aparc.DKTatlas.annot
130
+ cp ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.a2009s.annot ${SUBJECTS_DIR}/${subj}/label/${hemis_other}.aparc.a2009s.annot
131
+
132
+ pctsurfcon --s ${subj} --${hemis}-only
133
+
134
+ mri_brainvol_stats --subject ${subj}
135
+
136
+ ######## AParc-to-ASeg aparc
137
+ cd ${SUBJECTS_DIR}/${subj}/mri
138
+ mri_surf2volseg --o aparc+aseg.mgz --label-cortex --i aseg.mgz --threads ${num_threads} \
139
+ --lh-annot ${SUBJECTS_DIR}/${subj}/label/lh.aparc.annot 1000 \
140
+ --lh-cortex-mask ${SUBJECTS_DIR}/${subj}/label/lh.cortex.label \
141
+ --lh-white ${SUBJECTS_DIR}/${subj}/surf/lh.white \
142
+ --lh-pial ${SUBJECTS_DIR}/${subj}/surf/lh.pial \
143
+ --rh-annot ${SUBJECTS_DIR}/${subj}/label/rh.aparc.annot 2000 \
144
+ --rh-cortex-mask ${SUBJECTS_DIR}/${subj}/label/rh.cortex.label \
145
+ --rh-white ${SUBJECTS_DIR}/${subj}/surf/rh.white \
146
+ --rh-pial ${SUBJECTS_DIR}/${subj}/surf/rh.pial
147
+
148
+ ######## AParc-to-ASeg aparc.a2009s
149
+ cd ${SUBJECTS_DIR}/${subj}/mri
150
+ mri_surf2volseg --o aparc.a2009s+aseg.mgz \
151
+ --label-cortex --i aseg.mgz --threads ${num_threads} \
152
+ --lh-annot ${SUBJECTS_DIR}/${subj}/label/lh.aparc.a2009s.annot 11100 \
153
+ --lh-cortex-mask ${SUBJECTS_DIR}/${subj}/label/lh.cortex.label \
154
+ --lh-white ${SUBJECTS_DIR}/${subj}/surf/lh.white \
155
+ --lh-pial ${SUBJECTS_DIR}/${subj}/surf/lh.pial \
156
+ --rh-annot ${SUBJECTS_DIR}/${subj}/label/rh.aparc.a2009s.annot 12100 \
157
+ --rh-cortex-mask ${SUBJECTS_DIR}/${subj}/label/rh.cortex.label \
158
+ --rh-white ${SUBJECTS_DIR}/${subj}/surf/rh.white \
159
+ --rh-pial ${SUBJECTS_DIR}/${subj}/surf/rh.pial
160
+
161
+ ######## AParc-to-ASeg aparc.DKTatlas
162
+ cd ${SUBJECTS_DIR}/${subj}/mri
163
+ mri_surf2volseg --o aparc.DKTatlas+aseg.mgz \
164
+ --label-cortex --i aseg.mgz --threads ${num_threads} \
165
+ --lh-annot ${SUBJECTS_DIR}/${subj}/label/lh.aparc.DKTatlas.annot 1000 \
166
+ --lh-cortex-mask ${SUBJECTS_DIR}/${subj}/label/lh.cortex.label \
167
+ --lh-white ${SUBJECTS_DIR}/${subj}/surf/lh.white \
168
+ --lh-pial ${SUBJECTS_DIR}/${subj}/surf/lh.pial \
169
+ --rh-annot ${SUBJECTS_DIR}/${subj}/label/rh.aparc.DKTatlas.annot 2000 \
170
+ --rh-cortex-mask ${SUBJECTS_DIR}/${subj}/label/rh.cortex.label \
171
+ --rh-white ${SUBJECTS_DIR}/${subj}/surf/rh.white \
172
+ --rh-pial ${SUBJECTS_DIR}/${subj}/surf/rh.pial
173
+
174
+ ######## WMParc
175
+ cd ${SUBJECTS_DIR}/${subj}/mri
176
+ mri_surf2volseg --o wmparc.mgz \
177
+ --label-wm --i aparc+aseg.mgz --threads ${num_threads} \
178
+ --lh-annot ${SUBJECTS_DIR}/${subj}/label/lh.aparc.annot 3000 \
179
+ --lh-cortex-mask ${SUBJECTS_DIR}/${subj}/label/lh.cortex.label \
180
+ --lh-white ${SUBJECTS_DIR}/${subj}/surf/lh.white \
181
+ --lh-pial ${SUBJECTS_DIR}/${subj}/surf/lh.pial \
182
+ --rh-annot ${SUBJECTS_DIR}/${subj}/label/rh.aparc.annot 4000 \
183
+ --rh-cortex-mask ${SUBJECTS_DIR}/${subj}/label/rh.cortex.label \
184
+ --rh-white ${SUBJECTS_DIR}/${subj}/surf/rh.white \
185
+ --rh-pial ${SUBJECTS_DIR}/${subj}/surf/rh.pial
186
+
187
+ cd ${SUBJECTS_DIR}/${subj}
188
+ mri_segstats --seg mri/wmparc.mgz \
189
+ --sum stats/wmparc.stats --pv mri/norm.mgz \
190
+ --excludeid 0 --brainmask mri/brainmask.mgz --in mri/norm.mgz \
191
+ --in-intensity-name norm --in-intensity-units MR \
192
+ --subject ${subj} \
193
+ --surf-wm-vol --ctab ${freesurfer_path}/WMParcStatsLUT.txt --etiv
194
+
195
+ ######## Parcellation Stats
196
+ mris_anatomical_stats -th3 -mgz \
197
+ -cortex ${SUBJECTS_DIR}/${subj}/label/${hemis}.cortex.label \
198
+ -f ${SUBJECTS_DIR}/${subj}/stats/${hemis}.aparc.stats \
199
+ -b -a ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.annot \
200
+ -c ${SUBJECTS_DIR}/${subj}/label/aparc.annot.ctab ${subj} ${hemis} white
201
+
202
+ mri_brainvol_stats --subject ${subj}
203
+
204
+ mris_anatomical_stats -th3 -mgz \
205
+ -cortex ${SUBJECTS_DIR}/${subj}/label/${hemis}.cortex.label \
206
+ -f ${SUBJECTS_DIR}/${subj}/stats/${hemis}.aparc.pial.stats \
207
+ -b -a ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.annot \
208
+ -c ${SUBJECTS_DIR}/${subj}/label/aparc.annot.ctab ${subj} ${hemis} pial
209
+
210
+ ######## Parcellation Stats 2
211
+ mris_anatomical_stats -th3 -mgz \
212
+ -cortex ${SUBJECTS_DIR}/${subj}/label/${hemis}.cortex.label \
213
+ -f ${SUBJECTS_DIR}/${subj}/stats/${hemis}.aparc.a2009s.stats \
214
+ -b -a ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.a2009s.annot \
215
+ -c ${SUBJECTS_DIR}/${subj}/label/aparc.annot.a2009s.ctab ${subj} ${hemis} white
216
+
217
+ ######## Parcellation Stats 3
218
+ mris_anatomical_stats -th3 -mgz \
219
+ -cortex ${SUBJECTS_DIR}/${subj}/label/${hemis}.cortex.label \
220
+ -f ${SUBJECTS_DIR}/${subj}/stats/${hemis}.aparc.DKTatlas.stats \
221
+ -b -a ${SUBJECTS_DIR}/${subj}/label/${hemis}.aparc.DKTatlas.annot \
222
+ -c ${SUBJECTS_DIR}/${subj}/label/aparc.annot.DKTatlas.ctab ${subj} ${hemis} white
223
+
224
+ ######## ASeg Stats
225
+ mri_segstats --seg ${SUBJECTS_DIR}/${subj}/mri/aseg.mgz \
226
+ --sum ${SUBJECTS_DIR}/${subj}/stats/aseg.stats --pv ${SUBJECTS_DIR}/${subj}/mri/norm.mgz \
227
+ --empty --brainmask ${SUBJECTS_DIR}/${subj}/mri/brainmask.mgz --brain-vol-from-seg \
228
+ --excludeid 0 --excl-ctxgmwm --supratent --subcortgray \
229
+ --in ${SUBJECTS_DIR}/${subj}/mri/norm.mgz --in-intensity-name norm --in-intensity-units MR \
230
+ --etiv --surf-wm-vol --surf-ctx-vol --totalgray --euler \
231
+ --ctab ${freesurfer_path}/ASegStatsLUT.txt \
232
+ --subject ${subj}
233
+
234
+ duration=$(( SECONDS - start ))
235
+ echo "total time for this subject:" $duration
236
+ done
@@ -0,0 +1,37 @@
1
+ working_dir=$1
2
+ str_split=$2
3
+ generated_files_folder=$3
4
+ segm_path=$4
5
+ for i in $str_split; do subjects+=($i) ; done
6
+
7
+ for subj in "${subjects[@]}"
8
+ do
9
+ echo ${subj}
10
+
11
+ cp ${segm_path}/${subj}.nii.gz ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected.nii.gz
12
+
13
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected.nii.gz -replace 6 7 -o ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected.nii.gz
14
+
15
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected.nii.gz -replace 1 42 2 50 3 51 4 52 5 49 7 41 8 43 9 0 10 53 -o ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_RH_FS_labels.nii.gz
16
+
17
+ mri_convert ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_RH_FS_labels.nii.gz ${generated_files_folder}/${subj}_aseg.mgz
18
+ cp ${generated_files_folder}/${subj}_aseg.mgz ${generated_files_folder}/${subj}_aseg.presurf.mgz
19
+
20
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_RH_FS_labels.nii.gz -replace 0 100 42 142 50 150 51 151 52 152 49 149 41 241 43 143 53 153 -o ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_RH_FS_labels_presurf_100.nii.gz
21
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_RH_FS_labels_presurf_100.nii.gz -dup -lstat
22
+ mri_convert ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_RH_FS_labels_presurf_100.nii.gz ${generated_files_folder}/${subj}_aseg.presurf_100.mgz
23
+
24
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected.nii.gz -retain-labels 2 3 4 5 7 9 -o ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_WM_only.nii.gz
25
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_WM_only.nii.gz -replace 2 1 3 1 4 1 5 1 7 1 9 1 -o ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_WM_only.nii.gz
26
+
27
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_WM_only.nii.gz -comp -threshold 1 1 1 0 -o ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_WM_only_cc.nii.gz
28
+
29
+ mri_convert ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected_WM_only_cc.nii.gz ${generated_files_folder}/${subj}_wm.mgz
30
+ cp ${generated_files_folder}/${subj}_wm.mgz ${generated_files_folder}/${subj}_filled.mgz
31
+
32
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected.nii.gz -replace 1 42 2 41 3 41 4 41 5 41 7 41 8 41 9 41 10 0 -o ${generated_files_folder}/${subj}_ribbon.nii.gz
33
+ c3d ${generated_files_folder}/${subj}_reslice_aseg_ready_with_overlap_corrected.nii.gz -retain-labels 1 -o ${generated_files_folder}/${subj}_rh.ribbon.nii.gz
34
+
35
+ mri_convert ${generated_files_folder}/${subj}_rh.ribbon.nii.gz ${generated_files_folder}/${subj}_rh.ribbon.mgz
36
+ mri_convert ${generated_files_folder}/${subj}_ribbon.nii.gz ${generated_files_folder}/${subj}.ribbon.mgz
37
+ done;
@@ -0,0 +1,43 @@
1
+ # read the mri files and create a list of the subjects
2
+ freesurfer_path=$1
3
+ working_dir=$2
4
+ mri_path=$3
5
+ segm_path=$4
6
+ external_atlases_path=$5
7
+ num_threads=$6
8
+ autodet_stats_dat=$7
9
+
10
+ subjects=()
11
+ for file in ${mri_path}/*.nii.gz
12
+ do
13
+ fname=$(basename "$file" .nii.gz)
14
+ subjects+=(${fname})
15
+ done
16
+
17
+ echo "Here are the list of subjects to be processed: " ${subjects[@]}
18
+
19
+ ##### STEP 1: Prepare files from the initial 10-label deep learning based-segmentation
20
+ generated_files_folder=${working_dir}/files_prepared_for_pipeline
21
+ mkdir -p ${generated_files_folder}
22
+ prepare_segm_files.sh ${working_dir} "${subjects[*]}" ${generated_files_folder} ${segm_path}
23
+
24
+ ##### STEP 2: Create FreeSurfer-like files
25
+ make_fs_directories.sh ${working_dir} ${generated_files_folder} ${mri_path} "${subjects[*]}"
26
+
27
+ ##### STEP 3: Create mesh and downsample the same
28
+ tgt_dir_FS_mesh=${working_dir}/freesurfer_high_res_mesh
29
+ tgt_dir_FS_mesh_decimated=${working_dir}/decimated_mesh
30
+ mkdir -p ${tgt_dir_FS_mesh}
31
+ mkdir -p ${tgt_dir_FS_mesh_decimated}
32
+
33
+ # this file calls the Python script: decimate_mesh.py
34
+ create_mesh.sh ${working_dir} ${tgt_dir_FS_mesh} ${tgt_dir_FS_mesh_decimated} "${subjects[*]}"
35
+
36
+ ##### STEP 4: Perform some intial regsitration to get all the required orientations
37
+ do_mni_txs.sh ${freesurfer_path} ${working_dir} "${subjects[*]}"
38
+
39
+ ##### STEP 5: Perform surface-based topology correction
40
+ topology_correction.sh ${working_dir} "${subjects[*]}"
41
+
42
+ ##### STEP 6: Perform surface-based parcellation
43
+ parcellation.sh ${working_dir} "${subjects[*]}" ${freesurfer_path} ${num_threads} ${external_atlases_path} ${autodet_stats_dat}
@@ -0,0 +1,39 @@
1
+ working_dir=$1
2
+ str_split=$2
3
+ for i in $str_split; do subjects+=($i) ; done
4
+
5
+ hemis=rh
6
+ for subj in "${subjects[@]}"
7
+ do
8
+ echo ${subj}
9
+ start=$SECONDS
10
+
11
+ SUBJECTS_DIR=${working_dir}/${subj}
12
+ mris_extract_main_component ${SUBJECTS_DIR}/surf/${hemis}.orig.nofix ${SUBJECTS_DIR}/surf/${hemis}.orig.nofix
13
+
14
+ mris_smooth -nw ${SUBJECTS_DIR}/surf/${hemis}.orig.nofix ${SUBJECTS_DIR}/surf/${hemis}.smoothwm.nofix
15
+ mris_euler_number ${SUBJECTS_DIR}/surf/${hemis}.smoothwm.nofix
16
+
17
+ mris_inflate -no-save-sulc ${SUBJECTS_DIR}/surf/${hemis}.smoothwm.nofix ${SUBJECTS_DIR}/surf/${hemis}.inflated.nofix
18
+ mris_euler_number ${SUBJECTS_DIR}/surf/${hemis}.inflated.nofix
19
+
20
+ mris_sphere -q -p 6 -a 128 ${SUBJECTS_DIR}/surf/${hemis}.inflated.nofix ${SUBJECTS_DIR}/surf/${hemis}.qsphere.nofix
21
+
22
+ SUBJECTS_DIR=${working_dir}
23
+ mris_fix_topology -mgz -sphere qsphere.nofix -inflated inflated.nofix -orig orig.nofix -out orig.premesh -defect defect -ga ${subj} ${hemis} -threads 64 -verbose -errors -warnings
24
+ mris_euler_number ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.premesh
25
+
26
+ mris_inflate ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.premesh ${SUBJECTS_DIR}/${subj}/surf/${hemis}.inflated.fixed
27
+ mris_euler_number ${SUBJECTS_DIR}/${subj}/surf/${hemis}.inflated.fixed
28
+
29
+ mris_remove_intersection ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.premesh ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.premesh
30
+ mris_extract_main_component ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.premesh ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.premesh
31
+ mris_euler_number ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.premesh
32
+
33
+ cp ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig.premesh ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig
34
+ cp ${SUBJECTS_DIR}/${subj}/surf/${hemis}.inflated.fixed ${SUBJECTS_DIR}/${subj}/surf/${hemis}.inflated
35
+ mris_euler_number ${SUBJECTS_DIR}/${subj}/surf/${hemis}.orig
36
+
37
+ duration=$(( SECONDS - start ))
38
+ echo "total time for this subject:" $duration
39
+ done
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.1
2
+ Name: purple_mri
3
+ Version: 0.0.1
4
+ Summary: purple_mri: Penn Utilities for Registration and ParcelLation of Ex vivo MRI
5
+ Author-email: Pulkit Khandelwal <kpulkit95@gmail.com>
6
+ Project-URL: Homepage, https://github.com/Pulkit-Khandelwal/purple_mri
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy
9
+ Requires-Dist: torch
10
+ Requires-Dist: pykeops
11
+ Requires-Dist: pymeshlab
12
+ Requires-Dist: vtk
13
+ Requires-Dist: SimpleITK
14
+ Requires-Dist: geomloss
15
+
16
+ # purple-mri: **P**enn **U**tilities for **R**egistration and **P**arcel**L**ation of **E**x vivo **MRI**
17
+
18
+ We provide a set of tools packaged as `purple-mri` for segmentation, parcellation and registration of ultra high-resolution (< 300 microns) postmortem human brain hemisphere at 7 tesla t2w MRI at native subject-space resolution. This pipeline leverages advances in both deep learning and classical surface-based modeling techniques to produce parcellations in any atlas used in neuroimaging. The developed method allows us to perform vertex-wise analysis in the template space and thereby link morphometry measures with pathology measurements derived from histology.
19
+
20
+ Check out the [project page](https://pulkit-khandelwal.github.io/exvivo-brain-upenn/) and our latest papers [here](https://direct.mit.edu/imag/article/doi/10.1162/imag_a_00171/120741) and [here](https://arxiv.org/abs/2403.19497).
21
+
22
+ In particular, `purple-mri` allows you to do the following:
23
+ + obtain an initial 10 label segmentation: cortical GM, normal appearing WM, WMH, medial temporal lobe, corpus callosum, ventricles, caudate, putamen, globus pallidus and thalamus
24
+ + obtain surface-based native subject-space parcellation based on different brain atlases such as: DKT, Economo, Schaeffer etc
25
+ + create population specific volumetric and surface-based templates
26
+ + perform exvivo to invivo registration in volumetric intensity space
27
+ + perform surface-to-surface registration between exvivo or invivo
28
+ + perform intensity-based registration between 9.4 tesla MTL to 7 tesla whole hemsiphere registration
29
+ + perform vertex-wise and group-wise generalized linear modeling analysis for exvivo subject population for morphometry and histology
30
+
31
+ ## Steps (for segmentation and parcellation)
32
+ `purple-mri` follows a series of steps making use of bash scripts and Docker.
33
+
34
+ ### Pre-processing
35
+ Perform bias correction and image normalization/standardization. We use `N4BiasFieldCorrection` as part of the CLI tool [ANTs](https://github.com/ANTsX/ANTs) and [`c3d`](http://www.itksnap.org/pmwiki/pmwiki.php?n=Convert3D.Convert3D). We highly recommend using the option of an input mask in `N4BiasFieldCorrection` which can be obtained via corase threhsolding.
36
+ [Here](https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/tree/main/misc_scripts/perform_bias_correction.sh) is a sample script.
37
+
38
+ ### Deep learning-based initial labeling and CRUISE-based post-hoc topology correction
39
+ Currently, we have two Docker images. The first image provides the segmentation and the second employs [Nighres/CRUISE](https://nighres.readthedocs.io/en/latest/installation.html) for post-hoc topology correction.
40
+ Please follow the [link]([https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/blob/main/exvivo-segm-demo-docker.md](https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/docker/exvivo_docker.md) for detailed instructions on how to use Docker to get the segmentations. Some key commands are emphasized here:
41
+
42
+ Place the pre-processed image(s) (with a suffix _0000.nii.gz to your filenames) in a folder named `data_for_inference` within your working directory is `/your/working/directory`.
43
+ ```
44
+ docker pull pulks/docker_hippogang_exvivo_segm:v${LATEST_TAG}
45
+
46
+ docker run --gpus all --privileged -v /your/working/directory/:/data/exvivo/ -it pulks/docker_hippogang_exvivo_segm:v${LATEST_TAG} /bin/bash -c "bash /src/commands_nnunet_inference.sh ${OPTION}" >> logs.txt
47
+ ```
48
+ You will see the output in `/your/working/directory/data_for_inference/output_from_nnunet_inference`.
49
+
50
+ Next, correct for topology so that adjoining gyri and sulci are clearly separated. Copy the segmentations from `output_from_nnunet_inference` to a folder `data_for_topology_correction` in your wokring directory.
51
+ ```
52
+ docker pull pulks/docker_nighres:v1.0.0
53
+
54
+ docker run -v /your/working/directory/:/data/cruise_files/ -it pulks/docker_nighres:v1.0.0 /bin/bash -c "bash /data/prepare_cruise_files.sh"
55
+
56
+ # Locally run the file to get the final combined label file. See instructions [here](https://github.com/Pulkit-Khandelwal/upenn-picsl-brain-ex-vivo/blob/main/exvivo-segm-demo-docker.md) and links referenced therein.
57
+ bash clean_labels_final.sh
58
+ ```
59
+
60
+ ### Surface-based modeling to obtain whole-hemisphere parcellations
61
+ Once, you have obtained an initial 10-label topology corrected volumetric segmentation, you can proceed to the surface-based pipeline to obtain parcellations based on your favorite atlas. This step will be on your local machine. No GPUs required. To do this, you should have FreeSurfer installed locally. We have used FreeSurfer version 7.4.0 on linux obtained from [here](https://surfer.nmr.mgh.harvard.edu/fswiki/DownloadAndInstall). Moreover, there are some Python dependencies which can be found in the `dependencies.txt` file and installed using `pip`.
62
+
63
+ Run the following file which calls in several bash scripts which prepares the data, computes appropriate transformations and re-orients the images, corrects surface topology, and perform the parcellation into Desikan-Killiany-Tourville (DKT), Schaefer, Glasser and the Von Economo-Koskinos atlases.
64
+
65
+ For the surface-based modeling step, we assume that all the hemishpehrs are right hemispheres. So, we suggest flipping the left t2w MRI and its corresponding segmentation to left using the following `c3d` command: `c3d image_left.nii.gz -flip y image_right_flipped.nii.gz`
66
+
67
+ Clone the current repository and the run the following script `run_surface_pipeline.sh` from within the `purple_mri` folder which takes the following mandatory arguments:
68
+ `freesurfer_path`: path to the FreeSurfer installtion
69
+ `working_dir`: directory which will have the outputs for each subject stored
70
+ `mri_path`: mri images path
71
+ `segm_path`: 10-label segmentation path
72
+ `external_atlases_path`: directory with files for other atlases
73
+ `num_threads`: number of threads
74
+
75
+ Place your t2w MRI in a folder `mri_path` and the intial deep learning-based segmentations in `segm_path`.
76
+ Make sure your mri images and segmentation files have the same names ending with `.nii.gz`.
77
+ Place the `fsaverage` in the `working_dir` folder.
78
+
79
+ ```
80
+ cd purple_mri
81
+
82
+ bash run_surface_pipeline.sh freesurfer_path working_dir mri_path segm_path external_atlases_path num_threads
83
+ ```
84
+
85
+ ## Other scripts
86
+ ### Intensity-based volumetric template building
87
+ We build intensity-based volumetric templates using the [greedy](https://sites.google.com/view/greedyreg/about?authuser=0) tool. The required binaries (for Linux) and the scripts are located in the the `intensity_template` within the `scripts` directory. Follow the instructions [here](https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/scripts/intensity_template/README.md).
88
+
89
+
90
+ ### Ex vivo and in vivo registration
91
+ Script `exvivo_invivo_greedy_registration.sh` to register in vivo (t1w) and ex vivo (t2w) MRI is located in the folder `scripts`. We use [greedy](https://sites.google.com/view/greedyreg/about?authuser=0) to register the segmentations of in vivo aseg+aparc labels derived from FreeSurfer and 10-label initial deep learning segmentation of postmortem MRI. The warps are then used to regsiter the MRIs.
92
+
93
+ ### Perform GLM analyses
94
+ We perform vertex-wise analysis in `fsaverage` space to fit a generalized linear model (GLM) between cortical thickness (mm) and with global ratings of amyloid-β, Braak staging, CERAD, and semiquantitative ratings of the medial temporal lobe (MTL) neuronal loss and tau pathology, with age, sex and postmortem interval (PMI) as covariates. You can follow the steps detailed [here](https://github.com/Pulkit-Khandelwal/purple-mri/tree/main/glm).
95
+
96
+ ## Notes
97
+ + Our method has been developed to work on a single exvivo hemisphere.
98
+ + The deep learning-based segmentation was primarily trained on 7T t2w MRI. We have tested the model on t2* flash as well and it works pretty well but, if need be, we recommend re-training the model with some manual labels obtained on t2* flash MRI.
99
+
100
+ ## pip package
101
+
102
+ ## Introductory video
103
+ <div align="center">
104
+ <a href="https://youtu.be/0BOeUtlWlYw?si=7NeNDsoePOW3_J4Y">
105
+ <img src="https://github.com/Pulkit-Khandelwal/purple-mri/blob/main/images/thumbnail.png" style="width:75%;">
106
+ </a>
107
+ </div>
108
+
109
+ ## Citations
110
+ + Khandelwal, P., Duong, M. T., Sadaghiani, S., Lim, S., Denning, A. E., Chung, E., ... & Yushkevich, P. A. (2024). Automated deep learning segmentation of high-resolution 7 tesla postmortem MRI for quantitative analysis of structure-pathology correlations in neurodegenerative diseases. Imaging Neuroscience, 2, 1-30.
111
+ + Khandelwal, P., Duong, M. T., Fuentes, C., Denning, A., Trotman, W., Ittyerah, R., ... & Yushkevich, P. A. (2024). Surface-based parcellation and vertex-wise analysis of ultra high-resolution ex vivo 7 tesla MRI in neurodegenerative diseases. arXiv preprint arXiv:2403.19497.
112
+
@@ -0,0 +1,17 @@
1
+ README.md
2
+ pyproject.toml
3
+ purple_mri/__init__.py
4
+ purple_mri/__main__.py
5
+ purple_mri.egg-info/PKG-INFO
6
+ purple_mri.egg-info/SOURCES.txt
7
+ purple_mri.egg-info/dependency_links.txt
8
+ purple_mri.egg-info/requires.txt
9
+ purple_mri.egg-info/top_level.txt
10
+ purple_mri/scripts/create_mesh.sh
11
+ purple_mri/scripts/decimate_mesh.py
12
+ purple_mri/scripts/do_mni_txs.sh
13
+ purple_mri/scripts/make_fs_directories.sh
14
+ purple_mri/scripts/parcellation.sh
15
+ purple_mri/scripts/prepare_segm_files.sh
16
+ purple_mri/scripts/run_surface_pipeline.sh
17
+ purple_mri/scripts/topology_correction.sh
@@ -0,0 +1,7 @@
1
+ numpy
2
+ torch
3
+ pykeops
4
+ pymeshlab
5
+ vtk
6
+ SimpleITK
7
+ geomloss
@@ -0,0 +1 @@
1
+ purple_mri
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+
4
+ [project]
5
+ name = "purple_mri"
6
+ version = "0.0.1"
7
+ authors = [
8
+ { name="Pulkit Khandelwal", email="kpulkit95@gmail.com" },
9
+ ]
10
+ description = "purple_mri: Penn Utilities for Registration and ParcelLation of Ex vivo MRI"
11
+ dependencies = [
12
+ 'numpy',
13
+ 'torch',
14
+ 'pykeops',
15
+ 'pymeshlab',
16
+ 'vtk',
17
+ 'SimpleITK',
18
+ 'geomloss'
19
+ ]
20
+ readme = "README.md"
21
+ [tool.setuptools]
22
+ script-files = [
23
+ "purple_mri/scripts/run_surface_pipeline.sh",
24
+ "purple_mri/scripts/do_mni_txs.sh",
25
+ "purple_mri/scripts/prepare_segm_files.sh",
26
+ "purple_mri/scripts/create_mesh.sh",
27
+ "purple_mri/scripts/make_fs_directories.sh",
28
+ "purple_mri/scripts/parcellation.sh",
29
+ "purple_mri/scripts/topology_correction.sh",
30
+ "purple_mri/scripts/decimate_mesh.py"]
31
+
32
+ [project.urls]
33
+ Homepage = "https://github.com/Pulkit-Khandelwal/purple_mri"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+