classdef HomogenizedVarComputer < handle

    properties (Access = public)
        Cref
        dCref
        C
        dC
        rho
        drho
        Pp
        dPp
    end

    methods (Access = public, Static)

        function obj = create(cParams)
            f = HomogenizedVarComputerFactory();
            obj = f.create(cParams);
        end

    end

    methods (Access = public, Abstract)
        computeCtensor(obj)
        computePtensor(obj)
        computeDensity(obj)
    end

end


% CONFIGROBOT initializes parameters specific of a particular robot
%             (e.g., icubGazeboSim)

%% --- Initialization ---

Config.ON_GAZEBO         = true;
ROBOT_DOF                = 23;
Config.GRAV_ACC          = 9.81;

%%%% INITIAL CONDITIONS %%%%
Config.init_jointPos = [ 0.0,0.0,0.0, ...
                        -30.0,30.0,0.0,45.0, ...
                        -30.0,30.0,0.0,45.0, ...                   %
                         0.0,0.0,0.0,0.0,0.0,0.0, ...
                         0.0,0.0,0.0,0.0,0.0,0.0]*pi/180;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Robot configuration for WBToolbox
WBTConfigRobot           = WBToolbox.Configuration;
WBTConfigRobot.RobotName = 'icubSim';
WBTConfigRobot.UrdfFile  = 'model.urdf';
WBTConfigRobot.LocalName = 'WBT';

% Controlboards and joints list. Each joint is associated to the corresponding controlboard
WBTConfigRobot.ControlBoardsNames     = {'torso','left_arm','right_arm','left_leg','right_leg'};
WBTConfigRobot.ControlledJoints       = [];
Config.numOfJointsForEachControlboard = [];

ControlBoards                                        = struct();
ControlBoards.(WBTConfigRobot.ControlBoardsNames{1}) = {'torso_pitch','torso_roll','torso_yaw'};
ControlBoards.(WBTConfigRobot.ControlBoardsNames{2}) = {'l_shoulder_pitch','l_shoulder_roll','l_shoulder_yaw','l_elbow'};
ControlBoards.(WBTConfigRobot.ControlBoardsNames{3}) = {'r_shoulder_pitch','r_shoulder_roll','r_shoulder_yaw','r_elbow'};
ControlBoards.(WBTConfigRobot.ControlBoardsNames{4}) = {'l_hip_pitch','l_hip_roll','l_hip_yaw','l_knee','l_ankle_pitch','l_ankle_roll'};
ControlBoards.(WBTConfigRobot.ControlBoardsNames{5}) = {'r_hip_pitch','r_hip_roll','r_hip_yaw','r_knee','r_ankle_pitch','r_ankle_roll'};

for n = 1:length(WBTConfigRobot.ControlBoardsNames)

    WBTConfigRobot.ControlledJoints       = [WBTConfigRobot.ControlledJoints, ...
                                             ControlBoards.(WBTConfigRobot.ControlBoardsNames{n})];
    Config.numOfJointsForEachControlboard = [Config.numOfJointsForEachControlboard; length(ControlBoards.(WBTConfigRobot.ControlBoardsNames{n}))];
end

% Frames list
Frames.BASE       = 'root_link';
Frames.IMU        = 'imu_frame';
Frames.LEFT_FOOT  = 'l_sole';
Frames.RIGHT_FOOT = 'r_sole';
Frames.COM        = 'com';

% Config.SATURATE_TORQUE_DERIVATIVE: if true, the derivative of the control
% input is saturated. In this way, it is possible to reduce high frequency
% oscillations and discontinuities in the control input.
Config.SATURATE_TORQUE_DERIVATIVE         = false;

% if TRUE, the controller will STOP if the joints hit the joints limits
% and/or if the (unsigned) difference between two consecutive joints
% encoders measurements is greater than a given threshold.
Config.EMERGENCY_STOP_WITH_JOINTS_LIMITS  = false;
Config.EMERGENCY_STOP_WITH_ENCODER_SPIKES = false;

% Config.USE_MOTOR_REFLECTED_INERTIA: if set to true, motors reflected
% inertias are included in the system mass matrix. If
% Config.INCLUDE_COUPLING is true, then the coupling effect (some joints
% motion is the result of more than one motor motion) is taken into account.
% Config.INCLUDE_HARMONIC_DRIVE_INERTIA is true, then the harmonic drive
% reflected inertia is also considered
Config.USE_MOTOR_REFLECTED_INERTIA    = false;
Config.INCLUDE_COUPLING               = false;
Config.INCLUDE_HARMONIC_DRIVE_INERTIA = false;

% Config.USE_IMU4EST_BASE: if set to false, the base frame is estimated by
% assuming that either the left or the right foot stay stuck on the ground.
% Which foot the controller uses depends on the contact forces acting on it.
% If set to true, the base orientation is estimated by using the IMU, while
% the base position by assuming that the origin of either the right or the
% left foot do not move.
Config.USE_IMU4EST_BASE = false;

% Config.YAW_IMU_FILTER when the flag Config.USE_IMU4EST_BASE = true, then
% the orientation of the floating base is estimated as explained above. However,
% the foot is usually perpendicular to gravity when the robot stands on flat
% surfaces, and rotation about the gravity axis may be affected by the IMU drift
% in estimating this angle. Hence, when either of the flags Config.YAW_IMU_FILTER
% is set to true, then the yaw angle of the contact foot is ignored and kept
% equal to the initial value.
Config.FILTER_IMU_YAW   = true;

% Config.CORRECT_NECK_IMU: when set equal to true, the kinematics from the
% IMU and the contact foot is corrected by using the neck angles. If it set
% equal to false, recall that the neck is assumed to be in (0,0,0). Valid
% ONLY while using the ICUB HEAD IMU!
Config.CORRECT_NECK_IMU = false;

% Config.USE_QP_SOLVER: if set to true, a QP solver is used to account for
% inequality constraints of contact wrenches.
Config.USE_QP_SOLVER    = true;

% Ports name list
Ports.WRENCH_LEFT_FOOT  = '/wholeBodyDynamics/left_leg/cartesianEndEffectorWrench:o';
Ports.WRENCH_RIGHT_FOOT = '/wholeBodyDynamics/right_leg/cartesianEndEffectorWrench:o';
Ports.IMU               = ['/' WBTConfigRobot.RobotName '/inertial'];
Ports.NECK_POS          = ['/' WBTConfigRobot.RobotName '/head/state:o'];

% Ports dimensions
Ports.NECK_POS_PORT_SIZE         = 3;
Ports.IMU_PORT_SIZE              = 12;
Ports.IMU_PORT_ORIENTATION_INDEX = [1,2,3];
Ports.WRENCH_PORT_SIZE           = 6;


%% Copyright (C) 2016 Lagu
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published
%% by the Free Software Foundation; either version 3 of the License,
%% or (at your option) any later version.
%%
%% This software is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty
%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
%% the GNU General Public License for more details.
%%
%% You should have received a copy of the GNU General Public
%% License along with this software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

function z = cell2nosyms(x)

  for i=1:length(x)
    if isa(x{i}, 'sym')
      x{i} = double(x{i});
    end
  end

  z = x;

end


function [TrainX, TestX, TrainY, TestY, numSource, numTrain, numTarget, numTest] = CDPLSA_loadData(inputPath)
    load(inputPath);
    numSource = size(TrainData,2);                              % number of train file
    numTrain = zeros(1,numSource);
    TrainX = [];
    TrainY = [];
    for i = 1 : length(numTrain)
        numTrain(1,i) = size(TrainData{1,i},2);
        TrainX = [TrainX TrainData{1,i}];
        TrainY = [TrainY TrainLabel{1,i}];
    end

    numTarget = size(TestData,2);                              % number of train file
    numTest = zeros(1,numTarget);
    TestX = [];
    TestY = [];
    for i = 1 : length(numTest)
        numTest(1,i) = size(TestData{1,i},2);
        TestX = [TestX TestData{1,i}];
        TestY = [TestY TestLabel{1,i}];
    end
end


classdef MeasurementListX < BaseX
% MeasurementListX class
%
% Summary of MeasurementListX:
% Class implementation of the primitive Measurement List type.

    properties (Dependent)
        Measurements
        NumMeasurements
    end

    properties
        Vectors
        Models
        Tags
        Timestamp
        Metadata
    end

    methods
        function this = MeasurementListX(varargin)
        % Measurement Base constructor
        %
        % Parameters
        % ----------
        % measurements: vector of MeasurementX objects

            if nargin>1
                this.Vectors = varargin{1};
                this.Timestamp = varargin{2};
                if (nargin>2)
                    this.Tags = varargin{3};
                end
            elseif nargin && ~isempty(varargin{1})
                if isa(varargin{1},'MeasurementListX')
                    this.Vectors = varargin{1}.Vectors;
                    this.Tags = varargin{1}.Tags;
                    this.Models = varargin{1}.Models;
                    this.Timestamp = varargin{1}.Timestamp;
                    this.Metadata = varargin{1}.Metadata;
%                     if(isfield(varargin{1},'Tags'))
%                         this.Tags
                elseif isa(varargin{1},'MeasurementX')
                    measurements = varargin{1};
                    this.Vectors = [measurements.Vector];
                    this.Tags = [measurements.Tag];
                    this.Models = [measurements.Model];
                    this.Metadata = [measurements.Metadata];
                    this.Timestamp = measurements.Timestamp;
                else
                    this.Vectors = varargin{1};
                    this.Timestamp = [];
                end
            else
                this.Vectors = [];
                this.Timestamp = [];
            end
        end

        function measurements = getMeasurements(this, indices)
            numMeasurements = size(this.Vectors,2);
            measurements = MeasurementX.empty();
            if any(indices<1) || any(indices>numMeasurements)
                error('Index out of range');
            end
            for k=indices
                if ~isempty(this.Models)
                    model = this.Models(k);
                else
                    model = [];
                end
                if ~isempty(this.Tags)
                    tag = this.Tags(k);
                else
                    tag = [];
                end
                if ~isempty(this.Metadata)
                    metadata = this.Metadata(k);
                else
                    metadata = struct();
                end
                measurements(end+1) = MeasurementX(this.Vectors(:,k),...
                                               this.Timestamp,...
                                               model,...
                                               tag);
                measurements(end).Metadata = metadata;
            end
        end

        function numMeasurements = get.NumMeasurements(this)
            numMeasurements = size(this.Vectors,2);
        end

        function measurements = get.Measurements(this)
            if(isempty(this.Vectors))
                measurements = MeasurementX.empty();
            else
                for k = 1 : this.NumMeasurements
                    if ~isempty(this.Models)
                        model = this.Models(k);
                    else
                        model = [];
                    end
                    if ~isempty(this.Tags)
                        tag = this.Tags(k);
                    else
                        tag = [];
                    end
                    if ~isempty(this.Metadata)
                        metadata = this.Metadata(k);
                    else
                        metadata = struct();
                    end
                    measurements(k) = MeasurementX(this.Vectors(:,k),...
                                                   this.Timestamp,...
                                                   model,...
                                                   tag);
                    measurements(k).Metadata = metadata;
                end
            end
        end
    end
end


classdef GemAxesPanel < GemPanel
    % GemAxesPanel GEM control for Matlab panel containing axes
    %
    %     GemAxesPanel inherits from GemPanel, and inclues a GemAxes object
    %
    %
    %     Licence
    %     -------
    %     Part of GEM. https://github.com/tomdoel/gem
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties (Access = protected)
        Axes
    end

    properties (SetAccess = protected)
        VisualisationLabel
    end

    methods
        function obj = GemAxesPanel(parent)
            obj = obj@GemPanel(parent);

            obj.Axes = GemAxes(obj);
            obj.AddChild(obj.Axes);
            obj.BackgroundColour = 'white';
        end

        function CreateGuiComponent(obj, position)
            CreateGuiComponent@GemPanel(obj, position);
        end

        function Resize(obj, position)
            Resize@GemPanel(obj, position);
            obj.Axes.Resize(position);
        end

        function handle = GetRenderAxes(obj)
            % Returns a handle to the GEM Axes
            handle = obj.Axes;
        end

        function Clear(obj)
            % Clears the axes and resets the render panel
            obj.GetRenderAxes.Clear;
            obj.VisualisationLabel = [];
        end

        function SetVisualisationLabel(obj, label)
            obj.VisualisationLabel = label;
        end

        function frame = Capture(obj, image_size, orientation)
            drawnow;

            origin = [0.5, 0.5, 0.5];
            image_limit = origin + image_size;
            xlim_image = [min(origin), max(image_limit)];
            ylim_image = xlim_image;

            frame = obj.Axes.Capture(xlim_image, ylim_image);
        end
    end
end


function mylayer = riverplot_draw_layer(x_loc, n_rects, varargin)
%
% This is a subfunction of the riverplot toolbox.
%  - Draws a series of rects at an x location x_loc, number specified by n_rects
%  - rect1 and rect2 are structures created by riverplot_rect.m
%  - Ribbon covers a specified percentage of each rect
%  - Can start drawing from the top or bottom of each rect
%
% :Usage:
% ::
%
%     myribbon = riverplot_ribbon(rect1, rect2, [optional inputs])
%
% ..
%     Author and copyright information:
%
%     Copyright (C) 2016  Tor Wager
%
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.
% ..
%
% :Inputs:
%
%   **rect1:**
%        Structure with handles and decription of imrect class object,
%        created with riverplot_rect.m.  This is always the LEFTMOST
%        rect of the pair.
%
%   **rect2:**
%        Same as rect1, but this is the RIGHTMOST rect of the pair
%
% :Optional Inputs:
%   **coverage:**
%        'coverage' followed by 2-element vector for [rect1 rect2], where
%        each value is between 0 and 1 and specifies the percentage of the
%        plot the ribbon will cover.
%
%   **color:**
%        followed by [r g b] color spec for ribbon
%
%   **ax:**
%        followed by axis handle to plot
%
%   **from_bottom:**
%        align ribbon with bottom edges of rects
%
% :Outputs:
%
%   **myribbon:**
%        structure with handles and info for ribbon
%
%
% :Examples:
% ::
%
% create_figure('riverplot'); set(gca, 'YDir', 'reverse');
% layer1 = riverplot_draw_layer(2, 5);
% layer2 = riverplot_draw_layer(5, 3, 'colors', bucknerlab_colors(3));
% ribbon1 = riverplot_ribbon(layer1{1}, layer2{2}, 'coverage', [.5 .2], 'color', [.2 .5 .2], 'from_bottom');
% ribbon2 = riverplot_ribbon(layer1{1}, layer2{3}, 'coverage', [1 .5], 'color', [.7 .5 .5]);
%
% :References:
%   CITATION(s) HERE
%
% :See also:
%   - list other functions related to this one, and alternatives*
%

