function varargout = process_segment_cat12( varargin )
% 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], nVertices, isSphReg, isExtraMaps, isInteractive)
%                          process_segment_cat12('ComputeInteractive', iSubject, iAnatomy)

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2019-2023

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription() %#ok<DEFNU>
    % Description the process
    sProcess.Comment     = 'Segment MRI with CAT12';
    sProcess.Category    = 'Custom';
    sProcess.SubGroup    = {'Import', 'Import anatomy'};
    sProcess.Index       = 31;
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/Tutorials/SegCAT12';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'import'};
    sProcess.OutputTypes = {'import'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 0;
    % Option: Subject name
    sProcess.options.subjectname.Comment = 'Subject name:';
    sProcess.options.subjectname.Type    = 'subjectname';
    sProcess.options.subjectname.Value   = '';
    % Option: Number of vertices
    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: Volume atlases
    sProcess.options.vol.Comment = 'Compute volume parcellations';
    sProcess.options.vol.Type    = 'checkbox';
    sProcess.options.vol.Value   = 1;
    % Option: Import extra map
    sProcess.options.extramaps.Comment = 'Import additional cortical maps
Cortical thickness, gyrification index, sulcal depth';
    sProcess.options.extramaps.Type    = 'checkbox';
    sProcess.options.extramaps.Value   = 0;
    % Option: Compute cerebellum surfaces
    sProcess.options.cerebellum.Comment = 'Compute cerebellum surfaces [Experimental]';
    sProcess.options.cerebellum.Type    = 'checkbox';
    sProcess.options.cerebellum.Value   = 0;
    sProcess.options.cerebellum.Hidden  = 1;
end

%% ===== FORMAT COMMENT =====
function Comment = FormatComment(sProcess) %#ok<DEFNU>
    Comment = sProcess.Comment;
end

%% ===== RUN =====
function OutputFiles = Run(sProcess, sInputs) %#ok<DEFNU>
    OutputFiles = {};
    % Number of vertices
    nVertices = sProcess.options.nvertices.Value{1};
    if isempty(nVertices) || (nVertices < 50)
        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
    % Volume atlases?
    if isfield(sProcess.options, 'vol') && isfield(sProcess.options.vol, 'Value') && ~isempty(sProcess.options.vol.Value)
        isVolumeAtlases = sProcess.options.vol.Value;
    else
        isVolumeAtlases = 0;
    end
    % Cerebellum?
    if isfield(sProcess.options, 'cerebellum') && isfield(sProcess.options.cerebellum, 'Value') && ~isempty(sProcess.options.cerebellum.Value)
        isCerebellum = sProcess.options.cerebellum.Value;
    else
        isCerebellum = 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, 'extramaps') && isfield(sProcess.options.extramaps, 'Value') && ~isempty(sProcess.options.extramaps.Value)
        isExtraMaps = sProcess.options.extramaps.Value;
    else
        isExtraMaps = 0;
    end
    % Get subject name
    SubjectName = file_standardize(sProcess.options.subjectname.Value);
    if isempty(SubjectName)
        bst_report('Error', sProcess, [], 'Subject name is empty.');
        return;
    end
    % Get subject
    [sSubject, iSubject] = bst_get('Subject', SubjectName);
    if isempty(iSubject)
        bst_report('Error', sProcess, [], ['Subject "' SubjectName '" does not exist.']);
        return
    end
    % Call processing function
    [isOk, errMsg] = Compute(iSubject, [], nVertices, 0, TpmNii, isSphReg, isVolumeAtlases, isExtraMaps, isCerebellum);
    % Handling errors
    if ~isOk
        bst_report('Error', sProcess, [], errMsg);
    elseif ~isempty(errMsg)
        bst_report('Warning', sProcess, [], errMsg);
    end
    % Return an empty structure
    OutputFiles = {'import'};
end

