Skip to content

Commit

Permalink
CAT12: Updated version 12.7 + additional options
Browse files Browse the repository at this point in the history
  • Loading branch information
ftadel committed May 14, 2020
1 parent a78bff0 commit 1d91b3e
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 55 deletions.
41 changes: 22 additions & 19 deletions toolbox/io/import_anatomy_cat.m
Expand Up @@ -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};
Expand All @@ -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};
Expand All @@ -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};
Expand All @@ -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};
Expand Down Expand Up @@ -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


Expand Down
140 changes: 107 additions & 33 deletions toolbox/process/functions/process_segment_cat12.m
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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<BR><I>Required for atlases, group analysis and thickness maps</I>';
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


Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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 =====
Expand Down Expand Up @@ -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)
Expand All @@ -251,17 +322,20 @@ function ComputeInteractive(iSubject, iAnatomy) %#ok<DEFNU>
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);
Expand Down
6 changes: 3 additions & 3 deletions toolbox/process/panel_process_select.m
Expand Up @@ -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})
Expand Down Expand Up @@ -3017,13 +3017,13 @@ function ParseProcessFolder(isForced) %#ok<DEFNU>
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
Expand Down

0 comments on commit 1d91b3e

Please sign in to comment.