OSCR

Automated Surface-Based Segmentation of Deep Gray Matter Regions Based on Diffusion Tensor Images Reveals Unique Age Trajectories Over the Healthy Lifespan.

Code ↔ Paper

6 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 6 matches
  1. [1] § Materials and Methods › Surface‐Based Deep GM Segmentation on DTI ↔ microbrain/subcort_segmentation/mbrain_segment.py, lines 898–962 · score 0.81 · Harvard Oxford, initial mesh, Initial voxel, probability map, DTI imaging, atlas
  2. [2] § Materials and Methods › DTI Preprocessing ↔ scripts/microbrain_run.py, lines 275–344 · score 0.79 · Gibbs ringing, tensor models, brain mask, MD map, BET, denoised
  3. [3] § Materials and Methods › Surface‐Based Deep GM Segmentation on DTI ↔ microbrain/surfing/mbrain_cortical_segmentation.py, lines 850–928 · score 0.72 · cortical segmentation, CSF probabilities, probability map, external, forces, internal
  4. [4] § Materials and Methods › Surface‐Based Deep GM Segmentation on DTI ↔ microbrain/subcort_segmentation/mbrain_segment.py, lines 898–962 · score 0.57 · Harvard Oxford, probability maps, deformed, deformation, native, mesh
  5. [5] § Materials and Methods › Surface‐Based Deep GM Segmentation on DTI ↔ microbrain/subcort_segmentation/mbrain_segment.py, lines 581–651 · score 0.55 · Initial segmentation, right thalamus, closest, intensity, force, atlas
  6. [6] § Materials and Methods › DTI Preprocessing ↔ scripts/microbrain_run.py, lines 275–344 · score 0.54 · tensor models, MD map, gradients, fit, b0, Preprocessing

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 962 lines · 48 KB · MIT · 3 matches

  1. #!/usr/local/bin/python
  2. import microbrain.utils.surf_util as sutil
  3. import vtk
  4. from shutil import which
  5. from os import system, environ, path
  6. import numpy as np
  7. import nibabel as nib
  8. import inspect
  9. from skimage.morphology import binary_erosion
  10. # FSL Harvard Atlas label indices
  11. LEFT_WHITE_IDX = 0
  12. LEFT_CORTEX_IDX = 1
  13. LEFT_VENT_IDX = 2
  14. LEFT_THAL_IDX = 3
  15. LEFT_CAUDATE_IDX = 4
  16. LEFT_PUT_IDX = 5
  17. LEFT_GLOB_IDX = 6
  18. BRAIN_STEM_IDX = 7
  19. LEFT_HIPPO_IDX = 8
  20. LEFT_AMYG_IDX = 9
  21. LEFT_ACCUM_IDX = 10
  22. RIGHT_WHITE_IDX = 11
  23. RIGHT_CORTEX_IDX = 12
  24. RIGHT_VENT_IDX = 13
  25. RIGHT_THAL_IDX = 14
  26. RIGHT_CAUDATE_IDX = 15
  27. RIGHT_PUT_IDX = 16
  28. RIGHT_GLOB_IDX = 17
  29. RIGHT_HIPPO_IDX = 18
  30. RIGHT_AMYG_IDX = 19
  31. RIGHT_ACCUM_IDX = 20
  32. # indices specific for microbrain ROIs
  33. LEFT_HIPPOAMYG_IDX = 88
  34. LEFT_STRIATUM_IDX = 66
  35. RIGHT_HIPPOAMYG_IDX = 188
  36. RIGHT_STRIATUM_IDX = 166
  37. VENT_IDX = 200
  38. def is_tool(name):
  39. """
  40. Checks to see if third party binary is installed and accessible by command line
  41. Parameters
  42. ----------
  43. name: string
  44. the name of the command to look for
  45. Returns
  46. -------
  47. Boolean: true if command exists, false if not in path
  48. """
  49. return which(name) is not None
  50. def fsl_ext():
  51. """
  52. Gets the preferred image extension used by FSL
  53. Parameters
  54. ----------
  55. none
  56. Returns
  57. -------
  58. extension: a string containing the preferred output
  59. """
  60. fsl_extension = ''
  61. if environ['FSLOUTPUTTYPE'] == 'NIFTI':
  62. fsl_extension = '.nii'
  63. elif environ['FSLOUTPUTTYPE'] == 'NIFTI_GZ':
  64. fsl_extension = '.nii.gz'
  65. return fsl_extension
  66. def get_fsl_standard_dir():
  67. """
  68. Return tissue directory in microbrain repository
  69. Returns
  70. -------
  71. tissue_dir: string
  72. tissue path
  73. """
  74. import microbrain # ToDo. Is this the only way?
  75. module_path = inspect.getfile(microbrain)
  76. fsl_standard_dir = path.dirname(module_path) + "/data/fsl/standard/"
  77. return fsl_standard_dir
  78. def get_fsl_atlas_dir():
  79. """
  80. Return tissue directory in microbrain repository
  81. Returns
  82. -------
  83. tissue_dir: string
  84. tissue path
  85. """
  86. import microbrain # ToDo. Is this the only way?
  87. module_path = inspect.getfile(microbrain)
  88. fsl_atlas_dir = path.dirname(module_path) + "/data/fsl/atlases/"
  89. return fsl_atlas_dir
  90. def register_probatlas_to_native(fsource, ftemplate, fatlas, regDir, cpu_num=0):
  91. """
  92. Given an image will register this image to the template (ANTs SyN)
  93. Then applies this transform to an atlas
  94. Parameters
  95. ----------
  96. fsource: string
  97. filename of image in native space
  98. ftemplate: string
  99. filename of image template in MNI space (or normal space)
  100. fatlas: string
  101. filename of 4D nifti file in MNI space to be registered
  102. regDir: string
  103. directory to store output
  104. Optional Parameters
  105. -------------------
  106. cpu_num: integer
  107. number of cpu threads to use for registration
  108. Returns
  109. -------
  110. fatlas_out: filename for atlas registered to native space
  111. """
  112. if not path.exists(regDir):
  113. system('mkdir ' + regDir)
  114. if cpu_num > 0:
  115. cpu_str = ' -n ' + str(cpu_num)
  116. else:
  117. cpu_str = ''
  118. method_suffix = '_ANTsReg_native'
  119. ftempbasename = path.basename(ftemplate)
  120. fatlas_basename = path.basename(fatlas)
  121. fatlas_out = regDir + \
  122. fatlas_basename.replace('.nii.gz', method_suffix + fsl_ext())
  123. ftransform_out = regDir + 'ants_native2mni_'
  124. print('Running Ants Registration')
  125. # Make template mask
  126. ftemplate_mask = regDir + \
  127. ftempbasename.replace('.nii.gz', '_mask' + fsl_ext())
  128. if not path.exists(ftemplate_mask):
  129. system('fslmaths ' + ftemplate + ' -bin ' + ftemplate_mask)
  130. if not path.exists(ftransform_out + '1InverseWarp.nii.gz'):
  131. system('antsRegistrationSyN.sh' +
  132. ' -d 3' +
  133. ' -f ' + ftemplate +
  134. ' -m ' + fsource +
  135. ' -o ' + ftransform_out +
  136. ' -x ' + ftemplate_mask +
  137. cpu_str)
  138. print('Warping probabilistic atlas to native space')
  139. if not path.exists(fatlas_out):
  140. system('antsApplyTransforms' +
  141. ' -t [' + ftransform_out + '0GenericAffine.mat,1] ' +
  142. ' -t ' + ftransform_out + '1InverseWarp.nii.gz ' +
  143. ' -r ' + fsource +
  144. ' -e 3 ' +
  145. ' -i ' + fatlas +
  146. ' -o ' + fatlas_out)
  147. else:
  148. print("ANTs nonlinear registeration of atlases already performed")
  149. return fatlas_out
  150. def initial_voxel_labels_from_harvard(fharvard, output_prefix, outDir, md_file=None, md_thresh=0.0015, fa_file=None, fa_thresh=0.5):
  151. """
  152. Generates 3D meshes from the FSL harvard brain atlas.
  153. Parameters
  154. ----------
  155. fharvard: string
  156. filename for the harvard probabilistic atlas to be used (usually registered to native space)
  157. output_prefix: string
  158. prefix used for filenames for microbrain subject
  159. outDir: string
  160. output directory to store all files
  161. Optional Parameters:
  162. --------------------
  163. md_file: string
  164. filename for mean diffusivity map used to remove voxels from labels (useful in case of poor registration to native space)
  165. md_thresh: float
  166. removes voxels in lables with MD > md_thresh
  167. fa_file: string
  168. filename for fractional anisotropy map used to remove voxels from labels (useful in case of poor registration to native space)
  169. fa_thresh: string
  170. removes voxels in lables with FA > fa_thresh
  171. Returns
  172. -------
  173. None
  174. """
  175. if md_file:
  176. md_data = nib.load(md_file).get_fdata()
  177. if fa_file:
  178. fa_data = nib.load(fa_file).get_fdata()
  179. finitlabels_prefix = outDir + output_prefix + '_initialization'
  180. harvard_img = nib.load(fharvard)
  181. harvard_data = harvard_img.get_fdata()
  182. subcort_ind = [LEFT_THAL_IDX,
  183. LEFT_CAUDATE_IDX,
  184. LEFT_PUT_IDX,
  185. LEFT_GLOB_IDX,
  186. LEFT_HIPPO_IDX,
  187. LEFT_AMYG_IDX,
  188. LEFT_ACCUM_IDX,
  189. LEFT_HIPPOAMYG_IDX,
  190. LEFT_STRIATUM_IDX,
  191. RIGHT_THAL_IDX,
  192. RIGHT_CAUDATE_IDX,
  193. RIGHT_PUT_IDX,
  194. RIGHT_GLOB_IDX,
  195. RIGHT_HIPPO_IDX,
  196. RIGHT_AMYG_IDX,
  197. RIGHT_ACCUM_IDX,
  198. RIGHT_HIPPOAMYG_IDX,
  199. RIGHT_STRIATUM_IDX,
  200. VENT_IDX]
  201. subcort_label = ['LEFT_THALAMUS',
  202. 'LEFT_CAUDATE',
  203. 'LEFT_PUTAMEN',
  204. 'LEFT_GLOBUS',
  205. 'LEFT_HIPPO',
  206. 'LEFT_AMYGDALA',
  207. 'LEFT_ACCUMBENS',
  208. 'LEFT_HIPPOAMYG',
  209. 'LEFT_STRIATUM',
  210. 'RIGHT_THALAMUS',
  211. 'RIGHT_CAUDATE',
  212. 'RIGHT_PUTAMEN',
  213. 'RIGHT_GLOBUS',
  214. 'RIGHT_HIPPO',
  215. 'RIGHT_AMYGDALA',
  216. 'RIGHT_ACCUMBENS',
  217. 'RIGHT_HIPPOAMYG',
  218. 'RIGHT_STRIATUM',
  219. 'VENTRICLES']
  220. for sind, slabel in zip(subcort_ind, subcort_label):
  221. tmplabel = np.zeros(harvard_data.shape[0:3])
  222. if sind == RIGHT_ACCUM_IDX or sind == LEFT_ACCUM_IDX:
  223. tmplabel[binary_erosion(harvard_data[:, :, :, sind] > 25)] = 1
  224. elif sind == RIGHT_HIPPOAMYG_IDX:
  225. tmplabel[binary_erosion(np.logical_or(
  226. harvard_data[:, :, :, RIGHT_HIPPO_IDX] > 35, harvard_data[:, :, :, RIGHT_AMYG_IDX] > 35))] = 1
  227. elif sind == LEFT_HIPPOAMYG_IDX:
  228. tmplabel[binary_erosion(np.logical_or(
  229. harvard_data[:, :, :, LEFT_HIPPO_IDX] > 35, harvard_data[:, :, :, LEFT_AMYG_IDX] > 35))] = 1
  230. elif sind == RIGHT_STRIATUM_IDX:
  231. tmplabel[binary_erosion(np.logical_or(np.logical_or(harvard_data[:, :, :, RIGHT_PUT_IDX] > 15,
  232. harvard_data[:, :, :, RIGHT_CAUDATE_IDX] > 15), harvard_data[:, :, :, RIGHT_ACCUM_IDX] > 15))] = 1
  233. elif sind == LEFT_STRIATUM_IDX:
  234. tmplabel[binary_erosion(np.logical_or(np.logical_or(harvard_data[:, :, :, LEFT_PUT_IDX] > 15,
  235. harvard_data[:, :, :, LEFT_CAUDATE_IDX] > 15), harvard_data[:, :, :, LEFT_ACCUM_IDX] > 15))] = 1
  236. elif sind == RIGHT_AMYG_IDX or sind == LEFT_AMYG_IDX:
  237. tmplabel[binary_erosion(harvard_data[:, :, :, sind] > 35)] = 1
  238. elif sind == RIGHT_HIPPO_IDX or sind == LEFT_HIPPO_IDX:
  239. tmplabel[binary_erosion(harvard_data[:, :, :, sind] > 35)] = 1
  240. elif sind == VENT_IDX:
  241. tmplabel[harvard_data[:, :, :, LEFT_VENT_IDX] > 25] = 1
  242. tmplabel[harvard_data[:, :, :, RIGHT_VENT_IDX] > 25] = 1
  243. else:
  244. tmplabel[binary_erosion(harvard_data[:, :, :, sind] > 50)] = 1
  245. # # remove large MD voxels in GM if argument provided
  246. if sind != VENT_IDX:
  247. if md_file:
  248. tmplabel[md_data > md_thresh] = 0
  249. if fa_file:
  250. tmplabel[fa_data > fa_thresh] = 0
  251. finit_tmplabel = finitlabels_prefix + '_' + slabel + fsl_ext()
  252. nib.save(nib.Nifti1Image(tmplabel, harvard_img.affine), finit_tmplabel)
  253. system('mirtk extract-connected-components ' +
  254. finit_tmplabel + ' ' + finit_tmplabel)
  255. # Extract surfaces
  256. finit_surf = finitlabels_prefix + '_' + slabel + '.vtk'
  257. system('mirtk extract-surface ' + finit_tmplabel +
  258. ' ' + finit_surf + ' -isovalue 0.5')
  259. system('mirtk extract-connected-points ' +
  260. finit_surf + ' ' + finit_surf)
  261. system('mirtk smooth-surface ' + finit_surf + ' ' +
  262. finit_surf + ' -iterations 50 -lambda 0.05')
  263. # Label Surfaces
  264. system('mirtk project-onto-surface ' + finit_surf + ' ' + finit_surf +
  265. ' -constant ' + str(sind) + ' -pointdata -name struct_label')
  266. # Combine left and right thalamus
  267. lh_thalamus = sutil.read_surf_vtk(
  268. finitlabels_prefix + '_LEFT_THALAMUS.vtk')
  269. rh_thalamus = sutil.read_surf_vtk(
  270. finitlabels_prefix + '_RIGHT_THALAMUS.vtk')
  271. appender = vtk.vtkAppendPolyData()
  272. appender.AddInputData(lh_thalamus)
  273. appender.AddInputData(rh_thalamus)
  274. appender.Update()
  275. thalamus_surf = appender.GetOutput()
  276. sutil.write_surf_vtk(thalamus_surf, finitlabels_prefix + '_THALAMUS.vtk')
  277. return
  278. def extract_surfaces_from_labels(flabels, label_list, outDir, fout_prefix):
  279. """
  280. Given a 3D nifti file containing a voxelwise labeling of structures, output a smoothed 3D surface representation of the labels
  281. Parameters
  282. ----------
  283. flabels: string
  284. filename for 3D nifti file containing labels
  285. label_list: string
  286. list of label integers indicating which labels to convert to surfaces (e.g. [1, 3])
  287. outDir: string
  288. directory to output the meshes
  289. fout_prefix: string
  290. prefix for output files
  291. Returns
  292. -------
  293. list of outputed vtk files
  294. """
  295. # Read in labels output nifti images
  296. label_img = nib.load(flabels)
  297. label_data = label_img.get_fdata()
  298. fout_list = []
  299. for label_ind in label_list:
  300. # Write tmp nifti
  301. ftmpNII = outDir + 'tmplabel' + str(label_ind) + fsl_ext()
  302. tmplabel = np.zeros(label_data.shape)
  303. tmplabel[label_data == label_ind] = 1
  304. nib.save(nib.Nifti1Image(tmplabel,
  305. label_img.affine), ftmpNII)
  306. # Extract surface around label
  307. fout_surf = fout_prefix + '_' + str(label_ind) + '.vtk'
  308. system('mirtk extract-surface ' + ftmpNII +
  309. ' ' + fout_surf + ' -isovalue 0.5')
  310. system('rm ' + ftmpNII)
  311. # Smooth surface for the label
  312. system('mirtk smooth-surface ' + fout_surf + ' ' +
  313. fout_surf + ' -iterations 50 -lambda 0.2')
  314. # Add label to surface mesh
  315. system('mirtk project-onto-surface ' + fout_surf + ' ' + fout_surf +
  316. ' -constant ' + str(label_ind) + ' -pointdata -name struct_label')
  317. fout_list = fout_list + [fout_surf]
  318. return fout_list
  319. def deform_subcortical_surfaces(fdwi, ffa, fmd, fharvard_native, segDir, initSegDir, subID, cpu_num=0):
  320. """
  321. Script to segment subcortical brain regions with 3D surface based deformation using DTI images/maps
  322. Parameters
  323. ----------
  324. fdwi: string
  325. filename for mean diffusion weigthed image (suggested b1000) used for globus pallidus segmentation
  326. ffa: string
  327. filename for fa map
  328. ffmd: string
  329. filename for md map
  330. fharvard_native: string
  331. FSL harvard probabilistic atlas transformed to native space
  332. segDir: string
  333. parent directory to store pipeline output
  334. initSegDir: string
  335. directory containing initial structure surfaces generated using initial_voxel_labels_from_harvard
  336. subID: string
  337. microbrain subject ID
  338. Optional Parameters
  339. -------------------
  340. cpu_num: integer
  341. number of cpu threads for MIRTK deform-mesh to use (default is mirtk default of all available threads)
  342. Returns
  343. -------
  344. none
  345. """
  346. min_edgelength = 0.6
  347. max_edgelength = 1.1
  348. min_hippo_edgelength = 0.6
  349. max_hippo_edgelength = 1.1
  350. curv_w = 8.0
  351. gcurv_w = 2.0
  352. step_size = 0.1
  353. step_num = 200
  354. averages = '4 2 1'
  355. initial_seg_prefix = '_initialization'
  356. seg_prefix = '_refined'
  357. if cpu_num > 0:
  358. cpu_str = ' -threads ' + str(cpu_num) + ' '
  359. else:
  360. cpu_str = ' '
  361. # Make output folders
  362. MDFA_Dir = segDir + 'md_plus_fa_maps/'
  363. if not path.exists(MDFA_Dir):
  364. system('mkdir ' + MDFA_Dir)
  365. probForceDir = segDir + 'probability_force_maps/'
  366. if not path.exists(probForceDir):
  367. system('mkdir ' + probForceDir)
  368. meshDir = segDir + 'mesh_output/'
  369. if not path.exists(meshDir):
  370. system('mkdir ' + meshDir)
  371. voxelDir = segDir + 'voxel_output/'
  372. if not path.exists(voxelDir):
  373. system('mkdir ' + voxelDir)
  374. atroposDir = segDir + 'atropos_hippoamyg_seg/'
  375. if not path.exists(atroposDir):
  376. system('mkdir ' + atroposDir)
  377. fsubcortseg_vtk = meshDir + subID + seg_prefix + '_subcortGM.vtk'
  378. if not path.exists(fsubcortseg_vtk):
  379. print('Subcortical Deformation Segmentation')
  380. # Make composite map of FA + csf probabilities. (This map defines the borders of the caudate and the thalamus)
  381. fmd_plusFA = MDFA_Dir + \
  382. path.basename(fmd.replace(fsl_ext(), '_plusFA' + fsl_ext()))
  383. system('fslmaths ' + fmd + ' -mul 1000 -add ' + ffa + ' ' + fmd_plusFA)
  384. MD_plusFA_data = nib.load(fmd_plusFA).get_fdata()
  385. fa_img = nib.load(ffa)
  386. harvard_img = nib.load(fharvard_native)
  387. harvard_data = harvard_img.get_fdata()
  388. dwi_img = nib.load(fdwi)
  389. dwi_data = dwi_img.get_fdata()
  390. # Probabilistic based force for subcortical structures
  391. glob_prob_force = np.zeros(dwi_data.shape)
  392. glob_pos_ind = [LEFT_WHITE_IDX, LEFT_PUT_IDX, LEFT_CAUDATE_IDX, LEFT_ACCUM_IDX,
  393. RIGHT_WHITE_IDX, RIGHT_PUT_IDX, RIGHT_CAUDATE_IDX, RIGHT_ACCUM_IDX]
  394. glob_neg_ind = [LEFT_GLOB_IDX, RIGHT_GLOB_IDX]
  395. for pos_ind in glob_pos_ind:
  396. glob_prob_force = glob_prob_force + harvard_data[:, :, :, pos_ind]
  397. for neg_ind in glob_neg_ind:
  398. glob_prob_force = glob_prob_force - harvard_data[:, :, :, neg_ind]
  399. fglob_prob_force = probForceDir + subID + '_glob_prob_force' + fsl_ext()
  400. nib.save(nib.Nifti1Image(glob_prob_force,
  401. fa_img.affine), fglob_prob_force)
  402. # Deform globus pallidus based on meanDWI and resticting movement into high FA regions
  403. fglobus_lh = initSegDir + subID + initial_seg_prefix + '_LEFT_GLOBUS.vtk'
  404. fglobus_lh_refined = meshDir + subID + seg_prefix + '_LEFT_GLOBUS.vtk'
  405. if not path.exists(fglobus_lh_refined):
  406. system('mirtk deform-mesh ' + fglobus_lh + ' ' + fglobus_lh_refined + ' -image ' + fdwi + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fglob_prob_force + ' -distance 0.5 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(
  407. step_num) + ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_edgelength) + ' -max-edge-length ' + str(max_edgelength))
  408. sutil.surf_to_volume_mask(fdwi, fglobus_lh_refined, 1,
  409. voxelDir + subID + seg_prefix + '_LEFT_GLOBUS' + fsl_ext())
  410. fglobus_rh = initSegDir + subID + initial_seg_prefix + '_RIGHT_GLOBUS.vtk'
  411. fglobus_rh_refined = meshDir + subID + seg_prefix + '_RIGHT_GLOBUS.vtk'
  412. if not path.exists(fglobus_rh_refined):
  413. system('mirtk deform-mesh ' + fglobus_rh + ' ' + fglobus_rh_refined + ' -image ' + fdwi + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fglob_prob_force + ' -distance 0.5 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  414. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_edgelength) + ' -max-edge-length ' + str(max_edgelength))
  415. sutil.surf_to_volume_mask(fdwi, fglobus_rh_refined, 1,
  416. voxelDir + subID + seg_prefix + '_RIGHT_GLOBUS' + fsl_ext())
  417. # Generate map for Striatum deformation
  418. fa_globus = np.zeros(MD_plusFA_data.shape)
  419. fa_globus[:] = MD_plusFA_data[:]
  420. lh_globus_data = nib.load(
  421. voxelDir + subID + seg_prefix + '_LEFT_GLOBUS' + fsl_ext()).get_fdata()
  422. rh_globus_data = nib.load(
  423. voxelDir + subID + seg_prefix + '_RIGHT_GLOBUS' + fsl_ext()).get_fdata()
  424. fa_globus[lh_globus_data == 1] = 2
  425. fa_globus[rh_globus_data == 1] = 2
  426. fmd_plusFA_globus = MDFA_Dir + \
  427. path.basename(fmd_plusFA.replace(fsl_ext(), '_globus' + fsl_ext()))
  428. if not path.exists(fmd_plusFA_globus):
  429. nib.save(nib.Nifti1Image(
  430. fa_globus, fa_img.affine), fmd_plusFA_globus)
  431. # Probabilistic atlas based force for striatum
  432. striatum_prob_force = np.zeros(dwi_data.shape)
  433. striatum_pos_ind = [LEFT_CORTEX_IDX, LEFT_WHITE_IDX,
  434. LEFT_GLOB_IDX, RIGHT_CORTEX_IDX, RIGHT_WHITE_IDX, RIGHT_GLOB_IDX]
  435. striatum_neg_ind = [LEFT_PUT_IDX, LEFT_CAUDATE_IDX, LEFT_ACCUM_IDX,
  436. RIGHT_PUT_IDX, RIGHT_CAUDATE_IDX, RIGHT_ACCUM_IDX]
  437. for pos_ind in striatum_pos_ind:
  438. striatum_prob_force = striatum_prob_force + \
  439. harvard_data[:, :, :, pos_ind]
  440. for neg_ind in striatum_neg_ind:
  441. striatum_prob_force = striatum_prob_force - \
  442. harvard_data[:, :, :, neg_ind]
  443. fstriatum_prob_force = probForceDir + subID + '_striatum_prob_force' + fsl_ext()
  444. if not path.exists(fstriatum_prob_force):
  445. nib.save(nib.Nifti1Image(striatum_prob_force,
  446. fa_img.affine), fstriatum_prob_force)
  447. fstriatum_lh = initSegDir + subID + initial_seg_prefix + '_LEFT_STRIATUM.vtk'
  448. fstriatum_lh_refined = meshDir + subID + seg_prefix + '_LEFT_STRIATUM.vtk'
  449. if not path.exists(fstriatum_lh_refined):
  450. system('mirtk deform-mesh ' + fstriatum_lh + ' ' + fstriatum_lh_refined + ' -image ' + fmd_plusFA_globus + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fstriatum_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  451. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_edgelength) + ' -max-edge-length ' + str(max_edgelength) + ' -edge-distance-min-intensity 0.3')
  452. sutil.surf_to_volume_mask(fdwi, fstriatum_lh_refined, 1,
  453. voxelDir + subID + seg_prefix + '_LEFT_STRIATUM' + fsl_ext())
  454. fstriatum_rh = initSegDir + subID + initial_seg_prefix + '_RIGHT_STRIATUM.vtk'
  455. fstriatum_rh_refined = meshDir + subID + seg_prefix + '_RIGHT_STRIATUM.vtk'
  456. if not path.exists(fstriatum_rh_refined):
  457. system('mirtk deform-mesh ' + fstriatum_rh + ' ' + fstriatum_rh_refined + ' -image ' + fmd_plusFA_globus + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fstriatum_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  458. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_edgelength) + ' -max-edge-length ' + str(max_edgelength) + ' -edge-distance-min-intensity 0.3')
  459. sutil.surf_to_volume_mask(fdwi, fstriatum_rh_refined, 1,
  460. voxelDir + subID + seg_prefix + '_RIGHT_STRIATUM' + fsl_ext())
  461. fa_md_striatum = np.zeros(MD_plusFA_data.shape)
  462. fa_md_striatum[:] = MD_plusFA_data[:]
  463. lh_striatum_data = nib.load(
  464. voxelDir + subID + seg_prefix + '_LEFT_STRIATUM' + fsl_ext()).get_fdata()
  465. rh_striatum_data = nib.load(
  466. voxelDir + subID + seg_prefix + '_RIGHT_STRIATUM' + fsl_ext()).get_fdata()
  467. fa_md_striatum[lh_striatum_data == 1] = 2
  468. fa_md_striatum[rh_striatum_data == 1] = 2
  469. fmd_plusFA_striatum = MDFA_Dir + \
  470. path.basename(fmd_plusFA.replace(
  471. fsl_ext(), '_striatum' + fsl_ext()))
  472. if not path.exists(fmd_plusFA_striatum):
  473. nib.save(nib.Nifti1Image(fa_md_striatum,
  474. fa_img.affine), fmd_plusFA_striatum)
  475. # Probabilistic atlas based force for thalamus
  476. thal_prob_force = np.zeros(dwi_data.shape)
  477. thal_pos_ind = [LEFT_CORTEX_IDX, LEFT_WHITE_IDX, LEFT_HIPPO_IDX,
  478. RIGHT_CORTEX_IDX, RIGHT_WHITE_IDX, RIGHT_HIPPO_IDX]
  479. thal_neg_ind = [LEFT_THAL_IDX, RIGHT_THAL_IDX]
  480. for pos_ind in thal_pos_ind:
  481. thal_prob_force = thal_prob_force + harvard_data[:, :, :, pos_ind]
  482. for neg_ind in thal_neg_ind:
  483. thal_prob_force = thal_prob_force - harvard_data[:, :, :, neg_ind]
  484. fthal_prob_force = probForceDir + subID + '_thalamus_prob_force' + fsl_ext()
  485. if not path.exists(fthal_prob_force):
  486. nib.save(nib.Nifti1Image(thal_prob_force,
  487. fa_img.affine), fthal_prob_force)
  488. fthalamus = initSegDir + subID + initial_seg_prefix + '_THALAMUS.vtk'
  489. fthalamus_refined = meshDir + subID + seg_prefix + '_THALAMUS.vtk'
  490. if not path.exists(fthalamus_refined):
  491. system('mirtk deform-mesh ' + fthalamus + ' ' + fthalamus_refined + ' -image ' + fmd_plusFA_striatum + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fthal_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  492. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_edgelength) + ' -max-edge-length ' + str(max_edgelength) + ' -edge-distance-min-intensity 1.25')
  493. thalamus_surf = sutil.read_surf_vtk(fthalamus_refined)
  494. [lh_thalamus, rh_thalamus] = sutil.split_surface_by_label(
  495. thalamus_surf, label=[LEFT_THAL_IDX, RIGHT_THAL_IDX], label_name='struct_label')
  496. fthalamus_lh_refined = meshDir + subID + seg_prefix + '_LEFT_THALAMUS.vtk'
  497. if not path.exists(fthalamus_lh_refined):
  498. sutil.write_surf_vtk(lh_thalamus, fthalamus_lh_refined)
  499. sutil.surf_to_volume_mask(fdwi, fthalamus_lh_refined, 1,
  500. voxelDir + subID + seg_prefix + '_LEFT_THALAMUS' + fsl_ext())
  501. fthalamus_rh_refined = meshDir + subID + seg_prefix + '_RIGHT_THALAMUS.vtk'
  502. if not path.exists(fthalamus_rh_refined):
  503. sutil.write_surf_vtk(rh_thalamus, fthalamus_rh_refined)
  504. sutil.surf_to_volume_mask(fdwi, fthalamus_rh_refined, 1,
  505. voxelDir + subID + seg_prefix + '_RIGHT_THALAMUS' + fsl_ext())
  506. # Hippocampus/Amygdala segmentation
  507. hipamyg_prob_force = np.zeros(dwi_data.shape)
  508. hipamyg_pos_ind = [LEFT_CORTEX_IDX, LEFT_WHITE_IDX, LEFT_THAL_IDX,
  509. RIGHT_CORTEX_IDX, RIGHT_WHITE_IDX, RIGHT_THAL_IDX, BRAIN_STEM_IDX]
  510. hipamyg_neg_ind = [LEFT_HIPPO_IDX, LEFT_AMYG_IDX,
  511. RIGHT_HIPPO_IDX, RIGHT_AMYG_IDX]
  512. for pos_ind in hipamyg_pos_ind:
  513. hipamyg_prob_force = hipamyg_prob_force + \
  514. harvard_data[:, :, :, pos_ind]
  515. for neg_ind in hipamyg_neg_ind:
  516. hipamyg_prob_force = hipamyg_prob_force - \
  517. harvard_data[:, :, :, neg_ind]
  518. fhipamyg_prob_force = probForceDir + subID + '_hipamyg_prob_force' + fsl_ext()
  519. nib.save(nib.Nifti1Image(hipamyg_prob_force,
  520. fa_img.affine), fhipamyg_prob_force)
  521. fhippoamyg_lh = initSegDir + subID + initial_seg_prefix + '_LEFT_HIPPOAMYG.vtk'
  522. fhippoamyg_lh_refined = atroposDir + subID + seg_prefix + '_LEFT_HIPPOAMYG.vtk'
  523. if not path.exists(fhippoamyg_lh_refined):
  524. system('mirtk deform-mesh ' + fhippoamyg_lh + ' ' + fhippoamyg_lh_refined + ' -image ' + fmd_plusFA + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fhipamyg_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  525. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_hippo_edgelength) + ' -max-edge-length ' + str(max_hippo_edgelength) + ' -edge-distance-min-intensity 1.0')
  526. sutil.surf_to_volume_mask(fdwi, fhippoamyg_lh_refined, 1,
  527. atroposDir + subID + seg_prefix + '_LEFT_HIPPOAMYG' + fsl_ext())
  528. fhippoamyg_rh = initSegDir + subID + initial_seg_prefix + '_RIGHT_HIPPOAMYG.vtk'
  529. fhippoamyg_rh_refined = atroposDir + subID + seg_prefix + '_RIGHT_HIPPOAMYG.vtk'
  530. if not path.exists(fhippoamyg_rh_refined):
  531. system('mirtk deform-mesh ' + fhippoamyg_rh + ' ' + fhippoamyg_rh_refined + ' -image ' + fmd_plusFA + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fhipamyg_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  532. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_hippo_edgelength) + ' -max-edge-length ' + str(max_hippo_edgelength) + ' -edge-distance-min-intensity 1.0')
  533. sutil.surf_to_volume_mask(fdwi, fhippoamyg_rh_refined, 1,
  534. atroposDir + subID + seg_prefix + '_RIGHT_HIPPOAMYG' + fsl_ext())
  535. # Run 3 channel tissue segmentation to separate amygdala from hippocampus
  536. # prepare prob maps and separate primary eigenvector into separate nifti file
  537. atropos_prefix_lh = atroposDir + subID + \
  538. initial_seg_prefix + '_INITAMYGHIPPO_LH'
  539. atropos_prefix_lh_label = atroposDir + subID + \
  540. initial_seg_prefix + '_INITAMYGHIPPO_LH_LABELS' + fsl_ext()
  541. atropos_prefix_lh_probout = atroposDir + subID + \
  542. initial_seg_prefix + '_INITAMYGHIPPO_LH_PROBOUT_'
  543. famyg_lh_prob = atropos_prefix_lh + '_01' + fsl_ext()
  544. if not path.exists(famyg_lh_prob):
  545. nib.save(nib.Nifti1Image(
  546. harvard_data[:, :, :, LEFT_AMYG_IDX]/100, harvard_img.affine), famyg_lh_prob)
  547. fhippo_lh_prob = atropos_prefix_lh + '_02' + fsl_ext()
  548. if not path.exists(fhippo_lh_prob):
  549. nib.save(nib.Nifti1Image(
  550. harvard_data[:, :, :, LEFT_HIPPO_IDX]/100, harvard_img.affine), fhippo_lh_prob)
  551. fcortex_lh_prob = atropos_prefix_lh + '_03' + fsl_ext()
  552. if not path.exists(fcortex_lh_prob):
  553. nib.save(nib.Nifti1Image(
  554. harvard_data[:, :, :, LEFT_CORTEX_IDX]/100, harvard_img.affine), fcortex_lh_prob)
  555. atropos_prefix_rh = atroposDir + subID + \
  556. initial_seg_prefix + '_INITAMYGHIPPO_RH'
  557. atropos_prefix_rh_label = atroposDir + subID + \
  558. initial_seg_prefix + '_INITAMYGHIPPO_RH_LABELS' + fsl_ext()
  559. atropos_prefix_rh_probout = atroposDir + subID + \
  560. initial_seg_prefix + '_INITAMYGHIPPO_RH_PROBOUT_'
  561. famyg_rh_prob = atropos_prefix_rh + '_01' + fsl_ext()
  562. if not path.exists(famyg_rh_prob):
  563. nib.save(nib.Nifti1Image(
  564. harvard_data[:, :, :, RIGHT_AMYG_IDX]/100, harvard_img.affine), famyg_rh_prob)
  565. fhippo_rh_prob = atropos_prefix_rh + '_02' + fsl_ext()
  566. if not path.exists(fhippo_rh_prob):
  567. nib.save(nib.Nifti1Image(
  568. harvard_data[:, :, :, RIGHT_HIPPO_IDX]/100, harvard_img.affine), fhippo_rh_prob)
  569. fcortex_rh_prob = atropos_prefix_rh + '_03' + fsl_ext()
  570. if not path.exists(fcortex_rh_prob):
  571. nib.save(nib.Nifti1Image(
  572. harvard_data[:, :, :, RIGHT_CORTEX_IDX]/100, harvard_img.affine), fcortex_rh_prob)
  573. PriorWeight = 0.3
  574. if not path.exists(atropos_prefix_lh_label):
  575. system('Atropos' +
  576. ' -a [' + fmd_plusFA + ']' +
  577. ' -x ' + atroposDir + subID + seg_prefix + '_LEFT_HIPPOAMYG' + fsl_ext() +
  578. ' -i PriorProbabilityImages[3, ' + atropos_prefix_lh + '_%02d' + fsl_ext() + ',' + str(PriorWeight) + ',0.0001]' +
  579. ' -m [0.3, 2x2x2] ' +
  580. ' --use-partial-volume-likelihoods false ' +
  581. ' -s 1x3 -s 1x2 ' +
  582. ' -o [' + atropos_prefix_lh_label + ',' + atropos_prefix_lh_probout + '%02d' + fsl_ext() + ']' +
  583. ' -k HistogramParzenWindows[1.0,32]' +
  584. ' -v 1')
  585. if not path.exists(atropos_prefix_rh_label):
  586. system('Atropos' +
  587. ' -a [' + fmd_plusFA + ']' +
  588. ' -x ' + atroposDir + subID + seg_prefix + '_RIGHT_HIPPOAMYG' + fsl_ext() +
  589. ' -i PriorProbabilityImages[3, ' + atropos_prefix_rh + '_%02d' + fsl_ext() + ',' + str(PriorWeight) + ',0.0001]' +
  590. ' -m [0.3, 2x2x2] ' +
  591. ' --use-partial-volume-likelihoods false ' +
  592. ' -s 1x3 -s 1x2 ' +
  593. ' -o [' + atropos_prefix_rh_label + ',' + atropos_prefix_rh_probout + '%02d' + fsl_ext() + ']' +
  594. ' -k HistogramParzenWindows[1.0,32]' +
  595. ' -v 1')
  596. lh_labels = nib.load(atropos_prefix_lh_label).get_fdata()
  597. rh_labels = nib.load(atropos_prefix_rh_label).get_fdata()
  598. # Generate new surfaces for hippocampus and amygdala
  599. fhippoamyg_lh_step1 = atroposDir + subID + \
  600. initial_seg_prefix + '_LEFT_HIPPOAMYG_STEP1'
  601. fsurf_list = extract_surfaces_from_labels(
  602. atropos_prefix_lh_label, [1, 2], atroposDir, fhippoamyg_lh_step1)
  603. famyg_lh_step1 = fsurf_list[0]
  604. fhippo_lh_step1 = fsurf_list[1]
  605. fhippoamyg_rh_step1 = atroposDir + subID + \
  606. initial_seg_prefix + '_RIGHT_HIPPOAMYG_STEP1'
  607. fsurf_list = extract_surfaces_from_labels(
  608. atropos_prefix_rh_label, [1, 2], atroposDir, fhippoamyg_rh_step1)
  609. famyg_rh_step1 = fsurf_list[0]
  610. fhippo_rh_step1 = fsurf_list[1]
  611. # Build amygdala prob force
  612. amyg_prob_force = np.zeros(dwi_data.shape)
  613. amyg_pos_ind = [LEFT_CORTEX_IDX, LEFT_WHITE_IDX, LEFT_THAL_IDX, LEFT_HIPPO_IDX, RIGHT_HIPPO_IDX,
  614. RIGHT_CORTEX_IDX, RIGHT_WHITE_IDX, RIGHT_THAL_IDX, BRAIN_STEM_IDX]
  615. amyg_neg_ind = [LEFT_AMYG_IDX, RIGHT_AMYG_IDX]
  616. for pos_ind in amyg_pos_ind:
  617. amyg_prob_force = amyg_prob_force + \
  618. harvard_data[:, :, :, pos_ind]
  619. for neg_ind in amyg_neg_ind:
  620. amyg_prob_force = amyg_prob_force - \
  621. harvard_data[:, :, :, neg_ind]
  622. famyg_prob_force = probForceDir + subID + '_amyg_prob_force' + fsl_ext()
  623. nib.save(nib.Nifti1Image(amyg_prob_force,
  624. fa_img.affine), famyg_prob_force)
  625. # Add hippocampus/cortex labels to md+fa map
  626. fa_md_hippocortex = np.zeros(MD_plusFA_data.shape)
  627. fa_md_hippocortex[:] = MD_plusFA_data[:]
  628. fa_md_hippocortex[lh_labels == 2] = 2
  629. fa_md_hippocortex[rh_labels == 2] = 2
  630. fa_md_hippocortex[lh_labels == 3] = 2
  631. fa_md_hippocortex[rh_labels == 3] = 2
  632. fmd_plusFA_hippocortex = MDFA_Dir + \
  633. path.basename(fmd_plusFA.replace(
  634. fsl_ext(), '_hippocortex' + fsl_ext()))
  635. if not path.exists(fmd_plusFA_hippocortex):
  636. nib.save(nib.Nifti1Image(fa_md_hippocortex,
  637. fa_img.affine), fmd_plusFA_hippocortex)
  638. famyg_lh_refined = meshDir + subID + seg_prefix + '_LEFT_AMYGDALA.vtk'
  639. if not path.exists(famyg_lh_refined):
  640. system('mirtk deform-mesh ' + famyg_lh_step1 + ' ' + famyg_lh_refined + ' -image ' + fmd_plusFA_hippocortex + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + famyg_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  641. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_hippo_edgelength) + ' -max-edge-length ' + str(max_hippo_edgelength) + ' -edge-distance-min-intensity 1.0')
  642. system('mirtk project-onto-surface ' + famyg_lh_refined + ' ' + famyg_lh_refined +
  643. ' -constant ' + str(LEFT_AMYG_IDX) + ' -pointdata -name struct_label')
  644. sutil.surf_to_volume_mask(fdwi, famyg_lh_refined, 1,
  645. voxelDir + subID + seg_prefix + '_LEFT_AMYGDALA' + fsl_ext())
  646. famyg_rh_refined = meshDir + subID + seg_prefix + '_RIGHT_AMYGDALA.vtk'
  647. if not path.exists(famyg_rh_refined):
  648. system('mirtk deform-mesh ' + famyg_rh_step1 + ' ' + famyg_rh_refined + ' -image ' + fmd_plusFA_hippocortex + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + famyg_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  649. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_hippo_edgelength) + ' -max-edge-length ' + str(max_hippo_edgelength) + ' -edge-distance-min-intensity 1.0')
  650. system('mirtk project-onto-surface ' + famyg_rh_refined + ' ' + famyg_rh_refined +
  651. ' -constant ' + str(RIGHT_AMYG_IDX) + ' -pointdata -name struct_label')
  652. sutil.surf_to_volume_mask(fdwi, famyg_rh_refined, 1,
  653. voxelDir + subID + seg_prefix + '_RIGHT_AMYGDALA' + fsl_ext())
  654. # Build amygdala prob force
  655. hippo_prob_force = np.zeros(dwi_data.shape)
  656. hippo_pos_ind = [LEFT_CORTEX_IDX, LEFT_WHITE_IDX, LEFT_THAL_IDX, LEFT_AMYG_IDX, RIGHT_AMYG_IDX,
  657. RIGHT_CORTEX_IDX, RIGHT_WHITE_IDX, RIGHT_THAL_IDX, BRAIN_STEM_IDX]
  658. hippo_neg_ind = [LEFT_HIPPO_IDX, RIGHT_HIPPO_IDX]
  659. for pos_ind in hippo_pos_ind:
  660. hippo_prob_force = hippo_prob_force + \
  661. harvard_data[:, :, :, pos_ind]
  662. for neg_ind in hippo_neg_ind:
  663. hippo_prob_force = hippo_prob_force - \
  664. harvard_data[:, :, :, neg_ind]
  665. fhippo_prob_force = probForceDir + subID + '_hippo_prob_force' + fsl_ext()
  666. nib.save(nib.Nifti1Image(hippo_prob_force,
  667. fa_img.affine), fhippo_prob_force)
  668. # Add hippocampus/cortex labels to md+fa map
  669. fa_md_amyg = np.zeros(MD_plusFA_data.shape)
  670. fa_md_amyg[:] = MD_plusFA_data[:]
  671. fa_md_amyg[lh_labels == 1] = 2
  672. fa_md_amyg[rh_labels == 1] = 2
  673. fa_md_amyg[lh_labels == 3] = 2
  674. fa_md_amyg[rh_labels == 3] = 2
  675. fmd_plusFA_amyg = MDFA_Dir + \
  676. path.basename(fmd_plusFA.replace(
  677. fsl_ext(), '_amyg' + fsl_ext()))
  678. if not path.exists(fmd_plusFA_amyg):
  679. nib.save(nib.Nifti1Image(fa_md_amyg,
  680. fa_img.affine), fmd_plusFA_amyg)
  681. fhippo_lh_refined = meshDir + subID + seg_prefix + '_LEFT_HIPPO.vtk'
  682. if not path.exists(fhippo_lh_refined):
  683. system('mirtk deform-mesh ' + fhippo_lh_step1 + ' ' + fhippo_lh_refined + ' -image ' + fmd_plusFA_amyg + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fhippo_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  684. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_hippo_edgelength) + ' -max-edge-length ' + str(max_hippo_edgelength) + ' -edge-distance-min-intensity 1.0')
  685. system('mirtk project-onto-surface ' + fhippo_lh_refined + ' ' + fhippo_lh_refined +
  686. ' -constant ' + str(LEFT_HIPPO_IDX) + ' -pointdata -name struct_label')
  687. sutil.surf_to_volume_mask(fdwi, fhippo_lh_refined, 1,
  688. voxelDir + subID + seg_prefix + '_LEFT_HIPPO' + fsl_ext())
  689. fhippo_rh_refined = meshDir + subID + seg_prefix + '_RIGHT_HIPPO.vtk'
  690. if not path.exists(fhippo_rh_refined):
  691. system('mirtk deform-mesh ' + fhippo_rh_step1 + ' ' + fhippo_rh_refined + ' -image ' + fmd_plusFA_amyg + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fhippo_prob_force + ' -distance 0.25 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(step_num) +
  692. ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_hippo_edgelength) + ' -max-edge-length ' + str(max_hippo_edgelength) + ' -edge-distance-min-intensity 1.0')
  693. system('mirtk project-onto-surface ' + fhippo_rh_refined + ' ' + fhippo_rh_refined +
  694. ' -constant ' + str(RIGHT_HIPPO_IDX) + ' -pointdata -name struct_label')
  695. sutil.surf_to_volume_mask(fdwi, fhippo_rh_refined, 1,
  696. voxelDir + subID + seg_prefix + '_RIGHT_HIPPO' + fsl_ext())
  697. # Ventricle segmentation
  698. # Probabilistic based force for subcortical structures
  699. vent_prob_force = np.zeros(dwi_data.shape)
  700. vent_pos_ind = [LEFT_WHITE_IDX, LEFT_PUT_IDX, LEFT_CAUDATE_IDX, LEFT_ACCUM_IDX, LEFT_GLOB_IDX, LEFT_THAL_IDX,
  701. RIGHT_WHITE_IDX, RIGHT_PUT_IDX, RIGHT_CAUDATE_IDX, RIGHT_ACCUM_IDX, RIGHT_GLOB_IDX, RIGHT_THAL_IDX]
  702. vent_neg_ind = [LEFT_VENT_IDX, RIGHT_VENT_IDX]
  703. for pos_ind in vent_pos_ind:
  704. vent_prob_force = vent_prob_force + harvard_data[:, :, :, pos_ind]
  705. for neg_ind in vent_neg_ind:
  706. vent_prob_force = vent_prob_force - harvard_data[:, :, :, neg_ind]
  707. fvent_prob_force = probForceDir + subID + '_vent_prob_force' + fsl_ext()
  708. nib.save(nib.Nifti1Image(vent_prob_force,
  709. fa_img.affine), fvent_prob_force)
  710. # Deform ventricles on mean DWI
  711. fvent = initSegDir + subID + initial_seg_prefix + '_VENTRICLES.vtk'
  712. fvent_refined = meshDir + subID + seg_prefix + '_VENTRICLES.vtk'
  713. if not path.exists(fvent_refined):
  714. system('mirtk deform-mesh ' + fvent + ' ' + fvent_refined + ' -image ' + fdwi + ' -edge-distance 1.0 -edge-distance-averaging ' + averages + ' -edge-distance-smoothing 1 -edge-distance-median 1 -distance-image ' + fvent_prob_force + ' -distance 0.5 -distance-smoothing 1 -distance-averaging ' + averages + ' -distance-measure normal -optimizer EulerMethod -step ' + str(step_size) + ' -steps ' + str(
  715. step_num) + ' -epsilon 1e-6 -delta 0.001 -min-active 1% -reset-status -nointersection -fast-collision-test -min-width 0.01 -min-distance 0.01 -repulsion 4.0 -repulsion-distance 0.5 -repulsion-width 2.0 -curvature ' + str(curv_w) + ' -gauss-curvature ' + str(gcurv_w) + ' -edge-distance-type ClosestMaximum' + cpu_str + '-ascii -remesh 1 -min-edge-length ' + str(min_edgelength) + ' -max-edge-length ' + str(max_edgelength))
  716. system('mirtk project-onto-surface ' + fvent_refined + ' ' + fvent_refined +
  717. ' -constant ' + str(VENT_IDX) + ' -pointdata -name struct_label')
  718. sutil.surf_to_volume_mask(fdwi, fvent_refined, 1,
  719. voxelDir + subID + seg_prefix + '_VENTRICLES' + fsl_ext())
  720. # Append subcort surfs together into single vtk file
  721. fsubcortseg_vtk = meshDir + subID + seg_prefix + '_subcortGM.vtk'
  722. if not path.exists(fsubcortseg_vtk):
  723. appender = vtk.vtkAppendPolyData()
  724. appender.AddInputData(sutil.read_surf_vtk(fglobus_lh_refined))
  725. appender.AddInputData(sutil.read_surf_vtk(fglobus_rh_refined))
  726. appender.AddInputData(sutil.read_surf_vtk(fstriatum_lh_refined))
  727. appender.AddInputData(sutil.read_surf_vtk(fstriatum_rh_refined))
  728. appender.AddInputData(sutil.read_surf_vtk(fthalamus_lh_refined))
  729. appender.AddInputData(sutil.read_surf_vtk(fthalamus_rh_refined))
  730. appender.AddInputData(sutil.read_surf_vtk(famyg_rh_refined))
  731. appender.AddInputData(sutil.read_surf_vtk(famyg_lh_refined))
  732. appender.AddInputData(sutil.read_surf_vtk(fhippo_rh_refined))
  733. appender.AddInputData(sutil.read_surf_vtk(fhippo_lh_refined))
  734. appender.AddInputData(sutil.read_surf_vtk(fvent_refined))
  735. appender.Update()
  736. deepGM_surf = appender.GetOutput()
  737. sutil.write_surf_vtk(deepGM_surf, fsubcortseg_vtk)
  738. else:
  739. print('Subcortical Segmentation already performed: Skipping')
  740. return meshDir, voxelDir
  741. def segment(procDir, subID, preproc_suffix, shell_suffix, cpu_num=0):
  742. """
  743. Subcortical brain segmentation with 3D surface based deformation using DTI images/maps
  744. Parameters
  745. ----------
  746. procDir: string
  747. parent director containing subject
  748. subID: string
  749. the microbrain subject to be processed
  750. preproc_suffix: string
  751. suffix detailing what preprocessing has been performed
  752. shell_suffix: string
  753. suffix detailing what shells were used when running microbrain
  754. Optional Parameters
  755. -------------------
  756. cpu_num: integer
  757. number of threads to use for computationally intense tasks
  758. Returns
  759. -------
  760. none
  761. """
  762. subDir = procDir + '/' + subID
  763. segDir = subDir + '/subcortical_segmentation/'
  764. regDir = subDir + '/registration/'
  765. if preproc_suffix == '':
  766. suffix = '_' + shell_suffix
  767. fdwi = subDir + '/meanDWI/' + subID + '_mean_b' + \
  768. shell_suffix.split('b')[-1] + '_n4' + fsl_ext()
  769. else:
  770. suffix = '_' + preproc_suffix + '_' + shell_suffix
  771. fdwi = subDir + '/meanDWI/' + subID + '_' + \
  772. preproc_suffix + '_mean_b' + \
  773. shell_suffix.split('b')[-1] + '_n4' + fsl_ext()
  774. ffa = subDir + '/DTI_maps/' + subID + suffix + '_FA' + fsl_ext()
  775. fmd = subDir + '/DTI_maps/' + subID + suffix + '_MD' + fsl_ext()
  776. # Register probability maps
  777. ftemplate = get_fsl_standard_dir() + 'FSL_HCP1065_FA_1mm.nii.gz'
  778. fharvard = get_fsl_atlas_dir() + 'HarvardOxford/HarvardOxford-sub-prob-1mm.nii.gz'
  779. fharvard_native = register_probatlas_to_native(
  780. ffa, ftemplate, fharvard, regDir, cpu_num=cpu_num)
  781. # Parent Directory to store all output
  782. if not path.exists(segDir):
  783. system('mkdir ' + segDir)
  784. # Directory to store initial meshes
  785. initSegDir = segDir + 'structure_initialization/'
  786. if not path.exists(initSegDir):
  787. system('mkdir ' + initSegDir)
  788. initial_voxel_labels_from_harvard(
  789. fharvard_native, subID, initSegDir, md_file=fmd, fa_file=ffa)
  790. meshDir, voxelDir, = deform_subcortical_surfaces(
  791. fdwi, ffa, fmd, fharvard_native, segDir, initSegDir, subID, cpu_num=cpu_num)
  792. return meshDir, voxelDir

