diff --git a/toolbox/io/import_anatomy_cat.m b/toolbox/io/import_anatomy_cat.m
index f71f1f06a..598fb396f 100644
--- a/toolbox/io/import_anatomy_cat.m
+++ b/toolbox/io/import_anatomy_cat.m
@@ -330,8 +330,8 @@
end
end
-% Left FSAverage
-if ~isempty(FsAvgLhFile)
+% Left FSAverage (only if the spheres are available)
+if ~isempty(FsAvgLhFile) && ~isempty(TessLsphFile)
% Import file
[iAvgLh, BstFsAvgLhFile, nVertOrigAvgL] = import_surfaces(iSubject, FsAvgLhFile, 'GII-WORLD', 0);
BstFsAvgLhFile = BstFsAvgLhFile{1};
@@ -348,8 +348,8 @@
errorMsg = [errorMsg err];
end
end
-% Right FSAverage
-if ~isempty(FsAvgRhFile)
+% Right FSAverage (only if the spheres are available)
+if ~isempty(FsAvgRhFile) && ~isempty(TessRsphFile)
% Import file
[iAvgRh, BstFsAvgRhFile, nVertOrigAvgR] = import_surfaces(iSubject, FsAvgRhFile, 'GII-WORLD', 0);
BstFsAvgRhFile = BstFsAvgRhFile{1};
@@ -367,8 +367,8 @@
end
end
-% Left FSAverage 32k
-if ~isempty(Fs32kLhFile)
+% Left FSAverage 32k (only if the spheres are available)
+if ~isempty(Fs32kLhFile) && ~isempty(TessLsphFile)
% Import file
[i32kLh, BstFs32kLhFile, nVertOrig32kL] = import_surfaces(iSubject, Fs32kLhFile, 'GII-WORLD', 0);
BstFs32kLhFile = BstFs32kLhFile{1};
@@ -385,8 +385,8 @@
errorMsg = [errorMsg err];
end
end
-% Right FSAverage 32k
-if ~isempty(Fs32kRhFile)
+% Right FSAverage 32k (only if the spheres are available)
+if ~isempty(Fs32kRhFile) && ~isempty(TessRsphFile)
% Import file
[i32kRh, BstFs32kRhFile, nVertOrig32kR] = import_surfaces(iSubject, Fs32kRhFile, 'GII-WORLD', 0);
BstFs32kRhFile = BstFs32kRhFile{1};
@@ -417,17 +417,20 @@
%% ===== PROJECT ATLASES =====
rmFiles = {};
-% Project FSAverage atlases
-if ~isempty(FsAvgLhFile) && ~isempty(FsAvgRhFile)
- bst_project_scouts(BstFsAvgLhFile, BstTessLhFile, [], 1);
- bst_project_scouts(BstFsAvgRhFile, BstTessRhFile, [], 1);
- rmFiles = cat(2, rmFiles, {BstFsAvgLhFile, BstFsAvgRhFile});
-end
-% Project FSAverage 32k atlases
-if ~isempty(Fs32kLhFile) && ~isempty(Fs32kRhFile)
- bst_project_scouts(BstFs32kLhFile, BstTessLhFile, [], 1);
- bst_project_scouts(BstFs32kRhFile, BstTessRhFile, [], 1);
- rmFiles = cat(2, rmFiles, {BstFs32kLhFile, BstFs32kRhFile});
+% If the registered spheres are available
+if ~isempty(TessLsphFile) && ~isempty(TessRsphFile)
+ % Project FSAverage atlases
+ if ~isempty(FsAvgLhFile) && ~isempty(FsAvgRhFile)
+ bst_project_scouts(BstFsAvgLhFile, BstTessLhFile, [], 1);
+ bst_project_scouts(BstFsAvgRhFile, BstTessRhFile, [], 1);
+ rmFiles = cat(2, rmFiles, {BstFsAvgLhFile, BstFsAvgRhFile});
+ end
+ % Project FSAverage 32k atlases
+ if ~isempty(Fs32kLhFile) && ~isempty(Fs32kRhFile)
+ bst_project_scouts(BstFs32kLhFile, BstTessLhFile, [], 1);
+ bst_project_scouts(BstFs32kRhFile, BstTessRhFile, [], 1);
+ rmFiles = cat(2, rmFiles, {BstFs32kLhFile, BstFs32kRhFile});
+ end
end
diff --git a/toolbox/process/functions/process_segment_cat12.m b/toolbox/process/functions/process_segment_cat12.m
index c84d47fd8..4ecb7b4d9 100644
--- a/toolbox/process/functions/process_segment_cat12.m
+++ b/toolbox/process/functions/process_segment_cat12.m
@@ -2,7 +2,8 @@
% PROCESS_SEGMENT_CAT12: Run the segmentation of a T1 MRI with SPM12/CAT12.
%
% USAGE: OutputFiles = process_segment_cat12('Run', sProcess, sInputs)
-% [isOk, errMsg] = process_segment_cat12('Compute', iSubject, iAnatomy=[default])
+% [isOk, errMsg] = process_segment_cat12('Compute', iSubject, iAnatomy=[default], nVertices, isSphReg, isExtraMaps, isInteractive)
+% process_segment_cat12('ComputeInteractive', iSubject, iAnatomy)
% @=============================================================================
% This function is part of the Brainstorm software:
@@ -22,7 +23,7 @@
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
-% Authors: Francois Tadel, 2019
+% Authors: Francois Tadel, 2019-2020
eval(macro_method);
end
@@ -49,6 +50,28 @@
sProcess.options.nvertices.Comment = 'Number of vertices (cortex): ';
sProcess.options.nvertices.Type = 'value';
sProcess.options.nvertices.Value = {15000, '', 0};
+ % Option: TPM atlas
+ SelectOptions = {...
+ '', ... % Filename
+ 'Nifti1', ... % FileFormat
+ 'open', ... % Dialog type: {open,save}
+ 'Select TPM atlas...', ... % Window title
+ 'ImportAnat', ... % LastUsedDir: {ImportData,ImportChannel,ImportAnat,ExportChannel,ExportData,ExportAnat,ExportProtocol,ExportImage,ExportScript}
+ 'single', ... % Selection mode: {single,multiple}
+ 'files', ... % Selection mode: {files,dirs,files_and_dirs}
+ {{'.nii','.gz'}, 'MRI: NIfTI-1 (*.nii;*.nii.gz)', 'Nifti1'}, ... % Get all the available file formats
+ 'MriIn'}; % DefaultFormats: {ChannelIn,DataIn,DipolesIn,EventsIn,MriIn,NoiseCovIn,ResultsIn,SspIn,SurfaceIn,TimefreqIn
+ sProcess.options.tpmnii.Comment = 'TPM atlas: ';
+ sProcess.options.tpmnii.Type = 'filename';
+ sProcess.options.tpmnii.Value = SelectOptions;
+ % Option: Spherical registration
+ sProcess.options.sphreg.Comment = 'Use spherical registration
Required for atlases, group analysis and thickness maps';
+ sProcess.options.sphreg.Type = 'checkbox';
+ sProcess.options.sphreg.Value = 1;
+ % Option: Import thickness map
+ sProcess.options.thickness.Comment = 'Import cortical thickness map';
+ sProcess.options.thickness.Type = 'checkbox';
+ sProcess.options.thickness.Value = 0;
end
@@ -67,6 +90,25 @@
bst_report('Error', sProcess, [], 'Invalid number of vertices.');
return
end
+ % Spherical registration?
+ if isfield(sProcess.options, 'sphreg') && isfield(sProcess.options.sphreg, 'Value') && ~isempty(sProcess.options.sphreg.Value)
+ isSphReg = sProcess.options.sphreg.Value;
+ else
+ isSphReg = 1;
+ end
+ % TPM atlas
+ if isfield(sProcess.options, 'tpmnii') && isfield(sProcess.options.tpmnii, 'Value') && ~isempty(sProcess.options.tpmnii.Value) && ~isempty(sProcess.options.tpmnii.Value{1})
+ TpmNii = sProcess.options.tpmnii.Value{1};
+ else
+ TpmNii = bst_get('SpmTpmAtlas');
+ end
+ % Thickness maps
+ if isfield(sProcess.options, 'thickness') && isfield(sProcess.options.thickness, 'Value') && ~isempty(sProcess.options.thickness.Value)
+ isExtraMaps = sProcess.options.thickness.Value;
+ else
+ isExtraMaps = 0;
+ end
+ sProcess.options.thickness.Value
% Get subject name
SubjectName = file_standardize(sProcess.options.subjectname.Value);
if isempty(SubjectName)
@@ -80,7 +122,7 @@
return
end
% Call processing function
- [isOk, errMsg] = Compute(iSubject, [], nVertices, 0);
+ [isOk, errMsg] = Compute(iSubject, [], nVertices, TpmNii, isSphReg, isExtraMaps, 0);
% Handling errors
if ~isOk
bst_report('Error', sProcess, [], errMsg);
@@ -93,7 +135,7 @@
%% ===== COMPUTE CANONICAL SURFACES =====
-function [isOk, errMsg] = Compute(iSubject, iAnatomy, nVertices, isInteractive)
+function [isOk, errMsg] = Compute(iSubject, iAnatomy, nVertices, TpmNii, isSphReg, isExtraMaps, isInteractive)
isOk = 0;
errMsg = '';
% Initialize SPM
@@ -109,10 +151,24 @@
return;
end
% Check DARTEL template
- dartelTpm = bst_fullfile(bst_get('SpmDir'), 'toolbox', 'cat12', 'templates_1.50mm', 'Template_1_IXI555_MNI152.nii');
+ dartelTpm = bst_fullfile(bst_get('SpmDir'), 'toolbox', 'cat12', 'templates_volumes', 'Template_1_IXI555_MNI152.nii');
if ~file_exist(dartelTpm)
- errMsg = ['Missing CAT12 template: ' 10 dartelTpm];
- return;
+ dartelTpm = bst_fullfile(bst_get('SpmDir'), 'toolbox', 'cat12', 'templates_1.50mm', 'Template_1_IXI555_MNI152.nii');
+ if ~file_exist(dartelTpm)
+ errMsg = ['Missing CAT12 template: ' 10 dartelTpm];
+ return;
+ else
+ catVer = 12;
+ end
+ else
+ catVer = 12.7;
+ end
+ % Get default TPM.nii template
+ if isempty(TpmNii)
+ TpmNii = bst_get('SpmTpmAtlas');
+ end
+ if isempty(TpmNii) || ~file_exist(TpmNii)
+ error('Missing file TPM.nii');
end
% ===== GET SUBJECT =====
@@ -192,46 +248,61 @@
end
% ===== CALL CAT12 SEGMENTATION =====
- % Get TPM.nii template
- tpmFile = bst_get('SpmTpmAtlas');
- if isempty(tpmFile) || ~file_exist(tpmFile)
- error('Missing file TPM.nii');
- end
% Create SPM batch
matlabbatch{1}.spm.tools.cat.estwrite.data = {[NiiFile ',1']};
matlabbatch{1}.spm.tools.cat.estwrite.nproc = 0;
- matlabbatch{1}.spm.tools.cat.estwrite.opts.tpm = {tpmFile};
+ matlabbatch{1}.spm.tools.cat.estwrite.opts.tpm = {TpmNii};
matlabbatch{1}.spm.tools.cat.estwrite.opts.affreg = 'mni';
matlabbatch{1}.spm.tools.cat.estwrite.opts.biasstr = 0.5;
- matlabbatch{1}.spm.tools.cat.estwrite.opts.accstr = 0.5;
matlabbatch{1}.spm.tools.cat.estwrite.extopts.APP = 1070;
matlabbatch{1}.spm.tools.cat.estwrite.extopts.LASstr = 0.5;
matlabbatch{1}.spm.tools.cat.estwrite.extopts.gcutstr = 2;
matlabbatch{1}.spm.tools.cat.estwrite.extopts.registration.dartel.darteltpm = {dartelTpm};
matlabbatch{1}.spm.tools.cat.estwrite.extopts.vox = 1.5;
- matlabbatch{1}.spm.tools.cat.estwrite.extopts.restypes.fixed = [1 0.1];
- matlabbatch{1}.spm.tools.cat.estwrite.output.surface = 1;
- matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.neuromorphometrics = 0;
- matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.lpba40 = 0;
- matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.cobra = 0;
- matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.hammers = 0;
- matlabbatch{1}.spm.tools.cat.estwrite.output.GM.native = 1;
- matlabbatch{1}.spm.tools.cat.estwrite.output.GM.mod = 1;
- matlabbatch{1}.spm.tools.cat.estwrite.output.GM.dartel = 0;
- matlabbatch{1}.spm.tools.cat.estwrite.output.WM.native = 1;
- matlabbatch{1}.spm.tools.cat.estwrite.output.WM.mod = 1;
- matlabbatch{1}.spm.tools.cat.estwrite.output.WM.dartel = 0;
matlabbatch{1}.spm.tools.cat.estwrite.output.labelnative = 1;
- matlabbatch{1}.spm.tools.cat.estwrite.output.bias.warped = 1;
matlabbatch{1}.spm.tools.cat.estwrite.output.jacobianwarped = 0;
matlabbatch{1}.spm.tools.cat.estwrite.output.warps = [0 0];
+ % Spherical registration (much slower)
+ if isSphReg
+ matlabbatch{1}.spm.tools.cat.estwrite.output.surface = 1;
+ else
+ matlabbatch{1}.spm.tools.cat.estwrite.output.surface = 5;
+ end
+
+ % Switch depending on CAT12 versions
+ switch (catVer)
+ case 12
+ matlabbatch{1}.spm.tools.cat.estwrite.opts.accstr = 0.5;
+ matlabbatch{1}.spm.tools.cat.estwrite.extopts.restypes.fixed = [1 0.1];
+ matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.neuromorphometrics = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.lpba40 = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.cobra = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.hammers = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.GM.native = 1;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.GM.mod = 1;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.GM.dartel = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.WM.native = 1;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.WM.mod = 1;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.WM.dartel = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.bias.warped = 1;
+ case 12.7
+ matlabbatch{1}.spm.tools.cat.estwrite.extopts.restypes.optimal = [1 0.1];
+ matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.noROI = struct([]);
+ matlabbatch{1}.spm.tools.cat.estwrite.output.GM.native = 1;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.GM.mod = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.GM.dartel = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.WM.native = 1;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.WM.mod = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.WM.dartel = 0;
+ matlabbatch{1}.spm.tools.cat.estwrite.output.bias.warped = 0;
+ end
+
% Run SPM batch
spm_jobman('initcfg');
spm_jobman('run',matlabbatch);
% ===== IMPORT OUTPUT FOLDER =====
% Import CAT12 anatomy folder
- isExtraMaps = 0;
isKeepMri = 1;
errorMsg = import_anatomy_cat(iSubject, catDir, nVertices, isInteractive, [], isExtraMaps, isKeepMri);
if ~isempty(errorMsg)
@@ -251,17 +322,20 @@ function ComputeInteractive(iSubject, iAnatomy) %#ok
if (nargin < 2) || isempty(iAnatomy)
iAnatomy = [];
end
- % Open progress bar
- bst_progress('start', 'CAT12', 'CAT12 MRI segmentation...');
- bst_progress('setimage', 'logo_cat.gif');
% Ask for number of vertices
nVertices = java_dialog('input', 'Number of vertices on the cortex surface:', 'CAT12 segmentation', [], '15000');
if isempty(nVertices)
return
end
nVertices = str2double(nVertices);
- % Compute surfaces
- [isOk, errMsg] = Compute(iSubject, iAnatomy, nVertices, 1);
+ % Open progress bar
+ bst_progress('start', 'CAT12', 'CAT12 MRI segmentation...');
+ bst_progress('setimage', 'logo_cat.gif');
+ % Run CAT12
+ TpmNii = bst_get('SpmTpmAtlas');
+ isSphReg = 1;
+ isExtraMaps = 0;
+ [isOk, errMsg] = Compute(iSubject, iAnatomy, nVertices, TpmNii, isSphReg, isExtraMaps, 1);
% Error handling
if ~isOk
bst_error(errMsg, 'CAT12 MRI segmentation', 0);
diff --git a/toolbox/process/panel_process_select.m b/toolbox/process/panel_process_select.m
index 2bb355921..35957c5d1 100644
--- a/toolbox/process/panel_process_select.m
+++ b/toolbox/process/panel_process_select.m
@@ -2388,7 +2388,7 @@ function LoadPipelineFromFile()
% Create final string
optStr = [', ...' strComment, 10 strIdent '''' optNames{iOpt} ''', ' strPad str_format(optValue, 1, 2)];
% Replace raw filenames and subject names
- if isfield(opt, 'Type') && ismember(opt.Type, {'filename','datafile'}) && iscell(opt.Value)
+ if isfield(opt, 'Type') && ismember(opt.Type, {'filename','datafile'}) && iscell(opt.Value) && ~isempty(RawFiles)
% List of files
if iscell(optValue{1})
for ic = 1:length(optValue{1})
@@ -3017,13 +3017,13 @@ function ParseProcessFolder(isForced) %#ok
if iscell(opt.Value{1})
for ic = 1:length(opt.Value{1})
iFile = find(strcmpi(RawFiles, opt.Value{1}{ic}));
- if isempty(iFile)
+ if isempty(iFile) && ~isempty(opt.Value{1}{ic})
RawFiles{end+1} = opt.Value{1}{ic};
end
end
else
iFile = find(strcmpi(RawFiles, opt.Value{1}));
- if isempty(iFile)
+ if isempty(iFile) && ~isempty(opt.Value{1})
RawFiles{end+1} = opt.Value{1};
end
end