% ..
%    Programmers' notes:
%    Created by Tor Wager, July 2, 2016
% ..

% ..
%    DEFAULTS AND INPUTS
% ..

ax = gca;
colors = custom_colors([.4 .2 0], [.8 .5 .2], n_rects); % series of cells with colors for each layer

y_loc = 0;
x_wid = .5;
y_wid = 1;

% optional inputs with default values
for i = 1:length(varargin)
    if ischar(varargin{i})
        switch varargin{i}

            case 'ax', ax = varargin{i+1}; varargin{i+1} = [];

            case {'color', 'colors'}, colors = varargin{i+1}; varargin{i+1} = [];

            case 'from_bottom', from_bottom = true;

            case 'coverage', coverage = varargin{i+1}; varargin{i+1} = [];

            case {'y_loc', 'y_start'}, y_loc = varargin{i+1}; varargin{i+1} = [];

            otherwise, warning(['Unknown input string option:' varargin{i}]);
        end
    end
end

axes(ax)

% set y starting point for each
totalwid = y_wid + .1*y_wid;     % y space occupied, total
y_loc = y_loc:totalwid:(y_loc + totalwid.* n_rects);

if length(colors) < n_rects
    error('Too few colors entered!');
end

for i = 1:n_rects
    mylayer{i} = riverplot_rect('color', colors{i}, 'position', [x_loc y_loc(i) x_wid y_wid]);
end

end % function


function iList = MapGroupTree2List(iGroup, iSubj, iSess, iRun)
global maingui

% Function to convert from processing element 3-tuple index to
% a linear index used to select a listbox entry

viewSetting = maingui.listboxGroupTreeParams.viewSetting;
idxs = maingui.listboxGroupTreeParams.listMaps(viewSetting).idxs;

% Convert processing element tuple index to a scalar
scalar0 = index2scalar(iGroup, iSubj, iSess, iRun);

% Find closest match to processing element argument in the listMap
for ii = 1:size(idxs, 1)
    ig = idxs(ii,1);
    is = idxs(ii,2);
    ie = idxs(ii,3);
    ir = idxs(ii,4);
    scalar1 = index2scalar(ig, is, ie, ir);
    if scalar0<=scalar1
        break;
    end
end
iList = ii;

% -----------------------------------------------------
function scalar = index2scalar(ig, is, ie, ir)
scalar = ig*1000 + is*100 + ie*10 + ir;


function [h, ax]= visutil_addTitle(tit, VERTICAL, shift)
%[h, ax]= addTitle(tit, <vert=0, shift=1>);

if ~exist('shift', 'var'), shift=1; end
if ~exist('VERTICAL', 'var'),
  VERTICAL= 0;
elseif ischar(VERTICAL),
  VERTICAL= strmatch(VERTICAL, {'horizontal','vertical'})-1;
end

if VERTICAL,
  borderSize= 0.06;
  posShrink= [1-borderSize 1 1-borderSize 1];
  posShift= [1 0 0 0];
else
  borderSize= 0.1;
  posShrink= [1 1-borderSize 1 1-borderSize];
  posShift= [0 0 0 0];
end

if shift,
  hc= get(gcf, 'children');
  for hi= 1:length(hc),
    if strcmp(get(hc(hi), 'type'), 'axes'),
      pos= get(hc(hi), 'position');
      set(hc(hi), 'position', posShift - (posShift-pos) .* posShrink);
    end
  end
end

ax= visutil_getBackgroundAxis;
prop= {'visible', 'on', ...
       'horizontalAlignment', 'center', ...
       'verticalAlignment', 'middle'};
if VERTICAL,
  prop= {prop{:}, 'rotation', 90};
  h= visutil_textFit(borderSize/2, 0.5, tit, [borderSize 0.9], prop{:});
else
  h= visutil_textFit(0.5, 1-borderSize/2, tit, [0.8 borderSize], prop{:});
end


function test_example_ft_realtime_hilbert

% MEM 4gb
% WALLTIME 00:10:00

%
%% Realtime neurofeedback application based on Hilbert phase estimation
%
% This page describes the neurofeedback application that was developed by Marco Rotonda for his MSc thesis **"Controllo volontario della sincronizzazione di fase intraemisferica nella banda gamma eeg mediante neurofeedback"** (Voluntary control of intrahemispheric phase sychronization in the EEG gamma band using neurofeedback).
%
% The thesis (in Italian) which describes all details and the results is available [here](/assets/pdf/example/rt_hilbert/rotonda_thesis_msc.pdf).
%
% The signal analysis details are available [here](/assets/pdf/example/gamma_analisys.pdf).
%
% Neurofeedback, as the word suggest, is feeding back to the subject it's neuronal activity analyzed by it's EEG activity in (almost) real time. In this training we give back to the subjest a visual stimulation (vertical bars) when it's gamma phase synchronization between F3-P3 and F4-P4 increased over the baseline (bars up) or decreased (bars down).
% Here is the feedback
%
%
% If you scroll the script you can see that this image is a particular point of view of a 3D visualization. I you change the POV you could see all the data from the last 3 minutes.
%
%% # Procedure
%
% Get the FieldTripBufferDemo from the workshop_bci2000 folder on the FieldTrip FTP server and . Start BCI2000 and modifiy the config. The script works originally with 40 channels (see the variable 'lab' in the realtime_hilbert script), the samplingrate used is 1000Hz. Use a blocksize of 1000 samples. Ensure BCI2000 runs for more than 2 minutes in the application tab. Set config and start BCI2000.
% Start MATLAB and in the shell type realtime_hilbert.
%
% Now it will start the function realtime_baseline that for 2 minutes will record the subject baseline and store the results for realtime_hilbert.
% Basically there are 12 channels: 4 for EEG (I used F3-P3-F4-P4), 4 for the EOG, 4 for the EMG (front and neck). In this script, those are selected from the forty originally recorded channels you can find in the variable 'lab'.
% The algorithm will care to take away both EOG and EMG artifacts.
%
%% # MATLAB code for ft_realtime_hilbert
%
function ft_realtime_hilbert()

% FT_REALTIME_HILBERT is a neurofeedback application based on Hilbert phase estimation.
%
% Use as
%   ft_realtime_hilbert()
% with the following configuration options that are coded inside the function
%   cfg.channel    = cell-array, see FT_CHANNELSELECTION (default = 'gui')
%   cfg.foilim     = [Flow Fhigh] (default = [0 120])
%   cfg.blocksize  = number, size of the blocks/chuncks that are processed (default = 1 second)
%   cfg.bufferdata = whether to start on the 'first or 'last' data that is available (default = 'first')
%
% The source of the data is configured as
%   cfg.dataset       = string
% or alternatively to obtain more low-level control as
%   cfg.datafile      = string ( es:  cfg.datafile='buffer://localhost:1972';)
%   cfg.headerfile    = string ( es:  cfg.headerfile='buffer://localhost:1972';)
%   cfg.filename      = string ( es:  cfg.filename = 'buffer://localhost:1972';)
%   cfg.eventfile     = string ( es:  cfg.eventfile = 'buffer://localhost:1972';)
%   cfg.dataformat    = string, default is determined automatic
%   cfg.headerformat  = string, default is determined automatic
%   cfg.eventformat   = string, default is determined automatic
%
% To stop the realtime function, you have to press Ctrl-C

% Take off the warning message to avoid problems with ATAN2 and hilbert.
warning off all;

% This is to save subject data
starttime= DATESTR(now, 30);
subjname = input('Insert the subject name.>>>>>', 's');
trialdata=strcat(starttime,subjname);

realtime_baseline(); %This it will launch the baseline script

load means;  % get means from file created by realtime_baseline

cfg = [];
cfg.datafile = 'buffer://localhost:1972';
cfg.headerfile = 'buffer://localhost:1972';
cfg.filename = 'buffer://localhost:1972';

% set the default configuration options
if ~isfield(cfg, 'dataformat'),     cfg.dataformat = [];      end % default is detected automatically
if ~isfield(cfg, 'headerformat'),   cfg.headerformat = [];    end % default is detected automatically
if ~isfield(cfg, 'eventformat'),    cfg.eventformat = [];     end % default is detected automatically
if ~isfield(cfg, 'blocksize'),      cfg.blocksize = 1;        end % in seconds
if ~isfield(cfg, 'overlap'),        cfg.overlap = 0.5;        end % in seconds
if ~isfield(cfg, 'channel'),        cfg.channel = {'all', '-Fp1', '-Fp2',...
                                    '-F7','-Fz','-F8','-FT7', '-FC3', '-FCz',...
                                    '-FC4', '-FT8', '-T3', '-C3', '-Cz', '-C4','-T4','-TP7',...
                                    '-CP3', '-CPz', '-CP4','-TP8','-A1', '-T5', '-Pz',...
                                    '-T6','-A2', '-O1', '-Oz', '-O2'};
end                                                               % This will select F3 F4 P3 P4 for EEG
                                                                  % X1 X2 X3 X4 for EMG
                                                                  % X5 X6 X7 X8 for EOG
if ~isfield(cfg, 'foilim'),         cfg.foilim = [0.1 100];   end
if ~isfield(cfg, 'bufferdata'),     cfg.bufferdata='last';   end

% translate dataset into datafile+headerfile
cfg = ft_checkconfig(cfg, 'dataset2files', 'yes');
cfg = ft_checkconfig(cfg, 'required', {'datafile' 'headerfile'});

% ensure that the persistent variables related to caching are cleared
clear ft_read_header

% start by reading the header from the realtime buffer
hdr = ft_read_header(cfg.headerfile, 'cache', true);

% define a subset of channels for reading
lab=['X1 '; 'X2 '; 'Fp1'; 'Fp2'; 'X3 '; 'X4 '; 'F7 '; 'F3 '; 'Fz '; 'F4 ';...
    'F8 ';'FT7'; 'FC3'; 'FCz'; 'FC4'; 'FT8'; 'T3 '; 'C3 '; 'Cz '; 'C4 ';...
    'T4 ';'TP7'; 'CP3'; 'CPz'; 'CP4'; 'TP8'; 'A1 '; 'T5 '; 'P3 '; 'Pz ';...
    'P4 '; 'T6 ';'A2 '; 'O1 '; 'Oz '; 'O2 '; 'X5 '; 'X6 '; 'X7 '; 'X8 '];
label=cellstr(lab);
cfg.channel = ft_channelselection(cfg.channel, label);
chanindx    = match_str(label, cfg.channel);
nchan       = length(chanindx);
if nchan==0
  error('no channels were selected');
end

% determine the size of blocks to process
blocksize = cfg.blocksize * hdr.Fs;
overlap   = cfg.overlap * hdr.Fs;
prevSample  = 0;
count       = 0;

% Create arrays that contains the rhos found
vectordim = 360;         % vector dimention for the lasts 3 minutes of data
vl=zeros(vectordim,1);  % the visual vector of data for left synchrony
vr=zeros(vectordim,1);  % the visual vector of data for right synchrony
vl1=vl(1);              % the first element of the vector for the visual feedback
vr1=vr(1);              % the first element of the vector for the visual feedback

% This is the ratio above which accept the coherence
meanl = baselinel;           % It has to be calculated from the baseline
meanr = baseliner;           % It has to be calculated from the baseline

% This is the mean above which no EMG feedback has given
meanf = baselinef+(stf*2);             % It has to be calculated from the baseline
meann = baselinen+(stn*2);             % It has to be calculated from the baseline

% This is used to plot the feedback step
fullscreen = get(0,'ScreenSize');
fig1 = figure('NumberTitle','off', ...
    'MenuBar','none', ...
    'Units','pixels', ...
    'Position',[0 0 fullscreen(3) fullscreen(4)]);

% plot the feedback on the second monitor
% set(gcf,'position',[1025,1,1024,768]);

% fig2=figure;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% this is the general BCI loop where realtime incoming data is handled
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while true

    % Create a matrix that contains the rhos found
    M = [vl vr]; %#ok`<NASGU>`

    % Create a matrix for the visual feedback
    K = [vl1 vr1];

    % determine number of samples available in buffer
    hdr = ft_read_header(cfg.headerfile, 'cache', true);

    % see whether new samples are available
    newsamples = (hdr.nSamples*hdr.nTrials-prevSample);

    if newsamples>=blocksize

        % determine the samples to process
        if strcmp(cfg.bufferdata, 'last') && count==0
            begsample  = hdr.nSamples*hdr.nTrials - blocksize + 1;
            endsample  = hdr.nSamples*hdr.nTrials;
        elseif strcmp(cfg.bufferdata, 'last')
          begsample  = prevSample+1;
          endsample  = prevSample+blocksize ;
        elseif strcmp(cfg.bufferdata, 'first')
          begsample  = prevSample+1;
          endsample  = prevSample+blocksize ;
        else
            error('unsupported value for cfg.bufferdata');
        end

        % this allows overlapping data segments
        if overlap && (begsample>overlap) %#ok`<BDLGI>`
          begsample = begsample - overlap;
          endsample = endsample - overlap;
        end

        % remember up to where the data was read
        prevSample  = endsample;
        count       = count + 1;
        % fprintf('processing segment %d from sample %d to %d\n', count, begsample, endsample);

        % read data segment from buffer
        dat = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', begsample,...
            'endsample', endsample, 'chanindx', chanindx, 'checkboundary', false);

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % from here onward it is specific to the hilbert phase sinchronisation from the data %
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        % put the data in a fieldtrip-like raw structure
        data.trial{1} = dat;
        data.time{1}  = offset2time(begsample, hdr.Fs, endsample-begsample+1);
        data.label    = hdr.label(chanindx);
        data.hdr      = hdr;
        data.fsample  = hdr.Fs;

        % correction of EOG based on algoritm fro
        % Author: German Gomez-Herrero
        %         german.gomezherrero@ieee.org
        %         http://www.cs.tut.fi/~gomezher/index.htm
        %         Institute of Signal Processing
        %         Tampere University of Technology, 2007
        % Reference
        % [1] P. He et al., Med. Biol. Comput. 42 (2004), 407-412
        % [2] S. Haykin. Adaptive Filter Theory, (1996), Prentice Hall

        data.trial{2}(9,:)=data.trial{1}(9,:)-data.trial{1}(10,:);
        data.trial{2}(11,:)=data.trial{1}(11,:)-data.trial{1}(12,:);
        opt.refdata=[data.trial{2}(9,:);data.trial{2}(11,:)];
        [data.trial{3}] = crls_regression(data.trial{1}(5:8,:), opt);

        % Build a FIR filter for EMG correction
        N    = 150;      % Order
        gammaband = [35 45];
        emgband = [60 80];
        emgfnband = [60 499];
        flag = 'scale';  % Sampling Flag
        Beta = 0.9;      % Window Parameter
        win = kaiser(N+1, Beta);

        % Correction between EMG and EEG based on Sheer D.E. "Biofeedback training
        % of 40-Hz eeg and behavior", pp. 325-362, on Behavior and
        % brain electrical activity (1975), Plenum Press. New York

        gammafilter  = fir1(N, gammaband/(hdr.Fs/2), 'bandpass', win, flag);
        datfiltgamma1 = filtfilt(gammafilter,1,data.trial{1}(5,:));
        datfiltgamma2 = filtfilt(gammafilter,1,data.trial{1}(6,:));
        datfiltgamma3 = filtfilt(gammafilter,1,data.trial{1}(7,:));
        datfiltgamma4 = filtfilt(gammafilter,1,data.trial{1}(8,:));
        datfiltgamma = [datfiltgamma1; datfiltgamma2; datfiltgamma3; datfiltgamma4];

        emgfilter = fir1(N, emgband/(hdr.Fs/2), 'bandpass', win, flag);
        datfiltemg1 = filtfilt(emgfilter,1,data.trial{1}(5,:));
        datfiltemg2 = filtfilt(emgfilter,1,data.trial{1}(6,:));
        datfiltemg3 = filtfilt(emgfilter,1,data.trial{1}(7,:));
        datfiltemg4 = filtfilt(emgfilter,1,data.trial{1}(8,:));
        datfiltemg = [datfiltemg1; datfiltemg2; datfiltemg3; datfiltemg4];

        datfiltemgsqr = datfiltemg.^2;
        datfiltgammasqr = datfiltgamma.^2;
        datfiltcrossqr = (datfiltemg.*datfiltgamma).^2;

        correction = datfiltgammasqr-(datfiltcrossqr./datfiltemgsqr);

        data.trial{3}(5:8,:) = datfiltgamma - correction;

        % Find the EMG on forehead and neck
        data.trial{2}(1,:)=data.trial{1}(1,:)-data.trial{1}(2,:);   % Frontal electrods
        data.trial{2}(3,:)=data.trial{1}(3,:)-data.trial{1}(4,:);   % Neck electrods
        emgfnfilter = fir1(N, emgfnband/(hdr.Fs/2), 'bandpass', win, flag);
        datfiltemgf = filter(emgfnfilter,1,data.trial{2}(1,:));
        datfiltemgn = filter(emgfnfilter,1,data.trial{2}(3,:));
        datfiltemgf = abs(datfiltemgf);
        datfiltemgn = abs(datfiltemgn);
        extrMaxValuef = datfiltemgf(find(diff(sign(diff(datfiltemgf)))==-2)+1);
        extrMaxValuen = datfiltemgn(find(diff(sign(diff(datfiltemgn)))==-2)+1);
        extrMaxIndexf =   find(diff(sign(diff(datfiltemgf)))==-2)+1;
        extrMaxIndexn =   find(diff(sign(diff(datfiltemgn)))==-2)+1;
        upf = extrMaxValuef;
        upn = extrMaxValuen;
        upf_t = data.time{1}(extrMaxIndexf);
        upn_t = data.time{1}(extrMaxIndexn);
        upf = interp1(upf_t,upf,data.time{1},'linear');
        upn = interp1(upn_t,upn,data.time{1},'linear');
        emgfmean = nanmean (upf'); %#ok`<UDIM>`
        emgnmean = nanmean (upn'); %#ok`<UDIM>`
        % plot(data.time{1},upf,'r')

%
        % Istantaneous (proto)phase difference found via Hilbert
        % Based on Pikovsky, A. R. (2001). Synchronization. A Universal
        % Concept In Nonlinear Sciences. Cambridge: Cambridge University
        % Press, pag. 368 A2.7

        % crate the data needed for phase coherence index
        chan1=data.trial{3}(5,:); % F3
        chan2=data.trial{3}(6,:); % F4
        chan3=data.trial{3}(7,:); % P3
        chan4=data.trial{3}(8,:); % P4
        chan1h = hilbert(chan1);
        chan2h = hilbert(chan2);
        chan3h = hilbert(chan3);
        chan4h = hilbert(chan4);
        chan1hi = imag(chan1h);
        chan2hi = imag(chan2h);
        chan3hi = imag(chan3h);
        chan4hi = imag(chan4h);

        % find the istantaneous left hemisphere (proto)phase difference
        phil = atan2(((chan1hi .* chan3)-(chan1 .* chan3hi)),...
                     ((chan1 .* chan3)+(chan1hi .* chan3hi)));

        % find the istantaneous right hemisphere (proto)phase difference
        phir = atan2(((chan2hi .* chan4)-(chan2 .* chan4hi)),...
                     ((chan2 .* chan4)+(chan2hi .* chan4hi)));

        % find the right hemisphere synchronization index
        sumsinr = sum(sin(phir))/blocksize;
        sumcosr = sum(cos(phir))/blocksize;
        rhor = sqrt(sumsinr.^2 + sumcosr.^2);

        % find the left hemisphere synchronization index
        sumsinl = sum(sin(phil))/blocksize;
        sumcosl = sum(cos(phil))/blocksize;
        rhol = sqrt(sumsinl.^2 + sumcosl.^2);

        % Give the visual feedback
        if (meanf>emgfmean) && (meann>emgnmean)
            clf;
            visual = bar3(K,0.3);
            view([-90 0]);
            grid off;
            shading interp;
            for i = 1:length(visual)
                zdata = get(visual(i),'Zdata');
                set(visual(i),'Cdata',zdata,'EdgeColor','none')
                colormap hot;
            end
            set(gca,'ZColor',[0.8 0.8 0.8],'Zlim',[-1 1],'YColor',[0.8 0.8 0.8],...
                'Ylim',[0 3],'XColor',[0.8 0.8 0.8],'Xlim',[0.85 1.15],...
                'Color',[0.8 0.8 0.8],'CLim', [-1 1]);

            % Create colorbar
            colorbar([0.5 0.148 0.02 0.73],'ZColor',[0.8 0.8 0.8],'YTick',[],...
                'YColor',[0.8 0.8 0.8],'XColor',[0.8 0.8 0.8]);

            % Create textboxes
            annotation('textbox',[0.496 0.89 0.03 0.04],'String',{'+'},...
                'HorizontalAlignment','center','FontSize',20,'FitBoxToText','off','EdgeColor','none');
            annotation('textbox',[0.50 0.11 0.02 0.04],'String',{'-'},...
                'HorizontalAlignment','center','FontSize',20,'FitBoxToText','off','EdgeColor','none');
            annotation('textbox',[0.25 0.49 0.05 0.07],'String',{'Emisfero','sinistro'},...
                'HorizontalAlignment','center','FontSize',14,'FitBoxToText','off','EdgeColor','none');
            annotation('textbox',[0.735 0.49 0.05 0.07],'String',{'Emisfero','destro'},...
                'HorizontalAlignment','center','FontSize',14,'FitBoxToText','off','EdgeColor','none');

            %create a copy of the plot for the experimenter
            % h1=gcf;
            % h2=figure;
            % objects=allchild(h1);
            % fig2=copyobj(get(h1,'children'),h2);

            % force MATLAB to update the figure
            drawnow ;

            % add the step to the array for the feedback and upgrade the M
            % for the final performance plot

            vl = vl([end 1:end-1]);
            vl(1)=rhol-meanl;
            vl1=vl(1);

            vr = vr([end 1:end-1]);
            vr(1)=rhor-meanr;
            vr1=vr(1);

        elseif  emgfmean>meanf
            clf;
            set(gca,'ZColor',[0.8 0.8 0.8],'Zlim',[0 1],'YColor',[0.8 0.8 0.8],...
                'Ylim',[0 3],'XColor',[0.8 0.8 0.8],'Xlim',[0.85 1.15],...
                'OuterPosition', [-0.0175 0.185 1 0.605],...
                'Color',[0.8 0.8 0.8],'CLim', [-50 50]);
            annotation(fig1,'textbox',[0.20 0.35 0.6292 0.1929],...
                'String',{'Rilassa i muscoli della fronte'},...
                'HorizontalAlignment','center','FontSize',20,'FitBoxToText','off','EdgeColor','none',...
                'Color',[1 0 0]);
            drawnow ;

        elseif  emgnmean>meann
            clf;
            set(gca,'ZColor',[0.8 0.8 0.8],'Zlim',[0 1],'YColor',[0.8 0.8 0.8],...
                'Ylim',[0 3],'XColor',[0.8 0.8 0.8],'Xlim',[0.85 1.15],...
                'OuterPosition', [-0.0175 0.185 1 0.605],...
                'Color',[0.8 0.8 0.8],'CLim', [-1 1]);
            annotation(fig1,'textbox',[0.20 0.35 0.6292 0.1929],...
                'String',{'Rilassa i muscoli del collo'},...
                'HorizontalAlignment','center','FontSize',20,'FitBoxToText','off','EdgeColor','none',...
                'Color',[1 0 0]);
            drawnow ;

        end % end feedbacks

    end % if enough new samples

    if count > vectordim
        cd 'C:\TEST\hilbert\risultati';
        save (trialdata);
        save hilbert.mat;
        close all hidden;
        cd 'C:\TEST';
        break;
    end

end % while true

%% # MATLAB code for ft_realtime_baseline
%
function ft_realtime_baseline()

% FT_REALTIME_BASELINE is a neurofeedback application based on Hilbert phase estimation.
%
% Use as
%   ft_realtime_baseline()
% with the following configuration options that are coded inside the function
%   cfg.channel    = cell-array, see FT_CHANNELSELECTION (default = 'gui')
%   cfg.foilim     = [Flow Fhigh] (default = [0 120])
%   cfg.blocksize  = number, size of the blocks/chuncks that are processed (default = 1 second)
%   cfg.bufferdata = whether to start on the 'first or 'last' data that is available (default = 'first')
%
% The source of the data is configured as
%   cfg.dataset       = string
% or alternatively to obtain more low-level control as
%   cfg.datafile      = string ( es:  cfg.datafile='buffer://localhost:1972';)
%   cfg.headerfile    = string ( es:  cfg.headerfile='buffer://localhost:1972';)
%   cfg.filename      = string ( es:  cfg.filename = 'buffer://localhost:1972';)
%   cfg.eventfile     = string ( es:  cfg.eventfile = 'buffer://localhost:1972';)
%   cfg.dataformat    = string, default is determined automatic
%   cfg.headerformat  = string, default is determined automatic
%   cfg.eventformat   = string, default is determined automatic
%
% To stop the realtime function, you have to press Ctrl-C

%Take off the warning message to avoid problems with ATAN2 and hilbert.
warning off all;

cfg = [];
cfg.datafile = 'buffer://localhost:1972';
cfg.headerfile = 'buffer://localhost:1972';
cfg.filename = 'buffer://localhost:1972';

% set the default configuration options
if ~isfield(cfg, 'dataformat'),     cfg.dataformat = [];      end % default is detected automatically
if ~isfield(cfg, 'headerformat'),   cfg.headerformat = [];    end % default is detected automatically
if ~isfield(cfg, 'eventformat'),    cfg.eventformat = [];     end % default is detected automatically
if ~isfield(cfg, 'blocksize'),      cfg.blocksize = 1;        end % in seconds
if ~isfield(cfg, 'overlap'),        cfg.overlap = 0.5;        end % in seconds
if ~isfield(cfg, 'channel'),        cfg.channel = {'all', '-Fp1', '-Fp2',...
                                    '-F7','-Fz','-F8','-FT7', '-FC3', '-FCz',...
                                    '-FC4', '-FT8', '-T3', '-C3', '-Cz', '-C4','-T4','-TP7',...
                                    '-CP3', '-CPz', '-CP4','-TP8','-A1', '-T5', '-Pz',...
                                    '-T6','-A2', '-O1', '-Oz', '-O2'};
end                                                               % This will select F3 F4 P3 P4 for EEG
                                                                  % X1 X2 X3 X4 for EMG
                                                                  % X5 X6 X7 X8 for EOG
if ~isfield(cfg, 'foilim'),         cfg.foilim = [0.1 100];   end
if ~isfield(cfg, 'bufferdata'),     cfg.bufferdata='last';   end

% translate dataset into datafile+headerfile
cfg = checkconfig(cfg, 'dataset2files', 'yes');
cfg = checkconfig(cfg, 'required', {'datafile' 'headerfile'});

% ensure that the persistent variables related to caching are cleared
clear ft_read_header

% start by reading the header from the realtime buffer
hdr = ft_read_header(cfg.headerfile, 'cache', true);

% define a subset of channels for reading
lab=['X1 '; 'X2 '; 'Fp1'; 'Fp2'; 'X3 '; 'X4 '; 'F7 '; 'F3 '; 'Fz '; 'F4 ';...
    'F8 ';'FT7'; 'FC3'; 'FCz'; 'FC4'; 'FT8'; 'T3 '; 'C3 '; 'Cz '; 'C4 ';...
    'T4 ';'TP7'; 'CP3'; 'CPz'; 'CP4'; 'TP8'; 'A1 '; 'T5 '; 'P3 '; 'Pz ';...
    'P4 '; 'T6 ';'A2 '; 'O1 '; 'Oz '; 'O2 '; 'X5 '; 'X6 '; 'X7 '; 'X8 '];
label=cellstr(lab);
cfg.channel = ft_channelselection(cfg.channel, label);
chanindx    = match_str(label, cfg.channel);
nchan       = length(chanindx);
if nchan==0
  error('no channels were selected');
end

% determine the size of blocks to process
blocksize = cfg.blocksize * hdr.Fs;
overlap   = cfg.overlap * hdr.Fs;
prevSample  = 0;
count       = 0;

% Create arrays that contains the rhos found
nummaxarray = 240; % the step is 500ms so 240 are 2 minutes
i=1;
vlmean=zeros(1,nummaxarray);
vrmean=zeros(1,nummaxarray);
frontmeans=zeros(1,nummaxarray);
neckmeans=zeros(1,nummaxarray);

% This is used to plot the screen for the subject
fullscreen = get(0,'ScreenSize');
fig1 = figure('NumberTitle','off', ...
    'MenuBar','none', ...
    'Units','pixels', ...
    'Position',[0 0 fullscreen(3) fullscreen(4)]);

% plot the feedback on the second monitor
% set(gcf,'position',[1025,1,1024,768]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% this is the general BCI loop where realtime incoming data is handled
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while true

    % determine number of samples available in buffer
    hdr = ft_read_header(cfg.headerfile, 'cache', true);

    % see whether new samples are available
    newsamples = (hdr.nSamples*hdr.nTrials-prevSample);

    if newsamples>=blocksize

        % determine the samples to process
        if strcmp(cfg.bufferdata, 'last') && count==0
            begsample  = hdr.nSamples*hdr.nTrials - blocksize + 1;
            endsample  = hdr.nSamples*hdr.nTrials;
        elseif strcmp(cfg.bufferdata, 'last')
          begsample  = prevSample+1;
          endsample  = prevSample+blocksize ;
        elseif strcmp(cfg.bufferdata, 'first')
          begsample  = prevSample+1;
          endsample  = prevSample+blocksize ;
        else
            error('unsupported value for cfg.bufferdata');
        end

        % this allows overlapping data segments
        if overlap && (begsample>overlap) %#ok`<BDLGI>`
          begsample = begsample - overlap;
          endsample = endsample - overlap;
        end

        % remember up to where the data was read
        prevSample  = endsample;
        count       = count + 1;
        % fprintf('processing segment %d from sample %d to %d\n', count, begsample, endsample);

        % read data segment from buffer
        dat = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', begsample, 'endsample', endsample, 'chanindx', chanindx, 'checkboundary', false);

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % from here onward it is specific to the hilbert phase sinchronisation from the data %
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        % put the data in a fieldtrip-like raw structure
        data.trial{1} = dat;
        data.time{1}  = offset2time(begsample, hdr.Fs, endsample-begsample+1);
        data.label    = hdr.label(chanindx);
        data.hdr      = hdr;
        data.fsample  = hdr.Fs;

        % correction of EOG based on algoritm fro
        % Author: German Gomez-Herrero
        %         german.gomezherrero@ieee.org
        %         http://www.cs.tut.fi/~gomezher/index.htm
        %         Institute of Signal Processing
        %         Tampere University of Technology, 2007
        % Reference
        % [1] P. He et al., Med. Biol. Comput. 42 (2004), 407-412
        % [2] S. Haykin. Adaptive Filter Theory, (1996), Prentice Hall

        data.trial{2}(9,:)=data.trial{1}(9,:)-data.trial{1}(10,:);
        data.trial{2}(11,:)=data.trial{1}(11,:)-data.trial{1}(12,:);
        opt.refdata=[data.trial{2}(9,:);data.trial{2}(11,:)];
        [data.trial{3}] = crls_regression(data.trial{1}(5:8,:), opt);

        % Build a FIR filter for EMG correction
        N    = 150;      % Order
        gammaband = [35 45];
        emgband = [60 80];
        emgfnband = [60 499];
        flag = 'scale';  % Sampling Flag
        Beta = 0.9;      % Window Parameter
        win = kaiser(N+1, Beta);

        % Correction between EMG and EEG based on Sheer D.E. "Biofeedback training
        % of 40-Hz eeg and behavior", pp. 325-362, on Behavior and
        % brain electrical activity (1975), Plenum Press. New York

        gammafilter  = fir1(N, gammaband/(hdr.Fs/2), 'bandpass', win, flag);
        datfiltgamma1 = filtfilt(gammafilter,1,data.trial{1}(5,:));
        datfiltgamma2 = filtfilt(gammafilter,1,data.trial{1}(6,:));
        datfiltgamma3 = filtfilt(gammafilter,1,data.trial{1}(7,:));
        datfiltgamma4 = filtfilt(gammafilter,1,data.trial{1}(8,:));
        datfiltgamma = [datfiltgamma1; datfiltgamma2; datfiltgamma3; datfiltgamma4];

        emgfilter = fir1(N, emgband/(hdr.Fs/2), 'bandpass', win, flag);
        datfiltemg1 = filtfilt(emgfilter,1,data.trial{1}(5,:));
        datfiltemg2 = filtfilt(emgfilter,1,data.trial{1}(6,:));
        datfiltemg3 = filtfilt(emgfilter,1,data.trial{1}(7,:));
        datfiltemg4 = filtfilt(emgfilter,1,data.trial{1}(8,:));
        datfiltemg = [datfiltemg1; datfiltemg2; datfiltemg3; datfiltemg4];

        datfiltemgsqr = datfiltemg.^2;
        datfiltgammasqr = datfiltgamma.^2;
        datfiltcrossqr = (datfiltemg.*datfiltgamma).^2;

        correction = datfiltgammasqr-(datfiltcrossqr./datfiltemgsqr);

        data.trial{3}(5:8,:) = datfiltgamma - correction;

        % Find the EMG on forehead and neck
        data.trial{2}(1,:)=data.trial{1}(1,:)-data.trial{1}(2,:);   % Frontal electrods
        data.trial{2}(3,:)=data.trial{1}(3,:)-data.trial{1}(4,:);   % Neck electrods
        emgfnfilter = fir1(N, emgfnband/(hdr.Fs/2), 'bandpass', win, flag);
        datfiltemgf = filter(emgfnfilter,1,data.trial{2}(1,:));
        datfiltemgn = filter(emgfnfilter,1,data.trial{2}(3,:));
        datfiltemgf = abs(datfiltemgf);
        datfiltemgn = abs(datfiltemgn);
        extrMaxValuef = datfiltemgf(find(diff(sign(diff(datfiltemgf)))==-2)+1);
        extrMaxValuen = datfiltemgn(find(diff(sign(diff(datfiltemgn)))==-2)+1);
        extrMaxIndexf =   find(diff(sign(diff(datfiltemgf)))==-2)+1;
        extrMaxIndexn =   find(diff(sign(diff(datfiltemgn)))==-2)+1;
        upf = extrMaxValuef;
        upn = extrMaxValuen;
        upf_t = data.time{1}(extrMaxIndexf);
        upn_t = data.time{1}(extrMaxIndexn);
        upf = interp1(upf_t,upf,data.time{1},'linear');
        upn = interp1(upn_t,upn,data.time{1},'linear');
        emgfmean = nanmean (upf'); %#ok`<UDIM>`
        emgnmean = nanmean (upn'); %#ok`<UDIM>`
        % plot(data.time{1},upf,'r')

%
        % Istantaneous (proto)phase difference found via Hilbert
        % Based on Pikovsky, A. R. (2001). Synchronization. A Universal
        % Concept In Nonlinear Sciences. Cambridge: Cambridge University
        % Press, pag. 368 A2.7

        % crate the data needed for phase coherence index
        chan1=data.trial{3}(5,:); % F3
        chan2=data.trial{3}(6,:); % F4
        chan3=data.trial{3}(7,:); % P3
        chan4=data.trial{3}(8,:); % P4
        chan1h = hilbert(chan1);
        chan2h = hilbert(chan2);
        chan3h = hilbert(chan3);
        chan4h = hilbert(chan4);
        chan1hi = imag(chan1h);
        chan2hi = imag(chan2h);
        chan3hi = imag(chan3h);
        chan4hi = imag(chan4h);

        % find the istantaneous left hemisphere (proto)phase difference
        phil = atan2(((chan1hi .* chan3)-(chan1 .* chan3hi)),...
                     ((chan1 .* chan3)+(chan1hi .* chan3hi)));

        % find the istantaneous right hemisphere (proto)phase difference
        phir = atan2(((chan2hi .* chan4)-(chan2 .* chan4hi)),...
                     ((chan2 .* chan4)+(chan2hi .* chan4hi)));

        % find the right hemisphere synchronization index
        sumsinr = sum(sin(phir))/blocksize;
        sumcosr = sum(cos(phir))/blocksize;
        rhor = sqrt(sumsinr.^2 + sumcosr.^2);

        % find the left hemisphere synchronization index
        sumsinl = sum(sin(phil))/blocksize;
        sumcosl = sum(cos(phil))/blocksize;
        rhol = sqrt(sumsinl.^2 + sumcosl.^2);

        % update the array for the mean
        vlmean(i)=rhol;
        vrmean(i)=rhor;
        frontmeans(i)=emgfmean;
        neckmeans(i)=emgnmean;

        i=i+1;

    end % if enough new samples

    % screen for the subject
    clf;
    set(gca,'ZColor',[0.8 0.8 0.8],'Zlim',[-50 50],'YColor',[0.8 0.8 0.8],...
        'Ylim',[0 3],'XColor',[0.8 0.8 0.8],'Xlim',[0.85 1.15],...
        'DataAspectRatio',[0.2 0.1 3],'OuterPosition', [-0.0175 0.185 1 0.605],...
        'Color',[0.8 0.8 0.8],'CLim', [-50 50]);
    annotation(fig1,'textbox',[0.18 0.35 0.6292 0.1929],...
        'String',{'Rilassati mantenendo gli occhi aperti'},...
        'HorizontalAlignment','center','FontSize',20,'FitBoxToText','off','EdgeColor','none',...
        'Color',[1 0 0]);
    drawnow ;

    if count > (nummaxarray-1)
        close all hidden;
        break;
    end

end % while true

% print the mean baseline
baselinel = mean (vlmean);
fprintf ('mean baseline left= %d \n', baselinel);
baseliner = mean (vrmean);
fprintf ('mean baseline right= %d \n', baseliner);
baselinef = mean (frontmeans);
fprintf ('mean baseline forehead= %d \n', baselinef);
baselinen = mean (neckmeans);
fprintf ('mean baseline neck= %d \n', baselinen);
stf = std(frontmeans);
fprintf ('Std baseline front= %d \n', stf);
stn = std(neckmeans);
fprintf ('Std baseline neck= %d \n', stn);

save means.mat;   % save to the working folder - (edit jonaweber 2010)


function data = prepare_batch_feat_input_data(pooler, feature_paths, windows, data_param)
num_windows   = size(windows,1);
feat_dim      = data_param.feat_dim;
data          = zeros(feat_dim, num_windows, 'single');
num_threads   = 6;

if isfield(data_param, 'num_threads') && data_param.num_threads > 0
    num_threads = data_param.num_threads;
end

select_img_idx  = unique(windows(:,1));
num_sel_img     = length(select_img_idx);
feature_paths   = feature_paths(select_img_idx);
window_this_img = cell(num_sel_img, 1);
img_window_map  = cell(num_sel_img, 1);
for i = 1:num_sel_img
    indices = find(windows(:,1) == select_img_idx(i));
    window_this_img{i} = windows(indices, :);
    img_window_map{i}  = indices(:);
end
assert(sum(cellfun(@(x) size(x, 1), window_this_img, 'UniformOutput', true)) == num_windows);
assert(sum(cellfun(@(x) size(x, 1), img_window_map, 'UniformOutput', true)) == num_windows);

random_scale = data_param.random_scale;

num_blocks   = 3;
block_size   = ceil(num_sel_img / num_blocks);
for b = 1:num_blocks
    start_idx       = (b-1) * block_size + 1;
    stop_idx        = min(b*block_size,num_sel_img);
    this_block_size = stop_idx - start_idx + 1;

    block_sel_img_idx     = select_img_idx(start_idx:stop_idx);
    block_window_this_img = window_this_img(start_idx:stop_idx);
    block_feature_paths   = feature_paths(start_idx:stop_idx);

    block_feats    = cell(1,this_block_size);
    block_data_map = cell2mat(img_window_map(start_idx:stop_idx));

    assert(all(block_data_map > 0 & block_data_map <= num_windows));
    assert(length(unique(block_data_map)) == length(block_data_map));
    if num_threads == 1
        for i = 1:this_block_size
            assert(all(block_window_this_img{i}(:,1) == block_sel_img_idx(i)));
            %feat_cache = load(block_feature_paths{i}, 'feat');
            feat_cache  = read_feat_conv_data( block_feature_paths{i}, true );
            block_feats{i} = cell2mat(convFeat_to_poolFeat_multi_region(pooler, ...
                feat_cache.feat, block_window_this_img{i}(:, 4:7), random_scale));
        end
    else
        parfor (i = 1:this_block_size,num_threads)
            assert(all(block_window_this_img{i}(:,1) == block_sel_img_idx(i)));
            feat_cache  = read_feat_conv_data( block_feature_paths{i}, true );
            block_feats{i} = cell2mat(convFeat_to_poolFeat_multi_region(pooler, ...
                feat_cache.feat, block_window_this_img{i}(:, 4:7), random_scale));
        end
    end
    data(:,block_data_map) = cell2mat(block_feats);
    for i = 1:this_block_size, block_feats{i} = []; end
end
end


function [C,OutputFiles] = cifti(obj)
% Extract CIFTI-2 extension from a NIfTI-2 file and export data
%__________________________________________________________________________
% Copyright (C) 2019 Wellcome Trust Centre for Neuroimaging

C = [];
OutputFiles = {};

%-Check input is a CIFTI file
%--------------------------------------------------------------------------
if ~isfield(obj.hdr,'ext') || isempty(obj.hdr.ext) || obj.hdr.ext.ecode ~= 32
    return;
end

%-Parse CIFTI extension
%--------------------------------------------------------------------------
C.xml = char(obj.hdr.ext.edata(:)');
C.hdr = convert(xmltree(C.xml),[],'attributes',true);
s     = size(obj.dat); s = s(5:end);
C.dat = reshape(obj.dat,s);

%-Check input is a CIFTI-2 file
%--------------------------------------------------------------------------
switch C.hdr.attributes.Version
    case {'2'}
        % noop
    case {'1','1.0'}
        warning('CIFTI-1 file not supported.');
        return;
    otherwise
        warning('Unknown CIFTI version: %s.',C.hdr.attributes.Version);
        return;
end

%-Standard CIFTI Mapping Combinations
%==========================================================================

%-Dense Scalar (.dscalar.nii) or Dense Data Series (.dtseries.nii)
%--------------------------------------------------------------------------
if ismember(obj.hdr.intent_code,[3002, 3006]) % CONNECTIVITY_DENSE_SCALARS
                                              % CONNECTIVITY_DENSE_SERIES
    MapNames = {};
    Surfaces = {};
    Volumes  = {};
    vol      = struct;

    %-Read mapping information for each dimension
    %----------------------------------------------------------------------
    for i=1:numel(C.hdr.Matrix.MatrixIndicesMap)
        map = C.hdr.Matrix.MatrixIndicesMap{i};
        switch map.attributes.AppliesToMatrixDimension
            case '0'
                switch map.attributes.IndicesMapToDataType
                    case 'CIFTI_INDEX_TYPE_SCALARS'
                        MapNames = map.NamedMap;
                        if isstruct(MapNames), MapNames = {MapNames}; end
                        MapNames = cellfun(@(x) x.MapName,MapNames,'UniformOutput',false);
                    case 'CIFTI_INDEX_TYPE_SERIES'
                        MapNames = str2double(map.attributes.NumberOfSeriesPoints);
                        MapNames = arrayfun(@(x) sprintf('%04d',x),1:MapNames,'UniformOutput',false);
                    otherwise
                        error('Mismatch between NIfTI intent code and CIFTI index type.');
                end
            case '1'
                if ~strcmp(map.attributes.IndicesMapToDataType,'CIFTI_INDEX_TYPE_BRAIN_MODELS')
                    error('Mismatch between NIfTI intent code and CIFTI index type.');
                end
                if isstruct(map.BrainModel), map.BrainModel = {map.BrainModel}; end
                for j=1:numel(map.BrainModel)
                    switch map.BrainModel{j}.attributes.ModelType
                        case 'CIFTI_MODEL_TYPE_SURFACE'
                            nV  = str2double(map.BrainModel{j}.attributes.SurfaceNumberOfVertices);
                            off = str2double(map.BrainModel{j}.attributes.IndexOffset);
                            iV  = str2num(map.BrainModel{j}.VertexIndices) + 1;
                            if numel(iV) ~= str2double(map.BrainModel{j}.attributes.IndexCount)
                                error('Problem with number of vertices.');
                            end
                            BrainStructure = map.BrainModel{j}.attributes.BrainStructure(17:end);
                            Surfaces{end+1} = struct('nV',nV,'off',off,'iV',iV,'brain',BrainStructure);
                        case 'CIFTI_MODEL_TYPE_VOXELS'
                            off = str2double(map.BrainModel{j}.attributes.IndexOffset);
                            BrainStructure = map.BrainModel{j}.attributes.BrainStructure(17:end);
                            iV  = str2num(map.BrainModel{j}.VoxelIndicesIJK) + 1;
                            iV  = reshape(iV,3,[]);
                            if size(iV,2) ~= str2double(map.BrainModel{j}.attributes.IndexCount)
                                error('Problem with number of voxels.');
                            end
                            Volumes{end+1} = struct('off',off,'iV',iV,'brain',BrainStructure);
                    end
                end
                if ~isempty(Volumes)
                    vol.dim = str2num(map.Volume.attributes.VolumeDimensions);
                    vol.mat = str2num(map.Volume.TransformationMatrixVoxelIndicesIJKtoXYZ);
                    vol.mat = reshape(vol.mat,[4 4])' * [eye(4,3) [-1 -1 -1 1]'];
                    % assumes MeterExponent is -3
                end
            otherwise
                error('Data have to be dense scalars or series.');
        end
    end

    %-Export as GIfTI and NIfTI
    %----------------------------------------------------------------------
    for i=1:numel(MapNames)
        for j=1:numel(Surfaces)
            D = NaN(Surfaces{j}.nV,1);
            D(Surfaces{j}.iV) = C.dat(i,Surfaces{j}.off+(1:numel(Surfaces{j}.iV)));
            g = gifti(D);
            OutputFiles{end+1} = sprintf('%s_%s.gii',MapNames{i},Surfaces{j}.brain);
            save(g,OutputFiles{end},'ExternalFileBinary');
        end
        if ~isempty(Volumes)
            OutputFiles{end+1} = sprintf('%s.nii',MapNames{i});
            N = nifti; % using subsasgn as being used within the @nifti class
            N = subsasgn(N,substruct('.','dat'),file_array(OutputFiles{end},vol.dim,'float32-le',352));
            N = subsasgn(N,substruct('.','mat'),vol.mat);
            N = subsasgn(N,substruct('.','mat0'),vol.mat);
            N = subsasgn(N,substruct('.','mat_intent'),'Aligned');
            N = subsasgn(N,substruct('.','mat0_intent'),'Aligned');
            create(N);
            dat = NaN(vol.dim);
            for j=1:numel(Volumes)
                ind = sub2ind(vol.dim,Volumes{j}.iV(1,:),Volumes{j}.iV(2,:),Volumes{j}.iV(3,:));
                dat(ind) = C.dat(i,Volumes{j}.off+(1:numel(ind)));
            end
            N.dat = subsasgn(N.dat,substruct('()',repmat({':'},1,numel(vol.dim))),dat);
        end
    end
end


tic;
doChild = true;
if(ispc)
    tdir = '\\white.stanford.edu\biac2-wandell2\data\reading_longitude\templates\';
    baseDir = '\\white.stanford.edu\biac2-wandell2\data\reading_longitude\';
else
    %tdir = '/biac2/wandell2/data/reading_longitude/templates/';
    tdir = '/silver/scr1/data/templates/';
    baseDir = '/biac2/wandell2/data/reading_longitude/';
end
if(doChild)
    baseDir = fullfile(baseDir,'dti','*0*');
    tdir = fullfile(tdir,'child_new');
    % es's data are OK now.
    %excludeList = {'es041113','tk040817'};
    excludeList = {'tk040817'};
    tBaseName = 'SIRL%02d';
else
    baseDir = fullfile(baseDir,'dti_adults','*0*');
    tdir = fullfile(tdir,'adult_new');
    excludeList = {'ah051003','gf050826','da050311','bw040806'};
    tBaseName = 'SIRL%02dadult';
end

if(isempty(mfilename)) thisfilename = 'dtiBuildAdultTemplate.m';
else  thisfilename = mfilename; end
%[files,subCodes] = findSubjects(baseDir,
%'*_dt6',{'ah051003','gf050826'});
% 2006.03.28 RFD: we now excude da050311 because the top of the
% brain is cut-off in the dti and 'bw040806' as an age outlier.
[files,subCodes] = findSubjects(baseDir, '*_dt6_noMask',excludeList);
N = length(files);

forceBuildAll = false;
useBrainMaskScales = true;
tensorInterpMethod = 1;
tBaseName = sprintf(tBaseName,N);
useBrainMask = true;
if(useBrainMaskScales) suffix{1} = '_bmms';
else suffix{1} = '_ms'; end
suffix{2} = 'warp1'; suffix{3} = 'warp2'; suffix{4} = 'warp3';
mmPerVox = [1 1 1];

if(~exist(tdir,'dir'))
    mkdir(tdir);
end

spm_defaults; global defaults; defaults.analyze.flip = 0;
params = defaults.normalise.estimate;
params.smosrc = 4;

% 1. BOOTSTRAP THE INITIAL TEMPLATE
curName = [tBaseName suffix{1}];
curTemplate = fullfile(tdir,curName);
if(forceBuildAll | ~exist([curTemplate '.img'],'file'))
    % Build the zeroth-iteration template from a simple average
    % of all the ac-pc aligned brains

    % measure brain masks to get the minimumand maximum brain extent in
    % each dimension.
    clear minAcPc maxAcPc;
    for(ii=1:N)
        fprintf(['Measuring ' subCodes{ii} ':\t']);
        d = load(files{ii},'anat');
        % find x,y limits
        tmp = sum(d.anat.brainMask,3);
        x = find(sum(tmp,1)); x = [x(1) x(end)];
        y = find(sum(tmp,2)); y = [y(1) y(end)];
        % find z limits
        tmp = squeeze(sum(d.anat.brainMask,1));
        z = find(sum(tmp,1)); z = [z(1) z(end)];
        curSizeAcPc = mrAnatXformCoords(d.anat.xformToAcPc,[y;x;z]');
        minAcPc(ii,:) = curSizeAcPc(1,:);
        maxAcPc(ii,:) = curSizeAcPc(2,:);
        fprintf('RAS = [% 3.1f % 3.1f % 3.1f] mm, LPI: [% 3.1f % 3.1f % 3.1f] mm.\n',curSizeAcPc(2,:),abs(curSizeAcPc(1,:)));
    end
    meanBrainSizeFromMask = [mean(minAcPc); mean(maxAcPc)];

    % Load all the talscales
    for(ii=[1:N])
        fprintf('Loading scale factors from %s (%d of %d)...\n',subCodes{ii}, ii, N);
        d = load(files{ii},'anat');
        sf(ii) = d.anat.talScale;
    end
    % To get the mean extent, we average the Talairach scale factors
    % and then divide Talairach's actual dimensions (in mm) by these
    % scales.
    tal = mrAnatGetTalairachDists;
    if(useBrainMaskScales)
        meanExtent.sac = abs(meanBrainSizeFromMask(2,3));
        meanExtent.iac = abs(meanBrainSizeFromMask(1,3));
        meanExtent.lac = abs(meanBrainSizeFromMask(1,1));
        meanExtent.rac = abs(meanBrainSizeFromMask(2,1));
        meanExtent.aac = abs(meanBrainSizeFromMask(2,2));
        % We still need the AC-to-PC talScale, since the brain mask doesn't
        % give us that one. But, that one is also immune to the ambiguity
        % that plagues marking the brain-edge.
        meanExtent.acpc = abs(tal.acpc)/mean([sf(:).acpc]);
        meanExtent.ppc = abs(meanBrainSizeFromMask(1,2)) - meanExtent.acpc;
    else
        meanExtent.sac = abs(tal.sac)/mean([sf(:).sac]);
        meanExtent.iac = abs(tal.iac)/mean([sf(:).iac]);
        meanExtent.lac = abs(tal.lac)/mean([sf(:).lac]);
        meanExtent.rac = abs(tal.rac)/mean([sf(:).rac]);
        meanExtent.aac = abs(tal.aac)/mean([sf(:).aac]);
        meanExtent.acpc = abs(tal.acpc)/mean([sf(:).acpc]);
        meanExtent.ppc = abs(tal.ppc)/mean([sf(:).ppc]);
    end
    for(ii=[1:N])
        if(useBrainMaskScales)
            extent(ii).sac = abs(maxAcPc(ii,3));
            extent(ii).iac = abs(minAcPc(ii,3));
            extent(ii).lac = abs(minAcPc(ii,1));
            extent(ii).rac = abs(maxAcPc(ii,1));
            extent(ii).aac = abs(maxAcPc(ii,2));
            extent(ii).acpc = abs(tal.acpc)/sf(ii).acpc;
            extent(ii).ppc = abs(minAcPc(ii,2)) - meanExtent.acpc;
        else
            extent(ii).sac = abs(tal.sac)/sf(ii).sac;
            extent(ii).iac = abs(tal.iac)/sf(ii).iac;
            extent(ii).lac = abs(tal.lac)/sf(ii).lac;
            extent(ii).rac = abs(tal.rac)/sf(ii).rac;
            extent(ii).aac = abs(tal.aac)/sf(ii).aac;
            extent(ii).acpc = abs(tal.acpc)/sf(ii).acpc;
            extent(ii).ppc = abs(tal.ppc)/sf(ii).ppc;
        end
        newScale(ii).sac = meanExtent.sac/extent(ii).sac;
        newScale(ii).iac = meanExtent.iac/extent(ii).iac;
        newScale(ii).lac = meanExtent.lac/extent(ii).lac;
        newScale(ii).rac = meanExtent.rac/extent(ii).rac;
        newScale(ii).aac = meanExtent.aac/extent(ii).aac;
        newScale(ii).acpc = meanExtent.acpc/extent(ii).acpc;
        newScale(ii).ppc = meanExtent.ppc/extent(ii).ppc;
        newScale(ii).pcReference = -meanExtent.acpc;
    end

    % Reslice using the talscale measurements.
    d = load(files{1},'anat');
    ac = round(mrAnatXformCoords(inv(d.anat.xformToAcPc),[0 0 0]));
    im = double(d.anat.img);
    im = im./max(im(:));
    im(~d.anat.brainMask) = 0;
    sz = size(im);
    % t1's from dt6 files shouldn't need histogram clipping. But we will
    % scale every brain to 0-1.
    %imSkull = mrAnatHistogramClip(double(imSkull), 0.5, 0.99);
    %proportionNonBrain = sum(~d.anat.brainMask(:))./prod(size(d.anat.brainMask));
    %im = mrAnatHistogramClip(double(im), proportionNonBrain, 0.99);
    bb = [-d.anat.mmPerVox.*(ac-1); d.anat.mmPerVox.*(sz-ac)];
    ts = newScale(1); ts.talScaleDir = 'tal2acpc';
    % warp T1 to tal space
    ts.outMat = inv(d.anat.xformToAcPc);
    [im,newXform] = mrAnatResliceSpm(im,ts,bb,mmPerVox,[7 7 7 0 0 0],0);
    im(isnan(im)) = 0;
    im(im<0) = 0; im(im>1) = 1;
    allIm = zeros([sz N]);
    allIm(:,:,:,1) = im;
    for(ii=[2:N])
        fprintf('Processing %s (%d of %d)...\n',subCodes{ii}, ii, N);
        d = load(files{ii},'anat');
        % All coords should be the same.
        ac = round(mrAnatXformCoords(inv(d.anat.xformToAcPc),[0 0 0]));
        im = double(d.anat.img);
        im = im./max(im(:));
        im(~d.anat.brainMask) = 0;
        ts = newScale(ii); ts.talScaleDir = 'tal2acpc';
        ts.outMat = inv(d.anat.xformToAcPc);
        [im,newXform] = mrAnatResliceSpm(im,ts,bb,mmPerVox,[7 7 7 0 0 0],0);
        im(isnan(im)) = 0;
        im(im<0) = 0; im(im>1) = 1;
        allIm(:,:,:,ii) = im;
    end
    % Save all the resliced brains in a temp file.
    save(fullfile(tempdir, [curName '_all.mat']), 'allIm');
    for(ii=1:N)
        allIm(:,:,:,ii) = mrAnatHistogramClipOptimal(allIm(:,:,:,ii));
    end
    meanIm = mean(allIm,4);
    figure; image(makeMontage(uint8(meanIm*255))); colormap(gray(256)); axis equal tight off;

    ax = flipdim(permute(squeeze(allIm(:,:,ac(3),:)),[2,1,3]),1);
    cr = flipdim(permute(squeeze(allIm(:,ac(2),:,:)),[2,1,3]),1);
    sg = flipdim(permute(squeeze(allIm(ac(1),:,:,:)),[2,1,3]),1);
    ax(:,:,N+1) = mean(ax(:,:,[1:N]), 3);
    cr(:,:,N+1) = mean(cr(:,:,[1:N]), 3);
    sg(:,:,N+1) = mean(sg(:,:,[1:N]), 3);
    ax = uint8(ax.*255+0.5);
    cr = uint8(cr.*255+0.5);
    sg = uint8(sg.*255+0.5);

    figure;image(makeMontage(ax));colormap(gray(256));axis equal tight off;
    figure;image(makeMontage(cr));colormap(gray(256));axis equal tight off;
    figure;image(makeMontage(sg));colormap(gray(256));axis equal tight off;

    imwrite(makeMontage(ax), gray(256), fullfile(tdir, [tBaseName '_ax.png']));
    imwrite(makeMontage(cr), gray(256), fullfile(tdir, [tBaseName '_cr.png']));
    imwrite(makeMontage(sg), gray(256), fullfile(tdir, [tBaseName '_sg.png']));

    % Now build an atlas from the mean image
    V.dat = int16(meanIm.*(2^15-1)+0.5);
    notes = [curName ': average of ' num2str(N) ' mean-Tal-scaled brains. Created at ' datestr(now,31)];
    hdr = saveAnalyze(V.dat, curTemplate, mmPerVox, notes, ac);
    save(fullfile(tdir,[curName '_details.mat']), 'meanIm','notes','extent','meanExtent','ac','mmPerVox');
else
   disp([curTemplate ' exists- skipping. (Set forceBuildAll to rebuild.)']);
end

% 2. BUILD THE INTERMEDIATE TEMPLATE BY WARPING TO THE INITIAL TEMPLATE
prevTemplate = curTemplate;
curName = [tBaseName suffix{2}];
curTemplate = fullfile(tdir,curName);
if(forceBuildAll | ~exist([curTemplate '.img'],'file'))
    % Now use the mean-scaled template to generate a refined template using
    % non-linear warping.

    [im,mm,hdr] = loadAnalyze(prevTemplate);
    ac = round(mrAnatXformCoords(inv(hdr.mat),[0 0 0]));

    d = load(files{1},'anat');
    im = double(d.anat.img);
    im = im./max(im(:));
    sz = size(im);
    bb = [-d.anat.mmPerVox.*(ac-1); d.anat.mmPerVox.*(sz-ac)];
    % warp T1 to template space
    xform = d.anat.xformToAcPc;
    if(useBrainMask) im(~d.anat.brainMask) = 0; end
    sn = mrAnatComputeSpmSpatialNorm(im, xform, [prevTemplate '.img'], params);
    sn.outMat = inv(sn.VF.mat);
    [im,newXform] = mrAnatResliceSpm(im,sn,bb,mmPerVox,[7 7 7 0 0 0],0);
    im(isnan(im)) = 0;
    im(im<0) = 0; im(im>1) = 1;
    allIm = zeros([sz N]);
    allIm(:,:,:,1) = im;
    for(ii=[2:N])
        fprintf('Processing %s (%d of %d)...\n',subCodes{ii}, ii, N);
        d = load(files{ii},'anat');
        [p,f,e] = fileparts(files{ii});
        im = double(d.anat.img);
        im = im./max(im(:));
        xform = d.anat.xformToAcPc;
        if(useBrainMask) im(~d.anat.brainMask) = 0; end
        sn = mrAnatComputeSpmSpatialNorm(im, xform, [prevTemplate '.img'], params);
        sn.outMat = inv(sn.VF.mat);
        [im,newXform] = mrAnatResliceSpm(im,sn,bb,mmPerVox,[7 7 7 0 0 0],0);
        im(isnan(im)) = 0;
        im(im<0) = 0; im(im>1) = 1;
        allIm(:,:,:,ii) = im;
    end
    % Save all the resliced brains in a temp file.
    save(fullfile(tempdir, [curName '_all.mat']), 'allIm');
    for(ii=1:N)
        allIm(:,:,:,ii) = mrAnatHistogramClipOptimal(allIm(:,:,:,ii));
    end

    meanIm = mean(allIm,4);
    figure; image(makeMontage(uint8(meanIm*255)));
    colormap(gray(256)); axis equal tight off;

    ax = flipdim(permute(squeeze(allIm(:,:,ac(3),:)),[2,1,3]),1);
    cr = flipdim(permute(squeeze(allIm(:,ac(2),:,:)),[2,1,3]),1);
    sg = flipdim(permute(squeeze(allIm(ac(1),:,:,:)),[2,1,3]),1);
    ax(:,:,N+1) = mean(ax(:,:,[1:N]), 3);
    cr(:,:,N+1) = mean(cr(:,:,[1:N]), 3);
    sg(:,:,N+1) = mean(sg(:,:,[1:N]), 3);
    ax = uint8(ax.*255+0.5);
    cr = uint8(cr.*255+0.5);
    sg = uint8(sg.*255+0.5);
    figure;image(makeMontage(ax));colormap(gray(256));axis equal tight off;
    figure;image(makeMontage(cr));colormap(gray(256));axis equal tight off;
    figure;image(makeMontage(sg));colormap(gray(256));axis equal tight off;
    imwrite(makeMontage(ax), gray(256), fullfile(tdir, [tBaseName '_ax.png']));
    imwrite(makeMontage(cr), gray(256), fullfile(tdir, [tBaseName '_cr.png']));
    imwrite(makeMontage(sg), gray(256), fullfile(tdir, [tBaseName '_sg.png']));

    % Now build an atlas from the mean image
    V.dat = int16(meanIm.*(2^15-1)+0.5);
    [p,f,e]=fileparts(prevTemplate); tname = [f e];
    notes = [curName ': average of ' num2str(N) ' brains warped to ' tname '. Created at ' datestr(now,31)];
    hdr = saveAnalyze(V.dat, curTemplate, mmPerVox, notes, ac);
else
    disp([curTemplate ' exists- skipping. (Set forceBuildAll to rebuild.)']);
end

%
% 3. BUILD THE FINAL TEMPLATE BY WARPING TO THE INTERMEDIATE TEMPLATE
%
prevTemplate = curTemplate;
curName = [tBaseName];
curTemplate = fullfile(tdir,curName);
if(forceBuildAll | ~exist([curTemplate '.img'],'file'))
    outDir = fullfile(tdir, [tBaseName suffix{3}]);
    if(~exist(outDir)) mkdir(outDir); end
    for(ii=[1:N])
        fprintf('Processing %s (%d of %d)...\n',subCodes{ii}, ii, N);
        d = load(files{ii});
        im = double(d.anat.img);
        im = im./max(im(:));
        xform = d.anat.xformToAcPc;
        if(useBrainMask) im(~d.anat.brainMask) = 0; end
        sn = mrAnatComputeSpmSpatialNorm(im, xform, [prevTemplate '.img'], params);
        t1Rng = [min(d.anat.img(:)) max(d.anat.img(:))];
        b0Rng = [min(d.b0(:)) max(d.b0(:))];
        d = dtiSpmDeformer(d, sn, tensorInterpMethod, mmPerVox);
        d.anat.img(d.anat.img<t1Rng(1)) = t1Rng(1);
        d.anat.img(d.anat.img>t1Rng(2)) = t1Rng(2);
        d.anat.img = int16(d.anat.img+0.5);
        d.b0(d.b0<b0Rng(1)) = b0Rng(1);
        d.b0(d.b0>b0Rng(2)) = b0Rng(2);
        d.b0 = int16(d.b0+0.5);
        newFileName = fullfile(outDir, [subCodes{ii} '_sn']);
        disp(['Saving to ' newFileName '...']);
        dtiSaveStruct(d, newFileName);
    end

    % Now load all the warped dt6 files and build a template from them.
    snFiles = findSubjects(outDir, '*_sn*',{});
    disp(['Loading ' snFiles{1} '...']);
    dt = load(snFiles{1});
    avg = dt;
    avg.b0 = mrAnatHistogramClip(double(avg.b0),0.5,0.99);
    avg.anat.img = mrAnatHistogramClip(double(avg.anat.img),0.5,0.99);
    if(isfield(avg.anat,'brainMask'))
        avg.anat.brainMask = double(avg.anat.brainMask);
    end
    Nb0 = double(avg.b0>0);
    Nt1 = double(avg.anat.img>0);
    for(ii=2:length(snFiles))
        disp(['Loading ' snFiles{ii} '...']);
        dt = load(snFiles{ii});
        dt.dt6(isnan(dt.dt6)) = 0;
        b0 = mrAnatHistogramClip(double(dt.b0),0.4,0.99);
        b0(isnan(b0)) = 0;
        avg.b0 = avg.b0+b0;
        avg.dt6 = avg.dt6+dt.dt6;
        t1 = mrAnatHistogramClip(double(dt.anat.img),0.4,0.99);
        t1(isnan(t1)) = 0;
        avg.anat.img = avg.anat.img+t1;
        if(isfield(avg.anat,'brainMask') && isfield(dt.anat,'brainMask'))
            avg.anat.brainMask = avg.anat.brainMask+double(dt.anat.brainMask);
        end
        Nb0 = Nb0+double(b0>0);
        Nt1 = Nt1+double(t1>0);
    end
    avg.b0(Nb0>0) = avg.b0(Nb0>0)./Nb0(Nb0>0);
    for(ii=1:6)
        tmp = avg.dt6(:,:,:,ii);
        tmp(Nb0>0) = tmp(Nb0>0)./Nb0(Nb0>0);
        avg.dt6(:,:,:,ii) = tmp;
    end
    avg.anat.img(Nt1>0) = avg.anat.img(Nt1>0)./Nt1(Nt1>0);
    if(isfield(avg.anat,'brainMask'))
        avg.anat.brainMask = avg.anat.brainMask./N;
    end
    % Apply a new dt mask based on the average B0
    mask = dtiCleanImageMask(avg.b0>0.3, 5);
    avg.dt6(repmat(~mask, [1,1,1,6])) = 0;
    avg.notes.dataFiles = snFiles;
    avg.notes.normalizationTemplate = prevTemplate;
    avg.notes.normalizationParams = params;
    avg.notes.createdOn = datestr(now,31);
    fid=fopen(which(mfilename),'rt');thisScript=fread(fid);fclose(fid);
    avg.notes.buildScript = char(thisScript');
    newFileName = fullfile(outDir, ['average_dt6']);
    disp(['Saving to ' newFileName '...']);
    dtiSaveStruct(avg, newFileName);

    % Save mean T1 in analyze format
    V.dat = int16(avg.anat.img.*(2^15-1)+0.5);
    [p,f,e]=fileparts(prevTemplate); tname = [f e];
    notes = ['average of ' num2str(N) ' brains warped to ' tname '. Created at ' datestr(now,31)];
    origin = round(mrAnatXformCoords(inv(avg.anat.xformToAcPc),[0 0 0]));
    saveAnalyze(V.dat, fullfile(tdir,curName), mmPerVox, notes, origin);

    % Save mean T1 (skull-stripped) in analyze format
    % V.dat(avg.anat.brainMask<0.5) = 0;
    % saveAnalyze(V.dat, fullfile(tdir,'SIRL54ms_warp2_brain_thresh'), mmPerVox, notes, origin);
    % An alternative method of skull-stipping. This method essentially
    % treats the brainMask as a probability map rather than a hard
    % threshold. The results are very similar to the hard-thresh
    % version, but it leaves a softer edge in regions of uncertainty
    % (eg. orbital frontal and cerebellium).
    V.dat = int16(avg.anat.img.*avg.anat.brainMask.*(2^15-1)+0.5);
    saveAnalyze(V.dat, fullfile(tdir,[curName '_brain']), mmPerVox, notes, origin);

    % Save mean b=0 in analyze format
    V.dat = int16(avg.b0.*(2^15-1)+0.5);
    origin = round(mrAnatXformCoords(inv(avg.xformToAcPc),[0 0 0]));
    saveAnalyze(V.dat, fullfile(tdir,[curName '_EPI']),  avg.mmPerVox, notes, origin);
else
    disp([curTemplate ' exists- skipping. (Set forceBuildAll to rebuild.)']);
end

%
% 4. BUILD AN AVERAGE DATASET BY WARPING EACH TO THE WARP2 TEMPLATE
%
prevTemplate = fullfile(tdir,[curName '_brain']);
curName = [tBaseName suffix{4}];
outDir = fullfile(tdir, curName);
if(~exist(outDir)) mkdir(outDir); end
for(ii=[1:N])
  fprintf('Processing %s (%d of %d)...\n',subCodes{ii}, ii, N);
  d = load(files{ii});
  im = double(d.anat.img);
  im = im./max(im(:));
  xform = d.anat.xformToAcPc;
  if(useBrainMask) im(~d.anat.brainMask) = 0; end
  sn = mrAnatComputeSpmSpatialNorm(im, xform, [prevTemplate '.img'], params);
  t1Rng = [min(d.anat.img(:)) max(d.anat.img(:))];
  b0Rng = [min(d.b0(:)) max(d.b0(:))];
  d = dtiSpmDeformer(d, sn, tensorInterpMethod, mmPerVox);
  d.anat.img(d.anat.img<t1Rng(1)) = t1Rng(1);
  d.anat.img(d.anat.img>t1Rng(2)) = t1Rng(2);
  d.anat.img = int16(d.anat.img+0.5);
  d.b0(d.b0<b0Rng(1)) = b0Rng(1);
  d.b0(d.b0>b0Rng(2)) = b0Rng(2);
  d.b0 = int16(d.b0+0.5);

  newFileName = fullfile(outDir, [subCodes{ii} '_sn']);
  disp(['Saving to ' newFileName '...']);
  dtiSaveStruct(d, newFileName);
end
% Now load all the warped dt6 files and build an average brain
snFiles = findSubjects(outDir, '*_sn*',{});
N = length(snFiles);
disp(['Loading ' snFiles{1} '...']);
dt = load(snFiles{1});
avg = dt;
avg.b0 = mrAnatHistogramClip(double(avg.b0),0.5,0.99);
avg.anat.img = mrAnatHistogramClip(double(avg.anat.img),0.5,0.99);
if(isfield(avg.anat,'brainMask'))
  avg.anat.brainMask = double(avg.anat.brainMask);
end
Nb0 = double(avg.b0>0);
Nt1 = double(avg.anat.img>0);
for(ii=2:N)
  disp(['Loading ' snFiles{ii} '...']);
  dt = load(snFiles{ii});
  dt.dt6(isnan(dt.dt6)) = 0;
  b0 = mrAnatHistogramClip(double(dt.b0),0.4,0.99);
  b0(isnan(b0)) = 0;
  avg.b0 = avg.b0+b0;
  avg.dt6 = avg.dt6+dt.dt6;
  t1 = mrAnatHistogramClip(double(dt.anat.img),0.4,0.99);
  t1(isnan(t1)) = 0;
  avg.anat.img = avg.anat.img+t1;
  if(isfield(avg.anat,'brainMask') && isfield(dt.anat,'brainMask'))
    avg.anat.brainMask = avg.anat.brainMask+double(dt.anat.brainMask);
  end
  Nb0 = Nb0+double(b0>0);
  Nt1 = Nt1+double(t1>0);
end
avg.b0(Nb0>0) = avg.b0(Nb0>0)./Nb0(Nb0>0);
for(ii=1:6)
  tmp = avg.dt6(:,:,:,ii);
  tmp(Nb0>0) = tmp(Nb0>0)./Nb0(Nb0>0);
  avg.dt6(:,:,:,ii) = tmp;
end
avg.anat.img(Nt1>0) = avg.anat.img(Nt1>0)./Nt1(Nt1>0);
if(isfield(avg.anat,'brainMask'))
  avg.anat.brainMask = avg.anat.brainMask./N;
end
% Apply a new dt mask based on the average B0
mask = dtiCleanImageMask(avg.b0>0.3, 5);
avg.dt6(repmat(~mask, [1,1,1,6])) = 0;
avg.notes.dataFiles = snFiles;
avg.notes.normalizationTemplate = prevTemplate;
avg.notes.normalizationParams = params;
avg.notes.createdOn = datestr(now,31);
fid=fopen(which(mfilename),'rt');thisScript=fread(fid);fclose(fid);
avg.notes.buildScript = char(thisScript');
newFileName = fullfile(outDir, ['average_dt6']);
disp(['Saving to ' newFileName '...']);
dtiSaveStruct(avg, newFileName);
disp(['Finished (' num2str(toc) ' secs)']);

error('stop here');

%% Get demographics for subjects
%
%
baseDir = '/biac2/wandell2/data/reading_longitude/';
tdir = fullfile(baseDir,'templates','adult');
[files,subCodes] = findSubjects(fullfile(tdir,'SIRL20adultwarp3_averageDataset'), '*_sn', {});
fid = fopen(fullfile(tdir,'subjectInfo.csv'),'w');
fprintf(fid,'Name,Sex,Age,ExactAge,birthDate,scanDate\n');
for(ii=1:length(subCodes))
    if(strcmp(subCodes{ii}(1:2),'ab')) subCodes{ii} = ['aab' subCodes{ii}(3:end)]; end
    if(strcmp(subCodes{ii}(1:2),'rd')) subCodes{ii} = ['rfd' subCodes{ii}(3:end)]; end
    dtDir = fullfile(baseDir,'dti_adults',subCodes{ii});
    if(~exist(dtDir,'dir'))
        dtDir = fullfile(baseDir,'dti_adults','additional_runs',subCodes{ii});
    end
    dataDir = fullfile(dtDir,'dti');
    if(~exist(dataDir,'dir'))
        dataDir = fullfile(dtDir,'dti_6dir');
    end
    f = fullfile(dataDir,'B0_001.dcm');
    if(~exist(f,'file'))
        f = [f '.gz'];
        gunzip(f,'/tmp/');
        f = '/tmp/B0_001.dcm';
    end
    di = dicominfo(f);
    ad = datenum(di.AcquisitionDate,'yyyymmdd');
	bd = datenum(di.PatientBirthDate,'yyyymmdd');
    exactAge(ii) = (ad-bd)/364.25;
    sex(ii) = di.PatientSex=='M';
    fprintf(fid,'%s,%s,%s,%s,%0.2f,%s,%s\n',...
        subCodes{ii}, di.PatientName.FamilyName, di.PatientSex, di.PatientAge, exactAge(ii), di.PatientBirthDate, di.AcquisitionDate);
end
fclose(fid);
fprintf('Age: %0.0f - %0.0f years (mean %0.1f), %d females out of %d total.\n',...
    min(exactAge),max(exactAge),mean(exactAge),sum(~sex),length(sex));

%
% 5. BUILD AN MNI-EPI SET FOR COMPARISON
%
tic;
if(ispc)
    tdir = '\\white.stanford.edu\biac2-wandell2\data\reading_longitude\templates\adult';
    baseDir = '\\white.stanford.edu\biac2-wandell2\data\reading_longitude\dti_adults\*0*';
else
    tdir = '/biac2/wandell2/data/reading_longitude/templates/adult';
    baseDir = '/biac2/wandell2/data/reading_longitude/dti_adults/*0*';
end
tensorInterpMethod = 1;
tBaseName = 'SIRL20_adult';
mmPerVox = [1 1 1];
spm_defaults; global defaults; defaults.analyze.flip = 0;
params = defaults.normalise.estimate;
%params.smosrc = 4;
[files,subCodes] = findSubjects(baseDir, '*_dt6',{'ah051003','gf050826'});
N = length(files);

spmDir = fileparts(which('spm_normalise'));
prevTemplate = fullfile(spmDir,'templates','EPI.mnc');
curName = [tBaseName '_MNI_EPI'];
outDir = fullfile(tdir, curName);
if(~exist(outDir)) mkdir(outDir); end
for(ii=[1:N])
  fprintf('Processing %s (%d of %d)...\n',subCodes{ii}, ii, N);
  d = load(files{ii});
  im = double(d.b0);
  im = mrAnatHistogramClip(im);
  xform = d.anat.xformToAcPc;
  if(useBrainMask) im(~d.anat.brainMask) = 0; end
  sn = mrAnatComputeSpmSpatialNorm(im, xform, [prevTemplate '.img'], params);
  t1Rng = [min(d.anat.img(:)) max(d.anat.img(:))];
  b0Rng = [min(d.b0(:)) max(d.b0(:))];
  d = dtiSpmDeformer(d, sn, tensorInterpMethod, mmPerVox);
  d.anat.img(d.anat.img<t1Rng(1)) = t1Rng(1);
  d.anat.img(d.anat.img>t1Rng(2)) = t1Rng(2);
  d.anat.img = int16(d.anat.img+0.5);
  d.b0(d.b0<b0Rng(1)) = b0Rng(1);
  d.b0(d.b0>b0Rng(2)) = b0Rng(2);
  d.b0 = int16(d.b0+0.5);

  newFileName = fullfile(outDir, [subCodes{ii} '_sn']);
  disp(['Saving to ' newFileName '...']);
  dtiSaveStruct(d, newFileName);
end
% Now load all the warped dt6 files and build an average brain
files = findSubjects(outDir, '*_sn*',{});
N = length(files);
disp(['Loading ' files{1} '...']);
dt = load(files{1});
avg = dt;
avg.b0 = mrAnatHistogramClip(double(avg.b0),0.5,0.99);
avg.anat.img = mrAnatHistogramClip(double(avg.anat.img),0.5,0.99);
if(isfield(avg.anat,'brainMask'))
  avg.anat.brainMask = double(avg.anat.brainMask);
end
avg.dtBrainMask = double(avg.dtBrainMask);
Nb0 = double(avg.b0>0);
Nt1 = double(avg.anat.img>0);
for(ii=2:N)
  disp(['Loading ' files{ii} '...']);
  dt = load(files{ii});
  dt.dt6(isnan(dt.dt6)) = 0;
  b0 = mrAnatHistogramClip(double(dt.b0),0.4,0.99);
  b0(isnan(b0)) = 0;
  avg.b0 = avg.b0+b0;
  avg.dt6 = avg.dt6+dt.dt6;
  avg.dtBrainMask = avg.dtBrainMask+dt.dtBrainMask;
  t1 = mrAnatHistogramClip(double(dt.anat.img),0.4,0.99);
  t1(isnan(t1)) = 0;
  avg.anat.img = avg.anat.img+t1;
  if(isfield(avg.anat,'brainMask') && isfield(dt.anat,'brainMask'))
    avg.anat.brainMask = avg.anat.brainMask+double(dt.anat.brainMask);
  end
  Nb0 = Nb0+double(b0>0);
  Nt1 = Nt1+double(t1>0);
end
avg.b0(Nb0>0) = avg.b0(Nb0>0)./Nb0(Nb0>0);
for(ii=1:6)
  tmp = avg.dt6(:,:,:,ii);
  tmp(Nb0>0) = tmp(Nb0>0)./Nb0(Nb0>0);
  avg.dt6(:,:,:,ii) = tmp;
end
avg.anat.img(Nt1>0) = avg.anat.img(Nt1>0)./Nt1(Nt1>0);
if(isfield(avg.anat,'brainMask'))
  avg.anat.brainMask = avg.anat.brainMask./N;
end
avg.dtBrainMask = avg.dtBrainMask./N;
% Apply a new dt mask based on the average B0
mask = dtiCleanImageMask(avg.b0>0.3, 5);
avg.dt6(repmat(~mask, [1,1,1,6])) = 0;
avg.notes.dataFiles = files;
avg.notes.normalizationTemplate = template;
avg.notes.normalizationParams = params;
avg.notes.createdOn = datestr(now,31);
fid=fopen(which(thisfilename),'rt');thisScript=fread(fid);fclose(fid);
avg.notes.buildScript = char(thisScript');
newFileName = fullfile(outDir, ['average_dt6']);
disp(['Saving to ' newFileName '...']);
dtiSaveStruct(avg, newFileName);
disp(['Finished (' num2str(toc) ' secs)']);


function data = noZero(data)
% Return the array without zeros
%
% SYNTAX:
%   data = zeros(data)
%
% SEE ALSO
%   noZero nanRep

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:       Andrea Gatti
%  Contributors:     Andrea Gatti ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%   This program is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

    data = data(data ~= 0);
end


function new_par = update_parameters(new_par, par, type,NaN_fill)
% This function overwrite or create fields from par in new_par. The fields
%   used will be only the ones with type 'type' present in 'par'.
% new_par a struct() could be empty.
% par a struct() with parameters.
% type a string: 'detect' for parameters used in detection an alignment of
%   spikes. 'clus' for parameters used in detection or clustering. 'relevant' for both.

if ~exist('NaN_fill','var')
    NaN_fill = false;
end
detection_params = {'channels','segments_length', 'sr','tmax','tmin','w_pre', ...
    'w_post','alignment_window', 'stdmin','stdmax', 'detect_fmin', ...
    'detect_fmax','sort_fmin','sort_fmax', 'ref_ms', 'detection', ...
    'int_factor','interpolation','alignment_window','sort_order','detect_order','detection_date'};

clus_params = {'min_inputs','max_inputs','scales','features','template_sdnum', 'template_k', ...
    'template_k_min','template_type','force_feature','match', ...
    'max_spk','permut','mintemp', 'maxtemp', 'tempstep','SWCycles',...
    'KNearNeighb', 'min_clus','randomseed','force_auto','sorting_date','elbow_min','c_ov'};

batch_ploting_params = {'temp_plot','max_spikes_plot','print2file','plot_feature_stats'};

new_par_names = fieldnames(new_par);
load_par_names = fieldnames(par);
if strcmp(type,'detect') || strcmp(type,'relevant')
    for i= 1:length(detection_params)
        if ismember(detection_params(i),load_par_names)
            field = char(detection_params(i));
            new_par.(field ) = par.(field );
         elseif NaN_fill
            field = char(detection_params(i));
            new_par.(field) = NaN;
        end
    end
end

if strcmp(type,'batch_plot')
    for i= 1:length(batch_ploting_params)
        if ismember(batch_ploting_params(i),load_par_names)
            field = char(batch_ploting_params(i));
            new_par.(field ) = par.(field );
        end
    end
end

if strcmp(type,'clus') || strcmp(type,'relevant')
    for i= 1:length(clus_params)
        if ismember(clus_params(i),load_par_names)
            field = char(clus_params(i));
            new_par.(field ) = par.(field );
        end
    end
end

if strcmp(type,'none')
    for i= 1:length(new_par_names)
        if ~ (any((ismember(new_par_names(i),clus_params)) || any(ismember(new_par_names(i),detection_params))))
            field = char(new_par_names(i));
            if ismember(new_par_names(i),load_par_names)
                new_par.(field) = par.(field );
            else
                new_par.(field) = [];
            end
        end
    end

end

if isfield(par,'ref')
    new_par.ref_ms = double(par.ref) /par.sr *1000;
end

end


function evalTG(pres)

iids = imgList('test');

dirname = fullfile('pb',pres,'tg');
ignore = mkdir(dirname);
for i = 1:numel(iids),
  iid = iids(i);
  fprintf(2,'Computing Pb for image %d/%d (iid=%d) using %s (%s)...\n',...
          i,numel(iids),iid,'TG',pres);
  pb = pbTG(imgRead(iid));
  imwrite(pb,fullfile(dirname,sprintf('%d.bmp',iid)),'bmp');
end


function processing = FeaturePipe2GPU(processing)

for i=1:length(processing)
    if isfield(processing{i}, 'transform')
        processing{i}.transform = gpuArray(processing{i}.transform);
    end
    if isfield(processing{i}, 'bias')
        processing{i}.bias = gpuArray(processing{i}.bias);
    end
end


% ------------------------------------------------------------------------
%  Copyright (C)
%  Torr Vision Group (TVG)
%  University of Oxford - UK
%
%  Qizhu Li <liqizhu@robots.ox.ac.uk>
%  August 2018
% ------------------------------------------------------------------------
% This file is part of the weakly-supervised training method presented in:
%    Qizhu Li*, Anurag Arnab*, Philip H.S. Torr,
%    "Weakly- and Semi-Supervised Panoptic Segmentation,"
%    European Conference on Computer Vision (ECCV) 2018.
% Please consider citing the paper if you use this code.
% ------------------------------------------------------------------------
% This script demos generation of iterative ground truths for weakly-
% supervised experiments.
%
% It merges CAM predictions with MCG&Grabcut masks to produce GT for
% the first round of iterative training.
%  INPUT:
%  - results/cam/<split>/*.png: the CAMs obtained from a multi-class
%  classifier.
%  - results/mcg_and_grabcut/<split>/*.png: the combined cues from MCG
%  and Grabcut.
% ------------------------------------------------------------------------

clearvars;
addpath scripts
addpath utils
addpath visualisation

% Extract detections from Cityscapes ground truth file and save as .mat
% this only need to be done once, as they do not change over iterative
% training stages
demo_instanceTrainId_to_dets;

clearvars;
dataset = 'cityscapes';
split = 'train';
opts = get_opts(dataset, split);
opts.list_path = 'lists/demo_id.txt';
opts.pred_dir = fullfile('cam', split);
opts.sem_save_dir = 'pred_sem_cam_mandg_merged';
opts.ins_save_dir = 'pred_ins_cam_mandg_merged';
opts.run_score_thresh = false;
opts.visualise_results = true;
[opts, results] = run_sub(opts);

% visualise
visualise_results_cam_mandg(opts, results);


function contrib_prev = reverse_max_vl(l_prev, contrib_curr)
    contrib_prev = vl_nnpool(l_prev, [2,2], contrib_curr, 'Stride', 2);
end


function outputSummary(summaryTable, i, k, variation, shadRed)
% Internal function to print out a summaryTable
%
% USAGE:
%
%    outputSummary(summaryTable, i, k, variation, shadRed)
%
% INPUT:
%    summaryTable:   Cell containing the summary of shadow prices and reduced costs
%    i:              Row index in the summaryTable (solver)
%    k:              Column index in the summaryTable
%    variation:      String (can be either 'increase' or 'decrease')
%    shadRed:        String indicating whether the evaluation is a shadow price (SP) or reduced cost (RC)
%
% OUTPUT:
%    Prints an output to the console

    if summaryTable{i + 1, k} > 0
        fprintf([' + ', shadRed, ' is positive for metabolites that ', variation, ' OF flux\n']);
    elseif summaryTable{i + 1, k} < 0
        fprintf([' - ', shadRed, ' is negative for metabolites that ', variation, ' OF flux\n']);
    elseif summaryTable{i + 1, k} == 0
        fprintf([' * ', shadRed, ' is zero for metabolites that ', variation, ' OF flux\n']);
    end
end


function PrintFeature( input_A, input_B, all, back, outPath)
%PrintFeature print the feature correspondence.
%   Detailed explanation goes here
    fileListA = dir(input_A);
    fileListA = fileListA(3:length(fileListA));
    fileListB = dir(input_B);
    fileListB = fileListB(3:length(fileListB));
    nFrames = length(fileListA);
    if nFrames ~= size(all, 1)
        error('frame number not match');
    end
    for frameIndex = 1:nFrames
        IA = imread([input_A fileListA(frameIndex).name]);
        IB = imread([input_B fileListB(frameIndex).name]);
        pa_all = squeeze(all(frameIndex, :, 1:2));
        pb_all = squeeze(all(frameIndex, :, 3:4));
        pa_back = squeeze(back(frameIndex, :, 1:2));
        pb_back = squeeze(back(frameIndex, :, 3:4));

        IA = DrawFeature(IA, pa_all, 'red', 'o');
        IB = DrawFeature(IB, pb_all, 'red', 'o');

        IA = DrawFeature(IA, pa_back, 'green', 's');
        IB = DrawFeature(IB, pb_back, 'green', 's');
        if ~exist(outPath, 'dir')
            mkdir(outPath);
        end
        imwrite(IA, [outPath '/A' int2str(frameIndex) '.jpg']);
        imwrite(IB, [outPath '/B' int2str(frameIndex) '.jpg']);
    end
end


function run_experiments_seg_summary()
rcnn.name = 'rcnn' ;
rcnn.opts = {...
  'type', 'rcnn', ...
  'model', 'data/models/imagenet-vgg-m.mat', ...
  'layer', 19} ;

rcnnvd.name = 'rcnnvd' ;
rcnnvd.opts = {...
  'type', 'rcnn', ...
  'model', 'data/models/imagenet-vgg-verydeep-19.mat', ...
  'layer', 41} ;

dcnn.name = 'dcnn' ;
dcnn.opts = {...
  'type', 'dcnn', ...
  'model', 'data/models/imagenet-vgg-m.mat', ...
  'layer', 13, ...
  'numWords', 64} ;

dcnnvd.name = 'dcnnvd' ;
dcnnvd.opts = {...
  'type', 'dcnn', ...
  'model', 'data/models/imagenet-vgg-verydeep-19.mat', ...
  'layer', 35, ...
  'numWords', 64} ;

dsift.name = 'dsift' ;
dsift.opts = {...
  'type', 'dsift', ...
  'numWords', 256, ...
  'numPcaDimensions', 80} ;

datasetList = { 'msrc'} ; % add 'os'
numSplits = [1, 1] ;

setupNameList = {'rcnn', 'dcnn', 'rdcnn'} ;
encoderList = {{rcnn}, {dcnn}, {rcnn dcnn}} ;
if 1
  setupNameList =  horzcat(setupNameList, {'rcnnvd', 'dcnnvd', 'rdcnnvd'}) ;
  encoderList = horzcat(encoderList, {{rcnnvd}, {dcnnvd}, {rcnnvd dcnnvd}}) ;
end

t = LatexTable() ;
t.begin().hline().vline().pf('dataset').pf('measure (\\%%)').vline() ;
for ee = 1: numel(setupNameList)
  t.pf('%s', upper(setupNameList{ee})) ;
end
t.vline().pf('SoA') ;
t.vline().endl().hline() ;

for ii = 1 : numel(datasetList)
  switch datasetList{ii}
    case 'msrc'
      dn = 'MSRC' ; m = 'msrcAcc' ;
      art = '86.5~\cite{ladicky10what}' ;
    case 'os'
      dn = 'OS' ; m = 'acc' ;
      art = '--' ;
    otherwise, assert(false) ;
  end
  t.pf(dn).pf(m) ;
  for ee = 1: numel(encoderList)
    score = [] ;
    for jj = 1 : numSplits(ii)
      opts =  os_setup(...
        'dataset', datasetList{ii}, 'seed', jj, ...
        'encoders', encoderList{ee}, ...
        'prefix', 'exp01', ...
        'suffix', setupNameList{ee}) ;
      fprintf('loading %s\n', opts.segResultPath) ;
      res = load(opts.segResultPath) ;
      switch m
        case 'map11', score(end+1) = res.test.map11 ;
        case 'msrcAcc', score(end+1) = res.test.msrcAcc ;
        case 'acc', score(end+1) = res.test.acc ;
        otherwise, assert(false) ;
      end
    end
    if numel(score) > 1
      t.pf('%5.1f \\tiny$\\pm%3.1f$', 100*mean(score), 100*std(score)) ;
    else
      t.pf('%5.1f', 100*mean(score)) ;
    end
    if jj == 1
      figure(1) ; clf ;
      switch m
        case 'acc'
          imagesc(res.test.confusion) ;
          title(sprintf('%s accuracy: %.1f %%', upper(opts.suffix), res.test.acc*100)) ;
          vl_xmkdir(opts.segPublishDir) ;
          vl_figaspect(1) ;
          vl_printsize(.7) ;
          print(fullfile(opts.segPublishDir, ['confusion.pdf']), '-dpdf') ;
      end
    end
  end
  t.pf('%s',art).endl() ;
end
t.hline() ;
str = t.end() ;
disp(str) ;


% Copyright 2011 Zdenek Kalal
%
% This file is part of TLD.
%
% TLD is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% TLD is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with TLD.  If not, see <http://www.gnu.org/licenses/>.

function [bb,conf] = tldExample(opt)

global tld; % holds results and temporal variables

% INITIALIZATION ----------------------------------------------------------

opt.source = tldInitSource(opt.source); % select data source, camera/directory

figure(2); set(2,'KeyPressFcn', @handleKey); % open figure for display of results
finish = 0; function handleKey(~,~), finish = 1; end % by pressing any key, the process will exit

while 1
    source = tldInitFirstFrame(tld,opt.source,opt.model.min_win); % get initial bounding box, return 'empty' if bounding box is too small
    if ~isempty(source), opt.source = source; break; end % check size
end

tld = tldInit(opt,[]); % train initial detector and initialize the 'tld' structure
tld = tldDisplay(0,tld); % initialize display

% RUN-TIME ----------------------------------------------------------------

for i = 2:length(tld.source.idx) % for every frame

    tld = tldProcessFrame(tld,i); % process frame i
    tldDisplay(1,tld,i); % display results on frame i

    if finish % finish if any key was pressed
        if tld.source.camera
            stoppreview(tld.source.vid);
            closepreview(tld.source.vid);
             close(1);
        end
        close(2);
        bb = tld.bb; conf = tld.conf; % return results
        return;
    end

    if tld.plot.save == 1
        img = getframe;
        imwrite(img.cdata,[tld.output num2str(i,'%05d') '.png']);
    end

end

bb = tld.bb; conf = tld.conf; % return results

end