% READEDF - read eeg data in EDF format.
%
% Usage:
%    >> [data,header] = readedf(filename);
%
% Input:
%    filename - file name of the eeg data
%
% Output:
%    data   - eeg data in (channel, timepoint)
%    header - structured information about the read eeg data
%      header.length - length of header to jump to the first entry of eeg data
%      header.records - how many frames in the eeg data file
%      header.duration - duration (measured in second) of one frame
%      header.channels - channel number in eeg data file
%      header.channelname - channel name
%      header.transducer - type of eeg electrods used to acquire
%      header.physdime - details
%      header.physmin - details
%      header.physmax - details
%      header.digimin - details
%      header.digimax - details
%      header.prefilt - pre-filterization spec
%      header.samplerate - sampling rate
%
% Author: Jeng-Ren Duann, CNL/Salk Inst., 2001-12-21

% Copyright (C) Jeng-Ren Duann, CNL/Salk Inst., 2001-12-21
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

% 03-21-02 editing header, add help -ad

function [data,header] = readedf(filename);

if nargin < 1
    help readedf;
    return;
end

fp = fopen(filename,'r','ieee-le');
if fp == -1,
  error('File not found ...!');
  return;
end

hdr = setstr(fread(fp,256,'uchar')');
header.length = str2num(hdr(185:192));
header.records = str2num(hdr(237:244));
header.duration = str2num(hdr(245:252));
header.channels = str2num(hdr(253:256));
header.channelname = setstr(fread(fp,[16,header.channels],'char')');
header.transducer = setstr(fread(fp,[80,header.channels],'char')');
header.physdime = setstr(fread(fp,[8,header.channels],'char')');
header.physmin = str2num(setstr(fread(fp,[8,header.channels],'char')'));
header.physmax = str2num(setstr(fread(fp,[8,header.channels],'char')'));
header.digimin = str2num(setstr(fread(fp,[8,header.channels],'char')'));
header.digimax = str2num(setstr(fread(fp,[8,header.channels],'char')'));
header.prefilt = setstr(fread(fp,[80,header.channels],'char')');
header.samplerate = str2num(setstr(fread(fp,[8,header.channels],'char')'))./header.duration;

fseek(fp,header.length,-1);
data = fread(fp,'int16');
fclose(fp);

data = reshape(data,header.duration*header.samplerate(1),header.channels,header.records);
temp = [];
for i=1:header.records,
  temp = [temp data(:,:,i)'];
end
data = temp;


function z=mtkron(varargin)
    %"Tensor" Kronecker product (in "TT" order) of multiple matrices
    %   Z=MTKRON(A,B,C,...) Takes Kronecker product of the arguments
    %   See also TT_TENSOR/TKRON, TT_MATRIX/TKRON
    %
    %
    %   it also takes a cell array of tt_tensors as a single input
    %
    % 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 all questions, bugs and suggestions please mail
    %ivan.oseledets@gmail.com
    %---------------------------
    %Last tweaks by Alexey Boyko of Oseledets' group
    %alexey.boyko@skolkovotech.ru

    z=varargin{1};
    if numel(z)~=1
        % in case it's a cell array of tt_tensors as a single input
        varargin=z;
        z=varargin{1};
    end
    for i=2:numel(varargin)
      z=tkron(z,varargin{i});
    end
end


function [solution,output] = NMPC_Solve(x0,p,options)
    tStart = Timer();

    persistent lambdaInit muInit uInit xInit zInit LAMBDAInit;

    global ParNMPCGlobalVariable
    dim = ParNMPCGlobalVariable.dim;
    N   = ParNMPCGlobalVariable.N;

    % only for the very first problem
    solutionInitGuess = ParNMPCGlobalVariable.solutionInitGuess;

    % Reshape
    sizeSeg     = N/options.DoP;
    pSplit      = reshape(p,      dim.p,        sizeSeg, options.DoP);

    if isempty(xInit)
        lambdaInit = reshape(solutionInitGuess.lambda, dim.lambda,   sizeSeg, options.DoP);
        uInit      = reshape(solutionInitGuess.u,      dim.u,        sizeSeg, options.DoP);
        xInit      = reshape(solutionInitGuess.x,      dim.x,        sizeSeg, options.DoP);
        LAMBDAInit = reshape(solutionInitGuess.LAMBDA, dim.x, dim.x, sizeSeg, options.DoP);
        % assert
        if coder.target('MATLAB') % Normal excution
            checkFeasibility(solutionInitGuess,p);
            checkOptions(options);
        end
    end
    if dim.mu ~= 0
        muInit     = reshape(solutionInitGuess.mu,     dim.mu,       sizeSeg, options.DoP);
    end
    if dim.z ~= 0
        zInit      = reshape(solutionInitGuess.z,      dim.z,        sizeSeg, options.DoP);
    end

    % Init
    lambdaSplit = lambdaInit;
    if dim.mu ~= 0
        muSplit = muInit;
    else
        muSplit = zeros(dim.mu,sizeSeg, options.DoP);
    end
    uSplit      = uInit;
    xSplit      = xInit;
    if dim.z ~= 0
        zSplit = zInit;
    else
        zSplit = zeros(dim.z,sizeSeg, options.DoP);
    end
    LAMBDASplit = LAMBDAInit;

    output   = createOutput();
    solution = createSolution(dim,N);
    costL = 0;
    error = 0;
    tLineSearch = 0;
    if (options.rhoInit == options.rhoEnd)
        options.maxIterInit = options.maxIterTotal;
        options.tolInit = options.tolEnd;
    end
    rho     = options.rhoInit;
    mode    = 1;

    % initialize a filter [LAll;xEq+C;flag]
    lineSearchFilterWidth = 10;
    lineSearchFilter = zeros(3,lineSearchFilterWidth);

    % Iteration
    for iter=1:options.maxIterTotal
        % backup
        lambdaSplit_k = lambdaSplit;
        muSplit_k     = muSplit;
        uSplit_k      = uSplit;
        xSplit_k      = xSplit;
        %% Search direction
        [lambdaSplit,muSplit,uSplit,xSplit,zSplit,LAMBDASplit,KKTError,costL,tSearchDirection] = ...
            NMPC_Solve_SearchDirection(x0,pSplit,rho,lambdaSplit,muSplit,uSplit,xSplit,zSplit,LAMBDASplit);
        output.timeElapsed.searchDirection = output.timeElapsed.searchDirection + tSearchDirection;
        %% Line search
        stepSize = 1;
        if options.isLineSearch
            switch options.lineSearchMethod
                case 'merit'
                    scaling = 1.5;
                    lambdaSplitAbs = abs(lambdaSplit);
                    lambdaSplitMax3 =  max(lambdaSplitAbs,[],2);
                    phiX = max(lambdaSplitMax3,[],3);
                    muSplitAbs = abs(muSplit);
                    muSplitMax3 =  max(muSplitAbs,[],2);
                    phiC = max(muSplitMax3,[],3);
                    [lambdaSplit,muSplit,uSplit,xSplit,stepSize,tLineSearch] = ...
                        NMPC_LineSearch_Merit(x0,pSplit,rho,lambdaSplit_k,muSplit_k,uSplit_k,xSplit_k,...
                                        lambdaSplit,muSplit,uSplit,xSplit,phiX*scaling,phiC*scaling);
                case 'filter'
                    [lambdaSplit,muSplit,uSplit,xSplit,lineSearchFilter,stepSize,tLineSearch] = ...
                        NMPC_LineSearch_Filter(x0,pSplit,rho,lambdaSplit_k,muSplit_k,uSplit_k,xSplit_k,...
                                        lambdaSplit,muSplit,uSplit,xSplit,lineSearchFilter);
                otherwise
                    if coder.target('MATLAB') % Normal excution
                            warning('Specified linesearch method is not supported!');
                    end
            end
            output.timeElapsed.lineSearch = output.timeElapsed.lineSearch + tLineSearch;
        end
        %% KKT error
        tKKTErrorCheck = 0;
        if options.checkKKTErrorAfterIteration
            [KKTError,costL,tKKTErrorCheck]   = ...
                NMPC_KKTError(x0,pSplit,rho,lambdaSplit,muSplit,uSplit,xSplit);
            KKTErrorScaling = 1;
        else
            % avoid chattering of the num of iter
            KKTErrorScaling = 5;
        end
        sMax = 100;
        lambda_L1Norm = norm(lambdaSplit(:),1);
        HuScaling =  (lambda_L1Norm + norm(muSplit(:),1))/(dim.lambda+dim.mu)/N;
        HuScaling = max(sMax,HuScaling)/sMax;
        costateEquationScaling = max(sMax,lambda_L1Norm/dim.lambda/N)/sMax;
        error = max([KKTError.stateEquation*KKTErrorScaling;...
                     KKTError.C/KKTErrorScaling;...
                     KKTError.Hu/HuScaling/KKTErrorScaling;...
                     KKTError.costateEquation/costateEquationScaling/KKTErrorScaling]);
        output.timeElapsed.KKTErrorCheck = output.timeElapsed.KKTErrorCheck + tKKTErrorCheck;
        %% print
        if coder.target('MATLAB') % Normal excution
            if options.printLevel == 1
                printMsg = ['Iter: ',num2str(iter),...
                            '   KKTError: ',num2str(error),...
                            '   Cost: ',num2str(costL),...
                            '   rho: ',num2str(rho),...
                            '   Step size: ',num2str(stepSize)];
                disp(printMsg);
            end
        end
        %% barrier parameter update
        switch mode
            case 1 % init
                if (error < options.tolInit) || (iter >= options.maxIterInit)
                    mode = 2;
                    lambdaInit = lambdaSplit;
                    if dim.mu ~= 0
                        muInit     = muSplit;
                    end
                    uInit      = uSplit;
                    xInit      = xSplit;
                    if dim.z ~= 0
                        zInit     = zSplit;
                    end
                    LAMBDAInit = LAMBDASplit;

                    output.iterInit          = iter;
                    if (options.rhoInit == options.rhoEnd) && (error < options.tolEnd)
                        output.exitflag = 1;
                        break;
                    end
                end
            case 2 % decay
                rho = rho * options.rhoDecayRate;
                rho(rho<options.rhoEnd) = options.rhoEnd;
                if (error<options.tolEnd) && (rho == options.rhoEnd)
                    output.exitflag = 1;
                    break;
                end
        end
    end
    %% Reshape
    solution.lambda = reshape(lambdaSplit, dim.lambda,   N);
    solution.mu     = reshape(muSplit,     dim.mu,       N);
    solution.u      = reshape(uSplit,      dim.u,        N);
    solution.x      = reshape(xSplit,      dim.x,        N);
    solution.z      = reshape(zSplit,      dim.z,        N);
    solution.LAMBDA = reshape(LAMBDASplit, dim.x, dim.x, N);

    output.cost            = costL;
    output.KKTError        = error;
    output.rho             = rho;
    output.iterTotal       = iter;

    tEnd = Timer();

    output.timeElapsed.total = tEnd-tStart;
end


function [valScaled, valFactor, valUnits] = bst_getunits( val, DataType, FileName, DisplayUnits)
% BST_GETUNITS: Get in which units is expressed a value.
%
% USAGE:  [valScaled, valFactor, valUnits] = bst_getunits(val, DataType, FileName=[], DisplayUnits=[]);
%
% INPUT:
%    - val       : Value to analyze
%    - DataType  : Type of data in the value "val". Possible strings:
%                  'EEG', 'MEG', 'MEG MAG', 'MEG GRAD', 'ECOG', 'SEEG', '$MEG', '$EEG', '$ECOG', '$SEEG', 'results', 'sources', 'source', 'stat', ...
%    - fUnits : Units of the file (eg "" if unknown, "cm", "pA", "mml/l")
%
% OUTPUT:
%    - valScaled : value in the detected units (val * valFactor)
%    - valFactor : factor to convert val -> valScaled
%    - valUnits  : string that represents the units ('\muV', 'fT', 'pA.m', etc.)

% @=============================================================================
% 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, 2008-2022
%          Edouard Delaire, 2021-2022

% Parse inputs
if (nargin < 4) || isempty(DisplayUnits)
    DisplayUnits = [];
end

% Check if there is something special in the filename
if (nargin >= 3) && ~isempty(FileName)
    % Source files
    if ismember(lower(DataType), {'results', 'sources', 'source'})
        % Detect sLORETA source files
        if ~isempty(strfind(lower(FileName), 'sloreta'));
            DataType = 'sloreta';
        % Detect NIRS source files
        elseif ~isempty(strfind(lower(FileName), 'nirs'))
            DataType = 'nirs-src';
        end
    end
end

% Consider input data in absolute value
val = abs(val);
% If no modality (ex: surface mask, mri values...)
if isempty(DataType)
    DataType = 'none';
end

% If the display unit is already defined
if ~isempty(DisplayUnits)
    if ismember(lower(DataType), {'nirs', '$nirs','nirs-src'})
        if ~isempty(strfind(DisplayUnits, 'mol'))
            [valFactor, valUnits] = GetSIFactor(val, DisplayUnits);
        elseif ~isempty(strfind(DisplayUnits, 'cm'))
            valFactor = 1;
            valUnits  = 'cm';
        elseif ~isempty(strfind(DisplayUnits, 'delta'))
            [valFactor, valUnits] = GetExponent(val);
            valUnits = sprintf('%s(%s)',strrep(DisplayUnits,'delta ','\Delta'),valUnits);
        else
            [valFactor, valUnits] = GetExponent(val);
            iParent =  find(DisplayUnits == '(');
            if ~isempty(iParent)
                DisplayUnits = DisplayUnits(1:iParent-1);
            end
            valUnits = sprintf('%s(%s)',DisplayUnits,valUnits);
        end
    else
        valUnits = DisplayUnits;
        switch (DisplayUnits)
            case 'fT'
                valFactor = 1e15;
            case 'pA.m'
                valFactor = 1e12;
            case '\muV'
                valFactor = 1e6;
            case {'mV', 'mm'}
                valFactor = 1e3;
            otherwise
                valFactor = 1;
        end
    end

% Otherwise: Units depends= on the data modality
else
    switch lower(DataType)
        case {'meg', '$meg', 'meg grad', 'meg mag', '$meg grad', '$meg mag', 'meg grad2', 'meg grad3', 'meg gradnorm'}
            % MEG data in fT
            if (val < 1e-8)
                valFactor = 1e15;
                valUnits  = 'fT';
            % MEG data without units (zscore, stat...)
            else
                valFactor = 1;
                valUnits  = 'No units';
            end

        case {'eeg', '$eeg', 'ecog', '$ecog', 'seeg', '$seeg', 'eog', '$eog', 'ecg', '$ecg', 'emg', '$emg'}
            % EEG data in Volts, displayed in microVolts
            if (val < 0.01)
                valFactor = 1e6;
                valUnits = '\muV';
            % EEG data in Volts, displayed in milliVolts
            elseif (val < 1)
                valFactor = 1e3;
                valUnits = 'mV';
            % EEG data without units (zscore, stat...)
            else
                valFactor = 1;
                valUnits = 'No units';
            end
        case {'nirs', '$nirs','nirs-src'}
             [valFactor, valUnits] = GetExponent(val);
        case {'results', 'sources', 'source'}
            % Results in Amper.meter (display in picoAmper.meter)
            if (val < 1e-4)
                valFactor = 1e12;
                valUnits  = 'pA.m';
            % Results without units (zscore, stat...)
            else
                valFactor = 1;
                valUnits  = 'No units';
            end

        case 'sloreta'
            if (val < 1e-4)
                [valFactor, valUnits] = GetExponent(val);
            else
                valFactor = 1;
                valUnits  = 'No units';
            end

        case 'stat'
            if (val < 1e-13)
                [valFactor, valUnits] = GetExponent(val);
            elseif (val < 1e-8)
                valFactor = 1e12;
                valUnits  = 'pA.m';
            elseif (val < 1e-3)
                [valFactor, valUnits] = GetExponent(val);
            else
                valFactor = 1;
                valUnits  = 'No units';
            end

        case 'connect'
            valFactor = 1;
            valUnits  = 'score';

        case 'timefreq'
            [valFactor, valUnits] = GetExponent(val);

        case 'hlu'
            valFactor = 1e3;
            valUnits  = 'mm';

        case {'ica', 'ssp'}
            [valFactor, valUnits] = GetExponent(val);
            if (valFactor == 0)
                valUnits = 'a.u.';
            else
                valUnits = ['x' valUnits ' a.u.'];
            end

        otherwise
            if isempty(val) || ((val < 1000) && (val > 0.1))
                valFactor = 1;
                valUnits  = 'No units';
            else
                [valFactor, valUnits] = GetExponent(val);
            end
    end
end
% Scale input value
valScaled = val .* valFactor;

end

%% ===== GET EXPONENT =====
function [valFactor, valUnits] = GetExponent(val)
    if (val == 0)
        valFactor = 1;
        valUnits  = 'No units';
    else
        %exponent = round(log(val)/log(10) / 3) * 3;
        exponent = round(log(val)/log(10)) - 1;
        % Do not allow 10^-1 and 10^-2
        if (exponent == -1) || (exponent == -2)
            valFactor = 1;
            valUnits  = 'No units';
        else
            valFactor = 10 ^ -exponent;
            valUnits  = sprintf('10^{%d}', exponent);
        end
    end
end

function [valFactor, valUnits] = GetSIFactor(val, originalUnit)
    vpw = [    -24,    -21,   -18,    -15,   -12,    -9,     -6,   -3, 0   +3,    +6,    +9,   +12,   +15,  +18,    +21,    +24];
    pfn = {'yocto','zepto','atto','femto','pico','nano','micro','milli','','kilo','mega','giga','tera','peta','exa','zetta','yotta'};
    pfs = {'y'    ,'z'    ,'a'   ,'f'    ,'p'   ,'n'   ,'\mu'    ,'m' ,'','k'   ,'M'   ,'G'   ,'T'   ,'P'   ,'E'  ,'Z'    ,'Y'    };
    sgf = 5;
    dpw = mode(diff(vpw));

    [unit, modifier] = getUnit(originalUnit);
    if abs(val) > 10^-2
        valFactor = 1;
        valUnits = originalUnit;
        return
    end

    adj = n2pAdjust(log10(abs(val)),dpw);

    vec = val./10.^adj;
    % Determine the number of decimal places:
    p10 = 10.^(sgf-1-floor(log10(abs(vec))));
    % Round coefficients to decimal places:
    vec = round(vec.*p10)./p10;
    % Identify which prefix is required:
    idx = 1+any(abs(vec)==[10.^dpw,1]);
    pwr = 1+floor(log10(abs(vec(idx))));

    % Obtain the required prefix index:
    idp = find(adj(idx)==vpw);

    valFactor = 10^(- vpw(idp));
    valUnits  = sprintf('%s%s',pfs{idp-1}, unit);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%num2sip
function adj = n2pAdjust(pwr,dPw)
adj = dPw*((0:1)+floor(floor(pwr)/dPw));
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%n2pAdjust
function [unit, modifier] = getUnit(data)
% return the unit and the modifier from a string
% getUnit('mol/l') should return mol/l and 0
% getUnit('mmol/l') should return mol/l and -1
% getUnit('pA') should return A and -4

pfs = {'y'    ,'z'    ,'a'   ,'f'    ,'p'   ,'n'   ,'\mu'    ,'m' ,'','k'   ,'M'   ,'G'   ,'T'   ,'P'   ,'E'  ,'Z'    ,'Y'    };
vpw = [    -24,    -21,   -18,    -15,   -12,    -9,     -6,   -3, 0   +3,    +6,    +9,   +12,   +15,  +18,    +21,    +24];

Units = {'A','mol.l-1'};

unit = Units{cellfun(@(x)contains(data,x), Units)};
modifier = find(strcmp(strcat(pfs,unit),data)) - 9 ;

end


% designsim_gui_script
% Last modified 5/20/01 by Tor Wager		add optional trans2switch from GUI.  still need block.
% also added power calculation.

% sets defaults, reads GUI values from optimizeGUI, and runs simulation

disp('Designsim_gui_script')
disp('===============================')
disp('  ...Setting up variables from GUI.')
% returns vector of t values as t in workspace.

if ~exist('M') | ~isstruct(M),disp('	...No GA results (M struct) detected - using only random designs.'),end

clear SIM
clear H;

% ----------------------------------------------------------------
% * setup defauls
% ----------------------------------------------------------------
% fixed parameters
% --------------------
powerTvoxels = 30000;
powerTdf = 19;
format compact

% parameters from GUI
% --------------------
nonlinthreshold = 4;
noise_var = 0.3;
beta = [.5 .5 0 0;1 1 0 0];	% 20
c = [1 1 -1 -1];					% 13
niterations = 500;
conditions = [1 2 3 4];
ISI = 1.2;
restevery = 9;						% 26
restlength = 2;					% 25
HPlength = 60;						% 23
xc = [1 0];							% 24
trans2switch = 0;

% ----------------------------------------------------------------
% * setup input from GUI
% ----------------------------------------------------------------
% read values from GUI for GA
H = findobj('Tag', 'E1');                                                                                if ~isempty(H)
conditions = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E4');
ISI = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E12');
noise_var = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E13');
c = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E14');
niterations = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E15');
respMean = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E16');
respSD = str2num(get(H(1), 'String'));

H = findobj('Tag', 'C1');
addResponseVariability = get(H(1), 'Value');

% additional values required for random sim.

H = findobj('Tag', 'E2');
freqConditions = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E3');
scanLength = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E5');
TR = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E6');
cbalColinPowerWeights = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E7');
numGenerations = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E8');
sizeGenerations = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E9');
lowerLimit = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E10');
maxOrder = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E11');
plotFlag = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E20');
beta = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E23');
HPlength = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E24');
eval(['load ' get(H(1), 'String')]);

H = findobj('Tag', 'E25');
restlength = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E26');
restevery = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E27');
trans2switch = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E28');
trans2block = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E30');
NumStimthresh = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E31');
maxCbalDevthresh = str2num(get(H(1), 'String')); 	% counterbalancing deviation

H = findobj('Tag', 'E32');
maxFreqDevthresh = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E33');
nonlinthreshold = str2num(get(H(1), 'String'));

H = findobj('Tag', 'E34');
dofirst = str2num(get(H(1), 'String'));

end % ~isempty(H) : means found the GUI

% ----------------------------------------------------------------
% * setup lists, HRF, and other parameters
% ----------------------------------------------------------------

HRF = spm_hrf(.1);
HRF = HRF/ max(HRF);

SIM.beta = beta;
SIM.contrasts = c;
SIM.noise_var = noise_var;
SIM.xc = xc;
SIM.ISI = ISI;
SIM.HPlength = HPlength;
SIM.restevery = restevery;
SIM.restlen = restlength;
SIM.niterations = niterations;
SIM.noise_var = noise_var;
SIM.freqConditions = freqConditions;

SIM.NumStimthresh = NumStimthresh;
SIM.maxCbalDevthresh = maxCbalDevthresh;
SIM.maxFreqDevthresh = maxFreqDevthresh;
SIM.nonlinthreshold = nonlinthreshold;

disp('  ...Generating design list.')
% for building RANDOM designs to test against GA design
fitnessMatrix = zeros(4,sizeGenerations);
numStim = ceil(scanLength / (ISI));
numRestStim = (ceil(numStim/(mean(restevery)+restlength)) - 1) * restlength;
numStimEachCond = ceil((numStim-numRestStim) * freqConditions);			            % row vector of stim in each cond
numsamps = ceil(numStim*ISI/TR);

SIM.numsamps = numsamps;
if exist('M') & isstruct(M), SIM.numsamps = size(M.modelatTR,1);,end
SIM.numStimEachCond = numStimEachCond;

% this is overwritten if trans2switch is used.
unsortedList = [];
for i = 1:size(conditions,2)									% unsorted list of all stims in proper frequencies
   startIndex = size(unsortedList,1)+1;
   unsortedList(startIndex:(startIndex + 2 * numStimEachCond(i)-1),1) = conditions(i);
end

% ----------------------------------------------------------------
% * jitter setup
% ----------------------------------------------------------------

dojitter = 0;
if size(freqConditions,2) == size(conditions,2) + 1
    conditions = [conditions max(conditions)+1];   % insert 0 as last condition if jitter
    dojitter = 1;
elseif size(freqConditions,2) == size(conditions,2)
else error('Frequency and condition vectors must be same length, or freq must be 1 longer for jitter')
end

% ----------------------------------------------------------------
% * criterion measures setup
% ----------------------------------------------------------------
if ~isempty(NumStimthresh) | ~isempty(maxCbalDevthresh) | ~isempty(maxFreqDevthresh)
	docriterion = 1;
	if isempty(NumStimthresh),NumStimthresh = 10000;,end
 	if isempty(maxCbalDevthresh),maxCbalDevthresh = 10000;,end
	if isempty(maxFreqDevthresh),maxFreqDevthresh = 10000;,end
else
	docriterion = 0;
end

maxrestthresh = 2;					% max number of rests in a row.

% ----------------------------------------------------------------
% * stochastic variability in response times - now not used
% ----------------------------------------------------------------
if addResponseVariability == 1

else

% ----------------------------------------------------------------
% * simulation - get smoothing matrix
% ----------------------------------------------------------------
	figure;
    disp(['  ...loading smoothing matrix with hrf LP and HP filter length of ' num2str(HPlength)])
    [hpS] = use_spm_filter(TR,SIM.numsamps,'none','specify',HPlength);
	[fullS] = use_spm_filter(TR,SIM.numsamps,'hrf','specify',HPlength);

% ----------------------------------------------------------------
% * simulation - setup ga simulation with different noise vectors
% ----------------------------------------------------------------
	if exist('M') & isstruct(M),
	    if ISI > TR,stimList = M.stimlist(1:numsamps+1,1);,end   	% cut off to save time if it's too long
                %stimList = insert_rests(stimList,M.restlist,restlength,numStim);not necessary;done in GA
                stimList = sampleInSeconds(M.stimlist,ISI,.1);				% hi-res sample at .1 s, matches HRF
		dmodel = getPredictors(stimList, HRF);
		dmodel = resample(dmodel,1,TR*10);
		dmodel = modelSaturation(dmodel,nonlinthreshold);

		if size(dmodel,1) > SIM.numsamps
			disp('	...truncating dmodel to number of samples')
			dmodel = dmodel(1:SIM.numsamps,:);
		elseif size(dmodel,1) < SIM.numsamps
		        warning('	...stimlist for GA is too short for this ISI!  Results may not be accurate for this ISI!')
	                dmodel = [dmodel; zeros(SIM.numsamps - size(dmodel,1),size(dmodel,2))];
	        end

% ----------------------------------------------------------------
% * simulation - run ga simulation with different noise vectors
% ----------------------------------------------------------------

  		disp(['  ...simulating GA results with noisy data at variance ' num2str(noise_var)])
	        % Test idealized GA - no response variability
		fprintf('		...original	model')
    	[dummy,SIM.ga.se,SIM.ga.t] = designsim('myxc',dmodel,HRF,ISI,TR,noise_var,c,beta,0,xc,niterations);
 		fprintf('...high-pass filtered')
    	[dummy,SIM.ga.HPse,SIM.ga.HPt] = designsim('myxc',dmodel,HRF,ISI,TR,noise_var,c,beta,hpS,xc,niterations);
		fprintf('...smoothed\n')
		[dummy,SIM.ga.HLse,SIM.ga.HLt] = designsim('myxc',dmodel,HRF,ISI,TR,noise_var,c,beta,fullS,xc,niterations);
	end

    disp(['  ...simulating random designs with ' num2str(niterations) ' iterations...']);

SIM

% ----------------------------------------------------------------
% * simulation - setup random simulation - trans2switch
% ----------------------------------------------------------------

% This is part of the switching hack. uses 2 conditions, then figures out 4 columns from that.
% 5 is the rest condition.
if trans2switch
    if size(conditions,2) > 4
	NEWfreqConditions = [.5 .5 freqConditions(5)]; NEWconditions = [1 2 5];
    else NEWfreqConditions = [.5 .5];,NEWconditions = [1 2];
    end
	NEWnumStimEachCond = ceil((numStim-numRestStim) * NEWfreqConditions);			            % row vector of stim in each cond

	disp(['	...USING TRANS2SWITCH > num stim each cond = ' num2str(NEWnumStimEachCond)])

	for i = 1:size(NEWfreqConditions,2)									% unsorted list of all stims in proper frequencies
   		startIndex = size(unsortedList,1)+1;
   		unsortedList(startIndex:(startIndex + 2 * NEWnumStimEachCond(i)-1),1) = NEWconditions(i);
	end
end

% ----------------------------------------------------------------
% * simulation - setup random simulation - trans2block
% ----------------------------------------------------------------
if trans2block
	disp(['	...USING TRANS2BLOCK >'])
        freqConditions = [freqConditions./2 freqConditions./2];
        disp(['     freqConditions = ' num2str(freqConditions)])

        if dojitter
           maxcond = max(conditions)-1;
           conditions = [conditions(1:maxcond) maxcond+1:2*length(conditions)-1];
           disp(['     CONDITION ' num2str(conditions(end)) ' is blank jitter.'])
	else
           maxcond = max(conditions);
           conditions = [conditions maxcond+1:2*length(conditions)];
        end
        disp(['     conditions = ' num2str(conditions)])

	% ----------------------------------------------------------------
	% * setup special first trial
	% ----------------------------------------------------------------
	if isempty(dofirst)
		dofirst = 0;
	else
		disp(['	...block design: adding special predictor for first trial in block.'])
		try
			% this is really kludgy, but should give a rough estimate of how many first trials to expect.
			numfirst = numStim ./ mean(restevery);
			proportionfirst = numfirst./numStim;
		catch
			error('restevery not found...must use rest periods with transform2block!')
		end
		freqConditions = freqConditions - proportionfirst./size(freqConditions,2);
		freqConditions = [freqConditions proportionfirst];
		disp('	...first trial special condition - adjusted expected frequencies:')
		freqConditions
	end
end

% ----------------------------------------------------------------
% * simulation - setup random simulation - list and rest matrix
% ----------------------------------------------------------------
		disp('	...Setting up lists.')
                clear restMatrix, clear listMatrix
		% make rest matrix
		atleast = min(restevery);
		restPeriods = numStim / atleast + 5;	% make this many rows in restMatrix
		unsortedrestList = [];
		for i = 1:size(restevery,2):restPeriods
			unsortedrestList = [unsortedrestList;restevery'];
		end

		for i = 1:niterations
			restMatrix(:,i) = getRandom(unsortedrestList);
			listMatrix(:,i) = getRandom(unsortedList);
		end

		listMatrix = insert_rests(listMatrix,restMatrix,restlength,numStim);

		% insert rests before transforming
		for i = 1:niterations
			if trans2switch,
				listMatrix(:,i) = transform2switches(listMatrix(:,i));
		    end
			if trans2block,
             			listMatrix(:,i) = transform2block(listMatrix(:,i),restMatrix(:,i),restlength,dofirst);
      			end
                end

% ----------------------------------------------------------------
% * simulation - setup random simulation - criterion measures
% ----------------------------------------------------------------

              if docriterion
                disp('   ...Making sure all lists meet criteria...')

                % criterion measures
	        % ====================================================================
	        for i = 1:niterations
                	stimList = listMatrix(:,i);
			restList = restMatrix(:,i);

                	go = 0;tryindex = 1;

                	while ~go
                  		[maxNumStim,maxrest] = getMaxInARow(stimList);

                  		% ====== Frequency Deviation =======================================
                  		for j = 1:size(conditions,2)

         				freqMat(j) = sum(stimList == conditions(j)) / size(stimList,1);
      		  		end
                  		freqMat = freqMat ./ sum(freqMat);   % adjust for probe ''0''s
		  		maxFreqDev = max(abs(freqConditions(1:size(conditions,2)) - freqMat));

                  		% ====== Counterbalancing Deviation =======================================
                  		[cBal,dummy,maxDev] = getCounterBal(stimList, maxOrder,conditions,freqConditions);

                  		% ====== Test list for criteria satisfaction ==============================
		  		if maxNumStim < NumStimthresh & maxrest < maxrestthresh & maxDev < maxCbalDevthresh & maxFreqDev < maxFreqDevthresh
		     		go = 1;
		  		else
                     		restList        = getRandom(unsortedrestList);
			 		stimList		 = getRandom(unsortedList);
			 		stimList        = insert_rests(stimList,restList,restlength,numStim);
                     		if trans2switch,
                        		stimList = transform2switches(stimList);
                     		end
		     		if trans2block,
             					stimList = transform2block(stimList,restList,restlength,dofirst);
      			 		end

                     		tryindex = tryindex+1;
                  		end

		     	if mod(tryindex,100) == 0,disp(['Tried 100 times on model ' num2str(i)])
                          disp(['Avg. max stim in a row = ' num2str(maxNumStim)])
                          disp(['Avg. deviation from freqs = ' num2str(maxFreqDev)])
                          disp(['Avg. deviation from counterbal = ' num2str(maxDev)])
                          disp(['Avg. frequencies are = ' num2str(freqMat)])
                          disp(['Max restcond is ' num2str(maxrest)])
					conditions
					freqConditions
					freqMat
                     	end
				if mod(tryindex,500) == 0
					disp('Cannot meet criteria after 500 tries.')
					conditions
					freqConditions
					freqMat
					cBal
					error('Exiting now.')
				end
                	end  % end while

                	restMatrix(:,i) = restList;
			listMatrix(:,i) = stimList;
                	if mod(i,50) == 0, fprintf('%d ',i),end
                end  % end for ... iterations
	     end  % if docriterion

% ----------------------------------------------------------------
% * simulation - setup random simulation - make models
% ----------------------------------------------------------------

	for i = 1:niterations
      	% Test Random models

	  	% Prepare Stimulus List
      	        stimList = listMatrix(:,i);
		SIM.stimList = stimList;
		stimList = sampleInSeconds(stimList,ISI,.1);
		dmodel = getPredictors(stimList, HRF);
		dmodel = resample(dmodel,1,TR*10);
		dmodel = modelSaturation(dmodel,nonlinthreshold);

		if size(dmodel,1) > SIM.numsamps
			dmodel = dmodel(1:SIM.numsamps,:);
		elseif size(dmodel,1) < SIM.numsamps
			dmodel = [dmodel; zeros(SIM.numsamps - size(dmodel,1),size(dmodel,2))];
		end

% ----------------------------------------------------------------
% * simulation - run random simulation - no smoothing
% ----------------------------------------------------------------
% this gets the average over [numnoise] simulations with different noise vectors
   		if i == 1
	  		[dummy,SIM.rnd.se(:,i),SIM.rnd.t(:,i),GLM] = ...
			designsim('myxc',dmodel,HRF,ISI,TR,noise_var,c,beta,0,xc);	%added 4th output to plot
			set(gcf,'Position',[88         514        1185         420])	;drawnow
			subplot(4,1,4); plot(dmodel(:,1));title('First predictor of model')
			drawnow
		else
			[dummy,SIM.rnd.se(:,i),SIM.rnd.t(:,i)] = ...
			designsim('myxc',dmodel,HRF,ISI,TR,noise_var,c,beta,0,xc);
		end

% ----------------------------------------------------------------
% * simulation - run random simulation - HP filter
% ----------------------------------------------------------------
	% high-pass only
	[dummy, SIM.rnd.HPse(:,i),SIM.rnd.HPt(:,i)] = ...
	designsim('myxc',dmodel,HRF,ISI,TR,noise_var,c,beta,hpS,xc);

% ----------------------------------------------------------------
% * simulation - run random simulation - high and low filter
% ----------------------------------------------------------------

      	% now with smoothing
      	[dummy, SIM.rnd.HLse(:,i),SIM.rnd.HLt(:,i)] = designsim('myxc',dmodel,HRF,ISI,TR,noise_var,c,beta,fullS,xc);
      	fprintf('.')
	  if mod(i,30) == 0, fprintf(' %d ',i),end
	  if mod(i,90) == 0, fprintf('\n'),end

    end
	% for niterations

end
		% simulation with fixed response times.

% ----------------------------------------------------------------
% * power calculation for all sims
% ----------------------------------------------------------------

powerTcrit = tinv(1-.05/powerTvoxels,powerTdf);
for i = {'SIM.ga.t' 'SIM.ga.HPt' 'SIM.ga.HLt' 'SIM.rnd.t' 'SIM.rnd.HPt' 'SIM.rnd.HLt'}
	eval([i{1} 'power = sum(abs(' i{1} ') > powerTcrit) / length(' i{1} ');'])
end

	try
		plotSim(SIM)
	catch
		disp('Error plotting. command: plotSim(SIM)')
	end

save latestSIM SIM


function bemcp_example
% Simple function to test/demonstrate how the Boundary element functions are
% used in combination with Fildtrip/Forwinv routines.
%
% 1. A model is created as 3 concentric meshed spheres (using FT's
% icosahedron routines),
% 2. then random electrodes are placed on the upper part of the outer
% sphere.
% 3. the model is then "prepared" with 'ft_prepare_bemmodel', this bits
% takes most time as it requires LOTS of calculation.
% 4. sensors and volumes are plugged together by 'forwinv_prepare_vol_sens'
% 5. Finally the leadfiled for 3 orthogonal sources placed at one location
% is calculated with 'forwinv_compute_leadfield.m'
% 6. Display the 3 leadfields
%
% NOTE:
% this bit of code needs access to low level fieldtrip/forwinv routines
% which have been copy/pasted here under.
% Be aware that this way of programming is generally NOT advisable!
% I used it only to ensure a quick & dirty check of the BEM module...

% Christophe Phillips
% $Id: bemcp_example.m 4793 2012-07-19 11:35:24Z spm $

% create volume conductor starting from unit sphere
[pnt, tri] = icosahedron162;

vol = [];
vol.cond = [1 1/80 1];
vol.source = 1; % index of source compartment
vol.skin_surface   = 3; % index of skin surface
% inner_skull_surface
vol.bnd(1).pnt = pnt*88;
vol.bnd(1).tri = tri;
% outer_skull_surface
vol.bnd(2).pnt = pnt*92;
vol.bnd(2).tri = tri;
% skin_surface
vol.bnd(3).pnt = pnt*100;
vol.bnd(3).tri = tri;

% create the BEM system matrix
cfg = [];
cfg.method = 'bemcp';
vol1 = ft_prepare_bemmodel(cfg, vol);

% create some random electrodes
pnt = randn(200,3);
pnt = pnt(pnt(:,3)>0, :);  % only those on the upper half
sens = [];
for i=1:size(pnt,1)
  sens.pnt(i,:) = pnt(i,:) / norm(pnt(i,:)); % scale towards the skin surface
  sens.label{i} = sprintf('%02d', i);
end

% prepare the sensor array and volume conduction, i.e. set up the linear
% interpolation from vertices to electrodes
[vol2, sens] = forwinv_prepare_vol_sens(vol1, sens);

lf = forwinv_compute_leadfield([0 0 50], sens, vol2);

figure; triplot(sens.pnt, [], lf(:,1)); colorbar
figure; triplot(sens.pnt, [], lf(:,2)); colorbar
figure; triplot(sens.pnt, [], lf(:,3)); colorbar

return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Subfunctions from FieldTrip
function [pnt, dhk] = icosahedron162

% ICOSAHEDRON162 creates a 2-fold refined icosahedron

% Copyright (C) 2003, Robert Oostenveld
%
% $Log: icosahedron162.m,v $
% Revision 1.3  2003/11/28 09:40:12  roberto
% added a single help line
%
% Revision 1.2  2003/03/04 21:46:18  roberto
% added CVS log entry and synchronized all copyright labels
%

[pnt, dhk] = icosahedron;
[pnt, dhk] = refine(pnt, dhk);
[pnt, dhk] = refine(pnt, dhk);

pnt = pnt ./ repmat(sqrt(sum(pnt.^2,2)), 1,3);

return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [pnt, dhk] = icosahedron

% ICOSAHEDRON creates an icosahedron
%
% [pnt, dhk] = icosahedron
% creates an icosahedron with 12 vertices and 20 triangles
%
% See also OCTAHEDRON, ICOSAHEDRON42, ICOSAHEDRON162, ICOSAHEDRON642, ICOSAHEDRON2562

% Copyright (C) 2002, Robert Oostenveld
%
% $Log: icosahedron.m,v $
% Revision 1.4  2006/07/26 11:03:38  roboos
% added "see also octahedron"
%
% Revision 1.3  2003/03/11 15:35:20  roberto
% converted all files from DOS to UNIX
%
% Revision 1.2  2003/03/04 21:46:18  roberto
% added CVS log entry and synchronized all copyright labels
%

dhk = [
   1   2   3
   1   3   4
   1   4   5
   1   5   6
   1   6   2
   2   8   3
   3   9   4
   4  10   5
   5  11   6
   6   7   2
   7   8   2
   8   9   3
   9  10   4
  10  11   5
  11   7   6
  12   8   7
  12   9   8
  12  10   9
  12  11  10
  12   7  11
];

pnt = zeros(12, 3);

rho=0.4*sqrt(5);
phi=2*pi*(0:4)/5;

pnt( 1, :) = [0 0  1];			% top point

pnt(2:6, 1) = rho*cos(phi)';
pnt(2:6, 2) = rho*sin(phi)';
pnt(2:6, 3) = rho/2;

pnt(7:11, 1) = rho*cos(phi - pi/5)';
pnt(7:11, 2) = rho*sin(phi - pi/5)';
pnt(7:11, 3) = -rho/2;

pnt(12, :) = [0 0 -1];			% bottom point

return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [pntr, dhkr] = refine(pnt, dhk, method, varargin)

% REFINE a 3D surface that is described by a triangulation
%
% Use as
%   [pnt, tri] = refine(pnt, tri)
%   [pnt, tri] = refine(pnt, tri, 'updown', numtri)
%
% The default method is to refine the mesh globally by inserting a vertex at
% each edge according to the algorithm described in Banks, 1983.
%
% The alternative 'updown' method refines the mesh a couple of times
% using Banks' algorithm, followed by a downsampling using the REDUCEPATCH
% function.

% The Banks method is a memory efficient implementation which remembers
% the previously inserted vertices. The refinement algorithm executes in
% linear time with the number of triangles.

% Copyright (C) 2002-2005, Robert Oostenveld
%
% $Log: refine.m,v $
% Revision 1.4  2005/05/06 08:54:31  roboos
% added 'updown method, using matlab reducepatch function
%
% Revision 1.3  2003/03/11 15:35:20  roberto
% converted all files from DOS to UNIX
%
% Revision 1.2  2003/03/04 21:46:19  roberto
% added CVS log entry and synchronized all copyright labels
%

if nargin<3
  method = 'banks';
end

switch lower(method)
case 'banks'
  npnt   = size(pnt,1);
  ndhk   = size(dhk,1);
  insert = spalloc(3*npnt,3*npnt,3*ndhk);

  dhkr  = zeros(4*ndhk,3);		% allocate memory for the new triangles
  pntr  = zeros(npnt+3*ndhk,3);		% allocate memory for the maximum number of new vertices
  pntr(1:npnt,:) = pnt;			% insert the original vertices
  current = npnt;

  for i=1:ndhk

    if ~insert(dhk(i,1),dhk(i,2))
      current = current + 1;
      pntr(current,:) = (pnt(dhk(i,1),:) + pnt(dhk(i,2),:))/2;
      insert(dhk(i,1),dhk(i,2)) = current;
      insert(dhk(i,2),dhk(i,1)) = current;
      v12 = current;
    else
      v12 = insert(dhk(i,1),dhk(i,2));
    end

    if ~insert(dhk(i,2),dhk(i,3))
      current = current + 1;
      pntr(current,:) = (pnt(dhk(i,2),:) + pnt(dhk(i,3),:))/2;
      insert(dhk(i,2),dhk(i,3)) = current;
      insert(dhk(i,3),dhk(i,2)) = current;
      v23 = current;
    else
      v23 = insert(dhk(i,2),dhk(i,3));
    end

    if ~insert(dhk(i,3),dhk(i,1))
      current = current + 1;
      pntr(current,:) = (pnt(dhk(i,3),:) + pnt(dhk(i,1),:))/2;
      insert(dhk(i,3),dhk(i,1)) = current;
      insert(dhk(i,1),dhk(i,3)) = current;
      v31 = current;
    else
      v31 = insert(dhk(i,3),dhk(i,1));
    end

    % add the 4 new triangles with the correct indices
    dhkr(4*(i-1)+1, :) = [dhk(i,1) v12 v31];
    dhkr(4*(i-1)+2, :) = [dhk(i,2) v23 v12];
    dhkr(4*(i-1)+3, :) = [dhk(i,3) v31 v23];
    dhkr(4*(i-1)+4, :) = [v12 v23 v31];

  end

  % remove the space for the vertices that was not used
  pntr = pntr(1:current, :);

case 'updown'
  ndhk = size(dhk,1);
  while ndhk<varargin{1}
    % increase the number of triangles by a factor of 4
    [pnt, dhk] = refine(pnt, dhk, 'banks');
    ndhk = size(dhk,1);
  end
  % reduce number of triangles using Matlab function
  [dhkr, pntr] = reducepatch(dhk, pnt, varargin{1});

otherwise
  error(['unsupported method: ' method]);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [hs, hc, contour] = triplot(pnt, tri, val, mode, levels)

% TRIPLOT make 2D or 3D plot of triangulated surface and interpolated values
% The surface can be displayed with linear interpolated values or with
% linear interpolated contours of a potential distribution.
%
% Use as
%   triplot(pnt, tri, value)
%   triplot(pnt, tri, value, mode)
%   triplot(pnt, tri, value, mode, levels)
% This will make a plot of value on the surface described by triangles
% tri with vertices pnt. The matrix tri can be [], in which case a
% it will be computed using a delaunay triangulation.
%
% The visualization mode can be
%   'surface'     make interpolated plot of value on surface (default)
%   'faces'       plot white triangles only        (value can be [])
%   'faces_red'   plot red triangles only          (value can be [])
%   'faces_blue'  plot blue triangles only         (value can be [])
%   'faces_skin'  plot skin-colored triangles only (value can be [])
%   'face_index'  plot index of each triangle      (value can be [])
%   'nodes'       plot black vertices only         (value can be [])
%   'node_index'  plot index of each vertex        (value can be [])
%   'node_label'  plot label of each vertex        (value should be cell array)
%   'edges'       plot black edges only            (value can be [])
%   'contour'     make interpolated contour plot of value on surface
%   'contour_bw'  make interpolated black-white contour plot
%   'contour_rb'  make interpolated contour plot with red-blue
%
% With the optional levels, you can specify the levels at which contours will
% be plotted
%
% See also PATCH, COLORMAP, VIEW (general Matlab commands)

% updated on Mon Jul 23 12:41:44 MET DST 2001
% updated on Fri Jan 31 11:47:28 CET     2003

% Copyright (C) 2001=2006, Robert Oostenveld
%
% $Log: triplot.m,v $
% Revision 1.7  2008/06/24 13:37:51  roboos
% added option faces_blue
% always return handle to objects that were plotted
%
% Revision 1.6  2007/01/03 17:00:35  roboos
% updated documentation, changed layout of code and comments
%
% Revision 1.5  2006/09/19 16:11:35  roboos
% added support for line segments, removed "axis equal" at end
%
% Revision 1.4  2006/05/02 19:15:28  roboos
% added 'faces_red' style
%
% Revision 1.3  2004/06/28 07:51:39  roberto
% improved documentation, added faces_skin
%
% Revision 1.2  2003/03/17 10:37:29  roberto
% improved general help comments and added copyrights
%

% start with empty return values
hs      = [];
hc      = [];
contour = [];

% everything is added to the current figure
holdflag = ishold;
hold on

% check the input variables
if ~isempty(val)
  val = val(:);
end

if nargin<4
  mode = 'surface';
end

if isempty(tri) & ~strcmp(mode, 'nodes')
  % no triangulation was specified but a triangulation is needed
  if size(pnt,2)==2
    % make a 2d triangulation of the points using delaunay
    tri = delaunay(pnt(:,1), pnt(:,2));
  else
    % make a 2d triangulation of the projected points using delaunay
    prj = elproj(pnt);
    tri = delaunay(prj(:,1), prj(:,2));
  end
end

if size(tri,2)==2
  % lines are specified instead of triangles, convert to triangles
  tri(:,3) = tri(:,2);
end

if nargin<3
  warning('only displaying triangle edges')
  mode='edges';
  val = [];
elseif nargin<4
  % warning('default displaying surface')
  mode='surface';
elseif nargin<5
  % determine contour levels
  if ~isempty(val) & ~iscell(val)
    absmax = max(abs([min(val) max(val)]));
    levels = linspace(-absmax,absmax,21);
  else
    levels = [];
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% compute contours for 2D or 3D triangulation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if strcmp(mode, 'contour') || strcmp(mode, 'contour_bw') || strcmp(mode, 'contour_rb')
  triangle_val = val(tri);
  triangle_min = min(triangle_val, [], 2);
  triangle_max = max(triangle_val, [], 2);

  for cnt_indx=1:length(levels)
    cnt = levels(cnt_indx);
    use = cnt>=triangle_min & cnt<=triangle_max;
    counter = 0;
    intersect1 = [];
    intersect2 = [];

    for tri_indx=find(use)'
      pos  = pnt(tri(tri_indx,:), :);
      v(1) = triangle_val(tri_indx,1);
      v(2) = triangle_val(tri_indx,2);
      v(3) = triangle_val(tri_indx,3);
      la(1) = (cnt-v(1)) / (v(2)-v(1));	% abcissa between vertex 1 and 2
      la(2) = (cnt-v(2)) / (v(3)-v(2));	% abcissa between vertex 2 and 3
      la(3) = (cnt-v(3)) / (v(1)-v(3));	% abcissa between vertex 1 and 2
      abc(1,:) = pos(1,:) + la(1) * (pos(2,:) - pos(1,:));
      abc(2,:) = pos(2,:) + la(2) * (pos(3,:) - pos(2,:));
      abc(3,:) = pos(3,:) + la(3) * (pos(1,:) - pos(3,:));
      counter = counter + 1;
      sel     = find(la>=0 & la<=1);
      intersect1(counter, :) = abc(sel(1),:);
      intersect2(counter, :) = abc(sel(2),:);
    end

    % remember the details for external reference
    contour(cnt_indx).level = cnt;
    contour(cnt_indx).n     = counter;
    contour(cnt_indx).intersect1 = intersect1;
    contour(cnt_indx).intersect2 = intersect2;
  end

  % collect all different contourlevels for plotting
  intersect1 = [];
  intersect2 = [];
  cntlevel   = [];
  for cnt_indx=1:length(levels)
    intersect1 = [intersect1; contour(cnt_indx).intersect1];
    intersect2 = [intersect2; contour(cnt_indx).intersect2];
    cntlevel   = [cntlevel; ones(contour(cnt_indx).n,1) * levels(cnt_indx)];
  end

  X = [intersect1(:,1) intersect2(:,1)]';
  Y = [intersect1(:,2) intersect2(:,2)]';
  C = [cntlevel(:)     cntlevel(:)]';

  if size(pnt,2)>2
    Z = [intersect1(:,3) intersect2(:,3)]';
  else
    Z = zeros(2, length(cntlevel));
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% plot the desired detail
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch lower(mode)

  case 'faces'
    % plot the faces of the 2D or 3D triangulation
    hs = patch('Vertices', pnt, 'Faces', tri);
    set(hs, 'FaceColor', 'white');
    set(hs, 'EdgeColor', 'none');

  case 'faces_skin'
    % plot the faces of the 2D or 3D triangulation
    skin_surface   = [255 213 119]/255;
    inner_skull_surface  = [202 100 100]/255;
    cortex = [255 213 119]/255;
    hs = patch('Vertices', pnt, 'Faces', tri);
    set(hs, 'FaceColor', skin_surface);
    set(hs, 'EdgeColor', 'none');
    lighting gouraud
    material shiny
    camlight

  case 'faces_red'
    % plot the faces of the 2D or 3D triangulation
    hs = patch('Vertices', pnt, 'Faces', tri);
    set(hs, 'FaceColor', [1 0 0]);
    set(hs, 'EdgeColor', 'none');
    lighting gouraud
    material shiny
    camlight

  case 'faces_blue'
    % plot the faces of the 2D or 3D triangulation
    hs = patch('Vertices', pnt, 'Faces', tri);
    set(hs, 'FaceColor', [0 0 1]);
    set(hs, 'EdgeColor', 'none');
    lighting gouraud
    material shiny
    camlight

  case 'face_index'
    % plot the triangle indices (numbers) at each face
    for face_indx=1:size(tri,1)
      str = sprintf('%d', face_indx);
      tri_x = (pnt(tri(face_indx,1), 1) +  pnt(tri(face_indx,2), 1) +  pnt(tri(face_indx,3), 1))/3;
      tri_y = (pnt(tri(face_indx,1), 2) +  pnt(tri(face_indx,2), 2) +  pnt(tri(face_indx,3), 2))/3;
      tri_z = (pnt(tri(face_indx,1), 3) +  pnt(tri(face_indx,2), 3) +  pnt(tri(face_indx,3), 3))/3;
      h   = text(tri_x, tri_y, tri_z, str, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
      hs  = [hs; h];
    end

  case 'edges'
    % plot the edges of the 2D or 3D triangulation
    hs = patch('Vertices', pnt, 'Faces', tri);
    set(hs, 'FaceColor', 'none');
    set(hs, 'EdgeColor', 'black');

  case 'nodes'
    % plot the nodes (vertices) only as points
    if size(pnt, 2)==2
      hs = plot(pnt(:,1), pnt(:,2), 'k.');
    else
      hs = plot3(pnt(:,1), pnt(:,2), pnt(:,3), 'k.');
    end

  case 'nodes_blue'
    % plot the nodes (vertices) only as points
    if size(pnt, 2)==2
      hs = plot(pnt(:,1), pnt(:,2), 'b.', 'MarkerSize', 20);
    else
      hs = plot3(pnt(:,1), pnt(:,2), pnt(:,3), 'b.', 'MarkerSize', 20);
    end

  case 'nodes_red'
    % plot the nodes (vertices) only as points
    if size(pnt, 2)==2
      hs = plot(pnt(:,1), pnt(:,2), 'r.', 'MarkerSize', 20);
    else
      hs = plot3(pnt(:,1), pnt(:,2), pnt(:,3), 'r.', 'MarkerSize', 20);
    end

  case 'node_index'
    % plot the vertex indices (numbers) at each node
    for node_indx=1:size(pnt,1)
      str = sprintf('%d', node_indx);
      if size(pnt, 2)==2
        h   = text(pnt(node_indx, 1), pnt(node_indx, 2), str, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
      else
        h   = text(pnt(node_indx, 1), pnt(node_indx, 2), pnt(node_indx, 3), str, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
      end
      hs  = [hs; h];
    end

  case 'node_label'
    % plot the vertex indices (numbers) at each node
    for node_indx=1:size(pnt,1)
      str = val{node_indx};
      if ~isempty(str)
        if size(pnt, 2)==2
          h   = text(pnt(node_indx, 1), pnt(node_indx, 2), str, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
        else
          h   = text(pnt(node_indx, 1), pnt(node_indx, 2), pnt(node_indx, 3), str, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
        end
      else
        h = -1;
      end
      hs  = [hs; h];
    end

  case 'surface'
    % plot a 2D or 3D triangulated surface with linear interpolation
    if length(val)==size(pnt,1)
      hs = patch('Vertices', pnt, 'Faces', tri, 'FaceVertexCData', val, 'FaceColor', 'interp');
    else
      hs = patch('Vertices', pnt, 'Faces', tri, 'CData', val, 'FaceColor', 'flat');
    end
    set(hs, 'EdgeColor', 'none');

  case 'contour_bw'
    % make black-white contours
    hc = [];
    for i=1:length(cntlevel)
      if cntlevel(i)>0
        linestyle = '-';
        linewidth = 1;
      elseif cntlevel(i)<0
        linestyle = '--';
        linewidth = 1;
      else
        linestyle = '-';
        linewidth = 2;
      end
      h1 = patch('XData', X(:,i), 'Ydata', Y(:,i), ...
        'ZData', Z(:,i), 'CData', C(:,i), ...
        'facecolor','none','edgecolor','black', ...
        'linestyle', linestyle, 'linewidth', linewidth, ...
        'userdata',cntlevel(i));
      hc = [hc; h1];
    end

  case 'contour_rb'
    % make red-blue contours
    hc = [];
    for i=1:length(cntlevel)
      if cntlevel(i)>0
        edgecolor = 'red';
      elseif cntlevel(i)<0
        edgecolor = 'blue';
      else
        edgecolor = 'black';
      end
      h1 = patch('XData', X(:,i), 'Ydata', Y(:,i), ...
        'ZData', Z(:,i), 'CData', C(:,i), ...
        'facecolor','none','edgecolor',edgecolor, ...
        'linestyle', '-', 'linewidth', 3, ...
        'userdata',cntlevel(i));
      hc = [hc; h1];
    end

  case 'contour'
    % make full-color contours
    hc = [];
    for i=1:length(cntlevel)
      h1 = patch('XData', X(:,i), 'Ydata', Y(:,i), ...
        'ZData', Z(:,i), 'CData', C(:,i), ...
        'facecolor','none','edgecolor','flat',...
        'userdata',cntlevel(i));
      hc = [hc; h1];
    end

end	% switch

axis off
axis vis3d
axis equal

if nargout==0
  clear contour hc hs
end

if ~holdflag
  hold off
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [proj] = elproj(pos, method);

% ELPROJ makes a azimuthal projection of a 3D electrode cloud
%  on a plane tangent to the sphere fitted through the electrodes
%  the projection is along the z-axis
%
%  [proj] = elproj([x, y, z], 'method');
%
% Method should be one of these:
%	  'gnomic'
%	  'stereographic'
%	  'ortographic'
%	  'inverse'
%	  'polar'
%
% Imagine a plane being placed against (tangent to) a globe. If
% a light source inside the globe projects the graticule onto
% the plane the result would be a planar, or azimuthal, map
% projection. If the imaginary light is inside the globe a Gnomonic
% projection results, if the light is antipodal a Sterographic,
% and if at infinity, an Orthographic.
%
% The default projection is a polar projection (BESA like).
% An inverse projection is the opposite of the default polar projection.

% Copyright (C) 2000-2008, Robert Oostenveld
%
% $Log: elproj.m,v $
% Revision 1.4  2008/05/15 10:54:24  roboos
% updated documentation
%
% Revision 1.3  2007/03/20 10:29:35  roboos
% renamed method 'default' into 'polar'
%
% Revision 1.2  2003/03/17 10:37:28  roberto
% improved general help comments and added copyrights
%

x = pos(:,1);
y = pos(:,2);
if size(pos, 2)==3
  z = pos(:,3);
end

if nargin<2
  method='polar';
end

if nargin<3
  secant=1;
end

if strcmp(method, 'orthographic')
  % this method compresses the lowest electrodes very much
  % electrodes on the bottom half of the sphere are folded inwards
  xp = x;
  yp = y;
  num = length(find(z<0));
  str = sprintf('%d electrodes may be folded inwards in orthographic projection\n', num);
  if num
    warning(str);
  end
  proj = [xp yp];

elseif strcmp(method, 'gnomic')
  % the lightsource is in the middle of the sphere
  % electrodes on the equator are projected at infinity
  % electrodes below the equator are not projected at all
  rad = mean(sqrt(x.^2 + y.^2 + z.^2));
  phi = cart2pol(x, y);
  th  = atan(sqrt(x.^2 + y.^2) ./ z);
  xp  = cos(phi) .* tan(th) .* rad;
  yp  = sin(phi) .* tan(th) .* rad;
  num = length(find(th==pi/2 | z<0));
  str = sprintf('removing %d electrodes from gnomic projection\n', num);
  if num
    warning(str);
  end
  xp(find(th==pi/2 | z<0)) = NaN;
  yp(find(th==pi/2 | z<0)) = NaN;
  proj = [xp yp];

elseif strcmp(method, 'stereographic')
  % the lightsource is antipodal (on the south-pole)
  rad = mean(sqrt(x.^2 + y.^2 + z.^2));
  z   = z + rad;
  phi = cart2pol(x, y);
  th  = atan(sqrt(x.^2 + y.^2) ./ z);
  xp  = cos(phi) .* tan(th) .* rad * 2;
  yp  = sin(phi) .* tan(th) .* rad * 2;
  num = length(find(th==pi/2 | z<0));
  str = sprintf('removing %d electrodes from stereographic projection\n', num);
  if num
    warning(str);
  end
  xp(find(th==pi/2 | z<0)) = NaN;
  yp(find(th==pi/2 | z<0)) = NaN;
  proj = [xp yp];

elseif strcmp(method, 'inverse')
  % compute the inverse projection of the default angular projection
  [th, r] = cart2pol(x, y);
  [xi, yi, zi] = sph2cart(th, pi/2 - r, 1);
  proj = [xi, yi, zi];

else
  % use default angular projection
  [az, el, r] = cart2sph(x, y, z);
  [x, y] = pol2cart(az, pi/2 - el);
  proj = [x, y];
end


% ------------------------------------------------------------------------
%  Copyright (C)
%  Universitat Politecnica de Catalunya BarcelonaTech (UPC) - Spain
%  University of California Berkeley (UCB) - USA
%
%  Jordi Pont-Tuset <jordi.pont@upc.edu>
%  Pablo Arbelaez <arbelaez@berkeley.edu>
%  June 2014
% ------------------------------------------------------------------------
% This file is part of the MCG package presented in:
%    Arbelaez P, Pont-Tuset J, Barron J, Marques F, Malik J,
%    "Multiscale Combinatorial Grouping,"
%    Computer Vision and Pattern Recognition (CVPR) 2014.
% Please consider citing the paper if you use this code.
% ------------------------------------------------------------------------
function eval_and_save_labels(labels_folder,database,gt_set)

if nargin<2
    database = 'pascal2012';
end
if nargin<3
    gt_set = 'val2012';
end

% Get the name of the folder to refer to the method
if strcmp(labels_folder(end),filesep)
    labels_folder(end) = [];
end
tmp = strfind(labels_folder,filesep);
if isempty(tmp)
    method_name = labels_folder;
    masks_dir = fullfile(root_dir, 'datasets', database, method_name);
else
    method_name = labels_folder(tmp(end)+1:end);
    masks_dir = labels_folder;
end

% Results folder
res_dir   = fullfile(root_dir, 'results', database, method_name);
if ~exist(res_dir,'dir')
    mkdir(res_dir)
end

% Load which images to consider
im_ids = database_ids(database,gt_set);

% Sweep all images
num_images = numel(im_ids);
parfor ii=1:num_images
    curr_id = im_ids{ii};
    res_file = fullfile(res_dir,[curr_id '.mat']);

    % Are these candidates already evaluated?
    if ~exist(res_file, 'file')

        % Input file with candidates as labels
        labels_file = fullfile(masks_dir,[curr_id '.mat']);

        % Check if labels are computed
        if ~exist(labels_file, 'file')
            error(['Results ''' labels_file '''not found. Have you computed them?'])
        end

        % Load candidates
        cands = load(labels_file);

        % Load GT
        gt = get_ground_truth(database,curr_id);

        % Get all objects ids
        obj_ids = unique(gt.object);
        obj_ids(obj_ids==0) = [];
        obj_ids(obj_ids==255) = [];
        n_objs = numel(obj_ids);
        valid_pixels = (gt.object~=255);

        % Store true_areas
        true_areas = zeros(n_objs,1);
        for kk=1:n_objs
            true_areas(kk) = sum(gt.object(:)==kk);
        end

        % Store the class of each object
        obj_classes = zeros(n_objs,1);
        for kk=1:n_objs
            idx = find(gt.object==obj_ids(kk),1,'first');
            obj_classes(kk) = gt.class(idx);
        end

        % Overlap superpixels with GT objects
        n_leaves = length(unique(cands.superpixels));
        superpixels = cands.superpixels;
        superpixels(~valid_pixels) = 0;
        leave_fp   = zeros(n_objs,n_leaves);  % False positives
        leave_int  = zeros(n_objs,n_leaves);  % Intersection with GT
        for kk=1:n_objs
            tmp = hist(double(superpixels(:)).*(gt.object(:)==kk),(0:n_leaves));
            leave_int(kk,:) = tmp(2:end);
            tmp = hist(double(superpixels(:)).*(gt.object(:)~=kk),(0:n_leaves));
            leave_fp(kk,:) = tmp(2:end);
        end

        % Create matrix padded with zeros to be compatible with mex_eval_labels
        n_cands    = size(cands.labels,1);
        n_max_labels = length(unique(cands.superpixels));
        label_matrix = zeros(n_cands,n_max_labels);
        for jj=1:n_cands
            label_matrix(jj,1:length(cands.labels{jj})) = cands.labels{jj};
        end

        % Compute fp, fn etc. from these values on the superpixels
        inters     = zeros(n_objs,n_cands);
        false_pos  = zeros(n_objs,n_cands);
        false_neg  = zeros(n_objs,n_cands);
        jaccards   = zeros(n_objs,n_cands);
        if n_cands>0
            for kk=1:n_objs
                [inters(kk,:),false_pos(kk,:)] = mex_eval_labels(leave_int(kk,:),leave_fp(kk,:),label_matrix);
                false_neg(kk,:) = true_areas(kk)-inters(kk,:);
                jaccards(kk,:) = inters(kk,:)./(false_pos(kk,:)+true_areas(kk));
            end
        end
        assert(sum(isnan(jaccards(:)))==0)

        % Store results
        parsave(res_file,jaccards,inters,false_pos,false_neg,true_areas,obj_classes)
    end
end
end

function parsave(res_file,jaccards,inters,false_pos,false_neg,true_areas,obj_classes) %#ok<INUSD>
    save(res_file, 'jaccards','inters', 'false_pos', 'false_neg','true_areas','obj_classes');
end


function report = generateIssueReport(EEG)
% Generates an issue report for an EEG structure that has been robustly referenced
aveCorrThreshold = 0.91;
medCorrThreshold = 0.95;
if nargin < 1
    error('generateIssueReport:NotEnoughArgs', ...
        'generateIssueReport requires an EEG structure argument');
end
report = '';

if ~isstruct(EEG)
    report = 'Input not an EEG structure';
    return;
end

nDetect = getFieldIfExists(EEG, {'etc', 'noiseDetection'});
if isempty(nDetect)
    report = 'Input EEG has not been robustly referenced';
    return;
end

status = getFieldIfExists(nDetect, {'errors', 'status'});
if ~isempty(status) && ~strcmpi(status, 'good');
    report = ['EEG referencing has following errors: [' ...
               getStructureString(nDetect.errors) ']'];
    return;
end

badChans = getFieldIfExists(nDetect, ...
    {'reference', 'noisyStatistics', 'noisyChannels' 'all'});
if ~isempty(badChans)
    report = [report ...
        sprintf('Noisy channels not interpolated after referencing: %s\n', ...
        getListString(badChans))];
end

evaluationChans = length(getFieldIfExists(nDetect, ...
    {'reference', 'noisyStatistics', 'evaluationChannels'}));
if 0.25*evaluationChans < length(badChans)
     report = [report sprintf('Data set has %d of %d EEG channels bad\n', ...
               length(badChans), evaluationChannels)];
end

%% Median
theCorr = getFieldIfExists(nDetect, ...
         {'reference', 'noisyStatistics', 'maximumCorrelations'});
if ~isempty(theCorr)
    meanCorr = mean(theCorr(:));
    medianCorr = median(theCorr(:));
    if meanCorr> aveCorrThreshold || medianCorr > medCorrThreshold
      report = [report ...
          sprintf('Max win correlation [median=%g, mean=%g]\n', ...
                medianCorr, meanCorr)];
    end
end

devRef = getFieldIfExists(nDetect, ...
         {'reference', 'noisyStatistics', 'channelDeviations'});
devOrig = getFieldIfExists(nDetect, ...
         {'reference', 'noisyStatisticsOriginal', 'channelDeviations'});
if ~isempty(devRef) && ~isempty(devOrig)
   devRef = median(devRef(:));
   devOrig = median(devOrig(:));
   if devOrig < devRef
   report = [report  ...
        sprintf('Referencing did not improve amplitude [ref=%g, orig=%g]\n', ...
                devRev, devOrig)];
   end
end


function y = vl_nncrop(x, crop, dzdy, inputSize)
%VL_NNCROP CNN crop.
%   Y = VL_NNCROP(X, CROP) crops the input X spatially. CROP specifies the
%   amount of cropping as [TOP, BOTTOM, LEFT, RIGHT].
%
%   DZDX = VL_NNCROP(X, CROP, DZDY) computes the derivative DZDX of the
%   function projected on the output derivative DZDY. DZDX has the same
%   dimension as X and DZDY the same dimension as Y.
%
%   DZDX = VL_NNCROP([], CROP, DZDY, INPUTSIZE) is an alternative to
%   the previous call in which X is omitted and its size is passed as
%   INPUTSIZE.

% Copyright (C) 2015 Sebastien Ehrhardt and Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

if nargin < 4
  sz = [size(x,1) size(x,2) size(x,3) size(x,4)] ;
else
  sz = inputSize ;
end

sv = 1 + crop(1) : sz(1) - crop(2) ;
su = 1 + crop(3) : sz(2) - crop(4) ;

if nargin <= 2 || isempty(dzdy)
  y = x(sv, su, :, :) ;
else
  if isa(dzdy, 'gpuArray')
    y = gpuArray.zeros(sz, classUnderlying(dzdy)) ;
  else
    y = zeros(sz, class(dzdy)) ;
  end
  y(sv, su, :, :) = dzdy ;
end


clc;
clear all;

load('..\data\nlc_data_5zones.mat')
load('..\data\lc_data_20s_withpoints.mat')

% transfer to related coordinate, in terms of the host
%%% for the lc_data
r_lc_data = {};

Label = [points; 600*ones(length(nlc_data),2)];

for i = 1: length(lc_data)
    trajs = lc_data{i};
    origin_x = trajs.veh_s.x(1);
    origin_y = trajs.veh_s.y(1);

    R_trajs.veh_s_x = trajs.veh_s.x(1:100) - origin_x;
    R_trajs.veh_s_y = trajs.veh_s.y(1:100) - origin_y;
    Label(i,1) = trajs.veh_s.y(points(i,1)) - origin_y;
    Label(i,2) = trajs.veh_s.y(points(i,2)) - origin_y;

    da = [];

    if (trajs.veh_r.x(1) ~= 10000)
        R_trajs.veh_r_x = trajs.veh_r.x(1:100) - origin_x;
        R_trajs.veh_r_y = trajs.veh_r.y(1:100) - origin_y;
    else
        R_trajs.veh_r_x = 0*trajs.veh_r.x(1:100);
        R_trajs.veh_r_y = 0*trajs.veh_r.y(1:100);
    end
    if (trajs.veh_f.x(1) ~= 10000)
        R_trajs.veh_f_x = trajs.veh_f.x(1:100) - origin_x;
        R_trajs.veh_f_y = trajs.veh_f.y(1:100) - origin_y;
    else
        R_trajs.veh_f_x = 0*trajs.veh_f.x(1:100);
        R_trajs.veh_f_y = 0*trajs.veh_f.y(1:100);
    end

    if (trajs.veh_rt.x(1) ~= 10000)
        R_trajs.veh_rt_x = trajs.veh_rt.x(1:100) - origin_x;
        R_trajs.veh_rt_y = trajs.veh_rt.y(1:100) - origin_y;
    else
        R_trajs.veh_rt_x = 0*trajs.veh_rt.x(1:100);
        R_trajs.veh_rt_y = 0*trajs.veh_rt.y(1:100);
    end

    if (trajs.veh_ft.x(1) ~= 10000)
        R_trajs.veh_ft_x = trajs.veh_ft.x(1:100) - origin_x;
        R_trajs.veh_ft_y = trajs.veh_ft.y(1:100) - origin_y;
    else
        R_trajs.veh_ft_x = 0*trajs.veh_ft.x(1:100);
        R_trajs.veh_ft_y = 0*trajs.veh_ft.y(1:100);
    end

    if isfield(trajs, 'veh_st') && (trajs.veh_st.x(1) ~= 10000)
        R_trajs.veh_st_x = trajs.veh_st.x(1:100) - origin_x;
        R_trajs.veh_st_y = trajs.veh_st.y(1:100) - origin_y;
    else
        R_trajs.veh_st_x = 0*trajs.veh_ft.x(1:100);
        R_trajs.veh_st_y = 0*trajs.veh_ft.y(1:100);
    end

    da = [da;R_trajs.veh_s_x(end-19:end-10) ];
    da = [da;R_trajs.veh_f_x(end-19:end-10) ];
    da = [da;R_trajs.veh_rt_x(end-19:end-10) ];
    da = [da;R_trajs.veh_ft_x(end-19:end-10) ];
    da = [da;R_trajs.veh_st_x(end-19:end-10) ];

    r_lc_data{i}=R_trajs;
end

r_nlc_data = {};
for i = 1: length(nlc_data)
    da = [];
    trajs = nlc_data{i};
    origin_x = trajs.veh_s.x(1);
    origin_y = trajs.veh_s.y(1);

    R_trajs.veh_s_x = trajs.veh_s.x - origin_x;
    R_trajs.veh_s_y = trajs.veh_s.y - origin_y;

    if (trajs.veh_r.x(1) ~= 10000)
        R_trajs.veh_r_x = trajs.veh_r.x - origin_x;
        R_trajs.veh_r_y = trajs.veh_r.y - origin_y;
    else
        R_trajs.veh_r_x = 0*trajs.veh_r.x;
        R_trajs.veh_r_y = 0*trajs.veh_r.y;
    end

    if (trajs.veh_f.x(1) ~= 10000)
        R_trajs.veh_f_x = trajs.veh_f.x - origin_x;
        R_trajs.veh_f_y = trajs.veh_f.y - origin_y;
    else
        R_trajs.veh_f_x = 0*trajs.veh_f.x;
        R_trajs.veh_f_y = 0*trajs.veh_f.y;
    end

    if (trajs.veh_rt.x(1) ~= 10000)
        R_trajs.veh_rt_x = trajs.veh_rt.x - origin_x;
        R_trajs.veh_rt_y = trajs.veh_rt.y - origin_y;
    else
        R_trajs.veh_rt_x = 0*trajs.veh_rt.x;
        R_trajs.veh_rt_y = 0*trajs.veh_rt.y;
    end

    if (trajs.veh_ft.x(1) ~= 10000)
        R_trajs.veh_ft_x = trajs.veh_ft.x - origin_x;
        R_trajs.veh_ft_y = trajs.veh_ft.y - origin_y;
    else
        R_trajs.veh_ft_x = 0*trajs.veh_ft.x;
        R_trajs.veh_ft_y = 0*trajs.veh_ft.y;
    end

    if isfield(trajs, 'veh_st') && (trajs.veh_st.x(1) ~= 10000)
        R_trajs.veh_st_x = trajs.veh_st.x - origin_x;
        R_trajs.veh_st_y = trajs.veh_st.y - origin_y;
    else
        R_trajs.veh_st_x = 0*trajs.veh_ft.x;
        R_trajs.veh_st_y = 0*trajs.veh_ft.y;
    end
    da = [da;R_trajs.veh_s_x(end-19:end-10) ];
    da = [da;R_trajs.veh_f_x(end-19:end-10) ];
    da = [da;R_trajs.veh_rt_x(end-19:end-10) ];
    da = [da;R_trajs.veh_ft_x(end-19:end-10) ];
    da = [da;R_trajs.veh_st_x(end-19:end-10) ];

    r_nlc_data{i}=R_trajs;
end

save('../data/processed_relative.mat','Label','r_lc_data','r_nlc_data')


% dtiComputePlotDiffusionPropertiesAlongFiberGroup

% OVERVIEW:
% This script takes a group of subjects with a given fiber group(s) and set
% of ROIs and:
%   1. Loads the fibers and rois, as well as the dt6.mat file created
%      during preprocessing.
%   2. Computes diffusion properties along the fiber group using
%      dtiComputeDiffusionPropertiesAlongFG. (see that function for more
%      info.
%   3. Saves out a structure (dtval) with the tensor values for 'fa','md',
%      'rd', and 'ad'.
%   4. Plots the data
%   5. Saves the images to "saveDir"

% VARIABLES:
%   saveDir = the directory wherein the data and figures will be saved.
%   subs = the indetifying codes for each subject in your directory.
%         (e.g., {subs = 'sub1','sub2','sub3'...})
%   baseDir = the level of your directory structure that has your data at
%             the first level.
%   dirs = the name of the directory that contains each subject's dt6.mat
%          file - usually named for the number of diffusion directions.
%   fgName = cell array containg the names of each fiber group you wish to
%            compute properties for.
%   rois = cell array containing the names of the first of 2 rois used to
%          generate the fibers in fgName. NO FILE EXTENSIONS
%   roi2 = cell array containing the names of the second of 2 rois used to
%          generate the fibers in fgName. NO FILE EXTENTIONS
%   plotNames = a cell array contining one name for each fiber group, which
%               will be the name for each plot associated with that fiber
%               group.
%   numberOfNodes = the number of steps along the fg at which properties
%                   will be computed.
%   propertyofinterest = the properties that will be computed for each
%                        group.

% NOTES:
%  You will have to set variables in the first two sections. If  you have a
%  probelm with data not being found check the directory structure within the
%  loop.

%  You must provide the ROIs in rois and rois2 that were used to track the
%  fibers in fgName.
%   For example, if you used roiA and roiB to track fibergroup AB in
%   contrack, then the cell arrays should look like:
%       fgName  = {'fibergroupAB.pdb'};
%       rois    = {'roiA'};
%       rois2   = {'roiB'};

%  The name in the rois cell array will be used for naming the figures.
%  This can be changed in sections IV - VI if you don't wish to use this
%  default behavior.

% HISTORY:
% 2011.1.10 - LMP wrote the code.

%% I. Set directories, rois and plot names

saveDir = '/path/to/your/data/directory';
           if ~exist(saveDir,'file'), mkdir(saveDir); end

subs    = {'sub1','sub2','sub3'};
baseDir = '/path/to/your/subjects"/data/';
dirs    = 'dti06trilinrt';

fgName  = {'fibergroupAB.pdb','fibergroupCD.pdb'};
rois    = {'roiA','roiC'};
rois2   = {'roiB','roiD'};

plotName = {'Fiber Group AB Plot Name','Fiber Group CD Plot Name'};

%% II. Set up parameters

numberOfNodes      = 50;
propertyofinterest = {'fa','md', 'rd', 'ad'};
roi1name           = rois;
roi2name           = rois2;

%% III Loop over subjects and compute fiber properties
wb = mrvWaitbar(0,'Overall Script Progress');
for zz = 1:numel(propertyofinterest)
    for kk = 1:numel(fgName)
        for ii=1:numel(subs)
            sub      = dir(fullfile(baseDir,[subs{ii} '*']));
            subDir   = fullfile(baseDir,sub.name);
            dt6Dir   = fullfile(subDir,dirs);
            fiberDir = fullfile(dt6Dir,'fibers','conTrack');
            roiDir   = fullfile(dt6Dir,'ROIs');
            try
                % III. 1 LOAD THE DATA
                fibersFile = fullfile(fiberDir,fgName{kk});
                fg         = mtrImportFibers(fibersFile);
                roi1File   = fullfile(roiDir, [roi1name{kk} '.mat']);
                roi2File   = fullfile(roiDir, [roi2name{kk} '.mat']);
                roi1       = dtiReadRoi(roi1File);
                roi2       = dtiReadRoi(roi2File);
                dt         = dtiLoadDt6(fullfile(dt6Dir,'dt6.mat'));

                % III. 2 Compute
                [fa(:, ii),md(:, ii),rd(:, ii),ad(:, ii)]=...
                    dtiComputeDiffusionPropertiesAlongFG(fg, dt, roi1, roi2, numberOfNodes);
            catch ME
                disp(ME.message);
                disp(['PROBLEM loading data for subject: ' subs{ii} '. This subject will NOT be included in the graph!']);
            end
        end
        dtval.(propertyofinterest{zz}).(rois{kk}) = eval(propertyofinterest{zz});

    end
mrvWaitbar(zz/(numel(propertyofinterest)),wb);

end
save((fullfile(saveDir,'dtval.mat')),'dtval');

%% PLOT DATA

%% IV Plot results: Average for each roi.

load(fullfile(saveDir,'dtval.mat'));

    for zz = 1:numel(propertyofinterest) % fa,md,rd,ad
        for kk = 1:numel(rois)

            AVG = mean(dtval.(propertyofinterest{zz}).(rois{kk}),2);

            figure;
            hold on
            plot(AVG,'b','LineWidth',5);
            set(gca,'PlotBoxAspectRatio',[1,.7,1]);

           switch propertyofinterest{zz}
                case 'fa'
                    yText = 'FA (weighted)';
                    titleText = ['Fractional Anisotropy Along ' plotName{kk}];
                case 'md'
                    yText = 'MD \mum^2/msec (weighted)';
                    titleText = ['Mean Diffusivity Along ' plotName{kk}];
                case 'rd'
                    yText = 'RD \mum^2/msec (weighted)';
                    titleText = ['Radial Diffusivity Along ' plotName{kk}];
                case 'ad'
                    yText = 'AD \mum^2/msec (weighted)';
                    titleText = ['Axial Diffusivity Along ' plotName{kk}];
            end

            title(titleText);
            ylabel(yText);
            xlabel('Fiber Group Trajectory');
            set(gca,'xtick',[0 numberOfNodes]);
            set(gca,'xticklabel',{rois{kk},rois2{kk}})
            saveName = [plotName{kk} '_' propertyofinterest{zz}];
            saveas(gcf,(fullfile(saveDir,saveName)),'epsc2');
            hold off
        end
    end

%% V Plot results: Each fiber group on the same grapgh.

load(fullfile(saveDir,'dtval.mat'));
col = jet(numel(rois)); % set colors for graph.

    for zz = 1:numel(propertyofinterest) % fa,md,rd,ad
        figure;
        for kk = 1:numel(rois)

            AVG = mean(dtval.(propertyofinterest{zz}).(rois{kk}),2);

            hold on
            plot(AVG,'LineWidth',5,'color',col(kk,:));
            set(gca,'PlotBoxAspectRatio',[1,.7,1]);

            switch propertyofinterest{zz}
                case 'fa'
                    yText = 'FA (weighted)';
                    titleText = ['Fractional Anisotropy'];
                case 'md'
                    yText = 'MD \mum^2/msec (weighted)';
                    titleText = ['Mean Diffusivity'];
                case 'rd'
                    yText = 'RD \mum^2/msec (weighted)';
                    titleText = ['Radial Diffusivity'];
                case 'ad'
                    yText = 'AD \mum^2/msec (weighted)';
                    titleText = ['Axial Diffusivity '];
            end

            title(titleText);
            ylabel(yText);
            xlabel('Fiber Group Trajectory');

        end
            set(gca,'xtick',[0 numberOfNodes]);
            set(gca,'xticklabel',{rois{kk},rois2{kk}})
            ld = legend(plotName{:});
            set(ld,'Interpreter','tex','Location','NorthEast');
            saveName = [propertyofinterest{zz} '_allGroups'];
            saveas(gcf,(fullfile(saveDir,saveName)),'epsc2');
    end

%% VI Plot results for each roi sorted by subject

load(fullfile(saveDir,'dtval.mat'));

col = jet(numel(subs)); % set colors for graph.

for zz = 1:numel(propertyofinterest) % fa,md,rd,ad
    for kk = 1:numel(rois)

        AVG = mean(dtval.(propertyofinterest{zz}).(rois{kk}),2);

        figure;
        hold on
        % Loop over each subject and plot their data using a different color line (col)
        for ss = 1:numel(subs)
            plot(dtval.(propertyofinterest{zz}).(rois{kk})(:,ss),'color',col(ss,:));
        end
        ld = legend(subs{:});
        set(ld,'Interpreter','tex','Location','NorthEastOutSide');
        plot(AVG,'g','LineWidth',5);
        set(gca,'PlotBoxAspectRatio',[1,.7,1]);

        switch propertyofinterest{zz}
            case 'fa'
                yText = 'FA (weighted)';
                titleText = ['Fractional Anisotropy Along ' plotName{kk}];
            case 'md'
                yText = 'MD \mum^2/msec (weighted)';
                titleText = ['Mean Diffusivity Along ' plotName{kk}];
            case 'rd'
                yText = 'RD \mum^2/msec (weighted)';
                titleText = ['Radial Diffusivity Along ' plotName{kk}];
            case 'ad'
                yText = 'AD \mum^2/msec (weighted)';
                titleText = ['Axial Diffusivity Along ' plotName{kk}];
        end

        title(titleText);
        ylabel(yText);
        xlabel('Fiber Group Trajectory');
        set(gca,'xtick',[0 numberOfNodes]);
        set(gca,'xticklabel',{rois{kk},rois2{kk}});
        whitebg;
        saveName = [plotName{kk} '_' propertyofinterest{zz} '_SUBJECT_avgLine'];
        saveas(gcf,(fullfile(saveDir,saveName)),'epsc2');
    end
end
close(wb)
close all


classdef prtRvUniformImproper < prtRv
    % prtRvUniformImproper  Improper uniform random variable
    %
    %   RV = prtRvUniformImproper creates a prtRvUniformImproper object
    %   with unknown dimensionality nDimensions. nDimensions can be set
    %   manually or using the MLE method. A prtRvUniformImproper
    %   models an improper pdf that always yields a value of 1 no matter
    %   the input. prtRvUniformImproper is sometimes useful for creating
    %   one class classifiers. See the examples below for more information
    %
    %   The draw method of prtRvUniformImproper draws values uniformly
    %   distributed from realmin to realmax in each dimension.
    %
    %   RV = prtRvUniformImproper(PROPERTY1, VALUE1,...) creates a
    %   prtRvMultinomial object RV with properties as specified by
    %   PROPERTY/VALUE pairs.
    %
    %   A prtRvUniformImproper object inherits all properties from the
    %   prtRv class. In addition, it has the following properties:
    %
    %   nDimensions - dimensionality of the data modeled by this RV.
    %
    %  A prtRvUniformImproper object inherits all methods from the prtRv
    %  class. The MLE  method can be used to set the parameters from data.
    %
    %  Example:
    %
    %  % In this example we show that the PDF of a prtRvUniformImproper is
    %  % always 1
    %  dataSet = prtDataGenUnimodal;        % Load a dataset consisting of
    %                                       % 2 features
    %  dataSet = retainFeatures(dataSet,1); % Retain only the first feature
    %                                       % only for the example.
    %
    %  RV = prtRvUniformImproper;           % Create a prtRvUniform object
    %  RV = RV.mle(dataSet);                % Compute the bounds
    %
    %  RV.plotPdf([-10 10]);                % We must manually specify
    %                                       % plot limits since
    %                                       % prtRvUniformImproper does not
    %                                       % have actual plot limits
    %
    %
    %  % In this example we show how to build a one class MAP classifier
    %  dataSet = prtDataGenUnimodal;        % Load a dataset consisting of
    %                                       % 2 features
    %
    %  % Create and train a GLRT classifier that uses a
    %  % prtRvUniformImproper to model class 0 and a prtRvMvn to model
    %  % class 1
    %  glrtClass = train(prtClassGlrt('rvH0',prtRvUniformImproper,'rvH1',prtRvMvn),dataSet);
    %
    %  plot(glrtClass) % Contours only show the log-likelihood of class 1
    %
    %   See also: prtRv, prtRvMvn, prtRvGmm, prtRvMultinomial,
    %   prtRvVq, prtRvKde

    properties (SetAccess = private)
        name = 'Improper Uniform Random Variable'
        nameAbbreviation = 'RVImUnif';
    end

    properties (SetAccess = protected)
        isSupervised = false;
        isCrossValidateValid = true;
    end

    properties (Hidden = true, SetAccess = 'private', GetAccess = 'private')
        nDimensionsPrivate
    end

    properties (Hidden = true, Dependent = true)
        nDimensions
    end

    methods
        % The Constructor
        function R = prtRvUniformImproper(varargin)
            R = constructorInputParse(R,varargin{:});
        end

        function R = mle(R,X)
            X = R.dataInputParse(X); % Basic error checking etc
           R.nDimensionsPrivate = size(X,2);
        end

        function vals = pdf(R,X)
            X = R.dataInputParse(X); % Basic error checking etc

            [isValid, reasonStr] = R.isValid;
            assert(isValid,'PDF cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);

            vals = ones(size(X,1),1);
        end

        function vals = logPdf(R,X)
            X = R.dataInputParse(X); % Basic error checking etc
            [isValid, reasonStr] = R.isValid;
            assert(isValid,'LOGPDF cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);
            vals = log(pdf(R,X));
        end

        function vals = cdf(R,X)
            X = R.dataInputParse(X); % Basic error checking etc
            [isValid, reasonStr] = R.isValid;
            assert(isValid,'CDF cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);
            assert(size(X,2) == R.nDimensions,'Data, RV dimensionality missmatch. Input data, X, has dimensionality %d and this RV has dimensionality %d.', size(X,2), R.nDimensions)
            vals = nan(size(X,1),1);
        end

        function vals = draw(R,N)
            if nargin < 2
                N = 1;
            end

            assert(numel(N)==1 && N==floor(N) && N > 0,'N must be a positive integer scalar.')

            [isValid, reasonStr] = R.isValid;
            assert(isValid,'DRAW cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);

            vals = bsxfun(@times,bsxfun(@times,rand(N,R.nDimensions),realmax),sign(randn(N,1)));
        end

        function R = set.nDimensions(R,N)
            assert(numel(N)==1 && N==floor(N) && N > 0,'nDimensions must be a positive integer scalar.')
            R.nDimensionsPrivate = N;
        end

        function val = get.nDimensions(R)
            val = R.nDimensionsPrivate;
        end
    end

    methods (Hidden = true)
        function [val, reasonStr] = isValid(R)
            if numel(R) > 1
                val = false(size(R));
                for iR = 1:numel(R)
                    [val(iR), reasonStr] = isValid(R(iR));
                end
                return
            end

            val = true;
            reasonStr = '';
        end
        function val = plotLimits(R)
            [isValid, reasonStr] = R.isValid;
            if isValid
                val = zeros(2*R.nDimensions,1);
                val(1:2:end) = Inf;
                val(2:2:end) = -Inf;
                % We send backwards limits so that we don't effect plot
                % limits if you were to check the limits of a set of RVs.
                % In this case this RV would not change the resulting
                % max(upperBounds), min(lowerBounds)
            else
                error('prtRvUniformImproper:plotLimits','Plotting limits can not be determined for this RV. It is not yet valid %s.',reasonStr)
            end
        end
    end
end


function foreground = extractForeground(video,frameSkip,dataRange,minSigmaLevel,shadowLevel,significanceThreshold,useGraph,graphAlpha,morphStructureElement,returnLargestComponent)

% extractForeground:  Extract the foreground from a video.
%
% This file shows sample usage for extracting the moving foreground
% from a static background.  It is intended as an example only;
% More sophisitcated background modeling techniques, particularly
% adaptive ones, may be applied instead.  However, this should
% suffice for many simple videos.
%
% A number of parameters are available to control the behavior
% of the algorithm.  If these are unsupplied or empty, reasonable
% default values will be chosen.
%
% video:  This is the only required parameter.  It may consist
%   of a string containing the name of an avi file to load.
%   Alternately, it may contain the video frames as a cell
%   array of rgb images, stored as uint8 data.
%
% frameSkip:  Long videos may use enormous amounts of memory
%   during the intermediate processing stages.  If this becomes
%   a problem, frameSkip allows the background model to be
%   computed using every nth frame.
%
% dataRange:  A cheap way of approximating robust statistics.
%   Mean/deviation are computed only for data falling within
%   the specified percentile ranges.  For example, with the
%   default value of [.25 .75], outlier pixels in up to 25% of
%   the video frames will be ignored.
%
% minSigmaLevel:  Pixels with very low (or zero) deviation cause
%   trouble.  This parameter specifies a percentile level,
%   which gives a floor deviation value for all pixels.
%
% shadowLevel:  Amount of shadowing to account for.  Positive
%   values allow some darkening of the pixel intensity without
%   treating it as evidence of a foreground object.
%
% significanceThreshold:  Number of standard deviations required
%   for a pixel to be considered foreground, in isolation.
%   This is perhaps the single most important parameter.  If pieces
%   of the foreground are being left out, try decreasing its value.
%   If too much background is included, try increasing its value.
%   (Lax dataRange bounds can also cause pieces of foreground to be
%   left out, if an object obscures the background for too long.
%   Increasing the shadowLevel can also help prevent background
%   inclusion, particularly around subjects' legs.)
%
% useGraph:  Boolean control parameter.  If true, use graph cut
%   to find foreground.  If false, use morphology.
%
% graphAlpha:  Parameter controlling "clumpiness" of graph cut
%   operation.
%
% morphStructureElement:  Parameter controlling the morphological
%   operations if these are used.
%
% returnLargestComponent:  Boolean control parameter.  If true,
%   then return single largest connected foreground component.
%   If false, return raw labels.
%
% Usage:
%   function foreground = extractForeground(video,frameSkip,dataRange,minSigmaLevel,shadowLevel,significanceThreshold,useGraph,graphAlpha,morphStructureElement,returnLargestComponent)

% Apply default values if required
if (nargin < 2)|isempty(frameSkip), frameSkip = 1; end;
if (nargin < 3)|isempty(dataRange), dataRange = [.25 .75]; end;
if (nargin < 4)|isempty(minSigmaLevel), minSigmaLevel = 0.1; end;
if (nargin < 5)|isempty(shadowLevel), shadowLevel = 0.05; end;
if (nargin < 6)|isempty(significanceThreshold), significanceThreshold = 6; end;
if (nargin < 7)|isempty(useGraph), useGraph = 1; end;
if (nargin < 8)|isempty(graphAlpha), graphAlpha = 1; end;
if (nargin < 9)|isempty(morphStructureElement), morphStructureElement = strel('disk',1); end;
if (nargin < 10)|isempty(returnLargestComponent), returnLargestComponent = 1; end;

if ischar(video)
    % Load the video from an avi file.
    avi = aviread(video);
    pixels = double(cat(4,avi(1:frameSkip:end).cdata))/255;
    clear avi
else
    % Compile the pixel data into a single array
    pixels = double(cat(4,video{1:frameSkip:end}))/255;
    clear video
end;
% NOTE:  The result of the cat operation above may be very large.
% If it will not fit into memory, try increasing frameSkip.
% Another alternative is to decrease the video resolution.

% Convert to HSV color space.
nFrames = size(pixels,4);
for f = 1:nFrames
    pixels(:,:,:,f) = rgb2hsv(pixels(:,:,:,f));
end;

% Generate Gaussian background model in hsv space for each pixel.
[backgroundMean, backgroundDeviation] = hsvGaussModel(pixels,dataRange);
backgroundDeviation(:,:,1) = max(backgroundDeviation(:,:,1),pctile(nonzeros(backgroundDeviation(:,:,1)),minSigmaLevel));
backgroundDeviation(:,:,2) = max(backgroundDeviation(:,:,2),pctile(nonzeros(backgroundDeviation(:,:,2)),minSigmaLevel));
backgroundDeviation(:,:,3) = max(backgroundDeviation(:,:,3),pctile(nonzeros(backgroundDeviation(:,:,3)),minSigmaLevel));

% Do frame-by-frame differencing
connections = pixCon(size(backgroundMean(:,:,1)));
foreground = cell(1,nFrames);
for f = 1:nFrames
    % Find scaled deviation of this frame from background
    deviation = sum(hsvCompare(pixels(:,:,:,f),backgroundMean,shadowLevel)./backgroundDeviation,3);

    % Compare with threshold to generate labeling
    if useGraph
        % Use graph cuts
        alpha = graphAlpha/significanceThreshold;
        label = reshape(graphLabel(alpha*[max(2*significanceThreshold-deviation(:)',0);deviation(:)'],connections),size(deviation));
    else
        % Use morphological operations
        label = double(imopen(imclose(deviation > significanceThreshold,morphStructureElement),morphStructureElement));
    end;

    % clean up:  find largest connected component, etc.
    if returnLargestComponent
        label = fgRanked(label,1);
    end;
    foreground{f} = logical(label);  % Could use bwpack if desired
end;
% end of extractForeground

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Fits a gaussian to the specified distribution, in a robust manner.
%
% Returns the mean and standard deviation of the input arguments
% using the specified portion of the data.  Uses HSV color space
% for better shadow control.

function [mu,sigma] = hsvGaussModel(pixels,dataRange)

% statistics of s & v dimensions are simple.
[mu(:,:,2:3),sigma(:,:,2:3)] = fitGauss(pixels(:,:,2:3,:),dataRange,4);
hmu = polarMean(pixels(:,:,1,:)*2*pi,4);
h = zeros(size(pixels(:,:,1,:)));
nFrames = size(pixels,4);
for i = 1:nFrames
    h(:,:,1,i) = mod(pixels(:,:,1,i)*2*pi-hmu+pi,2*pi);
end;
[mu(:,:,1),sigma(:,:,1)] = fitGauss(h,dataRange,4);
mu(:,:,1) = mod(mu(:,:,1)-pi+hmu,2*pi)/(2*pi);
sigma(:,:,1) = sigma(:,:,1)/(2*pi);
% end of hsvGaussModel

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Fits a gaussian to the specified distribution, in a robust manner.
%
% Returns the mean and standard deviation of the input arguments
% using the specified portion of the data

function [mu,sigma] = fitGauss(m,dataRange,dim)

x = -3:0.01:3;
y = exp(-x.^2);
y = y./sum(y);
yy = cumsum(y);
fdev = sqrt(sum(y.*x.^2));
xbd = min(find(yy > dataRange(1))):min(find(yy > dataRange(2)));
pdev = sqrt(sum(y(xbd).*x(xbd).^2)/sum(y(xbd)));

dimlen = size(m,dim);
if all(dataRange == [0 1])|(dim > length(size(m)))
    % skip sorting step if we'll be using everything anyway
    ms = m;
else
    ms = sort(m,dim);
end;
dimind = round(dataRange*(dimlen-1)+1);
[refstr{1:length(size(m))}] = deal(':');
if (dim <= length(size(m)))
    refstr{dim} = dimind;
end;
sref = struct('type','()','subs',{refstr});
bds = subsref(ms,sref);
if (dim <= length(size(m)))
    sref.subs{dim} = dimind(1):dimind(2);
end;
data = subsref(ms,sref);
mu = mean(data,dim);
sigma = std(data,0,dim)*fdev/pdev;
% end of fitGauss

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% function d = hsvCompare(a,b,shadow)
%
% Returns the component differences between images in HSV color space.

function d = hsvCompare(a,b,shadow)

aclr = length(a(:))/3;
bclr = length(b(:))/3;
sa = a(aclr+1:2*aclr);
sb = b(bclr+1:2*bclr);
va = a(2*aclr+1:3*aclr);
vb = b(2*bclr+1:3*bclr);
d = zeros(size(a));
d(1:aclr) = (angdiff(2*pi*a(1:aclr),2*pi*b(1:bclr)).*min(sa,sb))';
d(aclr+1:2*aclr) = abs(sa-sb);
d(2*aclr+1:3*aclr) = va-vb;
neg = find(d(2*aclr+1:3*aclr)<0);
d(2*aclr+neg) = max(0,vb(neg)-va(neg)-shadow);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%function d = angdiff(th1, th2)
%
% Returns the difference between angles expressed in radians.
% This will always be <= pi.

function d = angdiff(th1, th2)

d = abs(mod(th1-th2+pi,2*pi)-pi);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Returns the "mean" of a set of angular variables

function pm = polarMean(th,dim)

th = mod(th,2*pi);
x = cos(th);
y = sin(th);
if (nargin < 2)
    pm = mod(atan2(mean(y),mean(x)),2*pi);
else
    pm = mod(atan2(mean(y,dim),mean(x,dim)),2*pi);
end;
% end of polarMean

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% PCTILE Percentile
%
% For vectors, PCTILE(X,Y) returns the element at the Yth percentile of X.
% For matrices, PCTILE(X,Y) returns a row vector containing the
% Yth percentile of each column.  Y must be between 0 and 1.
%
% PCTILE(X,Y,DIM) takes the percentile along dimension DIM of X.
%
% See also MIN, MAX, MEDIAN

function pct = pctile(x,pct,dim)

if (nargin < 3)
    [x,n] = shiftdim(x);
    dim = 1;
end;

sx = sort(x,dim);
subs = cell(1,length(size(x)));
[subs{:}] = deal(':');
subs{dim} = round(pct*(size(x,dim)-1))+1;
ref = struct('type','()','subs',{subs});
pct = subsref(sx,ref);

if (nargin < 3)
    pct = shiftdim(pct,-n);
end;
% end of pctile

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Returns the foreground connected component in the binary image
% supplied that have the specified ranked size(s).

function fgr = fgRanked(bin,rank)

fg = bwlabel(bin,4);
maxfg = max(fg(:));
h = hist(fg(find(bin)),[1:maxfg]);
[sh,sr] = sort(-h);
if (rank < 1)|(rank > max(find(sh > 0)))
    fgr = zeros(size(img))
else
    fgr = (fg==sr(rank));
end;
% end of fgRanked

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%