function spm_reslice(P,flags)
% Rigid body reslicing of images
% FORMAT spm_reslice(P,flags)
%
% P      - matrix or cell array of filenames {one string per row}
%          All operations are performed relative to the first image.
%          ie. Coregistration is to the first image, and resampling
%          of images is into the space of the first image.
%
% flags  - a structure containing various options.  The fields are:
%
%         mask   - mask output images (true/false) [default: true]
%                  To avoid artifactual movement-related variance the
%                  realigned set of images can be internally masked, within
%                  the set (i.e. if any image has a zero value at a voxel
%                  than all images have zero values at that voxel). Zero
%                  values occur when regions 'outside' the image are moved
%                  'inside' the image during realignment.
%
%         mean   - write mean image (true/false) [default: true]
%                  The average of all the realigned scans is written to
%                  an image file with 'mean' prefix.
%
%         interp - the B-spline interpolation method [default: 1]
%                  Non-finite values result in Fourier interpolation. Note
%                  that Fourier interpolation only works for purely rigid
%                  body transformations. Voxel sizes must all be identical
%                  and isotropic.
%
%         which  - values of 0, 1 or 2 are allowed [default: 2]
%                  0   - don't create any resliced images.
%                        Useful if you only want a mean resliced image.
%                  1   - don't reslice the first image.
%                        The first image is not actually moved, so it may
%                        not be necessary to resample it.
%                  2   - reslice all the images.
%                  If which is a 2-element vector, flags.mean will be set
%                  to flags.which(2).
%
%         wrap   - three values of either 0 or 1, representing wrapping in
%                  each of the dimensions. For fMRI, [1 1 0] would be used.
%                  For PET, it would be [0 0 0]. [default: [0 0 0]]
%
%         prefix - prefix for resliced images [default: 'r']
%
%__________________________________________________________________________
%
% The spatially realigned images are written to the original subdirectory
% with the same (prefixed) filename. They are all aligned with the first.
%
% Inputs:
% A series of images conforming to SPM data format (see 'Data Format'). The
% relative displacement of the images is stored in their header.
%
% Outputs:
% The routine uses information in their headers and writes the realigned
% image files to the same subdirectory with a prefix.
%__________________________________________________________________________
% Copyright (C) 1999-2017 Wellcome Trust Centre for Neuroimaging

% John Ashburner
% $Id: spm_reslice.m 7141 2017-07-26 09:05:05Z guillaume $

%__________________________________________________________________________
%
% The headers of the images contain a 4x4 affine transformation matrix 'M',
% usually affected by the `realignment' and `coregistration' modules.
% What these matrices contain is a mapping from the voxel coordinates
% (x0,y0,z0) (where the first voxel is at coordinate (1,1,1)), to
% coordinates in millimeters (x1,y1,z1).
%
% x1 = M(1,1)*x0 + M(1,2)*y0 + M(1,3)*z0 + M(1,4)
% y1 = M(2,1)*x0 + M(2,2)*y0 + M(2,3)*z0 + M(2,4)
% z1 = M(3,1)*x0 + M(3,2)*y0 + M(3,3)*z0 + M(3,4)
%
% Assuming that image1 has a transformation matrix M1, and image2 has a
% transformation matrix M2, the mapping from image1 to image2 is: M2\M1
% (ie. from the coordinate system of image1 into millimeters, followed
% by a mapping from millimeters into the space of image2).
%
% Several spatial transformations (realignment, coregistration,
% normalisation) can be combined into a single operation (without the
% necessity of resampling the images several times).
%__________________________________________________________________________
%
% Refs:
%
% Friston KJ, Williams SR, Howard R Frackowiak RSJ and Turner R (1995)
% Movement-related effect in fMRI time-series.  Mag. Res. Med. 35:346-355
%
% W. F. Eddy, M. Fitzgerald and D. C. Noll (1996) Improved Image
% Registration by Using Fourier Interpolation. Mag. Res. Med. 36(6):923-931
%
% R. W. Cox and A. Jesmanowicz (1999)  Real-Time 3D Image Registration
% for Functional MRI. Mag. Res. Med. 42(6):1014-1018
%__________________________________________________________________________

SVNid = '$Rev: 7141 $';

%-Say hello
%--------------------------------------------------------------------------
SPMid = spm('FnBanner',mfilename,SVNid);

%-Parameters
%--------------------------------------------------------------------------
if ~nargin,      P = spm_select([1 Inf],'image'); end
if iscellstr(P), P = char(P);    end
if ischar(P),    P = spm_vol(P); end

def_flags        = spm_get_defaults('realign.write');
def_flags.prefix = 'r';
if nargin < 2
    flags = def_flags;
else
    fnms = fieldnames(def_flags);
    for i=1:length(fnms)
        if ~isfield(flags,fnms{i})
            flags.(fnms{i}) = def_flags.(fnms{i});
        end
    end
end

if numel(flags.which) == 2
    flags.mean  = flags.which(2);
    flags.which = flags.which(1);
elseif ~isfield(flags,'mean')
    flags.mean  = 1;
end

%-Reslice
%--------------------------------------------------------------------------
if isempty(P)
    warning('Nothing to do.');
else
    reslice_images(P,flags);
end

fprintf('%-40s: %30s\n','Completed',spm('time'))                        %-#

%==========================================================================
%-function reslice_images(P,flags)
%==========================================================================
function reslice_images(P,flags)
% Reslice images volume by volume
% FORMAT reslice_images(P,flags)
% See main function for a description of the input parameters

if ~isfinite(flags.interp) % Use Fourier method
    % Check for non-rigid transformations in the matrixes
    for i=1:numel(P)
        pp = P(1).mat\P(i).mat;
        if any(abs(svd(pp(1:3,1:3))-1)>1e-7)
            fprintf('\n  Zooms  or shears  appear to  be needed');
            fprintf('\n  (probably due to non-isotropic voxels).');
            fprintf('\n  These  can not yet be  done  using  the');
            fprintf('\n  Fourier reslicing method.  Switching to');
            fprintf('\n  7th degree B-spline interpolation instead.\n\n');
            flags.interp = 7;
            break
        end
    end
end