mbrain_segment.py at commit 47d9efb, under MIT · at the source

Overview

Authors: Graham Little1,2, J. Alejandro Acosta‐Franco1, Christian Beaulieu1
  1. Department of Radiology and Diagnostic Imaging & Biomedical Engineering University of Alberta Edmonton Alberta Canada
  2. Department of Computer Science Université de Sherbrooke Sherbrooke Quebec Canada
Institutions: Université de Sherbrooke (Canada); University of Alberta (Canada)
Journal: NMR in biomedicine, volume 39, issue 8, article e70353
Dates: received 13 November 2025; accepted 16 June 2026; published online 9 July 2026; in print August 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1002/nbm.70353 · PMID 42423344 · PMCID PMC13348013 · OpenAlex W4387453483
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), human (organism)
Methods: Statistics, Machine learning, fMRI & imaging
MeSH: Aging*, Diffusion Tensor Imaging*, Gray Matter*, Adolescent, Adult, Aged, Algorithms, Automation, Female, Humans, Male, Middle Aged, Young Adult (* major topic)
Topic: Advanced Neuroimaging Techniques and Applications (Radiology, Nuclear Medicine and Imaging, Medicine), according to OpenAlex
Funding: University Hospital Foundation; Canadian Institutes of Health Research; Women's and Children's Health Research Institute; Canada Research Chairs; Natural Sciences and Engineering Research Council of Canada; Unifying Neuroscience and Artificial Intelligence in Quebec
Citations: not cited yet (Europe PMC); 66 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repository

