Skip to content

Instantly share code, notes, and snippets.

@mikbuch
Last active December 14, 2022 20:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikbuch/fb28aef0f77c7c7aeeff92a61b109d16 to your computer and use it in GitHub Desktop.
Save mikbuch/fb28aef0f77c7c7aeeff92a61b109d16 to your computer and use it in GitHub Desktop.
import argparse
import re
import subprocess as sp
'''
Script to automatize mapping neuroimaging data from volumes (NIfTI) to brain
surface (workbench).
Edit data: 2021-04-28
Author: Mikolaj Buchwald, mikolaj.buchwald@gmail.com
Affiliation: Adam Mickiewicz University in Poznań, Poland
This scirpt takes a *.nii.gz file and maps results from this file to workbench
surface.
### Download
curl https://gist.githubusercontent.com/mikbuch/fb28aef0f77c7c7aeeff92a61b109d16/raw/84ae6f3afe30f98ae37b81ebb5765dff1e4ea5f6/workbench_volume_to_surface.py -o workbench_volume_to_surface.py
### Example
Usage:
The ouptut filename is generated based on the input file and some postfixes,
hence you don't have to specify.
You pass the arguments in the following manner:
python workbench_volume_to_surface.py \
--in_nifti thresh_zstat.nii.gz \
--in_left_surf /Applications/workbench/HCP_S1200_GroupAvg_v1/S1200.L.midthickness_MSMAll.32k_fs_LR.surf.gii \
--in_right_surf /Applications/workbench/HCP_S1200_GroupAvg_v1/S1200.R.midthickness_MSMAll.32k_fs_LR.surf.gii
For this command the following output files will be created:
* thresh_zstat_hemi-L_.func.gii
* thresh_zstat_hemi-R_.func.gii
* thresh_zstat_upper-X_.info -- explained below
The underscore before the extentions was put there on purpose -- for easier
reading of the filename.
Additionally, an empty file with information on the upper bound (highest value)
of the NIfTI file will be created, e.g., Z-max value, e.g.:
* thresh_zstat_hemi_upper-6.45_.info
The underscore before the extentions was put there on purpose -- for easier
reading of the filename/upper value.
In order to run in debugging mode (no files will be generated), use
the following command:
python workbench_volume_to_surface.py \
--in_nifti thresh_zstat.nii.gz \
--in_left_surf /Applications/workbench/HCP_S1200_GroupAvg_v1/S1200.L.midthickness_MSMAll.32k_fs_LR.surf.gii \
--in_right_surf /Applications/workbench/HCP_S1200_GroupAvg_v1/S1200.R.midthickness_MSMAll.32k_fs_LR.surf.gii \
--debug
This script is available as public gists here:
https://gist.github.com/mikbuch/fb28aef0f77c7c7aeeff92a61b109d16
'''
parser = argparse.ArgumentParser(description='Volume to surface mapping \
in Workbench')
parser.add_argument('--in_nifti', '-n',
help="Input NIfTI file")
parser.add_argument('--in_left_surf', '-l',
help="Input left hemishphere surface.")
parser.add_argument('--in_right_surf', '-r',
help="Input right hemishphere surface.")
parser.add_argument('--debug',
action='store_true',
help='Use debugging mode, no files will be created.')
args = parser.parse_args()
hemispheres = [{'code': 'L', 'surface': args.in_left_surf},
{'code': 'R', 'surface': args.in_right_surf}]
for hemi in hemispheres:
###########################################################################
#
# Surface file
#
out_surf_file = re.sub('.nii.gz',
'_hemi-%s_.func.gii' % hemi['code'],
args.in_nifti)
cmd = 'wb_command -volume-to-surface-mapping %s %s %s ' \
'-trilinear' % (args.in_nifti, hemi['surface'], out_surf_file)
print('\n\n' + cmd + '\n')
if not args.debug:
process = sp.Popen(cmd, stdout=sp.PIPE, shell=True)
output = process.communicate()[0]
else:
print(' --- Debugging mode: Surface ---')
###########################################################################
#
# Info file
#
out_info_file = re.sub('.nii.gz', '_upper-%.2f_.info', args.in_nifti)
# Get highest value for info file.
cmd = 'fslstats %s -R' % (args.in_nifti)
if not args.debug:
print('\n\n' + cmd + '\n')
process = sp.Popen(cmd, stdout=sp.PIPE, shell=True)
output = process.communicate()[0]
print(output)
hi_value = float(str(output).split(' ')[1])
with open(out_info_file % hi_value, 'w') as f:
f.write('')
else:
print(' --- Debugging mode: Info ---')
print('\n\n Info file written as:\n' + out_info_file + '\n')
@ForoughAhmadi
Copy link

Hi Mikolaj!
I am using yous codes for dHCP data and getting this error:

While running:
wb_command -volume-to-surface-mapping None None None -trilinear