if flags.mask || flags.mean
    spm_progress_bar('Init',P(1).dim(3),'Computing available voxels','planes completed');
    x1    = repmat((1:P(1).dim(1))',1,P(1).dim(2));
    x2    = repmat( 1:P(1).dim(2)  ,P(1).dim(1),1);
    if flags.mean
        Count    = zeros(P(1).dim(1:3));
        Integral = zeros(P(1).dim(1:3));
    end
    if flags.mask, msk = cell(P(1).dim(3),1);  end
    for x3 = 1:P(1).dim(3)
        tmp = zeros(P(1).dim(1:2));
        for i = 1:numel(P)
            tmp = tmp + getmask(inv(P(1).mat\P(i).mat),x1,x2,x3,P(i).dim(1:3),flags.wrap);
        end
        if flags.mask, msk{x3} = find(tmp ~= numel(P)); end
        if flags.mean, Count(:,:,x3) = tmp; end
        spm_progress_bar('Set',x3);
    end
end

nread = numel(P);
if ~flags.mean
    if flags.which == 1, nread = nread - 1; end
    if flags.which == 0, nread = 0; end
end
spm_progress_bar('Init',nread,'Reslicing','volumes completed');

[x1,x2] = ndgrid(1:P(1).dim(1),1:P(1).dim(2));
nread   = 0;
d       = [flags.interp*[1 1 1]' flags.wrap(:)];

for i = 1:numel(P)

    if (i>1 && flags.which==1) || flags.which==2
        write_vol = 1;
    else
        write_vol = 0;
    end
    if write_vol || flags.mean
        read_vol = 1;
    else
        read_vol = 0;
    end

    if read_vol
        if ~isfinite(flags.interp)
            v = abs(kspace3d(spm_bsplinc(P(i),[0 0 0 ; 0 0 0]'),P(1).mat\P(i).mat));
            for x3 = 1:P(1).dim(3)
                if flags.mean
                    Integral(:,:,x3) = ...
                        Integral(:,:,x3) + ...
                        nan2zero(v(:,:,x3) .* ...
                        getmask(inv(P(1).mat\P(i).mat),x1,x2,x3,P(i).dim(1:3),flags.wrap));
                end
                if flags.mask
                    tmp = v(:,:,x3); tmp(msk{x3}) = NaN; v(:,:,x3) = tmp;
                end
            end
        else
            C = spm_bsplinc(P(i), d);
            v = zeros(P(1).dim);
            for x3 = 1:P(1).dim(3)
                [tmp,y1,y2,y3] = getmask(inv(P(1).mat\P(i).mat),x1,x2,x3,P(i).dim(1:3),flags.wrap);
                v(:,:,x3)      = spm_bsplins(C, y1,y2,y3, d);
                % v(~tmp)      = 0;

                if flags.mean
                    Integral(:,:,x3) = Integral(:,:,x3) + nan2zero(v(:,:,x3));
                end
                if flags.mask
                    tmp = v(:,:,x3); tmp(msk{x3}) = NaN; v(:,:,x3) = tmp;
                end
            end
        end
        if write_vol
            VO         = P(i);
            VO.fname   = spm_file(P(i).fname, 'prefix',flags.prefix);
            VO.dim     = P(1).dim(1:3);
            VO.dt      = P(i).dt;
            VO.pinfo   = P(i).pinfo;
            VO.mat     = P(1).mat;
            VO.descrip = 'spm - realigned';
            VO = spm_write_vol(VO,v);
        end

        nread = nread + 1;
    end
    spm_progress_bar('Set',nread);
end

if flags.mean
    % Write integral image (16 bit signed)
    %----------------------------------------------------------------------
    Integral    = Integral./Count;
    PO          = P(1);
    PO.fname    = spm_file(P(1).fname, 'prefix','mean');
    PO          = rmfield(PO,'pinfo');
    PO.pinfo    = [max(max(max(Integral)))/32767 0 0]';
    PO.n        = [1 1];
    PO.descrip  = 'spm - mean image';
    PO.dt       = [spm_type('int16') spm_platform('bigend')];
    spm_write_vol(PO,Integral);
end

spm_progress_bar('Clear');

%==========================================================================
%-function v = kspace3d(v,M)
%==========================================================================
function v = kspace3d(v,M)
% 3D rigid body transformation performed as shears in 1D Fourier space
% FORMAT v = kspace3d(v,M)
% v        - image stored as a 3D array
% M        - rigid body transformation matrix
%
% v        - transformed image
%
% References:
% R. W. Cox and A. Jesmanowicz (1999)
% Real-Time 3D Image Registration for Functional MRI
% Magnetic Resonance in Medicine 42(6):1014-1018
%
% W. F. Eddy, M. Fitzgerald and D. C. Noll (1996)
% Improved Image Registration by Using Fourier Interpolation
% Magnetic Resonance in Medicine 36(6):923-931

[S0,S1,S2,S3] = shear_decomp(M);

d  = [size(v) 1 1 1];
g = 2.^ceil(log2(d));
if any(g~=d)
    tmp = v;
    v   = zeros(g);
    v(1:d(1),1:d(2),1:d(3)) = tmp;
    clear tmp;
end

% XY-shear
tmp1 = -sqrt(-1)*2*pi*([0:((g(3)-1)/2) 0 (-g(3)/2+1):-1])/g(3);
for j=1:g(2)
    t        = reshape( exp((j*S3(3,2) + S3(3,1)*(1:g(1)) + S3(3,4)).'*tmp1) ,[g(1) 1 g(3)]);
    v(:,j,:) = real(ifft(fft(v(:,j,:),[],3).*t,[],3));
end

% XZ-shear
tmp1 = -sqrt(-1)*2*pi*([0:((g(2)-1)/2) 0 (-g(2)/2+1):-1])/g(2);
for k=1:g(3)
    t        = exp( (k*S2(2,3) + S2(2,1)*(1:g(1)) + S2(2,4)).'*tmp1);
    v(:,:,k) = real(ifft(fft(v(:,:,k),[],2).*t,[],2));
end

% YZ-shear
tmp1 = -sqrt(-1)*2*pi*([0:((g(1)-1)/2) 0 (-g(1)/2+1):-1])/g(1);
for k=1:g(3)
    t        = exp( tmp1.'*(k*S1(1,3) + S1(1,2)*(1:g(2)) + S1(1,4)));
    v(:,:,k) = real(ifft(fft(v(:,:,k),[],1).*t,[],1));
end

% XY-shear
tmp1 = -sqrt(-1)*2*pi*([0:((g(3)-1)/2) 0 (-g(3)/2+1):-1])/g(3);
for j=1:g(2)
    t        = reshape( exp( (j*S0(3,2) + S0(3,1)*(1:g(1)) + S0(3,4)).'*tmp1) ,[g(1) 1 g(3)]);
    v(:,j,:) = real(ifft(fft(v(:,j,:),[],3).*t,[],3));
end

if any(g~=d), v = v(1:d(1),1:d(2),1:d(3)); end

%==========================================================================
%-function [S0,S1,S2,S3] = shear_decomp(A)
%==========================================================================
function [S0,S1,S2,S3] = shear_decomp(A)
% Decompose rotation and translation matrix A into shears S0, S1, S2 and
% S3, such that A = S0*S1*S2*S3. The original procedure is documented in:
% R. W. Cox and A. Jesmanowicz (1999)
% Real-Time 3D Image Registration for Functional MRI
% Magnetic Resonance in Medicine 42(6):1014-1018

A0 = A(1:3,1:3);
if any(abs(svd(A0)-1)>1e-7), error('Cannot decompose matrix.'); end

t  = A0(2,3); if t==0, t=eps; end
a0 = pinv(A0([1 2],[2 3])')*[(A0(3,2)-(A0(2,2)-1)/t) (A0(3,3)-1)]';
S0 = [1 0 0; 0 1 0; a0(1) a0(2) 1];
A1 = S0\A0;  a1 = pinv(A1([2 3],[2 3])')*A1(1,[2 3])';  S1 = [1 a1(1) a1(2); 0 1 0; 0 0 1];
A2 = S1\A1;  a2 = pinv(A2([1 3],[1 3])')*A2(2,[1 3])';  S2 = [1 0 0; a2(1) 1 a2(2); 0 0 1];
A3 = S2\A2;  a3 = pinv(A3([1 2],[1 2])')*A3(3,[1 2])';  S3 = [1 0 0; 0 1 0; a3(1) a3(2) 1];

s3 = A(3,4)-a0(1)*A(1,4)-a0(2)*A(2,4);
s1 = A(1,4)-a1(1)*A(2,4);
s2 = A(2,4);
S0 = [[S0 [0  0 s3]'];[0 0 0 1]];
S1 = [[S1 [s1 0  0]'];[0 0 0 1]];
S2 = [[S2 [0 s2  0]'];[0 0 0 1]];
S3 = [[S3 [0  0  0]'];[0 0 0 1]];

%==========================================================================
%-function [Mask,y1,y2,y3] = getmask(M,x1,x2,x3,dim,wrp)
%==========================================================================
function [Mask,y1,y2,y3] = getmask(M,x1,x2,x3,dim,wrp)
tiny = 5e-2; % From spm_vol_utils.c
y1   = M(1,1)*x1+M(1,2)*x2+(M(1,3)*x3+M(1,4));
y2   = M(2,1)*x1+M(2,2)*x2+(M(2,3)*x3+M(2,4));
y3   = M(3,1)*x1+M(3,2)*x2+(M(3,3)*x3+M(3,4));
Mask = true(size(y1));
if ~wrp(1), Mask = Mask & (y1 >= (1-tiny) & y1 <= (dim(1)+tiny)); end
if ~wrp(2), Mask = Mask & (y2 >= (1-tiny) & y2 <= (dim(2)+tiny)); end
if ~wrp(3), Mask = Mask & (y3 >= (1-tiny) & y3 <= (dim(3)+tiny)); end

%==========================================================================
%-function vo = nan2zero(vi)
%==========================================================================
function vo = nan2zero(vi)
vo = vi;
vo(~isfinite(vo)) = 0;


%                            [ADA,absd] = getada3(ADA, A,Ajc1,Aord, udsqr,K)
% GETADA3  Compute ADA(i,j) = (D(d^2)*A.t(:,i))' *A.t(:,j),
%   and exploit sparsity as much as possible.
%   absd - length m output vector, containing
%     absd(i) = abs((D(d^2)*A.t(:,i))' *abs(A.t(:,i)).
%     Hence, diag(ADA)./absd gives a measure of cancelation (in [0,1]).
%
% ******************** INTERNAL FUNCTION OF SEDUMI ********************
%
% See also sedumi, getada1, getada2

function [ADA,absd] = getada3(ADA, A,Ajc1,Aord, udsqr,K) %#ok
%
% This file is part of SeDuMi 1.1 by Imre Polik and Oleksandr Romanko
% Copyright (C) 2005 McMaster University, Hamilton, CANADA  (since 1.1)
%
% Copyright (C) 2001 Jos F. Sturm (up to 1.05R5)
%   Dept. Econometrics & O.R., Tilburg University, the Netherlands.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% Affiliation SeDuMi 1.03 and 1.04Beta (2000):
%   Dept. Quantitative Economics, Maastricht University, the Netherlands.
%
% Affiliations up to SeDuMi 1.02 (AUG1998):
%   CRL, McMaster University, Canada.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% 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 2 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, write to the Free Software
% Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
% 02110-1301, USA
%

disp('The SeDuMi binaries are not installed.')
disp('In Matlab, launch "install_sedumi" in the folder you put the SeDuMi files.')
disp('For more information see the file Install.txt.')
error(' ')


function [state, y] = ft_preproc_online_downsample_apply(state, x)

% FT_PREPROC_ONLINE_DOWNSAMPLE_APPLY passes a signal through the online downsampler
% and returns the downsampler state and the downsampled signal. The state keeps track
% of the number of samples to be skipped in the next call.
%
% Use as
%    [state, dat] = ft_preproc_online_downsample_apply(state, x)
% where
%   dat   = Nchan x Ntime
%   state = downsampler state, see FT_PREPROC_ONLINE_DOWNSAMPLE_INIT
%
% See also PREPROC

% Copyright (C) 2010, Stefan Klanke
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

N = size(x,2);

% to get number K of sample we can write out, subtract the skipped samples,
% and then add maximum possible number of skip samples for next time (=state.factor-1)
K  = floor((N - state.numSkip + state.factor-1)/state.factor);

startIdx = 1+state.numSkip;
endIdx   = 1+state.numSkip + (K-1)*state.factor;

y = x(:,startIdx:state.factor:endIdx);
state.numSkip = state.factor-1-(N-endIdx); % for next time


% ------------------------------------------------------------------------
%          Run Allen Atlas Browser
% ------------------------------------------------------------------------

%% ENTER FILE LOCATION AND PROBE-SAVE-NAME

% directory of histology
processed_images_folder = 'C:\Drive\Histology\brainX\processed';

% name the saved probe points, to avoid overwriting another set of probes going in the same folder
probe_save_name_suffix = '';

% directory of reference atlas files
annotation_volume_location = 'C:\Drive\Histology\annotation_volume_10um_by_index.npy';
structure_tree_location = 'C:\Drive\Histology\structure_tree_safe_2017.csv';
template_volume_location = 'C:\Drive\Histology\template_volume_10um.npy';

% plane to view ('coronal', 'sagittal', 'transverse')
plane = 'coronal';

%% GET PROBE TRAJECTORY POINTS

% load the reference brain and region annotations
if ~exist('av','var') || ~exist('st','var') || ~exist('tv','var')
    disp('loading reference atlas...')
    av = readNPY(annotation_volume_location);
    st = loadStructureTree(structure_tree_location);
    tv = readNPY(template_volume_location);
end

% select the plane for the viewer
if strcmp(plane,'coronal')
    av_plot = av;
    tv_plot = tv;
elseif strcmp(plane,'sagittal')
    av_plot = permute(av,[3 2 1]);
    tv_plot = permute(tv,[3 2 1]);
elseif strcmp(plane,'transverse')
    av_plot = permute(av,[2 3 1]);
    tv_plot = permute(tv,[2 3 1]);
end

% create Atlas viewer figure
f = figure('Name','Atlas Viewer');

% show histology in Slice Viewer
try; figure(slice_figure_browser); title('');
catch; slice_figure_browser = figure('Name','Slice Viewer'); end
reference_size = size(tv_plot);
sliceBrowser(slice_figure_browser, processed_images_folder, f, reference_size);

% % use application in Atlas Transform Viewer
% % use this function if you have a processed_images_folder with appropriately processed .tif histology images
f = AtlasTransformBrowser(f, tv_plot, av_plot, st, slice_figure_browser, processed_images_folder, probe_save_name_suffix, plane);

% use the simpler version, which does not interface with processed slice images
% just run these two lines instead of the previous 5 lines of code
%
%  save_location = processed_images_folder;
%  f = allenAtlasBrowser(f, tv_plot, av_plot, st, save_location, probe_save_name_suffix, plane);


% Author: Guosheng Lin (guosheng.lin@gmail.com)

% perform segmentation prediction on user provided images.
% specify the location of your images, e.g., using the following
% folder which contains serveral example images:
% ds_config.img_data_dir='../datasets/custom_data';

function demo_refinenet_test_example_eyth()
 folders = {'vid4','vid6','vid9'};

 for i = 1:length(folders)
    rng('shuffle');

    addpath('./my_utils');
    dir_matConvNet='../libs/matconvnet/matlab';
    run(fullfile(dir_matConvNet, 'vl_setupnn.m'));

    run_config=[];
    ds_config=[];

    run_config.use_gpu=true;
    % run_config.use_gpu=false;
    run_config.gpu_idx=1;

    % result dir:
    result_name=[char(folders(i))]

    result_dir=fullfile('../cache_data', 'eyth_on_eyth_val/val_1', result_name);

    % the folder that contains testing images:
    ds_config.img_data_dir=strcat('../datasets/eyth/JPEGImages/test/',char(folders(i)));

    % using a trained model which is trained on VOC 2012
    % run_config.trained_model_path='../model_trained/refinenet_res101_voc2012.mat';
    % ds_config.class_info=gen_class_info_voc();

    % using the object parsing model
    run_config.trained_model_path='../model_trained/refinenet_res101_eyth.mat';
    ds_config.class_info=gen_class_info_ego();

    % for voc trained model, control the size of input images
    run_config.input_img_short_edge_min=450;
    run_config.input_img_short_edge_max=600;

    % set the input image scales, useful for multi-scale evaluation
    % e.g. using multiple scale settings (1.0 0.8 0.6) and average the resulting score maps.
    run_config.input_img_scale=1.0;

    run_config.gen_net_opts_fn=@gen_net_opts_model_type1;

    run_config.run_evaonly=true;
    ds_config.use_custom_data=true;
    ds_config.use_dummy_gt=true;
    run_config.use_dummy_gt=ds_config.use_dummy_gt;

    ds_config.ds_name='tmp_data';
    run_config.root_cache_dir=result_dir;
    mkdir_notexist(run_config.root_cache_dir);

    run_config.model_name=result_name;

    diary_dir=run_config.root_cache_dir;
    mkdir_notexist(diary_dir);
    diary(fullfile(diary_dir, 'output.txt'));
    diary on

    run_dir_name=fileparts(mfilename('fullpath'));
    [~, run_dir_name]=fileparts(run_dir_name);
    run_config.run_dir_name=run_dir_name;
    run_config.run_file_name=mfilename();

    ds_info=gen_dataset_info(ds_config);
    my_diary_flush();

    train_opts=run_config.gen_net_opts_fn(run_config, ds_info.class_info);

    imdb=my_gen_imdb(train_opts, ds_info);

    data_norm_info=[];
    data_norm_info.image_mean=128;

    imdb.ref.data_norm_info=data_norm_info;

    if run_config.use_gpu
        gpu_num=gpuDeviceCount;
        if gpu_num>=1
            gpuDevice(run_config.gpu_idx);
        else
            error('no gpu found!');
        end
    end

    [net_config, net_exp_info]=prepare_running_model(train_opts);

    my_net_tool(train_opts, imdb, net_config, net_exp_info);

    fprintf('\n\n--------------------------------------------------\n\n');
    disp('results are saved in:');
    disp(run_config.root_cache_dir);

    my_diary_flush();
    diary off

 end
end


function Calls = Automerge_Callback(Calls1,Calls2,AudioFile)
%% Merges two detection files into one

Calls=[Calls1; Calls2];

% Audio info
audio_info = audioinfo(AudioFile);

%% Merge overlapping boxes
Calls = merge_boxes(Calls.Box, Calls.Score, Calls.Type, audio_info, 1, 0, 0);


classdef Stitcher < handle
    %STITCHER  High level image stitcher
    %
    % It's possible to use this class without being aware of the entire
    % stitching pipeline. However, to be able to achieve higher stitching
    % stability and quality of the final images at least being familiar with
    % the theory is recommended.
    %
    % ![image](https://docs.opencv.org/3.3.1/StitchingPipeline.jpg)
    %
    % This figure illustrates the stitching module pipeline implemented in the
    % cv.Stitcher class. Using that class it's possible to configure/remove
    % some steps, i.e. adjust the stitching pipeline according to the
    % particular needs.
    %
    % The implemented stitching pipeline is very similar to the one proposed
    % in [BL07].
    %
    % # Camera models
    % There are currently 2 camera models implemented in stitching pipeline.
    %
    % - *Homography model* expecting perspective transformations between
    %   images implemented in `BestOf2NearestMatcher`,
    %   `HomographyBasedEstimator`, `BundleAdjusterReproj`, and
    %   `BundleAdjusterRay`.
    % - *Affine model* expecting affine transformation with 6 DOF or 4 DOF
    %   implemented in `AffineBestOf2NearestMatcher`, `AffineBasedEstimator`,
    %   `BundleAdjusterAffine`, `BundleAdjusterAffinePartial`, and
    %   `AffineWarper`.
    %
    % Homography model is useful for creating photo panoramas captured by
    % camera, while affine-based model can be used to stitch scans and object
    % captured by specialized devices. Use cv.Stitcher.Stitcher to get
    % preconfigured pipeline for one of those models.
    %
    % Note: Certain detailed settings of cv.Stitcher might not make sense.
    % Especially you should not mix classes implementing affine model and
    % classes implementing Homography model, as they work with different
    % transformations.
    %
    % ## Example
    % * A basic example on image stitching can be found in the
    %   `stitching_demo.m` sample
    % * A detailed example on image stitching can be found in the
    %   `stitching_detailed_demo.m` sample.
    %
    % ## References
    % [BL07]:
    % > Matthew Brown and David G Lowe.
    % > "Automatic panoramic image stitching using invariant features".
    % > International journal of computer vision, 74(1):59-73, 2007.
    %
    % See also: cv.Stitcher.Stitcher
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    properties (Dependent)
        % Registration resolution. default 0.6
        RegistrationResol
        % Seam estimation resolution. default 1
        SeamEstimationResol
        % Compositing resolution. default 'Orig'
        CompositingResol
        % Panorama confidence threshold. default 1
        PanoConfidenceThresh
        % Whether it should try to make panorama more horizontal (or vertical).
        % default true
        WaveCorrection
        % Correction kind. default 'Horiz'
        WaveCorrectKind
    end

    methods
        function this = Stitcher(varargin)
            %STITCHER  Creates a Stitcher configured in one of the stitching modes
            %
            %     obj = cv.Stitcher()
            %     obj = cv.Stitcher('OptionName',optionValue, ...)
            %
            % ## Options
            % * __Mode__ Scenario for stitcher operation. This is usually
            %   determined by source of images to stitch and their
            %   transformation. Default parameters will be chosen for
            %   operation in given scenario. Default 'Panorama'. One of:
            %   * __Panorama__ Mode for creating photo panoramas. Expects
            %     images under perspective transformation and projects
            %     resulting pano to sphere. See also `BestOf2NearestMatcher`,
            %     `SphericalWarper`.
            %   * __Scans__ Mode for composing scans. Expects images under
            %     affine transformation does not compensate exposure by
            %     default. See also `AffineBestOf2NearestMatcher`,
            %     `AffineWarper`
            % * __TryUseGPU__ Flag indicating whether GPU should be used
            %   whenever it's possible. default false
            %
            % See also: cv.Stitcher.stitch
            %
            this.id = Stitcher_(0, 'new', varargin{:});
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     obj.delete()
            %
            % See also: cv.Stitcher
            %
            if isempty(this.id), return; end
            Stitcher_(this.id, 'delete');
        end
    end

    methods
        function pano = stitch(this, images, varargin)
            %STITCH  Tries to stitch the given images
            %
            %     pano = obj.stitch(images)
            %     pano = obj.stitch(images, rois)
            %     [pano, status] = obj.stitch(...)
            %
            % ## Input
            % * __images__ Input cell-array of images.
            % * __rois__ Optional region of interest rectangles, a cell-array
            %   of cell-arrays of 4-elements vectors `{{[x,y,w,h], ...}, ...}`
            %   or `{[x,y,w,h; ...], ...}`.
            %
            % ## Output
            % * __pano__ Final pano.
            % * __status__ optional output status code. If not requested, the
            %   function throws an error if the operation fails. A string one
            %   of:
            %   * __OK__
            %   * **ERR_NEED_MORE_IMGS**
            %   * **ERR_HOMOGRAPHY_EST_FAIL**
            %   * **ERR_CAMERA_PARAMS_ADJUST_FAIL**
            %
            % The function throws an error if the stitch function returns a
            % non-OK status code.
            %
            % See also: cv.Stitcher.estimateTransform,
            %  cv.Stitcher.composePanorama
            %
            pano = Stitcher_(this.id, 'stitch', images, varargin{:});
        end

        function estimateTransform(this, images, varargin)
            %ESTIMATETRANSFORM  Estimate transformation
            %
            %     obj.estimateTransform(images)
            %     obj.estimateTransform(images, rois)
            %     status = obj.estimateTransform(...)
            %
            % ## Input
            % * __images__ Input cell-array of images.
            % * __rois__ Optional region of interest rectangles, a cell-array
            %   of cell-arrays of 4-elements vectors `{{[x,y,w,h], ...}, ...}`
            %   or `{[x,y,w,h; ...], ...}`.
            %
            % ## Output
            % * __status__ optional output status code. If not requested, the
            %   function throws an error if the operation fails. A string one
            %   of:
            %   * __OK__
            %   * **ERR_NEED_MORE_IMGS**
            %   * **ERR_HOMOGRAPHY_EST_FAIL**
            %   * **ERR_CAMERA_PARAMS_ADJUST_FAIL**
            %
            % This function tries to match the given images and to estimate
            % rotations of each camera.
            %
            % Note: Use the function only if you're aware of the stitching
            % pipeline, otherwise use cv.Stitcher.stitch.
            %
            % See also: cv.Stitcher.composePanorama
            %
            Stitcher_(this.id, 'estimateTransform', images, varargin{:});
        end

        function pano = composePanorama(this, varargin)
            %COMPOSEPANORAMA  Compose panorama
            %
            %     pano = obj.composePanorama()
            %     pano = obj.composePanorama(images)
            %     [pano, status] = obj.composePanorama(...)
            %
            % ## Input
            % * __images__ Input cell-array of images.
            %
            % ## Output
            % * __pano__ Final pano.
            % * __status__ optional output status code. If not requested, the
            %   function throws an error if the operation fails. A string one
            %   of:
            %   * __OK__
            %   * **ERR_NEED_MORE_IMGS**
            %   * **ERR_HOMOGRAPHY_EST_FAIL**
            %   * **ERR_CAMERA_PARAMS_ADJUST_FAIL**
            %
            % This function tries to compose the given images (or images
            % stored internally from the other function calls) into the final
            % `pano` under the assumption that the image transformations were
            % estimated before.
            %
            % Note: Use the function only if you're aware of the stitching
            % pipeline, otherwise use cv.Stitcher.stitch.
            %
            % See also: cv.Stitcher.estimateTransform
            %
            pano = Stitcher_(this.id, 'composePanorama', varargin{:});
        end

        function indices = component(this)
            %COMPONENT  Image indices
            %
            %     indices = obj.component()
            %
            % ## Output
            % * __indices__ Vector of integer indices (0-based).
            %
            % See also: cv.Stitcher.cameras, cv.Stitcher.workScale
            %
            indices = Stitcher_(this.id, 'component');
        end

        function params = cameras(this)
            %CAMERAS  Estimates camera parameters
            %
            %     params = obj.cameras()
            %
            % ## Output
            % * __params__ Describes camera parameters, a struct-array with
            %   the following fields:
            %   * __aspect__ Aspect ratio.
            %   * __focal__ Focal length.
            %   * __ppx__ Principal point X.
            %   * __ppy__ Principal point Y.
            %   * __R__ 3x3 camera rotation matrix.
            %   * __t__ 3x1 camera translation vector.
            %   * __K__ 3x3 camera intrinsic parameters.
            %
            % Note: Translation is assumed to be zero during the whole
            % stitching pipeline.
            %
            % See also: cv.Stitcher.component, cv.Stitcher.workScale
            %
            params = Stitcher_(this.id, 'cameras');
        end

        function wscale = workScale(this)
            %WORKSCALE  Work scale
            %
            %     wscale = obj.workScale()
            %
            % ## Output
            % * __wscale__ scalar double value.
            %
            % See also: cv.Stitcher.cameras, cv.Stitcher.component
            %
            wscale = Stitcher_(this.id, 'workScale');
        end
    end

    methods
        function mask = getMatchingMask(this)
            %GETMATCHINGMASK
            %
            %     mask = obj.getMatchingMask()
            %
            % ## Output
            % * __mask__
            %
            % See also: cv.Stitcher.setMatchingMask
            %
            mask = Stitcher_(this.id, 'getMatchingMask');
        end

        function setMatchingMask(this, mask)
            %SETMATCHINGMASK
            %
            %     obj.setMatchingMask(mask)
            %
            % ## Input
            % * __mask__
            %
            % See also: cv.Stitcher.getMatchingMask
            %
            Stitcher_(this.id, 'setMatchingMask', mask);
        end

        function value = getFeaturesFinder(this)
            %GETFEATURESFINDER  Get the features finder
            %
            %     value = obj.getFeaturesFinder()
            %
            % ## Output
            % * __value__ output scalar struct.
            %
            % See also: cv.Stitcher.setFeaturesFinder
            %
            value = Stitcher_(this.id, 'getFeaturesFinder');
        end

        function setFeaturesFinder(this, finderType, varargin)
            %SETFEATURESFINDER  Set the features finder
            %
            %     obj.setFeaturesFinder(finderType)
            %     obj.setFeaturesFinder(finderType, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __finderType__ Feature finder type. One of:
            %   * __OrbFeaturesFinder__ ORB features finder. See cv.ORB
            %   * __AKAZEFeaturesFinder__ AKAZE features finder. See cv.AKAZE
            %   * __SurfFeaturesFinder__ SURF features finder. See cv.SURF
            %     (requires `xfeatures2d` module)
            %   * __SurfFeaturesFinderGpu__ (requires CUDA and `xfeatures2d`
            %     module)
            %
            % ## Options
            % The following are options for the various finders:
            %
            % ### `OrbFeaturesFinder`
            % * __GridSize__ default [3,1]
            % * __NFeatures__ default 1500
            % * __ScaleFactor__ default 1.3
            % * __NLevels__ default 5
            %
            % ### `AKAZEFeaturesFinder`
            % * __DescriptorType__ default 'MLDB'
            % * __DescriptorSize__ default 0
            % * __DescriptorChannels__ default 3
            % * __Threshold__ default 0.001
            % * __NOctaves__ default 4
            % * __NOctaveLayers__ default 4
            % * __Diffusivity__ default `PM_G2`
            %
            % ### `SurfFeaturesFinder`
            % * __HessThresh__ default 300.0
            % * __NumOctaves__ default 3
            % * __NumLayers__ default 4
            % * __NumOctaveDescr__ default 3
            % * __NumLayersDesc__ default 4
            %
            % The class uses `OrbFeaturesFinder` by default or
            % `SurfFeaturesFinder` if `xfeatures2d` module is available.
            %
            % See also: cv.Stitcher.getFeaturesFinder, cv.FeaturesMatcher
            %
            Stitcher_(this.id, 'setFeaturesFinder', finderType, varargin{:});
        end

        function value = getFeaturesMatcher(this)
            %GETFEATURESMATCHER  Get the features matcher
            %
            %     value = obj.getFeaturesMatcher()
            %
            % ## Output
            % * __value__ output scalar struct.
            %
            % See also: cv.Stitcher.setFeaturesMatcher
            %
            value = Stitcher_(this.id, 'getFeaturesMatcher');
        end

        function setFeaturesMatcher(this, matcherType, varargin)
            %SETFEATURESMATCHER  Set the features matcher
            %
            %     obj.setFeaturesMatcher(matcherType)
            %     obj.setFeaturesMatcher(matcherType, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __matcherType__ Feature matcher type. One of:
            %   * __BestOf2NearestMatcher__ A "best of 2 nearest" matcher.
            %     Features matcher which finds two best matches for each
            %     feature and leaves the best one only if the ratio between
            %     descriptor distances is greater than the threshold
            %     `MatchConf`.
            %   * __BestOf2NearestRangeMatcher__
            %   * __AffineBestOf2NearestMatcher__ A "best of 2 nearest"
            %     matcher that expects affine trasformation between images.
            %     Features matcher similar to `BestOf2NearestMatcher` which
            %     finds two best matches for each feature and leaves the best
            %     one only if the ratio between descriptor distances is
            %     greater than the threshold `MatchConf`. Unlike
            %     `BestOf2NearestMatcher` this matcher uses affine
            %     transformation (affine trasformation estimate will be placed
            %     in `matches_info`).
            %
            % ## Options
            % The following are options accepted by all matchers:
            %
            % * __TryUseGPU__ Should try to use GPU or not. default false
            % * __MatchConf__ Match distances ration threshold. default 0.3
            % * __NumMatchesThresh1__ Minimum number of matches required for
            %   the 2D projective transform estimation used in the inliers
            %   classification step. default 6
            % * __NumMatchesThresh2__ Minimum number of matches required for
            %   the 2D projective transform re-estimation on inliers.
            %   default 6
            %
            % The following are options for the various algorithms:
            %
            % ### `BestOf2NearestRangeMatcher`
            % * __RangeWidth__ default 5
            %
            % ### `AffineBestOf2NearestMatcher`
            % * __FullAffine__ whether to use full affine transformation with
            %   6 degress of freedom or reduced transformation with 4 degrees
            %   of freedom using only rotation, translation and uniform
            %   scaling. default false
            %
            % The class uses `BestOf2NearestMatcher` by default.
            %
            % See also: cv.Stitcher.getFeaturesMatcher, cv.FeaturesMatcher
            %
            Stitcher_(this.id, 'setFeaturesMatcher', matcherType, varargin{:});
        end

        %{
        function value = getEstimator(this)
            %GETESTIMATOR  Get the estimator
            %
            %     value = obj.getEstimator()
            %
            % ## Output
            % * __value__ output scalar struct.
            %
            % See also: cv.Stitcher.setEstimator
            %
            value = Stitcher_(this.id, 'getEstimator');
        end

        function setEstimator(this, estimatorType, varargin)
            %SETESTIMATOR  Set the estimator
            %
            %     obj.setEstimator(estimatorType)
            %     obj.setEstimator(estimatorType, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __estimatorType__ Estimator type. One of:
            %   * __HomographyBasedEstimator__ Homography based rotation
            %     estimator.
            %   * __AffineBasedEstimator__ Affine transformation based
            %     estimator. This estimator uses pairwise transformations
            %     estimated by matcher to estimate final transformation for
            %     each camera.
            %
            % The following are options for the various algorithms:
            %
            % ### `HomographyBasedEstimator`
            % * __IsFocalsEstimated__ default false
            %
            % See also: cv.Stitcher.getEstimator. cv.Estimator
            %
            Stitcher_(this.id, 'setEstimator', estimatorType, varargin{:});
        end
        %}

        function value = getBundleAdjuster(this)
            %GETBUNDLEADJUSTER  Get the bundle adjuster
            %
            %     value = obj.getBundleAdjuster()
            %
            % ## Output
            % * __value__ output scalar struct.
            %
            % See also: cv.Stitcher.setBundleAdjuster
            %
            value = Stitcher_(this.id, 'getBundleAdjuster');
        end

        function setBundleAdjuster(this, adjusterType, varargin)
            %SETBUNDLEADJUSTER  Set the bundle adjuster
            %
            %     obj.setBundleAdjuster(adjusterType)
            %     obj.setBundleAdjuster(adjusterType, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __adjusterType__ camera parameters refinement method. One of:
            %   * __NoBundleAdjuster__ Stub bundle adjuster that does nothing.
            %   * __BundleAdjusterRay__ Implementation of the camera
            %     parameters refinement algorithm which minimizes sum of the
            %     distances between the rays passing through the camera center
            %     and a feature. It can estimate focal length. It ignores the
            %     refinement mask for now.
            %   * __BundleAdjusterReproj__ Implementation of the camera
            %     parameters refinement algorithm which minimizes sum of the
            %     reprojection error squares. It can estimate focal length,
            %     aspect ratio, principal point. You can affect only on them
            %     via the refinement mask.
            %   * __BundleAdjusterAffine__ Bundle adjuster that expects affine
            %     transformation represented in homogeneous coordinates in R
            %     for each camera param. Implements camera parameters
            %     refinement algorithm which minimizes sum of the reprojection
            %     error squares. It estimates all transformation parameters.
            %     Refinement mask is ignored. See also
            %     cv.AffineBasedEstimator, `AffineBestOf2NearestMatcher`.
            %   * __BundleAdjusterAffinePartial__ Bundle adjuster that expects
            %     affine transformation with 4 DOF represented in homogeneous
            %     coordinates in R for each camera param. Implements camera
            %     parameters refinement algorithm which minimizes sum of the
            %     reprojection error squares. It estimates all transformation
            %     parameters. Refinement mask is ignored.
            %
            % ## Options
            % The following are options accepted by all adjusters:
            %
            % * __ConfThresh__ default 1
            % * __RefinementMask__ default `eye(3)`
            % * __TermCriteria__ default
            %   `struct('type','Count+EPS', 'maxCount',1000, 'epsilon',eps)`
            %
            % The class uses `BundleAdjusterRay` by default.
            %
            % See also: cv.Stitcher.getBundleAdjuster, cv.BundleAdjuster
            %
            Stitcher_(this.id, 'setBundleAdjuster', adjusterType, varargin{:});
        end

        function value = getWarper(this)
            %GETWARPER  Get the warper
            %
            %     value = obj.getWarper()
            %
            % ## Output
            % * __value__ output scalar struct.
            %
            % See also: cv.Stitcher.setWarper
            %
            value = Stitcher_(this.id, 'getWarper');
        end

        function setWarper(this, warperType, varargin)
            %SETWARPER  Set the image warper
            %
            %     obj.setWarper(warperType)
            %     obj.setWarper(warperType, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __warperType__ image warper factory class type, used to create
            %   the rotation-based warper. One of:
            %   * __PlaneWarper__ Plane warper factory class. Warper that maps
            %     an image onto the `z = 1` plane.
            %   * __PlaneWarperGpu__ (requires CUDA)
            %   * __AffineWarper__ Affine warper factory class. Affine warper
            %     that uses rotations and translations. Uses affine
            %     transformation in homogeneous coordinates to represent both
            %     rotation and translation in camera rotation matrix.
            %   * __CylindricalWarper__ Cylindrical warper factory class.
            %     Warper that maps an image onto the `x*x + z*z = 1` cylinder.
            %   * __CylindricalWarperGpu__ (requires CUDA)
            %   * __SphericalWarper__ Warper that maps an image onto the unit
            %     sphere located at the origin. Projects image onto unit
            %     sphere with origin at [0,0,0] and radius `scale`, measured
            %     in pixels. A 360 panorama would therefore have a resulting
            %     width of `2*scale*pi` pixels. Poles are located at [0,-1,0]
            %     and [0,1,0] points.
            %   * __SphericalWarperGpu__ (requires CUDA)
            %   * __FisheyeWarper__
            %   * __StereographicWarper__
            %   * __CompressedRectilinearWarper__
            %   * __CompressedRectilinearPortraitWarper__
            %   * __PaniniWarper__
            %   * __PaniniPortraitWarper__
            %   * __MercatorWarper__
            %   * __TransverseMercatorWarper__
            %
            % ## Options
            % The following are options for the various warpers:
            %
            % ### `CompressedRectilinearWarper`, `CompressedRectilinearPortraitWarper`, `PaniniWarper`, `PaniniPortraitWarper`
            % * __A__ default 1
            % * __B__ default 1
            %
            % The class uses `SphericalWarper` by default.
            %
            % See also: cv.Stitcher.getWarper, cv.RotationWarper
            %
            Stitcher_(this.id, 'setWarper', warperType, varargin{:});
        end

        function value = getExposureCompensator(this)
            %GETEXPOSURECOMPENSATOR  Get the exposire compensator
            %
            %     value = obj.getExposureCompensator()
            %
            % ## Output
            % * __value__ output scalar struct.
            %
            % See also: cv.Stitcher.setExposureCompensator
            %
            value = Stitcher_(this.id, 'getExposureCompensator');
        end

        function setExposureCompensator(this, compensatorType, varargin)
            %SETEXPOSURECOMPENSATOR  Set the exposure compensator
            %
            %     obj.setExposureCompensator(compensatorType)
            %     obj.setExposureCompensator(compensatorType, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __compensatorType__ exposure compensator type. One of:
            %   * __NoExposureCompensator__ Stub exposure compensator which
            %     does nothing.
            %   * __GainCompensator__ Exposure compensator which tries to
            %     remove exposure related artifacts by adjusting image
            %     intensities, see [BL07] and [WJ10] for details.
            %   * __BlocksGainCompensator__ Exposure compensator which tries
            %     to remove exposure related artifacts by adjusting image
            %     block intensities, see [UES01] for details.
            %
            % ## Options
            % The following are options for the various compensators:
            %
            % ### `BlocksGainCompensator`
            % * __Width__ Block width. default 32
            % * __Heigth__ Block height. default 32
            %
            % The class uses `BlocksGainCompensator` by default.
            %
            % ## References
            % [BL07]:
            % > Matthew Brown and David G Lowe.
            % > "Automatic panoramic image stitching using invariant features".
            % > International journal of computer vision, 74(1):59-73, 2007.
            %
            % [WJ10]:
            % > Wei Xu and Jane Mulligan. "Performance evaluation of color
            % > correction approaches for automatic multi-view image and video
            % > stitching". In Computer Vision and Pattern Recognition (CVPR),
            % > 2010 IEEE Conference on, pages 263-270. IEEE, 2010.
            %
            % [UES01]:
            % > Matthew Uyttendaele, Ashley Eden, and R Skeliski.
            % > "Eliminating ghosting and exposure artifacts in image mosaics".
            % > In Computer Vision and Pattern Recognition, 2001. CVPR 2001.
            % > Proceedings of the 2001 IEEE Computer Society Conference on,
            % > volume 2, pages II-509. IEEE, 2001.
            %
            % See also: cv.Stitcher.getExposureCompensator,
            %  cv.ExposureCompensator
            %
            Stitcher_(this.id, 'setExposureCompensator', compensatorType, varargin{:});
        end

        function value = getSeamFinder(this)
            %GETSEAMFINDER  Get the seam finder
            %
            %     value = obj.getSeamFinder()
            %
            % ## Output
            % * __value__ output scalar struct.
            %
            % See also: cv.Stitcher.setSeamFinder
            %
            value = Stitcher_(this.id, 'getSeamFinder');
        end

        function setSeamFinder(this, seamType, varargin)
            %SETSEAMFINDER  Set the seam finder
            %
            %     obj.setSeamFinder(seamType)
            %     obj.setSeamFinder(seamType, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __seamType__ seam estimator type. One of:
            %   * __NoSeamFinder__ Stub seam estimator which does nothing.
            %   * __VoronoiSeamFinder__ Voronoi diagram-based pairwise seam
            %     estimator.
            %   * __DpSeamFinder__
            %   * __GraphCutSeamFinder__ Minimum graph cut-based seam
            %     estimator. See details in [V03].
            %   * __GraphCutSeamFinderGpu__ (requires CUDA)
            %
            % ## Options
            % The following are options for the various seam finders:
            %
            % ### `DpSeamFinder`
            % * __CostFunction__ default 'Color'. One of:
            %   * __Color__
            %   * __ColorGrad__
            %
            % ### `GraphCutSeamFinder`
            % * __CostType__ default 'ColorGrad'. One of:
            %   * __Color__
            %   * __ColorGrad__
            % * __TerminalCost__ default 10000.0
            % * __BadRegionPenaly__ default 1000.0
            %
            % The class uses `GraphCutSeamFinder` by default.
            %
            % ## References
            % [V03]:
            % > Vivek Kwatra, Arno Schodl, Irfan Essa, Greg Turk, and Aaron
            % > Bobick. "Graphcut textures: image and video synthesis using
            % > graph cuts". In ACM Transactions on Graphics (ToG), volume 22,
            % > pages 277-286. ACM, 2003.
            %
            % See also: cv.Stitcher.getSeamFinder, cv.SeamFinder
            %
            Stitcher_(this.id, 'setSeamFinder', seamType, varargin{:});
        end

        function value = getBlender(this)
            %GETBLENDER  Get the blender
            %
            %     value = obj.getBlender()
            %
            % ## Output
            % * __value__ output scalar struct.
            %
            % See also: cv.Stitcher.setBlender
            %
            value = Stitcher_(this.id, 'getBlender');
        end

        function setBlender(this, blenderType, varargin)
            %SETBLENDER  Set the blender
            %
            %     obj.setBlender(blenderType)
            %     obj.setBlender(blenderType, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __blenderType__ image blender type. One of:
            %   * __NoBlender__ Simple blender which puts one image over
            %     another.
            %   * __FeatherBlender__ Simple blender which mixes images at its
            %     borders.
            %   * __MultiBandBlender__ Blender which uses multi-band blending
            %     algorithm (see [BA83]).
            %
            % ## Options
            % The following are options for the various blenders:
            %
            % ### `FeatherBlender`
            % * __Sharpness__ default 0.02
            %
            % ### `MultiBandBlender`
            % * __TryGPU__ default false
            % * __NumBands__ default 5
            % * __WeightType__ One of:
            %   * __single__ (default)
            %   * __int16__
            %
            % The class uses `MultiBandBlender` by default.
            %
            % ## References
            % [BA83]:
            % > Peter J Burt and Edward H Adelson.
            % > "A multiresolution spline with application to image mosaics".
            % > ACM Transactions on Graphics (TOG), 2(4):217-236, 1983.
            %
            % See also: cv.Stitcher.getBlender, cv.Blender
            %
            Stitcher_(this.id, 'setBlender', blenderType, varargin{:});
        end
    end

    %% Getters/Setters
    methods
        function value = get.RegistrationResol(this)
            value = Stitcher_(this.id, 'get', 'RegistrationResol');
        end
        function set.RegistrationResol(this, value)
            Stitcher_(this.id, 'set', 'RegistrationResol', value);
        end

        function value = get.SeamEstimationResol(this)
            value = Stitcher_(this.id, 'get', 'SeamEstimationResol');
        end
        function set.SeamEstimationResol(this, value)
            Stitcher_(this.id, 'set', 'SeamEstimationResol', value);
        end

        function value = get.CompositingResol(this)
            value = Stitcher_(this.id, 'get', 'CompositingResol');
        end
        function set.CompositingResol(this, value)
            Stitcher_(this.id, 'set', 'CompositingResol', value);
        end

        function value = get.PanoConfidenceThresh(this)
            value = Stitcher_(this.id, 'get', 'PanoConfidenceThresh');
        end
        function set.PanoConfidenceThresh(this, value)
            Stitcher_(this.id, 'set', 'PanoConfidenceThresh', value);
        end

        function value = get.WaveCorrection(this)
            value = Stitcher_(this.id, 'get', 'WaveCorrection');
        end
        function set.WaveCorrection(this, value)
            Stitcher_(this.id, 'set', 'WaveCorrection', value);
        end

        function value = get.WaveCorrectKind(this)
            value = Stitcher_(this.id, 'get', 'WaveCorrectKind');
        end
        function set.WaveCorrectKind(this, value)
            Stitcher_(this.id, 'set', 'WaveCorrectKind', value);
        end
    end

end


function output = callfiltersdsp(model)

options = model.options.filtersd;

model = yalmip2nonlinearsolver(model);

if ~model.derivative_available
    disp('Derivate-free call to filterSD not yet implemented')
    error('Derivate-free call to filterSD not yet implemented')
end
if model.options.savedebug
    save filtersddebug model
end
showprogress('Calling filterSDSP',model.options.showprogress);

cu = [ repmat(0,length(model.bnonlinineq),1);
    repmat(0,length(model.bnonlineq),1);
    repmat(0,length(model.b),1);
    repmat(0,length(model.beq),1)];

cl = [ repmat(-inf,length(model.bnonlinineq),1);
    repmat(0,length(model.bnonlineq),1);
    repmat(-inf,length(model.b),1);
    repmat(0,length(model.beq),1)];

if isempty(cu)
    Flow = [];
    Fupp = [];
end

% These are needed to avoid recomputation due to ipopts double call to get
% f and df, and g and dg
global latest_x_f
global latest_x_g
global latest_df
global latest_f
global latest_G
global latest_g
global latest_xevaled
global latest_x_xevaled
latest_G = [];
latest_g = [];
latest_x_f = [];
latest_x_g = [];
latest_xevaled = [];
latest_x_xevaled = [];

funcs.objective = @(x)ipopt_callback_f(x,model);
funcs.gradient = @(x)ipopt_callback_df(x,model);
if ~isempty(cu)
    funcs.constraints = @(x)ipopt_callback_g(x,model);
    funcs.jacobian  = @(x)ipopt_callback_dg(x,model);
else
    funcs.constraints = [];
    funcs.jacobian = [];
end

lb  = model.lb(:)';
ub = model.ub(:)';

if ~isempty(cu)
   nljacstr = jacobiansparsityfromnonlinear(model);
else
   nljacstr = [];
end

if ~model.options.warmstart
    model.x0 = (lb+ub)/2;
    model.x0(isinf(ub)) = lb(isinf(ub))+1;
    model.x0(isinf(lb)) = ub(isinf(lb))-1;
    model.x0(isinf(model.x0)) = 0;
end

options.display = model.options.verbose;
solvertime = tic;
[xout,fval,exitflag,stats,lambda] = filtersdsp(funcs.objective, funcs.gradient, model.x0, lb, ub, funcs.constraints, funcs.jacobian,nljacstr, cl, cu, options);
solvertime = toc(solvertime);

% Duals currently not supported
lambda = [];

x = RecoverNonlinearSolverSolution(model,xout);

switch exitflag
    case {0}
        problem = 0;
    case {1}
        problem = 2;
    case {2,3}
        problem = 1;
    case {5}
        problem = 3;
    case {4,9}
        problem = 4;
    case 105
        problem = 16;
    otherwise
        problem = -1;
end

% Internal format for duals
D_struc = [];

% Save all data sent to solver?
if model.options.savesolverinput
    solverinput.model = model;
else
    solverinput = [];
end

% Save all data from the solver?
if model.options.savesolveroutput
    solveroutput.x = xout;
    solveroutput.exitflag = exitflag;
    solveroutput.stats = stats;
else
    solveroutput = [];
end

% Standard interface
output = createOutputStructure(x,D_struc,[],problem,'filterSD',solverinput,solveroutput,solvertime);


function [img_files, pos, target_sz, ground_truth, video_path] = load_video_info(base_path, video)
%LOAD_VIDEO_INFO
%   Loads all the relevant information for the video in the given path:
%   the list of image files (cell array of strings), initial position
%   (1x2), target size (1x2), the ground truth information for precision
%   calculations (Nx2, for N frames), and the path where the images are
%   located. The ordering of coordinates and sizes is always [y, x].
%
%   Joao F. Henriques, 2014
%   http://www.isr.uc.pt/~henriques/

	%see if there's a suffix, specifying one of multiple targets, for
	%example the dot and number in 'Jogging.1' or 'Jogging.2'.
	if numel(video) >= 2 && video(end-1) == '.' && ~isnan(str2double(video(end))),
		suffix = video(end-1:end);  %remember the suffix
		video = video(1:end-2);  %remove it from the video name
	else
		suffix = '';
	end

	%full path to the video's files
	if base_path(end) ~= '/' && base_path(end) ~= '\',
		base_path(end+1) = '/';
	end
	video_path = [base_path video '/'];

	%try to load ground truth from text file (Benchmark's format)
	filename = [video_path 'groundtruth_rect' suffix '.txt'];
	f = fopen(filename);
	assert(f ~= -1, ['No initial position or ground truth to load ("' filename '").'])

	%the format is [x, y, width, height]
	try
		ground_truth = textscan(f, '%f,%f,%f,%f', 'ReturnOnError',false);
	catch  %#ok, try different format (no commas)
		frewind(f);
		ground_truth = textscan(f, '%f %f %f %f');
	end
	ground_truth = cat(2, ground_truth{:});
	fclose(f);

	%set initial position and size
	target_sz = [ground_truth(1,4), ground_truth(1,3)];
	pos = [ground_truth(1,2), ground_truth(1,1)] + floor(target_sz/2);

	%from now on, work in the subfolder where all the images are
	video_path = [video_path 'img/'];

	%for these sequences, we must limit ourselves to a range of frames.
	%for all others, we just load all png/jpg files in the folder.
	frames = {'David', 300, 465; %770
			  'Football1', 1, 74;
			  'Freeman3', 1, 460;
			  'Freeman4', 1, 283};

	idx = find(strcmpi(video, frames(:,1)));

	if isempty(idx),
		%general case, just list all images
		img_files = dir([video_path '*.png']);
		if isempty(img_files),
			img_files = dir([video_path '*.jpg']);
			assert(~isempty(img_files), 'No image files to load.')
		end
		img_files = sort({img_files.name});
        target_sz = [ground_truth(1,4), ground_truth(1,3)];
	    pos = [ground_truth(1,2), ground_truth(1,1)] + floor(target_sz/2);
    else

        target_sz = [ground_truth(frames{idx, 2},4), ground_truth(frames{idx, 2},3)];
        pos = [ground_truth(frames{idx, 2},2), ground_truth(frames{idx, 2},1)] + floor(target_sz/2);
		%list specified frames. try png first, then jpg.
		if exist(sprintf('%s%04i.png', video_path, frames{idx,2}), 'file'),
			img_files = num2str((frames{idx,2} : frames{idx,3})', '%04i.png');

		elseif exist(sprintf('%s%04i.jpg', video_path, frames{idx,2}), 'file'),
			img_files = num2str((frames{idx,2} : frames{idx,3})', '%04i.jpg');

		else
			error('No image files to load.')
		end

		img_files = cellstr(img_files);
    end

    	if size(ground_truth,1) == 1,
		%we have ground truth for the first frame only (initial position)
		ground_truth = [];
	else
		%store positions instead of boxes
		ground_truth = ground_truth(:,[2,1]) + ground_truth(:,[4,3]) / 2;
	end

end


function obj = Q_pTop_func_new(in1,in2,in3)
coefs_tq1_11 = in2(31);
coefs_tq2_11 = in2(32);
coefs_tq3_11 = in2(33);
coef_Jacob1_qt_syms11 = in3(41);
coef_Jacob1_qt_syms12 = in3(45);
coef_Jacob1_qt_syms13 = in3(49);
coef_Jacob1_qt_syms14 = in3(53);
coef_Jacob1_qt_syms21 = in3(81);
coef_Jacob1_qt_syms22 = in3(85);
coef_Jacob1_qt_syms23 = in3(89);
coef_Jacob1_qt_syms24 = in3(93);
coef_Jacob1_qt_syms28 = in3(109);
coef_Jacob1_qt_syms29 = in3(113);
coef_Jacob1_qt_syms30 = in3(117);
coef_Jacob1_qt_syms31 = in3(121);
coef_Jacob1_qt_syms33 = in3(129);
coef_Jacob1_qt_syms34 = in3(133);
coef_Jacob1_qt_syms35 = in3(137);
coef_Jacob1_qt_syms36 = in3(141);
coef_Jacob2_qt_syms11 = in3(42);
coef_Jacob2_qt_syms12 = in3(46);
coef_Jacob2_qt_syms13 = in3(50);
coef_Jacob2_qt_syms14 = in3(54);
coef_Jacob2_qt_syms21 = in3(82);
coef_Jacob2_qt_syms22 = in3(86);
coef_Jacob2_qt_syms23 = in3(90);
coef_Jacob2_qt_syms24 = in3(94);
coef_Jacob2_qt_syms28 = in3(110);
coef_Jacob2_qt_syms29 = in3(114);
coef_Jacob2_qt_syms30 = in3(118);
coef_Jacob2_qt_syms31 = in3(122);
coef_Jacob2_qt_syms33 = in3(130);
coef_Jacob2_qt_syms34 = in3(134);
coef_Jacob2_qt_syms35 = in3(138);
coef_Jacob2_qt_syms36 = in3(142);
coef_Jacob3_qt_syms11 = in3(43);
coef_Jacob3_qt_syms12 = in3(47);
coef_Jacob3_qt_syms13 = in3(51);
coef_Jacob3_qt_syms14 = in3(55);
coef_Jacob3_qt_syms21 = in3(83);
coef_Jacob3_qt_syms22 = in3(87);
coef_Jacob3_qt_syms23 = in3(91);
coef_Jacob3_qt_syms24 = in3(95);
coef_Jacob3_qt_syms28 = in3(111);
coef_Jacob3_qt_syms29 = in3(115);
coef_Jacob3_qt_syms30 = in3(119);
coef_Jacob3_qt_syms31 = in3(123);
coef_Jacob3_qt_syms33 = in3(131);
coef_Jacob3_qt_syms34 = in3(135);
coef_Jacob3_qt_syms35 = in3(139);
coef_Jacob3_qt_syms36 = in3(143);
coef_Jacob4_qt_syms11 = in3(44);
coef_Jacob4_qt_syms12 = in3(48);
coef_Jacob4_qt_syms13 = in3(52);
coef_Jacob4_qt_syms14 = in3(56);
coef_Jacob4_qt_syms21 = in3(84);
coef_Jacob4_qt_syms22 = in3(88);
coef_Jacob4_qt_syms23 = in3(92);
coef_Jacob4_qt_syms24 = in3(96);
coef_Jacob4_qt_syms28 = in3(112);
coef_Jacob4_qt_syms29 = in3(116);
coef_Jacob4_qt_syms30 = in3(120);
coef_Jacob4_qt_syms31 = in3(124);
coef_Jacob4_qt_syms33 = in3(132);
coef_Jacob4_qt_syms34 = in3(136);
coef_Jacob4_qt_syms35 = in3(140);
coef_Jacob4_qt_syms36 = in3(144);
pinvG1_1 = in1(1);
pinvG1_2 = in1(4);
pinvG1_3 = in1(7);
pinvG2_1 = in1(2);
pinvG2_2 = in1(5);
pinvG2_3 = in1(8);
pinvG3_1 = in1(3);
pinvG3_2 = in1(6);
pinvG3_3 = in1(9);
obj = reshape([coef_Jacob1_qt_syms14+coefs_tq1_11.*coef_Jacob1_qt_syms11.*pinvG1_1+coefs_tq1_11.*coef_Jacob1_qt_syms12.*pinvG2_1+coefs_tq1_11.*coef_Jacob1_qt_syms13.*pinvG3_1+coefs_tq2_11.*coef_Jacob1_qt_syms11.*pinvG1_2+coefs_tq2_11.*coef_Jacob1_qt_syms12.*pinvG2_2+coefs_tq2_11.*coef_Jacob1_qt_syms13.*pinvG3_2+coefs_tq3_11.*coef_Jacob1_qt_syms11.*pinvG1_3+coefs_tq3_11.*coef_Jacob1_qt_syms12.*pinvG2_3+coefs_tq3_11.*coef_Jacob1_qt_syms13.*pinvG3_3,coef_Jacob2_qt_syms14+coefs_tq1_11.*coef_Jacob2_qt_syms11.*pinvG1_1+coefs_tq1_11.*coef_Jacob2_qt_syms12.*pinvG2_1+coefs_tq1_11.*coef_Jacob2_qt_syms13.*pinvG3_1+coefs_tq2_11.*coef_Jacob2_qt_syms11.*pinvG1_2+coefs_tq2_11.*coef_Jacob2_qt_syms12.*pinvG2_2+coefs_tq2_11.*coef_Jacob2_qt_syms13.*pinvG3_2+coefs_tq3_11.*coef_Jacob2_qt_syms11.*pinvG1_3+coefs_tq3_11.*coef_Jacob2_qt_syms12.*pinvG2_3+coefs_tq3_11.*coef_Jacob2_qt_syms13.*pinvG3_3,coef_Jacob3_qt_syms14+coefs_tq1_11.*coef_Jacob3_qt_syms11.*pinvG1_1+coefs_tq1_11.*coef_Jacob3_qt_syms12.*pinvG2_1+coefs_tq1_11.*coef_Jacob3_qt_syms13.*pinvG3_1+coefs_tq2_11.*coef_Jacob3_qt_syms11.*pinvG1_2+coefs_tq2_11.*coef_Jacob3_qt_syms12.*pinvG2_2+coefs_tq2_11.*coef_Jacob3_qt_syms13.*pinvG3_2+coefs_tq3_11.*coef_Jacob3_qt_syms11.*pinvG1_3+coefs_tq3_11.*coef_Jacob3_qt_syms12.*pinvG2_3+coefs_tq3_11.*coef_Jacob3_qt_syms13.*pinvG3_3,coef_Jacob4_qt_syms14+coefs_tq1_11.*coef_Jacob4_qt_syms11.*pinvG1_1+coefs_tq1_11.*coef_Jacob4_qt_syms12.*pinvG2_1+coefs_tq1_11.*coef_Jacob4_qt_syms13.*pinvG3_1+coefs_tq2_11.*coef_Jacob4_qt_syms11.*pinvG1_2+coefs_tq2_11.*coef_Jacob4_qt_syms12.*pinvG2_2+coefs_tq2_11.*coef_Jacob4_qt_syms13.*pinvG3_2+coefs_tq3_11.*coef_Jacob4_qt_syms11.*pinvG1_3+coefs_tq3_11.*coef_Jacob4_qt_syms12.*pinvG2_3+coefs_tq3_11.*coef_Jacob4_qt_syms13.*pinvG3_3,coef_Jacob1_qt_syms24+coefs_tq1_11.*coef_Jacob1_qt_syms21.*pinvG1_1+coefs_tq1_11.*coef_Jacob1_qt_syms22.*pinvG2_1+coefs_tq1_11.*coef_Jacob1_qt_syms23.*pinvG3_1+coefs_tq2_11.*coef_Jacob1_qt_syms21.*pinvG1_2+coefs_tq2_11.*coef_Jacob1_qt_syms22.*pinvG2_2+coefs_tq2_11.*coef_Jacob1_qt_syms23.*pinvG3_2+coefs_tq3_11.*coef_Jacob1_qt_syms21.*pinvG1_3+coefs_tq3_11.*coef_Jacob1_qt_syms22.*pinvG2_3+coefs_tq3_11.*coef_Jacob1_qt_syms23.*pinvG3_3,coef_Jacob2_qt_syms24+coefs_tq1_11.*coef_Jacob2_qt_syms21.*pinvG1_1+coefs_tq1_11.*coef_Jacob2_qt_syms22.*pinvG2_1+coefs_tq1_11.*coef_Jacob2_qt_syms23.*pinvG3_1+coefs_tq2_11.*coef_Jacob2_qt_syms21.*pinvG1_2+coefs_tq2_11.*coef_Jacob2_qt_syms22.*pinvG2_2+coefs_tq2_11.*coef_Jacob2_qt_syms23.*pinvG3_2+coefs_tq3_11.*coef_Jacob2_qt_syms21.*pinvG1_3+coefs_tq3_11.*coef_Jacob2_qt_syms22.*pinvG2_3+coefs_tq3_11.*coef_Jacob2_qt_syms23.*pinvG3_3,coef_Jacob3_qt_syms24+coefs_tq1_11.*coef_Jacob3_qt_syms21.*pinvG1_1+coefs_tq1_11.*coef_Jacob3_qt_syms22.*pinvG2_1+coefs_tq1_11.*coef_Jacob3_qt_syms23.*pinvG3_1+coefs_tq2_11.*coef_Jacob3_qt_syms21.*pinvG1_2+coefs_tq2_11.*coef_Jacob3_qt_syms22.*pinvG2_2+coefs_tq2_11.*coef_Jacob3_qt_syms23.*pinvG3_2+coefs_tq3_11.*coef_Jacob3_qt_syms21.*pinvG1_3+coefs_tq3_11.*coef_Jacob3_qt_syms22.*pinvG2_3+coefs_tq3_11.*coef_Jacob3_qt_syms23.*pinvG3_3,coef_Jacob4_qt_syms24+coefs_tq1_11.*coef_Jacob4_qt_syms21.*pinvG1_1+coefs_tq1_11.*coef_Jacob4_qt_syms22.*pinvG2_1+coefs_tq1_11.*coef_Jacob4_qt_syms23.*pinvG3_1+coefs_tq2_11.*coef_Jacob4_qt_syms21.*pinvG1_2+coefs_tq2_11.*coef_Jacob4_qt_syms22.*pinvG2_2+coefs_tq2_11.*coef_Jacob4_qt_syms23.*pinvG3_2+coefs_tq3_11.*coef_Jacob4_qt_syms21.*pinvG1_3+coefs_tq3_11.*coef_Jacob4_qt_syms22.*pinvG2_3+coefs_tq3_11.*coef_Jacob4_qt_syms23.*pinvG3_3,coef_Jacob1_qt_syms31+coefs_tq1_11.*coef_Jacob1_qt_syms28.*pinvG1_1+coefs_tq1_11.*coef_Jacob1_qt_syms29.*pinvG2_1+coefs_tq1_11.*coef_Jacob1_qt_syms30.*pinvG3_1+coefs_tq2_11.*coef_Jacob1_qt_syms28.*pinvG1_2+coefs_tq2_11.*coef_Jacob1_qt_syms29.*pinvG2_2+coefs_tq2_11.*coef_Jacob1_qt_syms30.*pinvG3_2+coefs_tq3_11.*coef_Jacob1_qt_syms28.*pinvG1_3+coefs_tq3_11.*coef_Jacob1_qt_syms29.*pinvG2_3+coefs_tq3_11.*coef_Jacob1_qt_syms30.*pinvG3_3,coef_Jacob2_qt_syms31+coefs_tq1_11.*coef_Jacob2_qt_syms28.*pinvG1_1+coefs_tq1_11.*coef_Jacob2_qt_syms29.*pinvG2_1+coefs_tq1_11.*coef_Jacob2_qt_syms30.*pinvG3_1+coefs_tq2_11.*coef_Jacob2_qt_syms28.*pinvG1_2+coefs_tq2_11.*coef_Jacob2_qt_syms29.*pinvG2_2+coefs_tq2_11.*coef_Jacob2_qt_syms30.*pinvG3_2+coefs_tq3_11.*coef_Jacob2_qt_syms28.*pinvG1_3+coefs_tq3_11.*coef_Jacob2_qt_syms29.*pinvG2_3+coefs_tq3_11.*coef_Jacob2_qt_syms30.*pinvG3_3,coef_Jacob3_qt_syms31+coefs_tq1_11.*coef_Jacob3_qt_syms28.*pinvG1_1+coefs_tq1_11.*coef_Jacob3_qt_syms29.*pinvG2_1+coefs_tq1_11.*coef_Jacob3_qt_syms30.*pinvG3_1+coefs_tq2_11.*coef_Jacob3_qt_syms28.*pinvG1_2+coefs_tq2_11.*coef_Jacob3_qt_syms29.*pinvG2_2+coefs_tq2_11.*coef_Jacob3_qt_syms30.*pinvG3_2+coefs_tq3_11.*coef_Jacob3_qt_syms28.*pinvG1_3+coefs_tq3_11.*coef_Jacob3_qt_syms29.*pinvG2_3+coefs_tq3_11.*coef_Jacob3_qt_syms30.*pinvG3_3,coef_Jacob4_qt_syms31+coefs_tq1_11.*coef_Jacob4_qt_syms28.*pinvG1_1+coefs_tq1_11.*coef_Jacob4_qt_syms29.*pinvG2_1+coefs_tq1_11.*coef_Jacob4_qt_syms30.*pinvG3_1+coefs_tq2_11.*coef_Jacob4_qt_syms28.*pinvG1_2+coefs_tq2_11.*coef_Jacob4_qt_syms29.*pinvG2_2+coefs_tq2_11.*coef_Jacob4_qt_syms30.*pinvG3_2+coefs_tq3_11.*coef_Jacob4_qt_syms28.*pinvG1_3+coefs_tq3_11.*coef_Jacob4_qt_syms29.*pinvG2_3+coefs_tq3_11.*coef_Jacob4_qt_syms30.*pinvG3_3,coef_Jacob1_qt_syms36+coefs_tq1_11.*coef_Jacob1_qt_syms33.*pinvG1_1+coefs_tq1_11.*coef_Jacob1_qt_syms34.*pinvG2_1+coefs_tq1_11.*coef_Jacob1_qt_syms35.*pinvG3_1+coefs_tq2_11.*coef_Jacob1_qt_syms33.*pinvG1_2+coefs_tq2_11.*coef_Jacob1_qt_syms34.*pinvG2_2+coefs_tq2_11.*coef_Jacob1_qt_syms35.*pinvG3_2+coefs_tq3_11.*coef_Jacob1_qt_syms33.*pinvG1_3+coefs_tq3_11.*coef_Jacob1_qt_syms34.*pinvG2_3+coefs_tq3_11.*coef_Jacob1_qt_syms35.*pinvG3_3,coef_Jacob2_qt_syms36+coefs_tq1_11.*coef_Jacob2_qt_syms33.*pinvG1_1+coefs_tq1_11.*coef_Jacob2_qt_syms34.*pinvG2_1+coefs_tq1_11.*coef_Jacob2_qt_syms35.*pinvG3_1+coefs_tq2_11.*coef_Jacob2_qt_syms33.*pinvG1_2+coefs_tq2_11.*coef_Jacob2_qt_syms34.*pinvG2_2+coefs_tq2_11.*coef_Jacob2_qt_syms35.*pinvG3_2+coefs_tq3_11.*coef_Jacob2_qt_syms33.*pinvG1_3+coefs_tq3_11.*coef_Jacob2_qt_syms34.*pinvG2_3+coefs_tq3_11.*coef_Jacob2_qt_syms35.*pinvG3_3,coef_Jacob3_qt_syms36+coefs_tq1_11.*coef_Jacob3_qt_syms33.*pinvG1_1+coefs_tq1_11.*coef_Jacob3_qt_syms34.*pinvG2_1+coefs_tq1_11.*coef_Jacob3_qt_syms35.*pinvG3_1+coefs_tq2_11.*coef_Jacob3_qt_syms33.*pinvG1_2+coefs_tq2_11.*coef_Jacob3_qt_syms34.*pinvG2_2+coefs_tq2_11.*coef_Jacob3_qt_syms35.*pinvG3_2+coefs_tq3_11.*coef_Jacob3_qt_syms33.*pinvG1_3+coefs_tq3_11.*coef_Jacob3_qt_syms34.*pinvG2_3+coefs_tq3_11.*coef_Jacob3_qt_syms35.*pinvG3_3,coef_Jacob4_qt_syms36+coefs_tq1_11.*coef_Jacob4_qt_syms33.*pinvG1_1+coefs_tq1_11.*coef_Jacob4_qt_syms34.*pinvG2_1+coefs_tq1_11.*coef_Jacob4_qt_syms35.*pinvG3_1+coefs_tq2_11.*coef_Jacob4_qt_syms33.*pinvG1_2+coefs_tq2_11.*coef_Jacob4_qt_syms34.*pinvG2_2+coefs_tq2_11.*coef_Jacob4_qt_syms35.*pinvG3_2+coefs_tq3_11.*coef_Jacob4_qt_syms33.*pinvG1_3+coefs_tq3_11.*coef_Jacob4_qt_syms34.*pinvG2_3+coefs_tq3_11.*coef_Jacob4_qt_syms35.*pinvG3_3],[4,4]);


function [modelUpdated,modelPruned,Ex_Rxns] = pruneModel(model,minGrowth, biomassRxn)
% This function prunes a model to its most compact subnetwork given some model
% constraints and a minimal growth rate by identifying and removing all blocked reactions.
%
% USAGE:
%
%    [modelUpdated, modelPruned, Ex_Rxns] = pruneModel(model, minGrowth, biomassRxn)
%
% INPUTS:
%    model:         model structure
%    minGrowth:     minimal Growth rate to be set on biomass reaction
%    biomassRxn:    biomass reaction name (default: 'biomass_reaction2')
%
% OUTPUTS:
%    modelUpdated:  same as input model but constraints on blocked reactions
%                   are set to be 0
%    modelPruned:   pruned model, where all blocked reactions are removed
%                   (attention this seems to cause issues with GPRs)
%    Ex_Rxns:       List of exchange reactions in pruned model
%
% .. Authors: - Ines Thiele, 02/2014
%             - Modified by Loic Marx, December 2018

if ~exist('biomassRxn','var')
    biomassRxn = checkObjective(model);
    biomassRxn = biomassRxn{1};
end

modelUpdated = model;
modelForPruning = model;
modelForPruning.lb(modelForPruning.lb < 0) = -1000;
modelForPruning.ub(modelForPruning.ub < 0) = 0; % in case  uptake is enforced
modelForPruning.ub(modelForPruning.ub > 0) = 1000;
modelForPruning.lb(modelForPruning.lb > 0) = 0; % in case  secretion is enforced
%set back biomass constraint
modelForPruning.lb(find(ismember(modelForPruning.rxns,biomassRxn)))=minGrowth;
epsilon =getCobraSolverParams('LP', 'feasTol')*100;
[modelForPruningPruned, BlockedRxns] = identifyBlockedRxns(modelForPruning,epsilon);
cnt =1;
for t=1:length(modelForPruningPruned.rxns)
    if  strfind(modelForPruningPruned.rxns{t}, 'EX_')
        Ex_Rxns(cnt,1) =modelForPruningPruned.rxns(t); %make exchange reaction list
        cnt=cnt+1;
    end
end

modelUpdated.lb(ismember(model.rxns,BlockedRxns.allRxns))=0;
modelUpdated.ub(ismember(model.rxns,BlockedRxns.allRxns))=0;

RxnsInModelMin = setdiff(model.rxns,BlockedRxns.allRxns); % all reactions that are not blocked
modelPruned = extractSubNetwork(model,RxnsInModelMin);


function [y,fs,h]=readcnx(filename,mode)
%READCNX  Read a .CNX format sound file [Y,FS,H]=(FILENAME)
%
% Inputs:
%           filename : character string containing filename (default extension .cnx)
%           mode:    't' = trim leading and trailing silences
%                    'h' = read header only
%             'd'    Look in data directory: voicebox('dir_data')
%
% Outputs:
%           y  : column vector containing waveform
%           fs : sample frequency
%           h  : parameter array:
%                h(1) = number of samples in file
%                h(2) = status: 0=good, 1=bad
%                h(3) = start sample number
%                h(4) = ending sample number
%                h(5) = speaker identification number
%                h(6) = speaker age group
%                h(7) = speaker sex: 0=male, 1=female
%                h(8) = ascii character
%                h(9) = repetition number
%
% This is the format of the BT Connex-S1 alphabet database
% Note: the decoding is not particularly robust and assumes
%       that all headers contain the same sequence of fields

%	   Copyright (C) Mike Brookes 1998
%      Version: $Id: readcnx.m,v 1.4 2007/05/04 07:01:39 dmb Exp $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   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 2 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 can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ix=[17 71; 18 0; 19 0; 10 0; 12 0; 13 77; 15 -1; 16 0; ];

if nargin<2  mode='0'; end
if any(mode=='d')
    filename=fullfile(voicebox('dir_data'),filename);
end
fid=fopen(filename,'rb','l');
if fid == -1
    fn=[filename,'.cnx'];
    fid=fopen(fn,'rb','l');
    if fid ~= -1 filename=fn; end
end
if fid == -1 error(sprintf('Can''t open %s for input',filename)); end
[hdr,n]=fread(fid,512,'uchar');
if n ~= 512 error(sprintf('Can''t read header from connex file %s',filename)); end
del=find(hdr(5:end)=='|')';
fs=sscanf(char(hdr(17:del(1)+3)),'%f');
h=zeros(size(ix,1),1);
for i=1:length(h)
    e=find(hdr(del(ix(i)-1)+5:del(ix(i))+3)=='=');
    if ix(i,2)
        h(i)=hdr(del(ix(i)-1)+e+5);
        if ix(i,2)>0
            h(i)=1-(h(i)==ix(i,2));
        end
    else
        h(i)=sscanf(char(hdr(del(ix(i)-1)+e+5:del(ix(i))+3)),'%d');
    end
end
if any(mode =='h')
    y=[];
elseif any(mode =='t')
    fseek(fid,2*h(2),0);
    [y,n]=fread(fid,h(3)-h(2)+1,'short');
    if n ~= h(3)-h(2)+1 error(sprintf('Error reading data from connex file %s',filename)); end
else
    y=fread(fid,inf,'short');
end
fseek(fid,0,1);
h=[ftell(fid)/2-256; h];
fclose(fid);


%Esto es el PURPOSE de la FUNCION que es sumar a + b
function [ c ] = funct1( a,b )
%FUNCT1 Summary of this function goes here
%   Detailed explanation goes here
%   Esta funcion suma a + b
c=a+b;
t=0:0.001:1;
plot(sin(t));
end


function varargout = process_timefreq( varargin )
% PROCESS_TIMEFREQ: Computes the time frequency decomposition of any signal in the database.
%
% USAGE:  sProcess = process_timefreq('GetDescription')
%           sInput = process_timefreq('Run',     sProcess, sInput)
%           TFmask = process_timefreq('GetEdgeEffectMask', Time, Freqs, tfOptions)

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

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription() %#ok<DEFNU>
    % Description the process
    sProcess.Comment     = 'Time-frequency (Morlet wavelets)';
    sProcess.Category    = 'Custom';
    sProcess.SubGroup    = 'Frequency';
    sProcess.Index       = 505;
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/Tutorials/TimeFrequency#Morlet_wavelets';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'data', 'results', 'matrix'};
    sProcess.OutputTypes = {'timefreq', 'timefreq', 'timefreq'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 1;
    % Options: Sensor types
    sProcess.options.sensortypes.Comment = 'Sensor types or names (empty=all): ';
    sProcess.options.sensortypes.Type    = 'text';
    sProcess.options.sensortypes.Value   = 'MEG, EEG';
    sProcess.options.sensortypes.InputTypes = {'data'};
    sProcess.options.sensortypes.Group   = 'input';
    % Options: Scouts
    sProcess.options.clusters.Comment = '';
    sProcess.options.clusters.Type    = 'scout_confirm';
    sProcess.options.clusters.Value   = {};
    sProcess.options.clusters.InputTypes = {'results'};
    sProcess.options.clusters.Group   = 'input';
    % Options: Scout function
    sProcess.options.scoutfunc.Comment    = {'Mean', 'Max', 'PCA', 'Std', 'All', 'Scout function:'};
    sProcess.options.scoutfunc.Type       = 'radio_line';
    sProcess.options.scoutfunc.Value      = 1;
    sProcess.options.scoutfunc.InputTypes = {'results'};
    sProcess.options.scoutfunc.Group   = 'input';
    % Options: Time-freq
    sProcess.options.edit.Comment = {'panel_timefreq_options', 'Morlet wavelet options: '};
    sProcess.options.edit.Type    = 'editpref';
    sProcess.options.edit.Value   = [];
    % Options: Normalize
    sProcess.options.normalize2020.Comment = 'Spectral flattening: Multiply output power values by frequency';
    sProcess.options.normalize2020.Type    = 'checkbox';
    sProcess.options.normalize2020.Value   = 0;
    % Old normalize option, for backwards compatibility.
    sProcess.options.normalize.Comment = {'None: Save non-standardized time-frequency maps', '1/f compensation: Multiply output values by frequency'; ...
                                          'none', 'multiply'};
    sProcess.options.normalize.Type    = 'radio_label';
    sProcess.options.normalize.Value   = 'none';
    sProcess.options.normalize.Hidden  = 1;
end

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

%% ===== RUN =====
function OutputFiles = Run(sProcess, sInputs) %#ok<DEFNU>
    % Initialize returned values
    OutputFiles = {};
    % Extract method name from the process name
    switch (func2str(sProcess.Function))
        case 'process_timefreq',      strProcess = 'morlet';
        case 'process_hilbert',       strProcess = 'hilbert';
        case 'process_fft',           strProcess = 'fft';
        case 'process_psd',           strProcess = 'psd';
        case 'process_sprint',        strProcess = 'sprint';
        case 'process_ft_mtmconvol',  strProcess = 'mtmconvol';
        otherwise,                    error('Unsupported process.');
    end
    % Get editable options (Edit... button)
    if isfield(sProcess.options, 'edit')
        tfOPTIONS = sProcess.options.edit.Value;
        % If user did not edit values: get default values
        if isempty(tfOPTIONS)
            [bstPanelNew, panelName] = panel_timefreq_options('CreatePanel', sProcess, sInputs);
            jPanel = gui_show(bstPanelNew, 'JavaWindow', panelName, 0, 0, 0);
            drawnow;
            tfOPTIONS = panel_timefreq_options('GetPanelContents');
            gui_hide(panelName);
        end
    % Else: get default options
    else
        tfOPTIONS = bst_timefreq();
        tfOPTIONS.Method = strProcess;
        switch tfOPTIONS.Method
            case 'fft',       tfOPTIONS.Comment = 'FFT';
            case 'psd',       tfOPTIONS.Comment = 'PSD';
            case 'sprint',    tfOPTIONS.Comment = 'SPRiNT';
            case 'morlet',    tfOPTIONS.Comment = 'Wavelet';
            case 'hilbert',   tfOPTIONS.Comment = 'Hilbert';
            case 'mtmconvol', tfOPTIONS.Comment = 'Multitaper';
        end
    end

    % Add other options
    tfOPTIONS.Method = strProcess;
    if isfield(sProcess.options, 'sensortypes')
        tfOPTIONS.SensorTypes = sProcess.options.sensortypes.Value;
    else
        tfOPTIONS.SensorTypes = [];
    end
    if isfield(sProcess.options, 'mirror') && ~isempty(sProcess.options.mirror) && ~isempty(sProcess.options.mirror.Value)
        tfOPTIONS.isMirror = sProcess.options.mirror.Value;
    else
        tfOPTIONS.isMirror = 0;
    end
    if isfield(sProcess.options, 'clusters') && ~isempty(sProcess.options.clusters) && ~isempty(sProcess.options.clusters.Value)
        tfOPTIONS.Clusters = sProcess.options.clusters.Value;
    else
        tfOPTIONS.Clusters = [];
    end
    % Override scouts function
    if isfield(sProcess.options, 'scoutfunc') && isfield(sProcess.options.scoutfunc, 'Value') && ~isempty(sProcess.options.scoutfunc.Value)
        switch lower(sProcess.options.scoutfunc.Value)
            case {1, 'mean'}, tfOPTIONS.ScoutFunc = 'mean';
            case {2, 'max'},  tfOPTIONS.ScoutFunc = 'max';
            case {3, 'pca'},  tfOPTIONS.ScoutFunc = 'pca';
            case {4, 'std'},  tfOPTIONS.ScoutFunc = 'std';
            case {5, 'all'},  tfOPTIONS.ScoutFunc = 'all';
            otherwise,  bst_report('Error', sProcess, [], 'Invalid scout function.');  return;
        end
    else
        tfOPTIONS.ScoutFunc = [];
    end
    % If a time window was specified
    if isfield(sProcess.options, 'timewindow') && ~isempty(sProcess.options.timewindow) && ~isempty(sProcess.options.timewindow.Value) && iscell(sProcess.options.timewindow.Value)
        tfOPTIONS.TimeWindow = sProcess.options.timewindow.Value{1};
    elseif ~isfield(tfOPTIONS, 'TimeWindow')
        tfOPTIONS.TimeWindow = [];
    end
    % If a window length was specified (PSD)
    if isfield(sProcess.options, 'win_length') && ~isempty(sProcess.options.win_length) && ~isempty(sProcess.options.win_length.Value) && iscell(sProcess.options.win_length.Value)
        tfOPTIONS.WinLength  = sProcess.options.win_length.Value{1};
        tfOPTIONS.WinOverlap = sProcess.options.win_overlap.Value{1};
    end
    if isfield(sProcess.options, 'win_std') && ~isempty(sProcess.options.win_std) && ~isempty(sProcess.options.win_std.Value)
        tfOPTIONS.WinStd = sProcess.options.win_std.Value;
        if tfOPTIONS.WinStd
            tfOPTIONS.Comment = [tfOPTIONS.Comment ' std'];
        end
    end
    % If units specified (PSD)
    if isfield(sProcess.options, 'units') && ~isempty(sProcess.options.units) && ~isempty(sProcess.options.units.Value)
        tfOPTIONS.PowerUnits = sProcess.options.units.Value;
    end
    % Multitaper options
    if isfield(sProcess.options, 'mt_taper') && ~isempty(sProcess.options.mt_taper) && ~isempty(sProcess.options.mt_taper.Value)
        if iscell(sProcess.options.mt_taper.Value)
            tfOPTIONS.ft_mtmconvol.taper = sProcess.options.mt_taper.Value{1};
        else
            tfOPTIONS.ft_mtmconvol.taper = sProcess.options.mt_taper.Value;
        end
    end
    if isfield(sProcess.options, 'mt_frequencies') && ~isempty(sProcess.options.mt_frequencies) && ~isempty(sProcess.options.mt_frequencies.Value)
        tfOPTIONS.ft_mtmconvol.frequencies = eval(sProcess.options.mt_frequencies.Value);
        % Add frequencies to comment
        tfOPTIONS.Comment = [tfOPTIONS.Comment, ' ', sProcess.options.mt_frequencies.Value, 'Hz'];
    end
    if isfield(sProcess.options, 'mt_freqmod') && ~isempty(sProcess.options.mt_freqmod) && ~isempty(sProcess.options.mt_freqmod.Value)
        tfOPTIONS.ft_mtmconvol.freqmod = sProcess.options.mt_freqmod.Value{1};
    end
    if isfield(sProcess.options, 'mt_timeres') && ~isempty(sProcess.options.mt_timeres) && ~isempty(sProcess.options.mt_timeres.Value)
        tfOPTIONS.ft_mtmconvol.timeres = sProcess.options.mt_timeres.Value{1};
    end
    if isfield(sProcess.options, 'mt_timestep') && ~isempty(sProcess.options.mt_timestep) && ~isempty(sProcess.options.mt_timestep.Value)
        tfOPTIONS.ft_mtmconvol.timestep = sProcess.options.mt_timestep.Value{1};
    end
    if isfield(sProcess.options, 'measure') && ~isempty(sProcess.options.measure) && ~isempty(sProcess.options.measure.Value)
        tfOPTIONS.Measure = sProcess.options.measure.Value;
        % Add measure to comment
        if strcmpi(tfOPTIONS.Measure, 'none')
            strMeasure = 'complex';
        else
            strMeasure = tfOPTIONS.Measure;
        end
        tfOPTIONS.Comment = [tfOPTIONS.Comment, ' ', strMeasure];
    end
    % if process is SPRiNT
    if isfield(sProcess.options, 'fooof')
       tfOPTIONS.SPRiNTopts = sProcess.options;
    end
    % Output
    if isfield(sProcess.options, 'avgoutput') && ~isempty(sProcess.options.avgoutput) && ~isempty(sProcess.options.avgoutput.Value)
        if sProcess.options.avgoutput.Value
            tfOPTIONS.Output = 'average';
        else
            tfOPTIONS.Output = 'all';
        end
    end
    % Frequency normalization
    if isfield(sProcess.options, 'normalize2020') && ~isempty(sProcess.options.normalize2020)
        if isequal(sProcess.options.normalize2020.Value, 1)
            tfOPTIONS.NormalizeFunc = 'multiply2020';
        elseif ischar(sProcess.options.normalize2020.Value)
            tfOPTIONS.NormalizeFunc = sProcess.options.normalize2020.Value;
        end
    elseif isfield(sProcess.options, 'normalize') && ~isempty(sProcess.options.normalize)
        if isequal(sProcess.options.normalize.Value, 1)
            tfOPTIONS.NormalizeFunc = 'multiply';
        elseif ischar(sProcess.options.normalize.Value)
            tfOPTIONS.NormalizeFunc = sProcess.options.normalize.Value;
        end
    else
        tfOPTIONS.NormalizeFunc = 'none';
    end

    % === EXTRACT CLUSTER/SCOUTS ===
    if ~isempty(tfOPTIONS.Clusters)
        % If cluster function should be applied AFTER time-freq: get all time series
        if strcmpi(tfOPTIONS.ClusterFuncTime, 'after')
            ExtractScoutFunc = 'all';
        else
            ExtractScoutFunc = tfOPTIONS.ScoutFunc;
        end
        AddRowComment = ~isempty(tfOPTIONS.ScoutFunc) && strcmpi(tfOPTIONS.ScoutFunc, 'all');
        % Flip sign only for results
        isflip = strcmpi(sInputs(1).FileType, 'results');
        % Call process
        ClustMat = bst_process('CallProcess', 'process_extract_scout', sInputs, [], ...
            'timewindow',     tfOPTIONS.TimeWindow, ...
            'scouts',         tfOPTIONS.Clusters, ...
            'scoutfunc',      ExtractScoutFunc, ...  % If ScoutFunc is not defined, use the scout function available in each scout
            'isflip',         isflip, ...
            'isnorm',         0, ...
            'concatenate',    0, ...
            'save',           0, ...
            'addrowcomment',  AddRowComment, ...
            'addfilecomment', 0, ...
            'progressbar',    0);
        if isempty(ClustMat)
            bst_report('Error', sProcess, sInputs, 'Cannot access clusters/scouts time series.');
            return;
        end
        % Get data to process
        DataToProcess = {ClustMat.Value};
        tfOPTIONS.TimeVector  = ClustMat(1).Time;
        tfOPTIONS.ListFiles   = {sInputs.FileName};
        tfOPTIONS.nComponents = [ClustMat.nComponents];
        tfOPTIONS.RowNames    = {};
        tfOPTIONS.SurfaceFile = {ClustMat.SurfaceFile};
        for iFile = 1:length(ClustMat)
             tfOPTIONS.RowNames{iFile} = ClustMat(iFile).Description;
        end
        clear ClustMat;
    % === DATA FILES ===
    else
        DataToProcess = {sInputs.FileName};
        tfOPTIONS.TimeVector = in_bst(sInputs(1).FileName, 'Time');
    end

    % === OUTPUT STUDY ===
    if strcmpi(tfOPTIONS.Output, 'average')
        % Get output study
        [sStudy, iStudy, Comment] = bst_process('GetOutputStudy', sProcess, sInputs);
        % If no valid output study can be found
        if isempty(iStudy)
            return;
        end
        % Save all outputs from bst_timefreq in target Study
        tfOPTIONS.iTargetStudy = iStudy;
    else
        tfOPTIONS.iTargetStudy = [];
    end

    % === START COMPUTATION ===
    [OutputFiles, Messages, isError] = bst_timefreq(DataToProcess, tfOPTIONS);
    if ~isempty(Messages)
        if isError
            bst_report('Error', sProcess, sInputs, Messages);
        elseif isempty(OutputFiles)
            bst_report('Warning', sProcess, sInputs, Messages);
        else
            bst_report('Info', sProcess, sInputs, Messages);
            disp(['BST> process_timefreq: ' Messages]);
        end
    end
end

%% ===== GET EDGE EFFECT MASK =====
function TFmask = GetEdgeEffectMask(Time, Freqs, tfOptions) %#ok<DEFNU>
    % Get time vector
    if ~iscell(Time)
        t = Time;
    else
        t = mean(cell2mat(Time(:,2:3)), 2)';
    end
    % Get frequency vector
    if ~iscell(Freqs)
        f = Freqs;
    else
        FreqBands = process_tf_bands('GetBounds', Freqs);
        f = mean(FreqBands, 2)';
    end

    % Morlet wavelets
    if isfield(tfOptions, 'Method') && strcmpi(tfOptions.Method, 'morlet') && isfield(tfOptions, 'MorletFc') && isfield(tfOptions, 'MorletFwhmTc')
        FWHM_t = tfOptions.MorletFwhmTc * tfOptions.MorletFc ./ f;
        TF_timeres = repmat(FWHM_t' ./ 2, [1,length(t)]);
        TFmask = (bst_bsxfun(@minus, t - t(1), TF_timeres) > 0);
        TFmask = (TFmask & bst_flip(TFmask, 2));

    % Hilbert transform
    elseif isfield(tfOptions, 'Method') && strcmpi(tfOptions.Method, 'hilbert')
        if iscell(Time)
            disp('BST> Edge effects map for Hilbert process is not available yet when time bands are selected.');
            TFmask = [];
        else
            % Sampling frequency
            sfreq = 1 ./ (t(2) - t(1));
            % Compute the transients for each bandpass filter
            TFmask = zeros(size(Freqs,1), length(t));
            for i = 1:size(Freqs,1)
                % Compute the filter specifications
                [tmp, FiltSpec] = process_bandpass('Compute', [], sfreq, FreqBands(i,1), FreqBands(i,2), 'bst-hfilter-2019');
                % Only the values outside of the transients are valid
                TFmask(i,(t - t(1) > FiltSpec.transient) & (t(end) - t > FiltSpec.transient)) = 1;
            end
        end
    else
        TFmask = [];
    end
end


function coast = ma_createNBodyCoast(name, coastType, coastToValue, revs, refBody, vars, soiSkipIds, lineColor, lineStyle, lineWidth, massLoss, forceModel, maxPropTime)
%ma_createNBodyCoast Summary of this function goes here
%   Detailed explanation goes here

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Valid coast type strings:
    % goto_ut        - goes to a specific Universal Time
    % goto_dt        - goes to a specific delta-time from the input state
    % goto_tru       - goes to a specific true anomaly
    % goto_apo       - goes to the next apogee
    % goto_peri      - goes to the next perigee
    % goto_asc_node  - goes to ascending node
    % goto_desc_node - goes to the descending node (asc node + pi)
    % goto_soi_trans - goes to the next SOI transition
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    coast = struct();
    coast.name          = name;
    coast.type          = 'NBodyCoast';
    coast.coastType     = coastType;
    coast.coastToValue  = coastToValue;
    coast.revs          = revs;
    coast.refBody       = refBody;
    coast.id            = rand(1);
    coast.vars          = vars;
    coast.soiSkipIds    = soiSkipIds;
    coast.forceModel    = forceModel;
    coast.lineColor     = lineColor;
    coast.lineStyle     = lineStyle;
    coast.lineWidth     = lineWidth;
    coast.massloss      = massLoss;
    coast.maxPropTime   = maxPropTime;
end