Its files are read in the Code ↔ Paper reader above, with 6 matches between paragraphs and lines of code.

LittleBrainLab/microbrain

License: MIT
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Commit: 47d9efbc459ea480d28fa7f6cc5c4f594008009a, 22 January 2025
Languages: Python (19)
Size: 48 files, 19 scripts
Software Heritage: not archived
Found in: the text, “Surface‐Based Deep GM Segmentation on DTI”
Holds: README, environment (requirements.txt, setup.cfg, setup.py)
Not found: license file, CITATION.cff, tests, continuous integration, documentation
Tools: NumPy (10 files), NiBabel (9 files), FSL (7 files), DIPY (6 files), ANTs (4 files), SciPy (2 files), dcm2niix (1 file), FreeSurfer (1 file), scikit-image (1 file), Connectome Workbench (1 file)
Availability: 1 check, the latest on 26 September 2026: the link answers
  • 26 September 2026: the link answers
20 files

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 19 scripts, each with its path and the digest of its content;
  • 6 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data availability statement

The paper has a data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

  • it says that the data are available on request

Read it in the paper: doi.org/10.1002/nbm.70353.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 3, 28 September 2026

  • Publisher: n/a → Wiley

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 3 authors, 13 MeSH terms, 6 funders, 66 references.

Cite