%% ===== COMPUTE CAT12 SEGMENTATION =====
function [isOk, errMsg] = Compute(iSubject, iAnatomy, nVertices, isInteractive, TpmNii, isSphReg, isVolumeAtlases, isExtraMaps, isCerebellum)
    errMsg = '';
    isOk = 0;
    % Initialize SPM12+CAT12
    [isInstalled, errMsg, PlugCat] = bst_plugin('Install', 'cat12', isInteractive, 1728);
    if ~isInstalled
        return;
    end
    bst_plugin('SetProgressLogo', 'cat12');
    % Check if SPM is in the path
    if ~exist('spm_jobman', 'file')
        errMsg = 'SPM must be in the Matlab path to use this feature.';
        return;
    end
    % Check if CAT12 is in the path
    if ~exist('cat12', 'file')
        errMsg = 'SPM subfolders must be in the Matlab path to use this feature (missing: spm12/toolbox/cat12).';
        return;
    end
    % Check CAT version
    [catName, catVer] = cat_version;
    if isempty(catVer)
        errMsg = 'Cannot identify CAT12 version: please re-install it.';
        return;
    end
    catVer = str2num(catVer);
    if (catVer < 1728)
        errMsg = [...
            'Please update CAT12.' 10 ...
            ' - Version of CAT installed on this computer: ' num2str(catVer) 10 ...
            ' - Minimum version of CAT supported by Brainstorm: 1728' 10 ...
            ' - http://www.neuro.uni-jena.de/cat/index.html#DOWNLOAD'];
        return;
    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 =====
    % Get subject
    [sSubject, iSubject] = bst_get('Subject', iSubject);
    if isempty(sSubject)
        errMsg = 'Subject does not exist.';
        return
    end
    % Check if a MRI is available for the subject
    if isempty(sSubject.Anatomy)
        errMsg = ['No MRI available for subject "' sSubject.Name '".'];
        return
    end
    % Get default MRI if not specified
    if isempty(iAnatomy)
        iAnatomy = sSubject.iAnatomy;
    end

    % ===== DELETE EXISTING SURFACES =====
    % Confirm with user that the existing surfaces will be removed
    if isInteractive && ~isempty(sSubject.Surface)
        isDel = java_dialog('confirm', ['Warning: There are already surfaces in this subject.' 10 ...
            'Running CAT12 will remove all the existing surfaces.' 10 10 ...
            'Delete the existing files?' 10 10], 'CAT12 segmentation');
        if ~isDel
            errMsg = 'Process aborted by user.';
            return;
        end
    end

    % ===== VERIFY FIDUCIALS IN MRI =====
    % Load MRI file
    T1FileBst = sSubject.Anatomy(iAnatomy).FileName;
    sMri = in_mri_bst(T1FileBst);
    % If the SCS transformation is not defined: compute MNI transformation to get a default one
    if isempty(sMri) || ~isfield(sMri, 'SCS') || ~isfield(sMri.SCS, 'NAS') || ~isfield(sMri.SCS, 'LPA') || ~isfield(sMri.SCS, 'RPA') || (length(sMri.SCS.NAS)~=3) || (length(sMri.SCS.LPA)~=3) || (length(sMri.SCS.RPA)~=3) || ~isfield(sMri.SCS, 'R') || isempty(sMri.SCS.R) || ~isfield(sMri.SCS, 'T') || isempty(sMri.SCS.T)
        % Issue warning
        errMsg = 'Missing NAS/LPA/RPA: Computing the MNI normalization to get default positions.';
        % Compute MNI normalization
        [sMri, errNorm] = bst_normalize_mni(T1FileBst);
        % Handle errors
        if ~isempty(errNorm)
            errMsg = [errMsg 10 'Error trying to compute the MNI normalization: ' 10 errNorm 10 ...
                'Missing fiducials: the surfaces cannot be aligned with the MRI.'];
        end
    end
    % A vox2ras matrix must be present in the MRI for running CAT12
    sMri = mri_add_world(T1FileBst, sMri);

    % ===== SAVE MRI AS NII =====
    bst_progress('text', 'Saving temporary files...');
    % Create temporay folder for CAT12 output
    TmpDir = bst_get('BrainstormTmpDir', 0, 'cat12');
    % Save MRI in .nii format
    subjid = strrep(sSubject.Name, '@', '');
    NiiFile = bst_fullfile(TmpDir, [subjid, '.nii']);
    out_mri_nii(sMri, NiiFile);
    % If a "world transformation" was not available in the MRI in the database, it was set to a default when saving to .nii
    % Let's reload this file to get the transformation matrix, it will be used when importing the results
    if ~isfield(sMri, 'InitTransf') || isempty(sMri.InitTransf) || isempty(find(strcmpi(sMri.InitTransf(:,1), 'vox2ras')))
        % Load again the file, with the default vox2ras transformation
        [tmp, vox2ras] = in_mri_nii(NiiFile, 0, 0, 0);
        % Prepare the history of transformations
        if ~isfield(sMri, 'InitTransf') || isempty(sMri.InitTransf)
            sMri.InitTransf = cell(0,2);
        end
        % Add this transformation in the MRI
        sMri.InitTransf(end+1,[1 2]) = {'vox2ras', vox2ras};
        % Save modification on hard drive
        bst_save(file_fullpath(T1FileBst), sMri, 'v7');
    end

    % ===== INITIALIZE SPM+CAT =====
    % Switch to CAT12 expert mode
    cat12('expert');
    % Hide CAT12 figures
    set([findall(0, 'Type', 'Figure', 'Tag', 'Interactive'), ...
         findall(0, 'Type', 'Figure', 'Tag', 'CAT'), ...
         findall(0, 'Type', 'Figure', 'Tag', 'Graphics')], 'Visible', 'off');
    % Initialize SPM job manager
    spm_jobman('initcfg');

    % ===== CALL CAT12 SEGMENTATION =====
    bst_progress('text', 'Starting SPM batch...    (see command window)');
    % Create SPM batch
    matlabbatch{1}.spm.tools.cat.estwrite.data = {NiiFile};
    matlabbatch{1}.spm.tools.cat.estwrite.nproc = 0;                % Blocking call to CAT12
    matlabbatch{1}.spm.tools.cat.estwrite.opts.tpm = {TpmNii};      % User-defined TPM atlas
    matlabbatch{1}.spm.tools.cat.estwrite.output.bias.warped = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.GM.native   = 1;   % GM tissue maps
    matlabbatch{1}.spm.tools.cat.estwrite.output.GM.warped   = 0;
    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;   % WM tissue maps
    matlabbatch{1}.spm.tools.cat.estwrite.output.WM.warped   = 0;
    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.TPMC.native = 1;   % Tissue classes 4-6 to create own TPMs
    matlabbatch{1}.spm.tools.cat.estwrite.output.TPMC.warped = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.TPMC.mod    = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.TPMC.dartel = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.CSF.native  = 1;   % CSF tissue maps
    matlabbatch{1}.spm.tools.cat.estwrite.output.CSF.warped  = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.CSF.mod     = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.CSF.dartel  = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.label.native = 1;  % Label: background=0, CSF=1, GM=2, WM=3, WMH=4
    matlabbatch{1}.spm.tools.cat.estwrite.output.label.warped = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.label.dartel = 0;
    matlabbatch{1}.spm.tools.cat.estwrite.output.labelnative = 1;  % Confirmed useful by CGaser in CAT12.8
    % CAT12.8 now saves everything in ICBM152NLinAsym09 space: we can use directly the MNI deformation fields
    matlabbatch{1}.spm.tools.cat.estwrite.output.warps = [1 1];  % Non-linear MNI normalization deformation fields: [forward inverse]
    % Volume atlases
    if isVolumeAtlases
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.neuromorphometrics = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.lpba40             = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.cobra              = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.aal3               = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.anatomy3           = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.ibsr               = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.julichbrain        = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.hammers            = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.mori               = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.thalamus           = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.Schaefer2018_100Parcels_17Networks_order = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.Schaefer2018_200Parcels_17Networks_order = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.Schaefer2018_400Parcels_17Networks_order = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.Schaefer2018_600Parcels_17Networks_order = 1;
        matlabbatch{1}.spm.tools.cat.estwrite.output.atlas.native = 1;  % Save atlases in native space
        matlabbatch{1}.spm.tools.cat.estwrite.output.atlas.warped = 0;
        matlabbatch{1}.spm.tools.cat.estwrite.output.atlas.dartel = 0;
    else
        % No ROIs
        matlabbatch{1}.spm.tools.cat.estwrite.output.ROImenu.noROI = struct([]);   % CGaser comment: Correct syntax to disable ROI processing for volumes
        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;
    end
    % Spherical registration (much slower)
    if isSphReg && ~isCerebellum    % CGaser comment: Cerebellum extraction is experimental, not to be used routinely
        matlabbatch{1}.spm.tools.cat.estwrite.output.surface = 1;   % 1: lh+rh
    elseif isSphReg && isCerebellum
        matlabbatch{1}.spm.tools.cat.estwrite.output.surface = 2;   % 2: lh+rh+cerebellum
    elseif ~isSphReg && ~isCerebellum
        matlabbatch{1}.spm.tools.cat.estwrite.output.surface = 5;   % 5: lh+rh (fast, no registration, quick review only)
    elseif ~isSphReg && isCerebellum
        matlabbatch{1}.spm.tools.cat.estwrite.output.surface = 6;   % 6: lh+rh+cerebellum  (fast, no registration, quick review only)
    end
    % Extract additional surface parameters: Cortical thickness, Gyrification index, Sulcal depth (can't be imported for default anatomy)
    if isExtraMaps && (iSubject > 0)
        matlabbatch{1}.spm.tools.cat.estwrite.output.surf_measures = 1;  % Thickness maps
        % Separate SPM process (second element in the batch)
        matlabbatch{2}.spm.tools.cat.stools.surfextract.data_surf(1) = cfg_dep('CAT12: Segmentation (current release): Left Central Surface', substruct('.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}), substruct('()',{1}, '.','lhcentral', '()',{':'}));
        matlabbatch{2}.spm.tools.cat.stools.surfextract.GI = 1;     % Gyrification index
        matlabbatch{2}.spm.tools.cat.stools.surfextract.SD = 1;     % Sulcal depth
        matlabbatch{2}.spm.tools.cat.stools.surfextract.nproc = 0;  % Blocking call to CAT12
    end

    % Run batch
    spm_jobman('run',matlabbatch);
    % Close CAT12 figures
    close([findall(0, 'Type', 'Figure', 'Tag', 'Interactive'), ...
           findall(0, 'Type', 'Figure', 'Tag', 'CAT')]);

    % ===== PROJECT ATLASES =====
    TessLhFile = file_find(TmpDir, 'lh.central.*.gii', 2);
    if exist('cat_surf_map_atlas', 'file') && file_exist(TessLhFile)
        % Get CAT12 dir
        CatDir = bst_fullfile(PlugCat.Path, PlugCat.SubFolder);
        % List of parcellations to project
        AnnotLhFiles = file_find(bst_fullfile(CatDir, 'atlases_surfaces'), 'lh.*.annot', 2, 0);
        % Import atlases (cat_surf_map_atlas calls both hemispheres at once)
        for iAnnot = 1:length(AnnotLhFiles)
            [fAnnotPath, fAnnotName] = bst_fileparts(AnnotLhFiles{iAnnot});
            bst_progress('text', ['Interpolating atlas: ' fAnnotName '...']);
            cat_surf_map_atlas(TessLhFile, AnnotLhFiles{iAnnot});
        end
    end

    % ===== IMPORT OUTPUT FOLDER =====
    % Import CAT12 anatomy folder
    isKeepMri = 1;
    errMsg = import_anatomy_cat(iSubject, TmpDir, nVertices, 0, [], isExtraMaps, isKeepMri);
    if ~isempty(errMsg)
        return;
    end
    % Delete temporary folder
    file_delete(TmpDir, 1, 1);
    % Remove logo
    bst_plugin('SetProgressLogo', []);
    % Return success
    isOk = 1;
end

%% ===== COMPUTE/INTERACTIVE =====
function ComputeInteractive(iSubject, iAnatomy) %#ok<DEFNU>
    % Get inputs
    if (nargin < 2) || isempty(iAnatomy)
        iAnatomy = [];
    end
    % 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);
    % Ask for volume atlases
    [isVolumeAtlases, isCancel] = java_dialog('confirm', ['Compute anatomical parcellations?' 10 10 ...
        ' - AAL3', 10 ...
        ' - Anatomy v3', 10 ...
        ' - CoBrALab' 10 ...
        ' - Hammers' 10 ...
        ' - IBSR', 10 ...
        ' - JulichBrain v2', 10 ...
        ' - LPBA40' 10 ...
        ' - Mori', 10 ...
        ' - Neuromorphometrics' 10 ...
        ' - Schaefer2018', 10 10], 'CAT12 MRI segmentation');
    if isCancel
        return
    end
    % Ask for cortical maps (not for default anatomy)
    if (iSubject > 0)
        [isExtraMaps, isCancel] = java_dialog('confirm', ['Compute cortical maps?' 10 10 ...
            ' - Cortical thickness', 10 ...
            ' - Gyrification index', 10 ...
            ' - Sulcal depth', 10 10], 'CAT12 MRI segmentation');
        if isCancel
            return
        end
    else
        isExtraMaps = 0;
    end
    % Open progress bar
    bst_progress('start', 'CAT12', 'CAT12 MRI segmentation...');
    % Run CAT12
    TpmNii = bst_get('SpmTpmAtlas');
    isInteractive = 1;
    isSphReg = 1;
    isCerebellum = 0;
    [isOk, errMsg] = Compute(iSubject, iAnatomy, nVertices, isInteractive, TpmNii, isSphReg, isVolumeAtlases, isExtraMaps, isCerebellum);
    % Error handling
    if ~isOk
        bst_error(errMsg, 'CAT12 MRI segmentation', 0);
    elseif ~isempty(errMsg)
        java_dialog('msgbox', ['Warning: ' errMsg]);
    end
    % Close progress bar
    bst_progress('stop');
end


function view = roiLoadHdf5(view, select, clr)
% got rid of absPathFlag,defaultPathFlag
%
% view = roiLoadHdf5(view,  [select], [color])

%% Analagous to old getROIfilename.m

global MRFILES;

pathStr=['/', view.subdir, '/ROIs'];
MRFILES = mrFilesSet(MRFILES, 'path', pathStr);

groups = mrFilesGet(MRFILES, 'groups');
% there should be no datasets here
datasets = mrFilesGet(MRFILES, 'datasets');

if ~isempty(datasets)
    error('mrFiles:roiLoadHdf5:Malformed', ...
              ['found dataset under' pathStr]);
end

if isempty(groups)
  myErrorDlg('No ROIs found')
end

roi_offset = length(pathStr)+2;
group_names = {};
for i = 1:length(groups)
    group_names = {group_names{:}, groups{i}(roi_offset:end)};
end

% right now we just return the max / most recent ROI from each group.  we
% should offer a full range!
[sel,ok] = listdlg('PromptString','Select an ROI',...
       'SelectionMode','multiple',...
       'ListString',group_names);

if ok
    groups = groups(sel);
    group_names = group_names(sel);
else
    groups = {};
    group_names = {};
end

%% Analagous to loadROI.m
if ~exist('select', 'var'),            select=1;           end

for i=1:length(groups)
    % This is a little inefficient, but not so bad
    MRFILES = mrFilesSet(MRFILES, 'path', groups{i});

    MRFILES = mrfPos(MRFILES, 'max');

    disp(['loading ', groups{i}]);
    thisROI = mrfLoadHdf5(MRFILES, 'coords');

    thisROI.name = group_names{i};

    % SHOULD THIS BE DONE?
    % this is guaranteed by the fact that we're using view.subdir
    % using view.subdir directly might even be better, but I'm guessing
    % these things are separate for a reason...
    thisROI.viewType = view.viewType;

    % Check color is set well
    if exist('clr','var') % from the function call
        thisROI.ROI.color=clr;
    end
    if ~isfield(thisROI,'color')
        thisROI.color='b';
    end

    view = addROI(view,thisROI,select);
end

disp('Done loading');


function callBoxDeleteCallback(rectangle,evt)

% Only do anything if the face was selected, not the markers
if ~strcmp(evt.SelectedPart, 'face')
    return
end

hObject = get(rectangle,'Parent');
handles = guidata(hObject);
clicked_tag = str2double(get(rectangle, 'Tag'));

switch  evt.SelectionType
    case 'right' % delete if right click
        handles.data.calls(clicked_tag,:) = [];
        SortCalls(hObject, [], handles, 'time', 0, clicked_tag - 1);
    case 'left' % Make it the current call if left clicked
        if clicked_tag ~= handles.data.currentcall
            handles.data.currentcall = clicked_tag;
            update_fig(hObject, [], handles)
        end
    case {'ctrl', 'double'}
        choosedialog(rectangle,handles);
end
end

function choosedialog(rectangle,handles)

hObject = handles.figure1;
axes_position = get(handles.focusWindow, 'Position');

axes_x_lim = xlim(handles.focusWindow);
axes_y_lim = ylim(handles.focusWindow);
position = get(rectangle, 'Position');
tag = get(rectangle, 'Tag');

dialog_width = 354;
dialog_heigth = 154;

rect_x_relative_to_axes = (position(1) + position(3) - axes_x_lim(1)) / (axes_x_lim(2) - axes_x_lim(1));
rect_y_relative_to_axes = (position(2) + position(4) - axes_y_lim(1)) / (axes_y_lim(2) - axes_y_lim(1));

set(hObject,'Units','Pixels');
fig_pos = get(hObject, 'Position');

x_position = fig_pos(1) + fig_pos(3) * (axes_position(1) + axes_position(3)*rect_x_relative_to_axes);
y_position = fig_pos(2) + fig_pos(4) * (axes_position(2) + axes_position(4)*rect_y_relative_to_axes) - dialog_heigth;

%Make sure the dialog stays within the figure
x_position = min(x_position,fig_pos(3)-dialog_width);
y_position = min(y_position,fig_pos(4)-dialog_heigth);

d = dialog('Position',[x_position y_position dialog_width dialog_heigth],'Name',['Change label for call ' tag],'Units','normal');

% Get the number of rows to columns
n_columns = floor(sqrt(length(handles.data.settings.labels)));
n_rows = ceil(length(handles.data.settings.labels) / n_columns);

button_width = 1 ./ n_columns;
button_height = 1 ./ n_rows;
label_index = 0;
padding = .1;

for c = 1:n_columns
    for r = n_rows:-1:1
        label_index = label_index + 1;
        if label_index > length(handles.data.settings.labels)
            continue
        end
        x_position = (c-1) / n_columns + button_width*padding/2;
        y_position = (r-1) / n_rows + button_height*padding/2;
        uicontrol('Parent',d,...
            'Units', 'normalized',...
            'Position',[x_position, y_position, button_width*(1-padding), button_height*(1-padding)],...
            'String',handles.data.settings.labels{label_index},...
            'Callback',{@label_callback,handles.data.settings.labels{label_index}},...
            'BackgroundColor',[0.302,0.502,0.302],...
            'ForegroundColor',[1.0 1.0 1.0]);
    end
end

uiwait(d);

    function label_callback(~,~,new_type)
        clicked_tag = str2double(tag);
        if ~isempty(i)
            handles.data.calls{clicked_tag,'Type'} = {new_type};
            delete(gcf);
            update_fig(hObject, [], handles);
        end
    end

end


function y = cvx_isvalid( x, full )
persistent remap
if isempty( remap ),
    remap = cvx_remap( 'valid' );
end
y = remap( cvx_classify( x ) );
if nargin < 2 || ~full,
	y = all( y );
else
	y = reshape( y, x.size_ );
end

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function vw = motionCompSetArgs(vw)
%
%   gb 14/04/05
%
%   vw = motionCompSetArgs(vw)
%
% Runs an interface to set the arguments of motionCompMutualInfMeanInit
% Also computes the MSE and the MI between consecutive frames of the new
% dataType.
%
global dataTYPES HOMEDIR

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Creates the figure
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

nScans = numberScans(vw);
nTrans = 4;

xs = 1.8;
ys = 1.8;

botMargin = 0.2;
butWidth = 8;
editWidthY = 1.4;
fontSize = 9;

height11 = nTrans + 2 + botMargin*2 + .5;
height21 = nScans + 2 + botMargin*2 + .5;
heightEdge = 1;
heightSep = 2;
height = height11 + height21 + heightSep + 2*heightEdge;

width1 = 22;
width2 = 22;
width3 = 35;
widthAlgo = width1;
widthSep = 5;
widthEdge = 1;
width = width1 + width2 + width3 + 2*widthSep + 2*widthEdge;

h = figure('MenuBar','none',...
    'Name','Choose parameters of the transformation',...
    'Units','char',...
    'Resize','off',...
    'NumberTitle','off',...
    'Position',[60,(60 - height*ys), width*xs,height*ys]);

hControl = cell(1,9);

scanNames = {};
for i = 1:nScans
    scanNames = [scanNames,{['Scan' num2str(i)]}];
end
hControl{1} = fillFigure('Scans',scanNames,h,widthEdge,height11 + heightSep + heightEdge,width1);

hControl{2} = fillFigure('Algorithms',{'Rigid (MI)','Non linear (MSE)','Apply GLM','Consecutive frame error'},...
    h,widthEdge,heightEdge,widthAlgo,'',0);

scanNames = [scanNames,{'Anatomy'}];
x = widthEdge + width1 + widthSep;
y = height11 + heightSep + heightEdge + nScans;
fillFigure('BaseScan',{},h,x,y,width2,'',0);
hControl{3} = uicontrol('Style','popupmenu',...
                'Units','char',...
                'String',scanNames,...
                'Position',[(x + widthSep)*xs,(y)*xs,(width1 - 2*widthSep)*xs,editWidthY],...
                'HorizontalAlignment','center',...
                'FontSize',fontSize);

y = y - nScans;
fillFigure('Original data type name',{},h,x,y,width2,'',0);
dataNames = {};
for i = 1:length(dataTYPES)
    dataNames = [dataNames,{dataTYPES(i).name}];
end

hControl{4} = uicontrol('Style','popupmenu',...
                'Units','char',...
                'String',dataNames,...
                'Position',[(x + widthSep)*xs,(y)*xs,(width1 - 2*widthSep)*xs,editWidthY],...
                'HorizontalAlignment','center',...
                'FontSize',fontSize);

y = heightEdge + nTrans;
fillFigure('New data type name',{},h,x,y,width2,'',0);

hControl{5} = uicontrol('Style','edit',...
                'Units','char',...
                'String','',...
                'Position',[(x + widthSep)*xs,(y)*xs,(width1 - 2*widthSep)*xs,editWidthY],...
                'HorizontalAlignment','center',...
                'FontSize',fontSize,...
                'Enable','Off');

x = widthEdge + width1 + width2 + 2*widthSep;
y = height11 + heightSep + heightEdge + nScans;
fillFigure('ROI',{},h,x,y,width3,'',0);

ROInames = {'None','ROIocc','ROIfront'};
for i = 1:length(vw.ROIs)
    ROInames = [ROInames,{vw.ROIs(i).name}];
end
ROIfiles = dir(roiDir(vw));
for i = 3:length(ROIfiles)
    if isempty(find(strcmp(ROInames,ROIfiles(i).name(1:end - 4)), 1))
        ROInames = [ROInames, {ROIfiles(i).name(1:end - 4)}];
    end
end

hControl{6} = uicontrol('Style','popupmenu',...
                'Units','char',...
                'String',ROInames,...
                'Position',[(x + widthSep)*xs,(y)*xs,(width1 - 2*widthSep)*xs,editWidthY],...
                'HorizontalAlignment','center',...
                'FontSize',fontSize);

x = width - widthEdge - width3/2;
nSlices = numberSlices(vw);
hControl{7} = createSlider('Slice',[(x + widthSep/2)*xs y*ys (width3/2 - 3/2*widthSep)*xs editWidthY],[1 nSlices]);

x = widthEdge + width1 + width2 + width3/4;
y = heightEdge + heightSep;
hControl{8} = gca;
set(hControl{8},'Units','char');
set(hControl{8},'Position',[(x + widthSep)*xs,(y)*xs,(width3 - 2*widthSep)*xs,(nScans + nTrans + heightSep - 2*botMargin)*ys]);

str = [vw.ui.displayMode,'Mode'];
modeStr=['vw.ui.',str];
mode = eval(modeStr);
cmap = mode.cmap;
numGrays = mode.numGrays;
numColors = mode.numColors;
clipMode = mode.clipMode;

% image(vw.ui.image);
% colormap(cmap);
% axis image;
% axis off;

x = widthEdge + width1 + width2 + width3 - butWidth - botMargin;
y = heightEdge + botMargin;
uicontrol('Style','pushbutton',...
    'String','Cancel',...
    'Units','char',...
    'Position',[x*xs,y*ys,butWidth*xs,ys],...
    'CallBack','uiresume',...
    'FontSize',fontSize,...
    'UserData','Cancel');

x = x - butWidth - widthEdge;
hControl{9} = uicontrol('Style','pushbutton',...
                'String','OK',...
                'Enable','Off',...
                'Units','char',...
                'Position',[x*xs,y*ys,butWidth*xs,ys],...
                'CallBack','uiresume',...
                'FontSize',fontSize,...
                'UserData','OK');

hControl{10} = 0;

for i = 1:(length(hControl) - 3)
    for j = 1:length(hControl{i})
        set(hControl{i}(j),'CallBack','uiresume');
        set(hControl{i}(j),'UserData','Update');
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Main Loop
%
% Update the arguments whenever the user adds
% something to the figure
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

response = 'Update';
while strcmp(response,'Update')
    uiwait

    % determine which button was hit.
    response = get(gco,'UserData');

    if isempty(response)
        close(get(0,'currentFigure'));
        fprintf('Motion Compensation Canceled by the user');
        return;
    end

    try
        if strcmp(get(gco,'Style'),'edit')
            hControl{end} = 1;
        end
    end

    % Update the arguments
    [scans,ROI,baseScan,newDataType,currentDataType,rigid,nonLinear,glmIndex,consError] = updateHControl(vw,hControl);

    % Update the new slice showed. If an ROI has been loaded, loads a slice
    % where the ROI is not zero.
    if ~ieNotDefined('ROI')
        if sum(sum(abs(ROI(:,:,get(hControl{7}(1),'Value'))))) == 0
            mn = mean(mean(ROI,1),2);
            displaySlices = find(mn > 0);
            [minimum,index] = min(abs(displaySlices - get(hControl{7}(1),'Value')));
            if ~isempty(displaySlices)
                set(hControl{7}(1),'Value',displaySlices(index));
                set(hControl{7}(2),'String',num2str(displaySlices(index)));
            else
                msgBox('This ROI is empty!','Warning!');
            end
        end
    end

    vw = viewSet(vw, 'Current Slice', get(hControl{7}(1),'Value'));

    % Recomputes the shown image
    vw = recomputeImage(vw,numGrays,numColors,clipMode);

    size1 = sliceDims(vw,1);
    size2 = size(vw.anat);
    T = maketform('affine',[size2(2)/size1(2) 0 0; 0 size2(1)/size1(1) 0; 0 0 1]);

    im = vw.ui.image;

    if ~ieNotDefined('ROI')

        im = cmap(double(im)+1);
        roi = ROI(:,:,str2num(get(hControl{7}(2),'String')));
        roi = imtransform(roi,T,'nearest');
        roi = [zeros(1,size(roi,2) + 1);zeros(size(roi,1),1),roi];

        im = repmat(im,[1 1 3]);
        roi = repmat(roi,[1 1 3]);
        color = [1 0 0];
        colorIndex = repmat(reshape(color,[1 1 length(color)]),[size(im,1) size(im,2) 1]);

        transparency = 2/3;
        im = (im + transparency)/(1 + transparency).*roi.*colorIndex + im.*(1 - roi);

    end
	image(im);
    colormap(cmap);
    axis image;
    axis off;

end

if ~ieNotDefined('ROI')
    ROIname = ['ROI_' newDataType];
end
close(h)
vw = refreshScreen(vw);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Once the ok button is pressed, the motion compensation algorithm is
% called. It can be followed by the glm and the computation of the
% consecutive frame errors.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if strcmp(response,'OK')
    vw = motionCompMutualInfMeanInit(vw,scans,ROI,baseScan,newDataType,currentDataType,rigid,nonLinear);

    % Runs the GLM
    if glmIndex
        er_runSelxavgBlock(vw,intersect(union(baseScan,scans),1:6),1);
    end

	% Creates the movie of the mean maps
%     try,	motionCompMeanMovie(vw);  end

    % Computes the consecutive-frame error
    if consError,
        try
            for i = 1:length(dataTYPES)
                if isequal(dataTYPES(i).name,currentDataType)
                    vw = viewSet(vw,'currentDataType',i);
                    break
                end
            end

            motionCompPlotMSE(vw,'',0);
            motionCompPlotMI(vw,'',0);

            if ~ieNotDefined('ROIname')
                motionCompPlotMSE(vw,ROIname,0);
                motionCompPlotMI(vw,ROIname,0);
            end

            if exist(fullfile(roiDir(vw),'ROIdef.mat'),'file')
                pathMSE = fullfile(dataDir(vw),['MSE_' vw.sessionCode '_' currentDataType '_ROIdef.mat']);
                if exist(pathMSE,'file')
                    delete(pathMSE);
                end
                pathMI = fullfile(dataDir(vw),['MI_' vw.sessionCode '_' currentDataType '_ROIdef.mat']);
                if exist(pathMI,'file')
                    delete(pathMI);
                end

                motionCompPlotMSE(vw,'ROIdef',0);
                motionCompPlotMI(vw,'ROIdef',0);
            end

            for i = 1:length(dataTYPES)
                if isequal(dataTYPES(i).name,newDataType)
                    vw = viewSet(vw,'currentDataType',i);
                    break
                end
            end

            motionCompPlotMSE(vw,'',0);
            motionCompPlotMI(vw,'',0);

            if ~ieNotDefined('ROIname')
                motionCompPlotMSE(vw,ROIname,0);
                motionCompPlotMI(vw,ROIname,0);
            end

            if exist(fullfile(roiDir(vw),'ROIdef.mat'),'file')
                pathMSE = fullfile(dataDir(vw),['MSE_' vw.sessionCode '_' newDataType '_ROIdef.mat']);
                if exist(pathMSE,'file')
                    delete(pathMSE);
                end
                pathMI = fullfile(dataDir(vw),['MI_' vw.sessionCode '_' newDataType '_ROIdef.mat']);
                if exist(pathMI,'file')
                    delete(pathMI);
                end

                motionCompPlotMSE(vw,'ROIdef',0);
                motionCompPlotMI(vw,'ROIdef',0);

            end
        end
    end
end

return

% /-----------------------------------------------------------------------/ %
function h_button = fillFigure(headerStr,optionStr,h,xoff,yoff,width,height,displayButtons)
% function reply = fillFigure(headerStr,optionStr)
%
% Button Dialog Box
%
%  Allows the user to toggle and select options in
%  the cell array string 'optionStr'.  Reply is a
%  boolean vector with length(optionStr) that indicates
%  selected options. reply is empty if the user
%  chooses to cancel.
%
%  Example:
%  reply = buttondlg('pick it',{'this','that','the other'})
%
%4/11/98 gmb   Wrote it
% 15/07/02  fwc     it will now make multiple columns of options if the number is large
% 2002.07.24  rfd & fwc: fixed minor bug where short checkbox labels were invisible.
% 2004.12.16  arw: Added option to select / deselect all
%
% gb 04/18/05
%
% Several options are added in order to make it more flexible and to
% integrate this window to an existing figure

OptionsPerColumn=11; % max number of options in one column

if nargin<2
    disp('Error: "bottondlg" requires two inputs');
    return
end

if ieNotDefined('xoff')
    xoff = 0;
end

if ieNotDefined('yoff')
    yoff = 0;
end

if ieNotDefined('displayButtons')
    displayButtons = 1;
end

if isunix
    fontSize = 10;
else
    fontSize = 9;
end

if strcmp(class(optionStr),'cell')
    optionStr = char(optionStr);
end

nOptions = size(optionStr,1);

ncols=ceil(nOptions/OptionsPerColumn);
nOptionsPerColumn=max(ceil(nOptions/ncols),0);

%scale factors for x and y axis coordinates
xs = 1.8;
ys = 1.8;

%default sizes
butWidth=10;
botMargin = 0.2;

if ieNotDefined('height')
    height = nOptionsPerColumn+2+botMargin*2+.5;
end

% If we don't have a minimum colwidth (5 in this case), short strings don't show up.
colwidth=max(size(optionStr,2),5);%

if ieNotDefined('width')
    width = ncols*colwidth+2;
    width = max(width,butWidth+2);
end

%open the figure
if ieNotDefined('h')
    h = figure('MenuBar','none',...
    'Units','char',...
    'Resize','off',...
    'NumberTitle','off',...
    'Position',[20, 10, width*xs,height*ys]);
end
bkColor = get(h,'Color');

%Display title text inside a frame
x = 1;
% y = nOptions+1+botMargin;
y = nOptionsPerColumn+1+botMargin;

x = x + xoff;
y = y + yoff;

uicontrol('Style','frame',...
    'Units','char',...
    'String',headerStr,...
    'Position',[x*xs,(y+.2)*ys,(width-2)*xs,ys*1.3],...
    'HorizontalAlignment','center',...
    'FontSize',fontSize);

uicontrol('Style','text',...
    'Units','char',...
    'String',headerStr,...
    'Position',[(x+.25)*xs,(y+.3)*ys,(width-2.5)*xs,ys*.9],...
    'HorizontalAlignment','center',...
    'FontSize',fontSize);

%Display the radio buttons
y = y+botMargin/2;
y0=y;
c=0;

for optionNum=1:nOptions
    y = y-1;
    h_button(optionNum) = ...
        uicontrol('Style','checkbox',...
        'Units','char',...
        'String',optionStr(optionNum,:),...
        'BackgroundColor',bkColor,...
        'Position',[x*xs+c*colwidth*xs,y*ys,colwidth*xs+(c+1)*colwidth*xs,ys],...
        'HorizontalAlignment','left',...
        'FontSize',fontSize);
    if optionNum>=(c+1)*nOptionsPerColumn
        c=c+1;
        y=y0;
    end
end

if displayButtons
	%Display the OK/Cancel buttons
	x = width - butWidth - 3;
	x = x + xoff;
	y = botMargin + yoff;

	sabutton=uicontrol('Style','pushbutton',...
        'String','SelAll',...
        'Units','char',...
        'Position',[x*xs+2,y*ys,butWidth*xs/2,ys],...
        'FontSize',fontSize-4,...
        'Callback',['set([',num2str(h_button,30),'],''Value'',1);uiresume'],...
        'UserData','Update');
	cabutton=uicontrol('Style','pushbutton',...
        'String','ClrAll',...
        'Units','char',...
        'Position',[x*xs+2+butWidth,y*ys,butWidth*xs/2,ys],...
        'FontSize',fontSize-4,...
        'Callback',['set([',num2str(h_button,30),'],''Value'',0);uiresume'],...
        'UserData','Update');
end

return;

% /------------------------------------------------------------------------------/ %
function [scans,ROI,baseScan,newDataType,currentDataType,rigid,nonLinear,glmIndex,consError] = updateHControl(vw,hControl)
%
% Updates the arguments from the current figure
%

nScans = length(hControl{1});
scans = [];
for i = 1:nScans
    if get(hControl{1}(i),'Value')
        scans = [scans i];
    end
end

scanNames = get(hControl{3},'String');
baseScan = get(hControl{3},'Value');

dataNames = get(hControl{4},'String');
currentDataType = dataNames{get(hControl{4},'Value')};
newDataType = get(hControl{5},'String');

rigid = get(hControl{2}(1),'Value');
nonLinear = get(hControl{2}(2),'Value');
glmIndex = get(hControl{2}(3),'Value');
consError = get(hControl{2}(4),'Value');

if gco == hControl{7}(2)
    val = str2num(get(hControl{7}(2),'String'));
    val = min(get(hControl{7}(1),'Max'),val);
    val = max(get(hControl{7}(1),'Min'),val);
    val = round(val);

    set(hControl{7}(1),'Value',val);
    set(hControl{7}(2),'String',num2str(val));
else
    val = get(hControl{7}(1),'Value');
    val = min(get(hControl{7}(1),'Max'),val);
    val = max(get(hControl{7}(1),'Min'),val);
    val = round(val);

    set(hControl{7}(1),'Value',val);
    set(hControl{7}(2),'String',num2str(val));
end

if (rigid | nonLinear) & ~isempty(setdiff(scans,baseScan))
    set(hControl{5},'Enable','On');
    set(hControl{end - 1},'Enable','On');

    if hControl{end} == 0;
        newDataName = '';
        if rigid
            newDataName = [newDataName 'Rigid'];
            if nonLinear
                newDataName = [newDataName '+'];
            end
        end

        if nonLinear
            newDataName = [newDataName 'NL'];
        end

        newDataName = [newDataName '_' scanNames{baseScan}];

        set(hControl{5},'String',newDataName);
    end

else
    set(hControl{5},'Enable','Off');
    set(hControl{5},'String','');
    set(hControl{end - 1},'Enable','Off');
    hControl{end} = 0;
end

ROINames = get(hControl{6},'String');
switch ROINames{get(hControl{6},'Value')}

    case 'None'
        ROI = '';

    case 'ROIocc'
        ROI = zeros([sliceDims(vw,1) numberSlices(vw)]);
        ROI((end - 50):(end - 20),30:(end - 30),15:19) = ones(size(ROI((end - 50):(end - 20),30:(end - 30),15:19)));

    case 'ROIfront'
        ROI = zeros([sliceDims(vw,1) numberSlices(vw)]);
        ROI((20:end - 20),30:(end - 30),2:8) = ones(size(ROI((20:end - 20),30:(end - 30),2:8)));

    otherwise
        ROI = motionCompGetROI(vw,ROINames{get(hControl{6},'Value')});

end

if baseScan == (nScans + 1)
    baseScan = 0;
end

return

% /-----------------------------------------------------------------------------/ %
function handle = createSlider(name,position,range)
%
% Creates a slider at a position and with a range specified by the user
%

color = get(gcf,'Color');

% Make slider
sliderHandle = ...
    uicontrol('Style','slider',...
    'Units','char',...
    'Position',position,...
    'min',range(1),...
    'max',range(2),...
    'SliderStep',[1/(range(2) - range(1)) 1/(range(2) - range(1))],...
    'val',floor(range(2)/2));

% Make label
labelOffset = [2,1.8,0,0];
labelPos = position - labelOffset;
labelPos(4) = 1.3;     % don't encroach on the slider

uicontrol('Style','text',...
          'Units','char',...
          'Position',labelPos,...
          'BackgroundColor',color,...
          'String',[name ':']);

editOffset = [7 - position(3),1.8,0,0];
editPos = position - editOffset;
editPos(3) = 5;
editPos(4) = 1.5;    % don't encroach on the slider
editHandle = ...
    uicontrol('Style','edit',...
    'Units','char',...
    'Position',editPos,...
    'String',num2str(get(sliderHandle,'Value')),...
    'BackgroundColor',color);

handle = [sliderHandle editHandle];


function varargout = mri_editMask(varargin)
% MRI_EDITMASK: Edit a 3D binary mask for a MRI.
%
% USAGE:  finalMask = mri_editMask(Mri)
%         finalMask = mri_editMask(Mri, Voxsize)
%         finalMask = mri_editMask(Mri, Voxsize, InitialMask)
%         finalMask = mri_editMask(Mri, Voxsize, InitialMask, InitialPos)
%         finalMask = mri_editMask(Mri, Voxsize, InitialMask, InitialPos, ColormapName)
%
% INPUT:
%    - Mri         : Full 3D matrix
%    - Voxsize     : Voxel size of the Mri volume (x,y,z)
%    - InitialMask : Full 3D matrix representing the initial mask
%                    (optional, if not specified, use an empty volume)
%    - InitialPos  : (dim, sliceIndex), slice to display when opening the window
%    - ColormapName: colormap name to display the anatomy
%
% OUTPUT:
%    - finalMask = final binary 3D mask
%
% A global variable is used to store application MRI and Masks : gEditMaskData
% Structure with following fields :
%    |- mri           : MRI that is currently processed
%    |- voxsize       : size of each mri voxel (x,y,z)
%    |- mask          : currently edited mask (for brain or grey matter)
%    |- isClicked     : structure that handles the mouse clicks and movements
%    |     |- source              : name of the object clicked by the user
%    |     |- clickPositionAxes   : click position in figure coordinates
%    |     |- clickPositionFigure : click position in axis coordinates
%    |- sliderValue   : [1,3] with the index of the current slice in each
%    |                  orientation for preview image (x,y,z)
%    |- orientation   : current orientation of preview slice (x,y,z)
%    |- intensityMax  : maximum intensity in image
%    |- colormap
%    |- colormapMax   : value above which all intensity are displayed as white

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2006-2010

%% ===== CHECK INPUT =====
global gEditMaskData;
% === EXTERNAL CALL ===
if (nargin >= 1) && isnumeric(varargin{1})
    % === PARSE INPUTS ===
    % Argument #1: MRI
    gEditMaskData.mri = varargin{1};
    % Argument #2: VOXEL SIZE
    if (nargin < 2) || isempty(varargin{2})
        gEditMaskData.voxsize = [1 1 1];
    else
        gEditMaskData.voxsize = varargin{2};
    end
    % Argument #3: MASK
    if (nargin < 3) || isempty(varargin{3})
        gEditMaskData.mask = false(size(gEditMaskData.mri));
    elseif any(size(varargin{3}) ~= size(gEditMaskData.mri))
        error('MRI and mask must have the same dimensions.');
    else
        gEditMaskData.mask = logical(varargin{3});
    end
    % Argument #4: INITIAL POSITION
    if (nargin < 4) || isempty(varargin{4})
        InitialPos = [];
    else
        InitialPos = varargin{4};
    end
    % Argument #5: COLORMAP
    if (nargin < 5) || isempty(varargin{5})
        gEditMaskData.colormap = 'gray';
    else
        gEditMaskData.colormap = varargin{5};
    end

    % === START MASK EDITOR ===
    % Progress bar
    bst_progress('start', 'Edit mask', 'Initialization...');
    % Call again function, to initialize GUI
    hFig = mri_editMask();
    % Define Mouse wheel callback separately (not supported by old versions of Matlab)
    if isprop(hFig, 'WindowScrollWheelFcn')
        set(hFig, 'WindowScrollWheelFcn',  @FigureMouseWheelCallback);
    end
    % Set initial orientation and position
    if ~isempty(InitialPos)
        SetOrientation(InitialPos(1));
        SetSliceLocation(InitialPos(2));
    end
    % Close progress bar
    bst_progress('stop');

    % === WAIT AND RETURN ===
    % Wait for end of edition
    waitfor(hFig);
    % Return edited mask
    if (nargout >= 1)
        varargout{1} = gEditMaskData.mask;
    end
    % Empty global variable
    gEditMaskData = [];

% === INTERNAL CALL : CREATE GUI ===
elseif (nargin == 0)
    % Begin initialization code - DO NOT EDIT
    gui_Singleton = 1;
    gui_State = struct('gui_Name',       mfilename, ...
                       'gui_Singleton',  gui_Singleton, ...
                       'gui_OpeningFcn', @figureEditMask_OpeningFcn, ...
                       'gui_OutputFcn',  @figureEditMask_OutputFcn, ...
                       'gui_LayoutFcn',  [] , ...
                       'gui_Callback',   []);
    if nargout
        [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
    else
        gui_mainfcn(gui_State, varargin{:});
    end
    % Update figures layout
    gui_layout('Update');

% === CALLBACKS ===
else
    if (nargout)
        [varargout{1:nargout}] = bst_call(str2func(varargin{1}), varargin{2:end});
    else
        bst_call(str2func(varargin{1}), varargin{2:end});
    end
end

%% ===== OUTPUT FUNCTION =====
function varargout = figureEditMask_OutputFcn(hObject, eventdata, handles)
    % Get default command line output from handles structure
    varargout{1} = hObject;

%% ===== OPENING FUNCTION =====
function figureEditMask_OpeningFcn(hObject, eventdata, handles, varargin)
    global gEditMaskData;
    % Check that MRI and MASK where defined
    if ~isfield(gEditMaskData, 'mri') || isempty(gEditMaskData.mri) || ~isfield(gEditMaskData, 'mask') || isempty(gEditMaskData.mask)
        error('Usage: mri_editMask(volume,mask);');
    end
    drawnow

    % === Replace Matlab slider by Java slider ===
    % Disable the Java-related warnings after 2019b
    if (bst_get('MatlabVersion') >= 907)
        warning('off', 'MATLAB:ui:javacomponent:FunctionToBeRemoved');
    end
%     sliderPos = get(handles.sliderPreview, 'Position');
%     hParent = get(handles.sliderPreview, 'Parent');
    delete(handles.sliderPreview);
    [handles.jSliderPreview, handles.sliderPreview] = javacomponent(javax.swing.JSlider(0,10,0), [0 0 1 1], hObject);
%     set(handles.sliderPreview, 'Units', 'Pixels', 'Position', sliderPos);
    java_setcb(handles.jSliderPreview, 'MouseReleasedCallback', @(h,ev)SetSliceLocation(ev.getSource().getValue()), ...
                                       'KeyPressedCallback',    @(h,ev)SetSliceLocation(ev.getSource().getValue()));

    % === REFRESH DISPLAY ===
    set(handles.mri_editMask, 'WindowStyle', 'normal');

    % ===== ICONS =====
    set(handles.toggleLassoMinus,   'CData', java_geticon('ICON_LASSO_MINUS'));
    set(handles.toggleLassoPlus,    'CData', java_geticon('ICON_LASSO_PLUS'));
    set(handles.toggleCurveMinus,   'CData', java_geticon('ICON_CURVE_MINUS'));
    set(handles.toggleCurvePlus,    'CData', java_geticon('ICON_CURVE_PLUS'));
    set(handles.buttonContrastDown, 'CData', java_geticon('ICON_BRIGHTNESS_MINUS'));
    set(handles.buttonContrastUp,   'CData', java_geticon('ICON_BRIGHTNESS_PLUS'));

    % Store handles in global variable
    handles.output = hObject;
    gEditMaskData.Handles = handles;
    % Keyboard shortcuts
    set([handles.mri_editMask, handles.buttonContrastDown, handles.buttonContrastUp, ...
         handles.buttonOk, handles.buttonCancel, ...
         handles.buttonAxial, handles.buttonCoronal, handles.buttonSagittal, ...
         handles.toggleLassoMinus, handles.toggleLassoPlus, handles.toggleCurveMinus, handles.toggleCurvePlus], ...
        'KeyPressFcn', @figureKeyPress_Callback);
    % Initial preview axes settings
    mriSize = size(gEditMaskData.mri);
    gEditMaskData.sliderValue = [round(mriSize(1)/2), round(mriSize(2)/2), round(mriSize(3)/2)];
    gEditMaskData.orientation = 3; % 1=x, 2=y, 3=z
    gEditMaskData.overlayColor = [1 1 0];
    gEditMaskData.overlayAlpha = .6;
    % Initial action: lasso
    SetAction('lasso+');
    % Mouse clicks and motion management
    gEditMaskData.isClicked.source = '';
    gEditMaskData.isClicked.clickPositionAxes = [];
    gEditMaskData.isClicked.clickPositionFigure = [];
    gEditMaskData.isClicked.roiPolygon = [];
%     % Initial action
%     set(handles.buttongroupAction, 'SelectedObject', handles.toggleLassoPlus);
%     % Update icons
%     gui_update_toggle([handles.toggleLassoPlus, handles.toggleLassoMinus, handles.toggleCurvePlus, handles.toggleCurveMinus]);
    % Initial contrast
    gEditMaskData.colormapMax = 256;
    gEditMaskData.intensityMax = max(gEditMaskData.mri(:));
    % Initialize axes
    SetOrientation(gEditMaskData.orientation);
    % Draw first slice
    UpdateSlice();

%% ===== RESIZE CALLBACK =====
function mri_editMask_ResizeFcn(varargin) %#ok<DEFNU>
    global gEditMaskData;
    if ~isfield(gEditMaskData, 'Handles') || ~ishandle(gEditMaskData.Handles.mri_editMask)
        return
    end
    handles = gEditMaskData.Handles;
    % Get figure and panels position and size
    figPos    = get(handles.mri_editMask,  'Position');
    rightPos  = get(handles.panelRight,    'Position');
    % Set right panel position
    set(handles.panelRight, 'Position', [0, ...
                                         figPos(4) - rightPos(4), ...
                                         rightPos(3), ...
                                         rightPos(4)]);
    % Set "MRI" panel position
    margin = 5;
    set(handles.panelMri, 'Position', [rightPos(3), ...
                                       margin, ...
                                       figPos(3) - rightPos(3) - margin, ...
                                       figPos(4) - 2 * margin]);
    % Set slider position
    set(handles.sliderPreview, 'Position', [11, figPos(4)-290, 140, 24]);

%% =================================================================================================
%  ===== DISPLAY MRI ===============================================================================
%  =================================================================================================
%% ===== SET ORIENTATION =====
function SetOrientation(orientation)
    global gEditMaskData;
    handles = gEditMaskData.Handles;
    % Save new orientation
    gEditMaskData.orientation = orientation;
    % Select right orientation button
    hButtons = [handles.buttonSagittal, handles.buttonCoronal, handles.buttonAxial];
    set(hButtons(orientation), 'Value', 1);

    % === PREPARE DISPLAY ===
    cubeSize = size(gEditMaskData.mri);
    FOV = cubeSize .* gEditMaskData.voxsize;
    % Empty axes
    cla(handles.axesPreview);
    % Set colormap
    colormap(handles.axesPreview, gEditMaskData.colormap);

    % === CREATE IMAGES ===
    % Get image size
    imgSize = cubeSize;
    imgSize(orientation) = [];
    FOV(orientation) = [];
    % MRI image
    handles.img_mri = image('XData',        [1, FOV(1)], ...
                            'YData',        [1, FOV(2)], ...
                            'CData',        zeros(imgSize(2), imgSize(1)), ...
                            'CDataMapping', 'direct', ...
                            'Parent',       gEditMaskData.Handles.axesPreview);
    % Overlay image
    handles.img_overlay = image('XData',     [1, FOV(1)], ...
                                'YData',     [1, FOV(2)], ...
                                'CData',     zeros([imgSize(2), imgSize(2), 3]), ...
                                'AlphaData', 0, ...
                                'Parent',    gEditMaskData.Handles.axesPreview);
    % Axes
    axis(handles.axesPreview, 'image', 'off');
    % Set mouse callbacks
    set([handles.axesPreview, handles.img_mri, handles.img_overlay], 'ButtonDownFcn', @previewMouseClick_Callback);
    % Save handles structure
    gEditMaskData.Handles = handles;

    % === ORIENTATION MARKERS ===
    if (orientation == 2)
        strOrient = 'PA';
    else
        strOrient = 'LR';
    end
    % Coronal
    V = axis(handles.axesPreview);
    fontSize = bst_get('FigFont');
    text(       6, 15, strOrient(1), 'verticalalignment', 'top', 'FontSize', fontSize, 'FontUnits', 'points', 'color','w', 'Parent', gEditMaskData.Handles.axesPreview);
    text(.95*V(2), 15, strOrient(2), 'verticalalignment', 'top', 'FontSize', fontSize, 'FontUnits', 'points', 'color','w', 'Parent', gEditMaskData.Handles.axesPreview);

    % === SLIDER ===
    % Slider bounds
    handles.jSliderPreview.setMinimum(1);
    handles.jSliderPreview.setMaximum(cubeSize(orientation));
    % Set slice location
    SetSliceLocation(gEditMaskData.sliderValue(orientation));

    % === COLORMAP ===
    UpdateColormap();

%% ===== SET SLICE LOCATION =====
function SetSliceLocation(sliceLoc)
    global gEditMaskData;
    handles = gEditMaskData.Handles;
    % Force location inside the MRI volume
    sliceLoc = bst_saturate(sliceLoc, [1, size(gEditMaskData.mri, gEditMaskData.orientation)]);
    % Save new position
    gEditMaskData.sliderValue(gEditMaskData.orientation) = sliceLoc;
    % Update slider position
    handles.jSliderPreview.setValue(sliceLoc);
    % Reset points selection
    gEditMaskData.isClicked.roiPolygon = [];
    delete(findobj(handles.axesPreview, 'Tag', 'ptCurve'));
    % Update text
    set(handles.textValue, 'String', sprintf('%d', sliceLoc));
    strOrient = {'x=','y=','z='};
    set(handles.textTitleValue, 'String', strOrient{gEditMaskData.orientation});
    % Update location axes
    UpdateLocationAxes();
    % Redraw slice
    UpdateSlice();

%% ===== UPDATE SLICE =====
function UpdateSlice()
    global gEditMaskData;
    % Get slice location
    sliceLoc = gEditMaskData.sliderValue(gEditMaskData.orientation);
    % Update MRI slice
    sliceMRI = mri_getslice(gEditMaskData.mri, sliceLoc, gEditMaskData.orientation)';
    set(gEditMaskData.Handles.img_mri, 'CData', double(sliceMRI) ./ double(gEditMaskData.intensityMax) .* 256);
    % Update overlay slice
    if ~isempty(gEditMaskData.mask)
        sliceOverlay = mri_getslice(gEditMaskData.mask, sliceLoc, gEditMaskData.orientation)';
        sliceAlpha   = .6 * double(sliceOverlay);
        sliceOverlay = cat(3, sliceOverlay * gEditMaskData.overlayColor(1), ...
                              sliceOverlay * gEditMaskData.overlayColor(2), ...
                              sliceOverlay * gEditMaskData.overlayColor(3));
        set(gEditMaskData.Handles.img_overlay, 'CData', double(sliceOverlay), ...
                                               'AlphaData', sliceAlpha);
    end
    % Update location line
    DrawLocationLine();
    drawnow();

%% =================================================================================================
%  ===== LOCATION FUNCTIONS ========================================================================
%  =================================================================================================
%% ===== UPDATE LOCATION AXES =====
function UpdateLocationAxes()
    global gEditMaskData;
    % Get a centered slice, orthogonal to the direction of the preview slice
    switch (gEditMaskData.orientation)
        case 1 % Coronal preview => extract a sagittal slice
            locOrient = 3;
            lineOrient = 1;
        case 2 % Axial preview => extract a sagittal slice
            locOrient = 3;
            lineOrient = 2;
        case 3 % Sagittal preview => extract an axial slice
            locOrient = 2;
            lineOrient = 2;
    end
    % Get slice at the middle of the volume
    cubeSize = size(gEditMaskData.mri);
    locPosition = round(cubeSize(locOrient)/2);
    locSlice = mri_getslice(gEditMaskData.mri, locPosition, locOrient);
    % Get pixel size
    FOV = cubeSize .* gEditMaskData.voxsize;
    FOV(locOrient) = [];

    % Empty axes
    cla(gEditMaskData.Handles.axesLocation);
    % Display slice on location axes
    gEditMaskData.img_location = image('XData',         [1, FOV(1)], ...
                                       'YData',         [1, FOV(2)], ...
                                       'CData',         double(locSlice)' ./ double(gEditMaskData.intensityMax) .* 256, ...
                                       'CDataMapping',  'scaled', ...
                                       'Parent',        gEditMaskData.Handles.axesLocation, ...
                                       'ButtonDownFcn', @locationMouseClick_Callback);
    % Configure axes
    axis(gEditMaskData.Handles.axesLocation, 'image', 'off');
    set(gEditMaskData.Handles.axesLocation, 'UserData', lineOrient);

%% ===== DRAW LOCATION LINE =====
function DrawLocationLine()
    global gEditMaskData;
    % Get line orientation (UserData of the location Axes)
    lineOrient = get(gEditMaskData.Handles.axesLocation, 'UserData');
    % Get values from interface controls
    n = gEditMaskData.sliderValue(gEditMaskData.orientation) * gEditMaskData.voxsize(gEditMaskData.orientation);
    XLim = get(gEditMaskData.Handles.axesLocation, 'XLim');
    YLim = get(gEditMaskData.Handles.axesLocation, 'YLim');
    % Display a line that represent the location of the slice
    delete(findobj(gEditMaskData.Handles.axesLocation, 'Tag', 'locationLine'));
    switch(lineOrient)
        case 1 % Vertical line
            line([n,n]+.5, YLim+.5, [1,1], 'Color', [1 .2 .2], ...
                 'Parent', gEditMaskData.Handles.axesLocation, 'Tag', 'locationLine');
        case 2 % Horizontal line
            line(XLim+.5, [n,n], [1,1], 'Color', [1 .2 .2], ...
                 'Parent', gEditMaskData.Handles.axesLocation, 'Tag', 'locationLine');
    end
    drawnow;

%% ===== LOCATION AXES CALLBACK =====
function locationMouseClick_Callback(varargin)
    global gEditMaskData;
    % Get application handles
    handles = gEditMaskData.Handles;
    % Get line orientation (UserData of the location Axes)
    lineOrient = get(handles.axesLocation, 'UserData');
    % Mouse location on the axis
    temp = get(handles.axesLocation, 'CurrentPoint');
    curptAxes = temp(1,1:2);
    % Update slice location
    switch(lineOrient)
        case 1 % Vertical line
            n = round(curptAxes(1) * gEditMaskData.voxsize(1) - .5);
        case 2 % Horizontal line
            n = round(curptAxes(2) * gEditMaskData.voxsize(2) - .5);
    end
    SetSliceLocation(n);

%% =================================================================================================
%  ===== AXES CALLBACKS ============================================================================
%  =================================================================================================
%% ===== KEYBOARD CALLBACK =====
function figureKeyPress_Callback(hObject, eventdata, varargin)
    global gEditMaskData;
    % Get GUI handles
    handles = gEditMaskData.Handles;
    % If the focus is on the slider, set the focus on the axes, to avoid conflits between uicontrol
    % automatic keyboard handling and, and this manual handling
    if (get(handles.mri_editMask, 'CurrentObject') == handles.sliderPreview)
        uicontrol(handles.buttonAxial);
    end
    % Get current slice location
    sliceLoc = handles.jSliderPreview.getValue();
    % Switch between keys
    switch (eventdata.Key)
        % PAGE UP : increase slice indice (10)
        case 'pageup'
            SetSliceLocation(sliceLoc + 10);
        % PAGE DOWN : decrease slice indice (10)
        case 'pagedown'
            SetSliceLocation(sliceLoc - 10);
        % RIGHT ARROW : increase slice indice (1)
        case 'rightarrow'
            SetSliceLocation(sliceLoc + 1);
        % LEFT ARROW : decrease slice indice
        case 'leftarrow'
            SetSliceLocation(sliceLoc - 1);
    end

%% ===== MOUSE CLICK =====
function previewMouseClick_Callback(varargin)
    global gEditMaskData;
    % Get figure handles
    hFig  = gEditMaskData.Handles.mri_editMask;
    hAxes = gEditMaskData.Handles.axesPreview;
    % Mouse location on the figure
    gEditMaskData.isClicked.source = 'preview';
    temp = get(hFig, 'CurrentPoint');
    gEditMaskData.isClicked.clickPositionFigure = temp(1,1:2);
    % Mouse location on the axis
    temp = get(hAxes, 'CurrentPoint');
    curptAxes= temp(1,1:2);
    % Apply changes
    switch(gEditMaskData.action)
        case {'lasso+', 'lasso-'}
            % Reset selection
            gEditMaskData.isClicked.roiPolygon = [];
            % Add first point to the ROI polygon
            gEditMaskData.isClicked.roiPolygon(1,1:2) = curptAxes;
    end

%% ===== MOUSE MOVE =====
function figureMouseMove_Callback(varargin) %#ok<DEFNU>
    global gEditMaskData;
    if ~isfield(gEditMaskData, 'Handles')
        return;
    end
    handles = gEditMaskData.Handles;
    % Mouse location on the figure
    temp = get(handles.mri_editMask, 'CurrentPoint');
    curptFigure = temp(1,1:2);
    % Mouse location on the axis
    temp = get(handles.axesPreview, 'CurrentPoint');
    curptAxes= temp(1,1:2);

    switch(gEditMaskData.isClicked.source)
        case 'preview'
            % Mouse motion
            mouseMotionFigure = gEditMaskData.isClicked.clickPositionFigure - curptFigure;
            gEditMaskData.isClicked.clickPositionFigure = curptFigure;
            % Mouse selection type ?
            switch(lower(get(handles.mri_editMask, 'SelectionType')))
                % Normal left click : Currently selected action
                case 'normal'
                    switch(gEditMaskData.action)
                        case {'lasso-', 'lasso+'}
                            % Add current point to the ROI polygon
                            n_1 = size(gEditMaskData.isClicked.roiPolygon,1);
                            gEditMaskData.isClicked.roiPolygon(n_1+1,1:2) = curptAxes;
                            % Draw line between current polygon vertex and last polygon vertex
                            line('XData',[gEditMaskData.isClicked.roiPolygon(n_1,1), gEditMaskData.isClicked.roiPolygon(n_1+1,1)], ...
                                 'YData',[gEditMaskData.isClicked.roiPolygon(n_1,2), gEditMaskData.isClicked.roiPolygon(n_1+1,2)], ...
                                 'ZData',[.1 .1], 'Color', [1 .2 .2], ...
                                 'Parent', handles.axesPreview, ...
                                 'Tag', 'ptCurve', ...
                                 'ButtonDownFcn', @previewMouseClick_Callback);
                    end

                % (Control + Left click) or right click : Change color scale
                case 'alt'
                    % Increase/decrease image contrast
                    delete(findobj(handles.axesPreview, 'Tag', 'selectionArea'));
                    gEditMaskData.colormapMax = max(8, min(505, gEditMaskData.colormapMax + mouseMotionFigure(2)));
                    UpdateColormap();
            end
    end
    drawnow

%% ===== MOUSE UP =====
function figureMouseUp_Callback(varargin) %#ok<DEFNU>
    global gEditMaskData;
    handles = gEditMaskData.Handles;
    gEditMaskData.isClicked.source = '';
    % Mouse location on the axes
    temp = get(handles.axesPreview, 'CurrentPoint');
    curptAxes= temp(1,1:2);
    % Add or remove new mask
    isAddNewMask = ~isempty(strfind(gEditMaskData.action, '+'));
    % If the mouse pointer is on the preview axes
    switch(gEditMaskData.action)
        case {'lasso+', 'lasso-'}
            % Close the polygon and display the polygon mask
            n = size(gEditMaskData.isClicked.roiPolygon,1);
            if (n > 1)
                gEditMaskData.isClicked.roiPolygon(n+1,1:2) = gEditMaskData.isClicked.roiPolygon(1,1:2);
                % Extract the binary mask from the polygon
                roiMask = getMask(gEditMaskData.isClicked.roiPolygon);
                % Update mask volume
                AddMaskSlice(roiMask, isAddNewMask);
                % Display mask border
                delete(findobj(handles.axesPreview, 'Tag', 'ptCurve'));
            end

        case {'curve+', 'curve-'}
            % Left button : add point
            % Right button : add point and end curve
            % Get new point
            newPt = curptAxes;
            % Add it to list of points
            n = size(gEditMaskData.isClicked.roiPolygon,1);
            gEditMaskData.isClicked.roiPolygon(n+1,1:2) = newPt;
            % Plot point
            hold on
            plot3(handles.axesPreview, newPt(1), newPt(2), 0.2, 'r.', 'Tag', 'ptCurve');
            % Only for right button
            if strcmpi(get(handles.mri_editMask, 'SelectionType'), 'alt') && (n > 1)
                % Add first point to close spline
                gEditMaskData.isClicked.roiPolygon(n+2,1:2) = gEditMaskData.isClicked.roiPolygon(1,1:2);
                % Interpolate with a spline curve and finer spacing.
                t = 1:n+2;
                ts = 1:0.1:n+2;
                splineRoi = spline(t, gEditMaskData.isClicked.roiPolygon', ts);
                % Delete all curve points
                delete(findobj(handles.axesPreview, 'Tag', 'ptCurve'));
                % Plot the interpolated closed curve
                line(splineRoi(1,:), splineRoi(2,:), ones(1,size(splineRoi,2)) * 0.2, ...
                     'Color',     [1 0 0], ...
                     'LineStyle', '-', ...
                     'Tag',       'ptCurve', ...
                     'Parent',    handles.axesPreview);
                % Extract the binary mask from the polygon
                roiMask = getMask(splineRoi');
                % Update mask volume
                AddMaskSlice(roiMask, isAddNewMask);
                % Reset polygon selection
                gEditMaskData.isClicked.roiPolygon = [];
            end
    end

%% ===== MOUSE WHEEL =====
% Move slices
function FigureMouseWheelCallback(hObject, event, varargin)
    global gEditMaskData;
    % Get new slice index
    iSlice = gEditMaskData.sliderValue(gEditMaskData.orientation) - double(event.VerticalScrollCount);
    % Go to new slice
    SetSliceLocation(iSlice);

%% ===== ACTION BUTTONS CALLBACKS =====
function buttongroupAction_SelectionChangeFcn(varargin) %#ok<DEFNU>
    global gEditMaskData;
    handles = gEditMaskData.Handles;
    % Get selected tool button
    selButton = get(handles.buttongroupAction, 'SelectedObject');
    % If no button is selected, for selection of "Lasso+"
    if isempty(selButton)
        selButton = handles.toggleLassoPlus;
        set(handles.buttongroupAction, 'SelectedObject', selButton);
    end
    % Associate an action name with each button
    switch (selButton)
        case handles.toggleLassoMinus
            action = 'lasso-';
        case handles.toggleLassoPlus
            action = 'lasso+';
        case handles.toggleCurveMinus
            action = 'curve-';
        case handles.toggleCurvePlus
            action = 'curve+';
    end
    SetAction(action);

%% ===== SET ACTION =====
function SetAction(action)
    global gEditMaskData;
    handles = gEditMaskData.Handles;
    % Set action
    switch lower(action)
        case 'lasso+'
            set(handles.toggleLassoPlus, 'Value', 1);
        case 'lasso-'
            set(handles.toggleLassoMinus, 'Value', 1);
        case 'curve+'
            set(handles.toggleCurvePlus, 'Value', 1);
        case 'curve-'
            set(handles.toggleCurveMinus, 'Value', 1);
    end
    gEditMaskData.action = action;
    % Update icons
    gui_update_toggle([handles.toggleLassoPlus, handles.toggleLassoMinus, handles.toggleCurvePlus, handles.toggleCurveMinus]);
    % Reset polygon selection
    gEditMaskData.isClicked.roiPolygon = [];
    delete(findobj(handles.axesPreview, 'Tag', 'ptCurve'));

%% ===== GET POLYGON =====
function roiMask = getMask(roiPolygon)
    global gEditMaskData;
    % Get slice size
    sliceSize = size(gEditMaskData.mri);
    sliceSize(gEditMaskData.orientation) = [];
    % Get pixel size
    pixSize = gEditMaskData.voxsize;
    pixSize(gEditMaskData.orientation) = [];
    % Build full coordinates of each pixel
    sliceX = meshgrid(1:sliceSize(1),1:sliceSize(2));
    sliceX = sliceX(:);
    sliceY = meshgrid(1:sliceSize(2),1:sliceSize(1))';
    sliceY = sliceY(:);
    % Test which pixels are inside the polygon
    iInsidePixels = inpolygon(sliceX(:), sliceY, roiPolygon(:,1) / pixSize(1), roiPolygon(:,2) / pixSize(2));
    iInsidePixels = sub2ind(sliceSize, round(sliceX(iInsidePixels)), round(sliceY(iInsidePixels)));
    % Build mask
    roiMask = false(sliceSize);
    roiMask(iInsidePixels) = 1;

%% ===== ADD MASK SLICE =====
function AddMaskSlice(sliceMask, isAddNewMask)
    % Update volume
    global gEditMaskData;
    n = gEditMaskData.sliderValue(gEditMaskData.orientation);
    % Get previous slice from mask
    initSlice = mri_getslice(gEditMaskData.mask, n, gEditMaskData.orientation);
    % Add or remove
    if isAddNewMask
        sliceMask = (initSlice | sliceMask);
    else
        sliceMask = (initSlice & ~sliceMask);
    end
    % Depends on orientation
    switch (gEditMaskData.orientation)
        case 1
            gEditMaskData.mask(n,:,:) = sliceMask;
        case 2
            gEditMaskData.mask(:,n,:) = sliceMask;
        case 3
            gEditMaskData.mask(:,:,n) = sliceMask;
    end
    % Update display
    UpdateSlice();

%% =================================================================================================
%  ===== COLORMAP AND CONTRAST =====================================================================
%  =================================================================================================
%% ===== INCREASE CONTRAST =====
function buttonContrastUp_Callback(varargin) %#ok<DEFNU>
    global gEditMaskData;
    gEditMaskData.colormapMax = max(8, gEditMaskData.colormapMax - 20);
    UpdateColormap();

%% ===== DECREASE CONTRAST =====
function buttonContrastDown_Callback(varargin) %#ok<DEFNU>
    global gEditMaskData;
    gEditMaskData.colormapMax = min(505, gEditMaskData.colormapMax + 20);
    UpdateColormap();

%% ===== UPDATE COLORMAP =====
function UpdateColormap()
    global gEditMaskData;
    mapName = gEditMaskData.colormap;
    % Between 0 and 256 : fill the map with the top color of the colormap (bright)
    if (gEditMaskData.colormapMax <= 256)
        map = eval(sprintf('%s(%d)', lower(mapName), gEditMaskData.colormapMax));
        nmap = repmat(map(gEditMaskData.colormapMax,:),256,1);
        nmap(1:gEditMaskData.colormapMax, :) = map;
    % Between 256 and 512 : fill the map with the bottom color of the colormap (dark)
    else
        map = eval(sprintf('%s(%d)', lower(mapName), 256 - mod(gEditMaskData.colormapMax, 256)));
        nmap = repmat(map(1,:),256,1);
        nmap(257-length(map):256, :) = map;
    end
    set(gEditMaskData.Handles.mri_editMask, 'Colormap', nmap);

%% =================================================================================================
%  ===== VALIDATION BUTTONS ========================================================================
%  =================================================================================================
%% ===== CANCEL BUTTON =====
function buttonCancel_Callback(varargin) %#ok<DEFNU>
    global gEditMaskData;
    % Return an empty mask
    gEditMaskData.mask = [];
    % Delete window
    delete(gEditMaskData.Handles.mri_editMask);
    drawnow;

%% ===== OK BUTTON =====
function buttonOk_Callback(varargin)  %#ok<DEFNU>
    global gEditMaskData;
    % Delete window
    delete(gEditMaskData.Handles.mri_editMask);
    drawnow;


function cab(varargin)

% This function closes all figures currently open EXCEPT for
% those listed as arguments.  'cab' stands for 'close all but'.
%
% Usage:
%       cab figure_handle1 figure_handle2 ...
%       cab(figure_handle1, figure_handle2, ...)
%       cab('last') % or also:  cab last
%
%   - The 'last' option closes all figures except the last one opened.
%   - Calling 'cab' with no arguments is a convenient
%     alternative to 'close all'
%
% Example:
%   figure(5)
%   figure(7)
%   figure(9)
%   figure(11)
%   cab(7, 11)  % or also:  cab 7 11

% all_figs = findall(0, 'type', 'figure');  % Uncomment this to include ALL windows, including those with hidden handles (e.g. GUIs)
all_figs = findobj(0, 'type', 'figure');
figs2keep = [];
for i = 1:nargin
    if ischar(varargin{i})
        if strcmp(varargin{i}, 'last')
            figs2keep = all_figs(1);
            %figs2keep = gcf;
        else
            % In this case, function was called as follows:  cab 1 2 3
            figs2keep = [figs2keep, str2num(varargin{i})];
        end
    else
        % In this case, function was called as follows:  cab(1, 2, 3)
        figs2keep = [figs2keep, varargin{i}];
    end
end

delete(setdiff(all_figs, figs2keep))


function pass = test_toFileEIG(pref)
%TEST_TOFILEEIG  Test exporting all EIG demos to an m-file.
%
% This test only checks whether nothing breaks, it does not try to solve the
% problems.

% This test won't work if we can't write to the current directory.
[ignored, attr] = fileattrib(pwd);
if ( ~attr.UserWrite )
    warning('CHEBFUN:tests:chebgui:test_toFileEIG:perms', ...
        'Cannot write to chebfunroot/tests/chebgui/.  Bypassing test.');
    pass = true;
    return;
end

% Disable discretization warnings.
% TODO: Remove this when #1555 gets merged.
warnstate = warning('OFF', 'CHEBOPPREF:PARSEDISCRETIZATION');

% Find the folders which demos are stored in. The chebguiDemos folder lives in
% the trunk folder, find the path of the Chebfun trunk.
trunkPath = chebfunroot();

% Append directory information
bvppath = fullfile(trunkPath, 'chebguiDemos', 'eigdemos');

% Set up file to exporting to
tempPath = fullfile(trunkPath, 'tests', 'chebgui');
tempFileName = 'tempExporterTest.m';

% Obtain directory information:
D = dir(bvppath);

% Create a BVP exporter object:
exporter = chebguiExporter.constructor('eig');

% Wrap the test in a try-catch statement to ensure we don't files hanging around
% in the test folder:
try

    % Loop through the demos and export
    for demoCounter = 3:length(D)

        % The path to the .guifile
        demoPath = fullfile(bvppath, D(demoCounter).name);

        % Load demo
        cg = chebgui.demo2chebgui(demoPath);

        % Export the demo!
        toFile(exporter, cg, tempFileName, tempPath)
    end

    % Got here without crashing == success!
    pass = 1;

catch
    % Something went wrong == fail :(
    pass = 0;
end

% Delete the temporary file we wrote to:
delete(fullfile(tempPath, tempFileName))

% TODO: Remove this when #1555 gets merged.
warning(warnstate.state, 'CHEBOPPREF:PARSEDISCRETIZATION')
end


function [values]=readparm(fname,parm,numval,log_flag)
%READPARM read a parameter from a file
%   [values]=readparm(fname,parm,numval,log_flag)
%   Andy Hooper, June 2011
%
%   ======================================================================
%   09/2006 AH: 'v' option added

%
if nargin<3
    numval=1;
end

if nargin<4
    log_flag=1;
end

fid=fopen(fname);
parms=textscan(fid,'%s');
fclose(fid);

parms=parms{1};
ix=strmatch(parm,parms);
msg=[parms{ix},'='];
for i=1:numval
    parmval=parms{ix+i};
    msg=[msg,parmval,' '];
    if isempty(str2num(parmval))
        values{i}=parmval;
    else
        values{i}=str2num(parmval);
    end
end

if log_flag
    logit(msg)
end

if numval==1
    values=values{1};
end


function [status, results] = mrtrix_mrconvert(orig_data_file, mif_filename, bkgrnd, verbose)
%
% Convert a nifti image to a mrtrix .mif image.
% Example
% mrtrix_mrconvert('t1.nii.gz', 't1.mif')

if notDefined('bkgrnd'),  bkgrnd  = false;end
if notDefined('verbose'), verbose = true; end

% First, deal with the possibility that the original data is compressed:
if strcmp(  orig_data_file(end-1:end), 'gz')
    % Try uncompressing it with gunzip:
    [status, results] = system(sprintf('gunzip %s', orig_data_file));
    % Need to change the target for conversion:
    convert_file = orig_data_file(1:end-3);
    if status ~= 0 && ~exist(convert_file,'file')
        error('There was some problem extracting the raw data file. \n UNIX Message: %s \n',results);
    end
else
    convert_file = orig_data_file;
end

cmd_str = sprintf('mrconvert %s %s', convert_file, mif_filename);

[status,results] = mrtrix_cmd(cmd_str, bkgrnd, verbose);

% Rezip it:
if orig_data_file(end-1:end) == 'gz'

    [s,r] = system(sprintf('gzip %s', convert_file));
end


function plot_DR30_miss(plot_obj,plot_args,legend_string)
% Plots the point on the minDCF curve at which the number of misses
% falls below 30 (see Doddington's Rule of 30).
% Inputs:
%   plot_args: A cell array of arguments to be passed to 'plot' that control
%     the appearance of the curve. See Matlab's help on 'plot' for information.
%   legend_string: Optional. A string to describe this curve in the legend.
%     This string will be prepended with the system name.

if ischar(plot_args)
    plot_args = {plot_args};
end

figure(plot_obj.fh);
assert(iscell(plot_args))
lh = plot(plot_obj.plo(plot_obj.dr30Miss),plot_obj.minDCF(plot_obj.dr30Miss),plot_args{:});

if exist('legend_string','var') && ~isempty(legend_string)
    assert(ischar(legend_string))
    plot_obj.add_legend_entry(lh,legend_string,true);
end

end


function [ drecksMDH, iLCPositions ] = fMeas_mainLUTDrecks( sFilename )
%FMEAS_MAIN main function for extracting Data, Loop counters, evalInfoMask
% and drecksMDH
%
% (c) Christian Wuerslin, Thomas Kuestner
% ---------------------------------------------------------------------

% input read parameter
% Set, Seg, Smp
% measReadPara = {[0 inf], [0 inf], [21 inf]}; % for CS_Trufi and CS_Flash, CS_Flash_Retro, CS_EPI

[sPath, sName, sExt] = fileparts(sFilename);

if(~exist(fullfile(sPath,[sName,'.mat']),'file'))
    fprintf('Creating look-up table for measdata file\n');
    fMeasCreateLUT_main(sFilename);
end

% load data
matfile = whos('-file', fullfile(sPath,[sName,'.mat']));
if(ismember('iLCDrecks', {matfile.name}) && ismember('iLCPositions', {matfile.name}))
    % drecksMDH 1.0
%     [dData, iLC, iEvalInfoMask] = fMeasRead(fullfile(sPath,[sName,sExt]), 'Set', measReadPara{1}, 'Seg', measReadPara{2}, 'Smp', measReadPara{3});
    [drecksMDH, iLCPositions] = fMeasReadDrecksMDH(fullfile(sPath,[sName,sExt]));

elseif(ismember('SDrecksMDH', {matfile.name}))
    % drecksMDH 2.0
%     [dData, iLC, iEvalInfoMask] = fMeasRead(fullfile(sPath,[sName,sExt]), 'Set', measReadPara{1}, 'Seg', measReadPara{2}, 'Smp', measReadPara{3});
    load(fullfile(sPath,[sName,'.mat']), 'SDrecksMDH');
    drecksMDH = SDrecksMDH;
    iLCPositions = [];
else
    % no drecksMDH at all
%     [dData, iLC, iEvalInfoMask] = fMeasRead(fullfile(sPath,[sName,sExt]), 'Set', measReadPara{1}, 'Seg', measReadPara{2}, 'Smp', measReadPara{3});
    drecksMDH = [];
    iLCPositions = [];
end

end


function varargout = myparse(params,varargin)

nin = length(varargin)/2;
nout = nargout;
if mod(2*nin,2)~=0 || mod(length(params),2)~=0,
  error('Odd number of parameters expected');
end;

% set defaults
varargout = varargin(2:2:2*nout);

% parameter names
names = varargin(1:2:end);

% go through parameters
for i = 1:2:length(params),

  % check if it matches names{j}
  if ~ischar(params{i}),
    error('Input %d is not a string.',i);
  end

  %BJA:  6x faster than that below
  idx=find(strcmpi(params{i},names));
  if(isempty(idx))
    warning('myparse:unknownParameterName','Unknown parameter name: %s, ignoring\n',params{i});
  else
    varargout{idx} = params{i+1};
  end

%  if ~any(strcmpi(params{i},names)),
%    warning('myparse:unknownParameterName','Unknown parameter name: %s, ignoring\n',params{i});
%  end
%
%  for j = 1:length(names),
%
%    % set value
%    if strcmpi(params{i},names{j}),
%      varargout{j} = params{i+1};
%    end;
%
%  end;

end;


function [transformed_sequence] = sequence_pixelchange(sequence, operation, name)
% sequence_pixelchange Returns sequence with arbitrary pixel transformation
%
% This sequence converter returns sequence with arbitrary pixel transformation that preserves the
% size of the image and the groundtruth.
%
% Cache notice: The results of this function are cached in the workspace cache directory.
%
% Input:
% - sequence (structure): A valid sequence structure.
% - operation (function): A handle of the pixel transformation function.
% - name (string, optional): Name of the operation for caching purposes.
%
% Output:
% - tranform_sequence (structure): A sequence descriptor of a converted sequence.

if ischar(operation)
    operation_name = operation;
    operation = str2func(operation_name);
else
    operation_name = func2str(operation);
end;

if ~isempty(name) && ischar(name)
    operation_name = name;
end;

cache_directory = fullfile(get_global_variable('directory'), 'cache', ...
    sprintf('pixelchange_%s', operation_name), sequence.name);

mkpath(cache_directory);

cache_groundtruth = fullfile(cache_directory, 'groundtruth.txt');

sequence_groundtruth = fullfile(sequence.directory, 'groundtruth.txt');

if file_newer_than(cache_groundtruth, sequence_groundtruth)
    transformed_sequence = sequence_create(cache_directory, 'name', sequence.name);
    transformed_sequence.values.names = sequence.values.names;
    transformed_sequence.values.data = sequence.values.data;
    return;
end;

print_debug('Generating cached sequence ''%s'' for operation ''%s''...', sequence.name, operation_name);

tags_cache_names = cell(0, 0);
tags_cache_data = false(sequence.length, 0);

for i = 1:sequence.length

    original_image = imread(sequence_get_image(sequence, i));
    original_tags = get_tags(sequence, i);

    [transformed_image, transformed_tags] = operation(original_image, ...
        original_tags, i, sequence.length);

    for l = 1:length(transformed_tags)
        if ~ismember(transformed_tags{l}, tags_cache_names)
            tags_cache_data = cat(2, tags_cache_data, false(sequence.length, 0));
            tags_cache_names{end+1} = transformed_tags{l};  %#ok<AGROW>
        end;
        tags_cache_data(i, strcmp(tags_cache_names, transformed_tags{l})) = 1;
    end;

    if size(transformed_image, 3) == 1
        transformed_image = repmat(rgb2gray(transformed_image), [1 1 3]);
    end;

    if size(original_image, 1) ~= size(transformed_image, 1) || ...
            size(original_image, 2) ~= size(transformed_image, 2)
        error('The operation should return image of same width and height.');
    end;

    imwrite(transformed_image, fullfile(cache_directory, sprintf('%08d.jpg', i)));

end;

for l = 1:length(tags_cache_names)
    csvwrite(fullfile(cache_directory, sprintf('%s.tag', ...
        tags_cache_names{l})), tags_cache_data(:, l));
end;

write_trajectory(cache_groundtruth, sequence.groundtruth);

transformed_sequence = sequence_create(cache_directory, 'name', sequence.name);

transformed_sequence.values.names = sequence.values.names;
transformed_sequence.values.data = sequence.values.data;


function title = p26_title ( )

%*****************************************************************************80
%
%% P26_TITLE returns the title of problem P26.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string TITLE, the title of the problem.
%
  title = 'Problem 26, Enright and Pryce #F1';

  return
end


function answer = is_function_called (line, func)
    % number of occurrences of each pattern:
    n1 = length( regexp(line, ['\<' func '\>']) );
    n2 = length( regexp(line, ['''.*\<' func '\>.*''']) );

    answer = n1 > n2;
end

%!test
%! myassert(is_function_called ('test', 'test'));
%! myassert(is_function_called ('abc test', 'test'));
%! myassert(is_function_called ('test abc', 'test'));
%! myassert(is_function_called ('abc test abc', 'test'));
%! myassert(~is_function_called ('abctest', 'test'));
%! myassert(~is_function_called ('testabc', 'test'));
%! myassert(~is_function_called ('abc ''test'' abc', 'test'));
%! myassert(~is_function_called ('''abc test abc''', 'test'));
%! myassert(is_function_called ('''abc'' test abc', 'test'));
%! myassert(is_function_called ('abc test ''abc''', 'test'));

%!test
%! myassert(is_function_called(...
%!     'myassert (s.identifier, ''myassert:error'');', 'myassert'));


function test_example_bids_meg

% MEM 4gb
% WALLTIME 00:10:00

%
%% Converting an example MEG dataset for sharing in BIDS
%
%
% The general description of how MEG data can be shared in the [BIDS format](https://bids.neuroimaging.io) is described in the paper [MEG-BIDS, the brain imaging data structure extended to magnetoencephalography](https://doi.org/10.1038/sdata.2018.110) by Guiomar Niso, et al. Scientific Data volume 5, Article number: 180110 (2018). The BIDS standard itself with all details can be found on <https://bids-standard.org>.
%
%% # CTF
%
% The CTF MEG file format consists of recordings that are represented in a directory with the extension `*.ds`. The directory contains multiple files, where the `*.res4` contains most of the header information, and the `*.meg4` files (there can be multiple) contain the data. However, also the other files contain relevant data and/or metadata, such as markers and information on how the data has been processed.
%
% In general you **should not** simply rename the directory, or mess with the files in the directory by hand, since there are multiple files that need to have a consistent file naming structure. The CTF Linux command-line software includes tools for anonimizing and renaming datasets in a consistent fashion and [this example page](/faq/how_can_i_anonymize_a_ctf_dataset/) also presents a way of doing it directly in MATLAB.
%
%% ## Example
%
% This dataset corresponds to the paper by Erik te Woerd et al. [Impaired auditory-to-motor entrainment in Parkinson’s disease](https://doi.org/10.1152/jn.00547.2016). J Neurophysiol. 2017 May 1;117(5):1853-1864. doi: 10.1152/jn.00547.2016.
%
% The complete dataset consists of MEG data recorded from 15 Parkinson patients and 15 control participants. In three of the sessions the recording was interrupted, causing those sessions to be split over 2 runs. Consequently, there are 33 CTF `*.ds` dataset directories to start with. The data from two participants was excluded from further analysis.
%
% Control subjects are coded from S101 to S115, patients are coded from S201 to S215. Besides the pseudonimized subject identifier, there is also a run number in the original file name (which is relevant for three of the recordings), the project number, the experimenter, and the date at which the recording was done. Since the date might be recognizeable for the participants and/or their family members, we will treat that as potentially identifying information and scrub it from the dataset.
%
% The data is anonimized using the `go_anonymiseDs.m` function from [this example page](/faq/how_can_i_anonymize_a_ctf_dataset/#using-matlab). This reads in the data with a low-level CTF function, scrubs potentially identifying  information, and writes it with a low-level CTF function. Some of the auxiliary files that can optionally be present (for example when the data was opened with the CTF DataEditor application) and the headlocalizer data will be ignored upon reading, and hence also not appear in the copy that is written.
%
% The anonimized version of the CTF data has a short descriptive name. Using the **[data2bids](https://github.com/fieldtrip/fieldtrip/blob/release/data2bids.m)** we copy and rename the CTF data so that it has the right directory structure and file names, and we add the metadata.
%
%
subj = {
  'S101'
  'S102'
  'S103'
  'S104'
  'S105'
  'S106'
  'S107'
  'S108'
  'S109'
  'S110'
  'S111'
  'S112'
  'S113'
  'S114'
  'S115'
  'S201'
  'S202'
  'S203'
  'S204'
  'S205'
  'S206'
  'S207'
  'S208'
  'S209'
  'S210'
  'S211'
  'S212'
  'S213'
  'S214'
  'S215'
  };

for subindx=1:numel(subj)
  for runindx=1:2

    % the number 3018009.04 in the dataset name refers to the DCCN project identifier
    % all data acquisition was done using study-specific participant identifiers rather than names
    % the CTF dataset name contains the recording date, but here we use a wildcard instead

    d = dir(sprintf('../original/301800904eritwoe%s00%d_1200hz_*_01.ds', subj{subindx}, runindx));
    if isempty(d)
      % for most subjects the data was recorded in a single run
      % in that case run 2 does not exist
      continue
    else
      origname = fullfile(d.folder, d.name);
      anonname = fullfile(d.folder, sprintf('%s_%d.ds', subj{subindx}, runindx));
      disp(anonname); % this is just an intermediate name, the final name will be assigned by data2bids
    end

    if ~isfolder(anonname)
      go_anonymiseDs(origname, anonname);
    end

    cfg = [];

    cfg.bidsroot = '../bids';  % write to the present working directory
    cfg.sub = subj{subindx};
    cfg.run = runindx;
    cfg.dataset = anonname; % this is the intermediate name

    cfg.datatype = 'meg';
    cfg.method = 'copy'; % the original data is in a BIDS-compliant format and can simply be copied

    cfg.InstitutionName             = 'Radboud University';
    cfg.InstitutionalDepartmentName = 'Donders Institute for Brain, Cognition and Behaviour';
    cfg.InstitutionAddress          = 'Kapittelweg 29, 6525 EN, Nijmegen, The Netherlands';

    % required for dataset_description.json
    cfg.dataset_description.Name                = 'Impaired auditory-to-motor entrainment in Parkinson''s disease';
    cfg.dataset_description.BIDSVersion         = 'v1.5.0';

    % optional for dataset_description.json
    cfg.dataset_description.License             = 'RU-DI-HD-1.0';
    cfg.dataset_description.Authors             = 'Te Woerd ES, Oostenveld R, de Lange FP, Praamstra P';
    cfg.dataset_description.ReferencesAndLinks  = {'https://doi.org/10.1152/jn.00547.2016'};
    cfg.dataset_description.EthicsApprovals     = 'DCCN 3018009.04';

    cfg.TaskDescription = 'The experiment consisted of an auditory target detection task. Three cue tones of different frequencies (900, 1,100 and 1,300 Hz; 50-ms duration) predicted the probability (10, 30, 50%) of the next stimulus being the target tone (2,000 Hz; 50-ms duration) (Fig. 1A). The pitch of standard tones was chosen to be separated by 200 Hz and the target differed 700 Hz from the highest standard tone, which enabled subjects to detect the target tone easily. Participants were informed about the meaning of the standard tones and instructed to press the response button as swift as possible with the index finger of their dominant hand.';
    cfg.task = 'auditory';

    try
      data2bids(cfg);
    catch
      % this is probably because the output dataset already exists
      % this is due to running the script multiple times
      disp(lasterr)
    end

  end % for each run
end % for each subject
%
% Following this conversion, the `participant.tsv` file only contains the subject identifiers. There is more information in an Excel file, such as the age, sex, clinical state, questionaire data, lab notes. In principle it would be possible to copy that into the MATLAB script and use data2bids to export that, but in this case it was easier to use "save-as" and then select "tab-delimited-text" as the output format.


function y=horzcat(varargin)
%% TT-Toolbox 2.2.1, 2009-2016
%This is TT Toolbox, written by Ivan Oseledets et al.
%Institute of Numerical Mathematics, Moscow, Russia
%webpage: http://spring.inm.ras.ru/osel

%for questions on this particular code email Alexey Boyko, Skolkovo Institute of Science and Technology,
% a.boyko@skoltech.ru or alexey.boyko@skolkovotech.ru
%Moscow, Russia, 2016
%%

%now you can assemble rectangular matrices horizontally like
%ttAA=[ttA ttA]

%Attention!
%Due to limitations of MATLAB, for simultaneous horizontal and vertical concatenation
% use
% ttM=tt_blockwise({ttA ttB ttC; ttD ttE ttF ;ttG ttH ttI })
% instead of
% ttM=[ttA ttB ttC; ttD ttE ttF ;ttG ttH ttI ]

y=tt_blockwise(varargin);
end


any(cellfun(@exist,{'arraydeal', 'chopdeal'})==3)


function [cm,cmd] = getColormaps

fnd = dir([mtex_path filesep 'plotting' filesep 'colormaps' filesep '*ColorMap.m']);

% remove extension to create command
cmd = cellfun(@(x) x(1:end-2),{fnd.name},'UniformOutput',false);

% remove ColorMap
cm = cellfun(@(x) x(1:end-8),cmd,'UniformOutput',false);

end


function r = cache_file_is_there_and_newer_than(cache_file,main_file)

r = false;
main_info = dir(main_file);
main_date = datenum(main_info.date);
cache_info = dir(cache_file);
if(~isempty(cache_info)) %if there is a cache file (and it is newer than the main file)
    cache_date = datenum(cache_info.date);
    if  cache_date>main_date
        r = true;
    end
end


function [model,labels] = fgplvmReadFromFile(fileName)

% FGPLVMREADFROMFILE Load a file produced by the C++ implementation.
% FORMAT
% DESC loads a GP-LVM model from a file produced by the C++
% implementation of the GP-LVM.
% ARG fileName : the file name written by the C++ software.
% RETURN model : a MATLAB GP-LVM model structure containing the
% model from the file.
% RETURN labels : any available labels from the GP-LVM file.
%
% SEEALSO : fgplvmReadFromFID, fgplvmCreate
%
% COPYRIGHT : Neil D. Lawrence, 2005

% FGPLVM

FID = fopen(fileName);
if FID==-1
  error(['Cannot find file ' fileName])
end
[model, labels] = fgplvmReadFromFID(FID);
fclose(FID);


path = '../traindata/original_segment/';
for i = 1:19
    save_folder = ['../testdata/original_mask/' sprintf('%02d',i) '/'];
    mkdir(save_folder);

    dirs = dir(['../data/original_segment/' sprintf('%02d',i),'/*.mat']);
    dirs = struct2cell(dirs);
    for j = 2976:size(dirs,2)
        delete(['../data/original_segment/' sprintf('%02d',i),'/' dirs{1,j}])
        %load(['../data/original_segment/' sprintf('%02d',i),'/' dirs{1,j}]);
        %save([save_folder dirs{1,j}],'library_mask','library_mask_pole');

    end

end