ERROR: NAME OF FILE: None

File does not exist.

Would you please help me to fix this error?
I don't know the reason of the input argument convertion to None type.

Best regards,
Forough

@mikbuch
Copy link
Author

mikbuch commented Dec 12, 2022

Hi Forough, what is the file name of the volume you are trying to map to a surface?

I mean, e.g.: "thresh_zstat1.nii.gz"

@ForoughAhmadi
Copy link

Hi
I am using bold.nii data and also these lines before your code for masking

path_bold = r'D:\data\sub-CC00060XX03_ses-12501_task-rest_desc-preproc_bold.nii'
path_mask = r'D:\data\sub-CC00060XX03_ses-12501_task-rest_desc-preproc_space-bold_brainmask.nii'

bold = nib.load(path_bold)
mask = nib.load(path_mask)

brain_masker = NiftiMasker(mask_img=mask, standardize=True,t_r=0.392)
brain_ts =np.array(brain_masker.fit_transform(bold))

new_image = brain_masker.inverse_transform(brain_ts)

func_file = new_image
surfacemidthick1 = r'D:\data\sub-CC00060XX03_ses-12501_hemi-L_space-T2w_midthickness.surf.gii'
surfacemidthick2 = r'D:\data\sub-CC00060XX03_ses-12501_hemi-R_space-T2w_midthickness.surf.gii'
#label_out = 'D:\data\sub-CC00060XX03_ses-12501_hemi-L_space-T2w_midthickness.func.gii'

parser = argparse.ArgumentParser(description='Volume to surface mapping
in Workbench')

parser.add_argument('--func_file', '-n',
help="Input NIfTI file")
parser.add_argument('--surfacemidthick1', '-l',
help="Input left hemishphere surface.")
parser.add_argument('--surfacemidthick2', '-r',
help="Input right hemishphere surface.")
parser.add_argument('--debug',
action='store_true',
help='Use debugging mode, no files will be created.')

args = parser.parse_args()

hemispheres = [{'code': 'L', 'surface': args.surfacemidthick1},
{'code': 'R', 'surface': args.surfacemidthick2}]

for hemi in hemispheres:

###########################################################################
#
#                               Surface file
#
out_surf_file = re.sub('.nii',
                       '_hemi-%s_.func.gii' % hemi['code'],
                        str(args.func_file))

cmd = 'wb_command -volume-to-surface-mapping %s %s %s ' \
      '-trilinear' % (args.func_file, hemi['surface'], out_surf_file)

@mikbuch
Copy link
Author

mikbuch commented Dec 12, 2022

Hi, my code is intended for command line use (i.e., in the bash). If you wish to use it in a script (specify paths, etc. in the Python script), you have to get rid of the parser part, and use your variable names, e.g.:

path_bold = r'D:\data\sub-CC00060XX03_ses-12501_task-rest_desc-preproc_bold.nii'
path_mask = r'D:\data\sub-CC00060XX03_ses-12501_task-rest_desc-preproc_space-bold_brainmask.nii'

bold = nib.load(path_bold)
mask = nib.load(path_mask)

brain_masker = NiftiMasker(mask_img=mask, standardize=True,t_r=0.392)
brain_ts =np.array(brain_masker.fit_transform(bold))

new_image = brain_masker.inverse_transform(brain_ts)

func_file = new_image
surfacemidthick1 = r'D:\data\sub-CC00060XX03_ses-12501_hemi-L_space-T2w_midthickness.surf.gii'
surfacemidthick2 = r'D:\data\sub-CC00060XX03_ses-12501_hemi-R_space-T2w_midthickness.surf.gii'
#label_out = 'D:\data\sub-CC00060XX03_ses-12501_hemi-L_space-T2w_midthickness.func.gii'

##############
# Left hemisphere

out_surf_file = re.sub('.nii',
                       '_hemi-l_.func.gii',
                       func_file)

cmd = 'wb_command -volume-to-surface-mapping %s %s %s ' \
      '-trilinear' % (func_file, surfacemidthick1, out_surf_file)

process = sp.Popen(cmd, stdout=sp.PIPE, shell=True)
output = process.communicate()[0]

###############
# Right hemisphere

out_surf_file = re.sub('.nii',
                       '_hemi-r_.func.gii',
                       func_file)

cmd = 'wb_command -volume-to-surface-mapping %s %s %s ' \
      '-trilinear' % (func_file, surfacemidthick2, out_surf_file)

process = sp.Popen(cmd, stdout=sp.PIPE, shell=True)
output = process.communicate()[0]

@ForoughAhmadi
Copy link

OH! You're right.
I am new in this field and facing many challenges in this way.
Thank you for your explanation and guidance.

@mikbuch
Copy link
Author

mikbuch commented Dec 14, 2022

No problem, everybody started at some point.

Good luck with your research!

@ForoughAhmadi
Copy link

I appreciate it, Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment