Summary of what happened:
Hey all,
I’m using MATLAB to generate seedmaps from a dtseries by selecting vertices derived from a spherical ROI in the cortex. To do this, I take the spherical ROI nii (in the volume), project it to the surface using -volume-to-surface-mapping (nii to gifti conversion) for both L and R hemispheres, and then combine the two gii files into a cifti output that is used to select relevant vertices for the seedmap.
Generally, this works, but I have been having some issues with a few subject’s midthickness surfaces that cause the conversion from nifti to gifti to fail, resulting in no nonzero vertices despite the ROI intersecting the midthickness when viewed by workbench. The surfaces in both working and nonworking subjects are generally agree with the subjects’ MNI T1w. I’ve attached a screenshot to illustrate how similar a working surface and a nonworking surface are and how the ROI touches both.
Any input on why this may be happening would be greatly appreciated!
Command used (and if a helper script was used, a link to the helper script or the command generated): -volume-to-surface-mapping,
function success = process_cortical_roi(volumepattern, sub, roi_cifti_out, sub_output_dir, ROI_num)
% Converts a single cortical ROI from NIfTI to surface-based GIFTI and then to CIFTI
success = false; % Default to failure
base_dir = '/projects//las/psych/cgra'';
!
workbenchdir = fullfile(base_dir, 'Scripts/workbench3/bin_rh_linux64/');
% Output directories
roi_output_dir = fullfile(sub_output_dir, 'roi_dscalar');
if ~exist(roi_output_dir, 'dir'), mkdir(roi_output_dir); end
% Medial wall masks
medial_mask_L = fullfile(base_dir, 'Scripts/CIFTI_RELATED/Resources/cifti_masks/L.atlasroi.32k_fs_LR.shape.gii');
medial_mask_R = fullfile(base_dir, 'Scripts/CIFTI_RELATED/Resources/cifti_masks/R.atlasroi.32k_fs_LR.shape.gii');
% Surface paths
Lsurface = fullfile(base_dir, sprintf('PD/Nifti/derivatives/defaced_FS73_outputs/FREESURFER_fs_LR_oldfmriprep/sub-%s/MNI/fsaverage_LR32k/sub-%s.L.midthickness.32k_fs_LR.surf.gii', sub, sub));
Rsurface = fullfile(base_dir, sprintf('PD/Nifti/derivatives/defaced_FS73_outputs/FREESURFER_fs_LR_oldfmriprep/sub-%s/MNI/fsaverage_LR32k/sub-%s.R.midthickness.32k_fs_LR.surf.gii', sub, sub));
% Load the full individual ROI NIfTI file
roi_nii = niftiread(volumepattern);
roi_nii_info = niftiinfo(volumepattern);
% Extract only the specified ROI
roi_mask = roi_nii;
roi_mask(roi_nii ~= ROI_num) = 0;
% Convert datatype to match original NIfTI
roi_mask = cast(roi_mask, class(roi_nii));
% Check if the extracted ROI has nonzero voxels
num_roi_voxels = sum(roi_mask(:) > 0);
if num_roi_voxels == 0
warning(' ROI %d has no nonzero voxels. Skipping mapping.', ROI_num);
return;
end
fprintf('ROI %d has %d nonzero voxels. Proceeding with mapping...\n', ROI_num, num_roi_voxels);
% Save temporary NIfTI file
roi_tempfile = fullfile(roi_output_dir, sprintf('%s_S300roi%s.nii.gz', sub, num2str(ROI_num)));
niftiwrite(roi_mask, roi_tempfile, roi_nii_info);
gzip(roi_tempfile);
% Output GIFTI filenames
left_gifti = fullfile(roi_output_dir, sprintf('%s_S300roi%s_L.func.gii', sub, num2str(ROI_num)));
right_gifti = fullfile(roi_output_dir, sprintf('%s_S300roi%s_R.func.gii', sub, num2str(ROI_num)));
% Run surface mapping
system(sprintf('%s/wb_command -volume-to-surface-mapping %s %s %s -enclosing', workbenchdir, roi_tempfile, Lsurface, left_gifti));
system(sprintf('%s/wb_command -volume-to-surface-mapping %s %s %s -enclosing', workbenchdir, roi_tempfile, Rsurface, right_gifti));
% Verify the mapped surface GIFTI files
if isfile(left_gifti)
gifti_L = gifti(left_gifti);
num_L_voxels = sum(gifti_L.cdata(:) > 0);
fprintf('LEFT GIFTI CHECK: %d nonzero vertices in %s\n', num_L_voxels, left_gifti);
else
warning(' LEFT GIFTI FILE MISSING: %s', left_gifti);
return;
end
if isfile(right_gifti)
gifti_R = gifti(right_gifti);
num_R_voxels = sum(gifti_R.cdata(:) > 0);
fprintf('RIGHT GIFTI CHECK: %d nonzero vertices in %s\n', num_R_voxels, right_gifti);
else
warning(' RIGHT GIFTI FILE MISSING: %s', right_gifti);
return;
end
% If no nonzero vertices, skip CIFTI conversion
if num_L_voxels == 0 && num_R_voxels == 0
warning(' No nonzero vertices for ROI %s. Skipping CIFTI conversion.', num2str(ROI_num));
return;
end
% Apply Medial Wall Masking before final conversion
left_gifti_masked = fullfile(roi_output_dir, sprintf('%s_S300roi%s_L_masked.func.gii', sub, num2str(ROI_num)));
right_gifti_masked = fullfile(roi_output_dir, sprintf('%s_S300roi%s_R_masked.func.gii', sub, num2str(ROI_num)));
system(sprintf('%s/wb_command -metric-mask %s %s %s', workbenchdir, left_gifti, medial_mask_L, left_gifti_masked));
system(sprintf('%s/wb_command -metric-mask %s %s %s', workbenchdir, right_gifti, medial_mask_R, right_gifti_masked));
% Combine into CIFTI
system(sprintf('%s/wb_command -cifti-create-dense-scalar %s -left-metric %s -roi-left %s -right-metric %s -roi-right %s', ...
workbenchdir, roi_cifti_out, left_gifti_masked, medial_mask_L, right_gifti_masked, medial_mask_R));
fprintf(' Cortical ROI CIFTI created: %s\n', roi_cifti_out);
% If the function reaches here, return success
success = true;
end
Version:
MATLAB 2024a, Workbench 1.4.2
Environment (Docker, Singularity / Apptainer, custom installation):
Data formatted according to a validatable standard? Please provide the output of the validator:
PASTE VALIDATOR OUTPUT HERE
Relevant log outputs (up to 20 lines):
Processing subject PM20001...
catData truncated to 9000 time points (120 minutes of scan time).
Processing cortical ROI 039... ROI 39 has 69 nonzero voxels. Proceeding with mapping...
LEFT GIFTI CHECK: 0 nonzero vertices in /projects/illinois/las/psych/cgra/member_directories/jchernicky/seedmap_from_roi_nii/pleasework/PM20001/roi_dscalar/PM20001_S300roi39_L.func.gii
RIGHT GIFTI CHECK: 0 nonzero vertices in /projects/illinois/las/psych/cgra/member_directories/jchernicky/seedmap_from_roi_nii/pleasework/PM20001/roi_dscalar/PM20001_S300roi39_R.func.gii
Warning: No nonzero vertices for ROI 39. Skipping CIFTI
conversion.
> In test>process_cortical_roi (line 170)
In test (line 80)
Processing subject PM24026...
catData truncated to 9000 time points (120 minutes of scan time).
Processing cortical ROI 039...
ROI 39 has 69 nonzero voxels. Proceeding with mapping...
LEFT GIFTI CHECK: 0 nonzero vertices in /projects/illinois/las/psych/cgra/member_directories/jchernicky/seedmap_from_roi_nii/pleasework/PM24026/roi_dscalar/PM24026_S300roi39_L.func.gii
RIGHT GIFTI CHECK: 67 nonzero vertices in /projects//las/psych/cgra/member_directories/jchernicky/seedmap_from_roi_nii/pleasework/PM24026/roi_dscalar/PM24026_S300roi39_R.func.gii
Screenshots / relevant information:
CleanShot 2025-03-11 at 12.43.21@2x|690x245!