This paper

Little, G., Acosta‐Franco, J. A., & Beaulieu, C. (2026). Automated Surface-Based Segmentation of Deep Gray Matter Regions Based on Diffusion Tensor Images Reveals Unique Age Trajectories Over the Healthy Lifespan. NMR in biomedicine, 39(8), e70353. https://doi.org/10.1002/nbm.70353

BibTeX

@article{little2026automated,
author = {Little, Graham and Acosta‐Franco, J. Alejandro and Beaulieu, Christian},
title = {{Automated Surface-Based Segmentation of Deep Gray Matter Regions Based on Diffusion Tensor Images Reveals Unique Age Trajectories Over the Healthy Lifespan}},
journal = {NMR in biomedicine},
year = {2026},
month = aug,
volume = {39},
number = {8},
pages = {e70353},
publisher = {Wiley},
issn = {0952-3480},
doi = {10.1002/nbm.70353},
url = {https://doi.org/10.1002/nbm.70353},
pmid = {42423344},
pmcid = {PMC13348013}
}

RIS

TY - JOUR
AU - Little, Graham
AU - Acosta‐Franco, J. Alejandro
AU - Beaulieu, Christian
TI - Automated Surface-Based Segmentation of Deep Gray Matter Regions Based on Diffusion Tensor Images Reveals Unique Age Trajectories Over the Healthy Lifespan
T2 - NMR in biomedicine
J2 - NMR Biomed
PY - 2026
DA - 2026/08/01
VL - 39
IS - 8
SP - e70353
SN - 0952-3480
PB - Wiley
DO - 10.1002/nbm.70353
UR - https://doi.org/10.1002/nbm.70353
LA - en
ER -

CSL-JSON

{
"id": "10.1002/nbm.70353",
"type": "article-journal",
"title": "Automated Surface-Based Segmentation of Deep Gray Matter Regions Based on Diffusion Tensor Images Reveals Unique Age Trajectories Over the Healthy Lifespan",
"container-title": "NMR in biomedicine",
"author": [
{
"family": "Little",
"given": "Graham"
},
{
"family": "Acosta‐Franco",
"given": "J. Alejandro"
},
{
"family": "Beaulieu",
"given": "Christian"
}
],
"container-title-short": "NMR Biomed",
"volume": "39",
"issue": "8",
"page": "e70353",
"DOI": "10.1002/nbm.70353",
"PMID": "42423344",
"PMCID": "PMC13348013",
"ISSN": "0952-3480",
"publisher": "Wiley",
"URL": "https://doi.org/10.1002/nbm.70353",
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
1
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1002/nbm.70355
High-Resolution Diffusion Kurtosis Imaging of Hippocampus Subfields Across the Healthy Lifespan.
Journal: NMR in biomedicine
In common: structural MRI / diffusion, 11 references, author Christian Beaulieu
[2] doi:10.1371/journal.pbio.3003856 [code]
Aging and metabolism contribute separately to brain-body health.
Journal: PLoS biology
In common: Connectome Workbench, ANTs, FreeSurfer, 4 other tools, structural MRI / diffusion, 6 references
[3] doi:10.1162/imag.a.1183 [code]
Learning-based segmentation of diffusion-weighted MR images with arbitrary <i>q</i>-space samplings.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: scikit-image, NiBabel, SciPy, 1 other tool, structural MRI / diffusion, 9 references
[4] doi:10.7554/elife.108408 [code]
Frequency and laminar profile of feature-specific visual activity revealed by interleaved EEG-fMRI.
Journal: eLife
In common: DIPY, Connectome Workbench, ANTs, 6 other tools, 2 references
[5] doi:10.1038/s41467-026-71719-y [code]
Brain functional-structural gradient coupling reflects development, behavior and genetic influences.
Journal: Nature communications
In common: dcm2niix, DIPY, ANTs, 5 other tools, 2 references
[6] doi:10.1016/j.ynirp.2026.100360 [code]
CIVET-Chimp: An automated pipeline for MRI-based cortical surface extraction in chimpanzees.
Journal: Neuroimage. Reports
In common: Connectome Workbench, ANTs, FreeSurfer, 2 other tools, structural MRI / diffusion, 5 references
[7] doi:10.1016/j.crmeth.2026.101473 [code]
AmygdalaGo-BOLT for boundary-aware segmentation of the human amygdala.
Journal: Cell reports methods
In common: Connectome Workbench, ANTs, FreeSurfer, 5 other tools, structural MRI / diffusion, 2 references
[8] doi:10.1162/imag.a.1366 [code]
MICAFlow: Fast and robust MRI preprocessing bridging research neuroimaging and clinical practice.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: DIPY, ANTs, FreeSurfer, 3 other tools, structural MRI / diffusion, 5 references
[9] doi:10.1038/s41598-026-54446-8 [code]
Deep learning-based Desikan-Killiany parcellation of the brain using diffusion MRI.
Journal: Scientific reports
In common: DIPY, FreeSurfer, scikit-image, 3 other tools, structural MRI / diffusion, 4 references
[10] doi:10.1038/s41467-026-71918-7 [code]
Developmental disinhibition gates language lateralization in childhood.
Journal: Nature communications
In common: dcm2niix, ANTs, FreeSurfer, 4 other tools, 3 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.