%PNMTEST Test program for the PNM Toolbox.
%   PNMTEST is a test program for the PNM Toolbox. It is not really
%   intended for end users. It checks the most important read/write
%   functionality to see if the PNM Toolbox behaves as expected.
%
%   See also PNMDEMO.

%   Author:      Peter J. Acklam
%   Time-stamp:  1998-05-11 17:15:29
%   E-mail:      jacklam@math.uio.no (Internet)
%   URL:         http://www.math.uio.no/~jacklam

more off;
echo on;
home; clc;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% PPM test
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% Read PPM image as an RGB image.
%

[ r, g, b ] = ppmread( 'logo5' );

%pause

%
% Simplify color map and display image to see if it appears to be OK.
%

[ x, map ] = im2ind( r, g, b );

figure( gcf ); clf;
colormap( map ); image( x ); axis image;

pause

%
% Write an ascii and a binary encoded version from indexed data.
%

ppmwrite( x, map, 'logo5_asc', 'ascii' );
ppmwrite( x, map, 'logo5_bin', 'binary' );

%pause

%
% Read them as indexed images and compare them.
%

[ x1, map1 ] = ppmread( 'logo5_asc' );
[ x2, map2 ] = ppmread( 'logo5_bin' );

if any( any( map1(x1(:),:) ) ~= any( map2(x2(:),:) ) )
   error( 'Test failed.' );
end

%pause

%
% Read them as RGB images and compare them.
%

[ r1, g1, b1 ] = ppmread( 'logo5_asc' );
[ r2, g2, b2 ] = ppmread( 'logo5_bin' );

if any( r1(:) ~= r2(:) ) | any( g1(:) ~= g2(:) ) | any( b1(:) ~= b2(:) )
   error( 'Test failed.' );
end

%pause

%
% The indexed and RGB images should be identical.
%

if any( any( map1(x1(:),:) ~= [ r(:) g(:) b(:) ] ) )
   error( 'Test failed.' );
end

%pause

%
% Write an ascii and a binary encoded version from RGB data.
%

ppmwrite( r, g, b, 'logo5_asc', 'ascii' );
ppmwrite( r, g, b, 'logo5_bin', 'binary' );

%pause

%
% Read them as indexed images and compare them.
%

[ x1, map1 ] = ppmread( 'logo5_asc' );
[ x2, map2 ] = ppmread( 'logo5_bin' );

if any( any( map1(x1(:),:) ~= map2(x2(:),:) ) )
   error( 'Test failed.' );
end

%pause

%
% Read them as RGB images and compare them.
%

[ r1, g1, b1 ] = ppmread( 'logo5_asc' );
[ r2, g2, b2 ] = ppmread( 'logo5_bin' );

if any( r1(:) ~= r2(:) ) | any( g1(:) ~= g2(:) ) | any( b1(:) ~= b2(:) )
   error( 'Test failed.' );
end

%pause

%
% The indexed and RGB images should be identical.
%

if any( any( map1(x1(:),:) ~= [ r(:) g(:) b(:) ] ) )
   error( 'Test failed.' );
end

%pause

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% PGM test
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

pgmwrite( x, map, 'logo5', 'binary' );
i = pgmread( 'logo5' );

%pause

%
% Simplify color map and display image to see if it appears to be OK.
%

[ x, map ] = im2ind( i );

figure( gcf ); clf;
colormap( map ); image( x ); axis image;

pause

%
% Write an ascii and a binary encoded version from indexed data.
%

pgmwrite( x, map, 'logo5_asc', 'ascii' );
pgmwrite( x, map, 'logo5_bin', 'binary' );

%pause

%
% Read them as indexed images and compare them.
%

[ x1, map1 ] = pgmread( 'logo5_asc' );
[ x2, map2 ] = pgmread( 'logo5_bin' );

if any( any( map1(x1(:),:) ~= map2(x2(:),:) ) )
   error( 'Test failed.' );
end

%pause

%
% Read them as intensity images and compare them.
%

i1 = pgmread( 'logo5_asc' );
i2 = pgmread( 'logo5_bin' );

if any( i1(:) ~= i2(:) )
   error( 'Test failed.' );
end

%pause

%
% The indexed and intensity images should be identical.
%

if any( any( map1(x1(:),:) ~= [ i(:) i(:) i(:) ] ) )
   error( 'Test failed.' );
end

%pause

%
% Write an ascii and a binary encoded version from intensity data.
%

pgmwrite( i, 'logo5_asc', 'ascii' );
pgmwrite( i, 'logo5_bin', 'binary' );

%pause

%
% Read them as indexed images and compare them.
%

[ x1, map1 ] = pgmread( 'logo5_asc' );
[ x2, map2 ] = pgmread( 'logo5_bin' );

if any( any( map1(x1(:),:) ~= map2(x2(:),:) ) )
   error( 'Test failed.' );
end

%pause

%
% Read them as intensity images and compare them.
%

i1 = pgmread( 'logo5_asc' );
i2 = pgmread( 'logo5_bin' );

if any( i1(:) ~= i2(:) )
   error( 'Test failed.' );
end

%pause

%
% The indexed and intensity images should be identical.
%

if any( any( map1(x1(:),:) ~= [ i(:) i(:) i(:) ] ) )
   error( 'Test failed.' );
end

%pause

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% PBM test
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

pbmwrite( x, map, 'logo5', 'binary' );
i = pbmread( 'logo5' );

%pause

%
% Simplify color map and display image to see if it appears to be OK.
%

[ x, map ] = im2ind( i );

figure( gcf ); clf;
colormap( map ); image( x ); axis image;

pause

%
% Write an ascii and a binary encoded version from indexed data.
%

pbmwrite( x, map, 'logo5_asc', 'ascii' );
pbmwrite( x, map, 'logo5_bin', 'binary' );

%pause

%
% Read them as indexed images and compare them.
%

[ x1, map1 ] = pbmread( 'logo5_asc' );
[ x2, map2 ] = pbmread( 'logo5_bin' );

if any( any( map1(x1(:),:) ~= map2(x2(:),:) ) )
   error( 'Test failed.' );
end

%pause

%
% Read them as intensity images and compare them.
%

i1 = pbmread( 'logo5_asc' );
i2 = pbmread( 'logo5_bin' );

if any( i1(:) ~= i2(:) )
   error( 'Test failed.' );
end

%pause

%
% The indexed and intensity images should be identical.
%

if any( any( map1(x1(:),:) ~= [ i(:) i(:) i(:) ] ) )
   error( 'Test failed.' );
end

%pause

%
% Write an ascii and a binary encoded version from intensity data.
%

pbmwrite( i, 'logo5_asc', 'ascii' );
pbmwrite( i, 'logo5_bin', 'binary' );

%pause

%
% Read them as indexed images and compare them.
%

[ x1, map1 ] = pbmread( 'logo5_asc' );
[ x2, map2 ] = pbmread( 'logo5_bin' );

if any( any( map1(x1(:),:) ~= map2(x2(:),:) ) )
   error( 'Test failed.' );
end

%pause

%
% Read them as intensity images and compare them.
%

i1 = pbmread( 'logo5_asc' );
i2 = pbmread( 'logo5_bin' );

if any( i1(:) ~= i2(:) )
   error( 'Test failed.' );
end

%pause

%
% The indexed and intensity images should be identical.
%

if any( any( map1(x1(:),:) ~= [ i(:) i(:) i(:) ] ) )
   error( 'Test failed.' );
end

%pause

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Miscellaneous testing.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% PPMREAD should be able to read a PGM image as an indexed image.
%

[ x1, map1 ] = ppmread( 'logo5_bin.pgm' );
[ x2, map2 ] = pgmread( 'logo5_bin.pgm' );

if any( x1(:) ~= x2(:) ) | any( map1(:) ~= map2(:) )
   error( 'Test failed.' );
end

%
% PPMREAD should be able to read a PGM image as RGB image.
%

[ r, g, b ] = ppmread( 'logo5_bin.pgm' );
i           = pgmread( 'logo5_bin.pgm' );

if any( r(:) ~= i(:) ) | any( g(:) ~= i(:) ) | any( b(:) ~= i(:) )
   error( 'Test failed.' );
end

%
% PPMREAD should be able to read a PBM image as indexed image.
%

[ x1, map1 ] = ppmread( 'logo5_bin.pbm' );
[ x2, map2 ] = pbmread( 'logo5_bin.pbm' );

if any( x1(:) ~= x2(:) ) | any( map1(:) ~= map2(:) )
   error( 'Test failed.' );
end

%
% PPMREAD should be able to read a PBM image as an RGB image.
%

[ r, g, b ] = ppmread( 'logo5_bin.pbm' );
i           = pbmread( 'logo5_bin.pbm' );

if any( r(:) ~= i(:) ) | any( g(:) ~= i(:) ) | any( b(:) ~= i(:) )
   error( 'Test failed.' );
end

%
% PGMREAD should be able to read a PBM image as an indexed image.
%

[ x1, map1 ] = pgmread( 'logo5_bin.pbm' );
[ x2, map2 ] = pbmread( 'logo5_bin.pbm' );

if any( x1(:) ~= x2(:) ) | any( map1(:) ~= map2(:) )
   error( 'Test failed.' );
end

%
% PGMREAD should be able to read PBM a image as an intensity image.
%

i1 = pgmread( 'logo5_bin.pbm' );
i2 = pbmread( 'logo5_bin.pbm' );

if any( i1(:) ~= i2(:) )
   error( 'Test failed.' );
end

%
% That should be all for now, so clean up.
%

delete logo5.pgm logo5.pbm
delete logo5_asc.ppm logo5_asc.pgm logo5_asc.pbm
delete logo5_bin.ppm logo5_bin.pgm logo5_bin.pbm

echo off

fprintf( '\nPassed all tests.\n\n' );


function [cov] = mne_read_noise_cov(fname)
%
% [cov] = mne_read_noise_cov(fname)
%
% Reads a noise-covariance matrix from a fiff file
%
% fname      - The name of the file
%
%

%
%
%   Author : Matti Hamalainen, MGH Martinos Center
%   License : BSD 3-clause
%
%   Revision 1.5  2006/05/03 19:09:03  msh
%   Fixed even more compatibility issues.
%
%   Revision 1.4  2006/04/23 15:29:41  msh
%   Added MGH to the copyright
%
%   Revision 1.3  2006/04/20 21:49:38  msh
%   Added mne_read_inverse_operator
%   Changed some of the routines accordingly for more flexibility.
%
%   Revision 1.2  2006/04/18 20:44:46  msh
%   Added reading of forward solution.
%   Use length instead of size when appropriate
%
%   Revision 1.1  2006/04/12 17:09:28  msh
%   Added routines for reading noise-covariance matrices
%
%

me='MNE:mne_read_noise_cov';

global FIFF;
if isempty(FIFF)
   FIFF = fiff_define_constants();
end
%
%   Open the file, create directory
%
[ fid, tree ] = fiff_open(fname);
try
   cov = mne_read_cov(fid,tree,FIFF.FIFFV_MNE_NOISE_COV);
catch
   fclose(fid);
   error(me,'%s',mne_omit_first_line(lasterr));
end

return;

end


function Prepare_data_combined_all()

    % Read in in-the-wild data and Multi-PIE data and concatenate them
    root = '../prepared_data/';
    Collect_combined_data(root, '0.25');
    Collect_combined_data(root, '0.35');
    Collect_combined_data(root, '0.5');
    Collect_combined_data(root, '1');
end

function Collect_combined_data(root, scale)

    wild_locs = dir(sprintf('%s/wild_%s*.mat', root, scale));
    mpie_locs = dir(sprintf('%s/mpie_%s*.mat', root, scale));

    % For a particular loaded m_pie check if an appropriate in-the-wild
    % exists
    for i=1:numel(mpie_locs)

        load([root, mpie_locs(i).name]);

        imgs_used_pie = actual_imgs_used;
        samples_pie = all_images;
        centres_pie = centres;
        landmark_locations_pie = landmark_locations;

        wild_to_use = -1;
        for j=1:numel(wild_locs)
            load([root, wild_locs(j).name], 'centres');
            if(isequal(centres_pie, centres))
                wild_to_use = j;
            end
        end

        % Reset the centres
        centres = centres_pie;

        if(wild_to_use ~= -1)
            load([root, wild_locs(wild_to_use).name]);
            actual_imgs_used = cat(1, actual_imgs_used, imgs_used_pie);
            all_images = cat(1, all_images, samples_pie);
            landmark_locations = cat(1, landmark_locations, landmark_locations_pie);
        end

        save(sprintf('%s/combined_%s_%d.mat', root, scale, i), 'actual_imgs_used', 'all_images', 'centres', 'landmark_locations', 'training_scale', 'visiIndex');
    end

end


function h = prtPlotUtilScatter(cX)
% Internal function PRT function

nPlotDimensions = size(cX,2);
if nPlotDimensions < 1
    warning('prt:prtPlotUtilScatter:NoPlotDimensionality','No plot dimensions requested.');
    return
end
if nPlotDimensions > 3
    error('prt:prtPlotUtilScatter:plotDimensionality','The number of requested plot dimensions (%d) is greater than 3.',nPlotDimensions);
end

switch nPlotDimensions
    case 1
        h = scatter(cX, ones(size(cX)));
    case 2
        h = scatter(cX(:,1), cX(:,2));
    case 3
        h = scatter3(cX(:,1), cX(:,2), cX(:,3));
end


function orientation = histogramOrientation(hist_data)

%initialize output
orientation = [];

try
    %check to see if patch is in the shape of "vertical" rectangles :)
    if  size(hist_data.XData,1)==4  && size(hist_data.XData, 2) > 1 && ...
            all(hist_data.XData(1,:)==hist_data.XData(2,:)) && ...
            all(hist_data.XData(3,:)==hist_data.XData(4,:)) && ...
            all(hist_data.YData(1,:)==hist_data.YData(4,:)) && ...
            all(hist_data.YData(2,:)==hist_data.YData(3,:));
        orientation = 'v';
        %check to see if patch is in the shape of "horizontal" rectangles :)
    elseif size(hist_data.YData,1)==4 && size(hist_data.YData, 2) > 1 && ...
            all(hist_data.YData(1,:)==hist_data.YData(2,:)) && ...
            all(hist_data.YData(3,:)==hist_data.YData(4,:)) && ...
            all(hist_data.XData(1,:)==hist_data.XData(4,:)) && ...
            all(hist_data.XData(2,:)==hist_data.XData(3,:));
        orientation = 'h';
    end
end


function G=GradSymbolic(p)
%create gradient profile

global VMgd

% Initialize parameters
GradLine=p.GradLine;
GradXEqu=p.GradXEqu;
GradYEqu=p.GradYEqu;
GradZEqu=p.GradZEqu;

% Initialize display grid
X=VMgd.xgrid;
Y=VMgd.ygrid;
Z=VMgd.zgrid;

try
    eval(['G(:,:,:,1)=' GradXEqu ';']);
    eval(['G(:,:,:,2)=' GradYEqu ';']);
    eval(['G(:,:,:,3)=' GradZEqu ';']);
catch me
    G = zeros(size(VMgd.xgrid));
    error_msg{1,1}='ERROR!!! Creating gradient profile using symbolic equation fails!';
    error_msg{2,1}=me.message;
    errordlg(error_msg);
end

end


function frst=show_progress(cnt,ttl,frst);

persistent hit

%Initialise hit only when it is first declared as an empty array
if frst==0
    hit=zeros(20,1);
    fprintf('10%% 20%% 30%% 40%% 50%% 60%% 70%% 80%% 90%% 100%%\n');
end

prp=cnt/ttl;
if prp>=0.05 & hit(1)==0
    fprintf('||');
    hit(1)=1;
elseif prp>=0.1 & hit(2)==0
    fprintf('||');
    hit(2)=1;
elseif prp>=0.15 & hit(3)==0
    fprintf('||');
    hit(3)=1;
elseif prp>=0.2 & hit(4)==0
    fprintf('||');
    hit(4)=1;
elseif prp>=0.25 & hit(5)==0
    fprintf('||');
    hit(5)=1;
elseif prp>=0.3 & hit(6)==0
    fprintf('||');
    hit(6)=1;
elseif prp>=0.35 & hit(7)==0
    fprintf('||');
    hit(7)=1;
elseif prp>=0.4 & hit(8)==0
    fprintf('||');
    hit(8)=1;
elseif prp>=0.45 & hit(9)==0
    fprintf('||');
    hit(9)=1;
elseif prp>=0.5 & hit(10)==0
    fprintf('||');
    hit(10)=1;
elseif prp>=0.55 & hit(11)==0
    fprintf('||');
    hit(11)=1;
elseif prp>=0.6 & hit(12)==0
    fprintf('||');
    hit(12)=1;
elseif prp>=0.65 & hit(13)==0
    fprintf('||');
    hit(13)=1;
elseif prp>=0.7 & hit(14)==0
    fprintf('||');
    hit(14)=1;
elseif prp>=0.75 & hit(15)==0
    fprintf('||');
    hit(15)=1;
elseif prp>=0.8 & hit(16)==0
    fprintf('||');
    hit(16)=1;
elseif prp>=0.85 & hit(17)==0
    fprintf('||');
    hit(17)=1;
elseif prp>=0.9 & hit(18)==0
    fprintf('||');
    hit(18)=1;
elseif prp>=0.95 & hit(19)==0
    fprintf('||');
    hit(19)=1;
elseif prp>=0.99 & hit(20)==0
    fprintf('||\n');
    hit(20)=1;
end

frst=1;


function x = sparsify( x, mode )

global cvx___
narginchk(2,2);
persistent remap

%
% Check mode argument
%

if ~ischar( mode ) || size( mode, 1 ) ~= 1,
    error( 'Second arugment must be a string.' );
end
isobj = strcmp( mode, 'objective' );

pr = cvx___.problems( end );
touch( pr.self, x );
bz = x.basis_ ~= 0;
bs = sum( bz, 1 );
bc = bz( 1, : );
tt = bs > bc + 1;
at = any( tt );
if at,

    %
    % Replace posynomials with log-convex monomials --- that is, unless
    % we are taking the exponential of one. (Not that I know why we
    % would do that!) In that case, we should just use a standard
    % linear replacement and leave it at that.
    %

    if ~isequal( mode, 'exponential' ),
        if isempty( remap ),
            remap = cvx_remap( 'posynomial' );
        end
        t2 = remap( cvx_classify( x ) );
        if any( t2 ),
            if all( t2 ),
                x = exp( log( x ) );
            else
                x = cvx_subsasgn( x, t2, exp( log( cvx_subsref( x, t2 ) ) ) );
            end
            bc( t2 ) = 0;
            tt = tt & ~t2;
            at = any( tt );
        end
    end

    %
    % Replace other multivariable forms with single-variable forms
    %

    if at,
        abc = any( bc( :, tt ) );
        if abc,
            xc = cvx_constant( x );
            x = x - xc;
        end
        forms = cvx___.linforms;
        repls = cvx___.linrepls;
        [ x, forms, repls ] = replcols( x, tt, 'full', forms, repls, isobj );
        cvx___.linforms = forms;
        cvx___.linrepls = repls;
        if abc,
            x = x + xc;
        end
    end

end

%
% Arguments: no constraints on coefficients or constant values
% Objectives:     all replaced with coefficient > 0, constant terms preserved
% Exponentiation: coefficient == 1, constant terms perserved
% Logarithm:      coefficient >  0, constant terms eliminated
%

switch mode,
    case { 'argument', 'constraint' },
        tt = false;
    case 'objective',
        tt = ~tt | sum( x.basis_, 1 ) < x.basis_( 1, : );
        usexc = true;
    case 'logarithm',
        tt = sum( x.basis_, 1 ) < x.basis_( 1, : );
        usexc = false;
    case 'exponential';
        tt = sum( x.basis_, 1 ) ~= x.basis_( 1, : ) + 1;
        usexc = true;
    otherwise,
        error( [ 'Invalid normalization mode: ', mode ] );
end
if any( tt ),
    if usexc,
        abc = any( bc );
        if abc,
            xc = cvx_constant( x );
            x = x - xc;
        end
    else
        abc = false;
    end
    forms = cvx___.uniforms;
    repls = cvx___.unirepls;
    [ x, forms, repls ] = replcols( x, tt, 'none', forms, repls, isobj );
    cvx___.uniforms = forms;
    cvx___.unirepls = repls;
    if abc,
        x = x + xc;
    end
end

function [ x, forms, repls ] = replcols( x, tt, mode, forms, repls, isobj )

%
% Sift through the forms, removing duplicates
%

global cvx___
bN = vec( cvx_subsref( x, tt ) );
nO = length( forms );
nN = length( bN );
if nO ~= 0,
    bN = [ forms ; bN ];
end
[ bNR, bN ] = bcompress( bN, mode, nO );
bNR = bNR( :, nO + 1 : end );
nB = length( bN ) - nO;

%
% Create the replacement variables
%

if nB ~= 0,
    forms   = bN;
    bN      = cvx_subsref( bN, nO + 1 : nO + nB, 1 );
    newrepl = newvar( cvx___.problems( end ).self, '', nB );
    [ ndxs, temp ] = find( newrepl.basis_ ); %#ok
    repls = [ repls ; newrepl ];
    bV = cvx_vexity( bN );
    cvx___.vexity( ndxs ) = bV;
    cvx___.readonly( ndxs ) = vec( cvx_readlevel( bN ) );
    if ~isobj,
        ss = bV == 0;
        if any( ss ),
            temp = cvx_basis( bN );
            temp = any( temp( :, ss ), 2 );
            temp( ndxs( ss ) ) = true;
            cvx___.canslack( temp ) = false;
        end
    end
end

%
% Re-expand the structure
%

x = cvx_subsasgn( x, tt, buncompress( bNR, repls, nN ) );

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


classdef globalICP < handle
    % GLOBALICP Class for global ICP problems.

    properties

        % Corresponding points
        CP

        % Point clouds
        PC

        % Path to folder for output data
        OutputFolder

        % Path to folder for temporary data
        TempFolder

        % Various data
        D

    end

    methods

        function obj = globalICP(varargin)
        % GLOBALICP Constructor method for global ICP class.
        % ----------------------------------------------------------------------
        % DESCRIPTION/NOTES
        % With the globalICP class the alignment of two or more point clouds can
        % be refined. A prerequisite for this is an approximate alignment of the
        % point clouds.
        % ----------------------------------------------------------------------
        % INPUT
        % 1 ['OutputFolder', OutputFolder]
        %   Path to directory in which output files are stored. If this option
        %   is omitted, the path given by the command 'cd' is used as directory.
        %
        % 2 ['TempFolder', TempFolder]
        %   Folder in which temporary files are saved, e.g. imported point
        %   clouds. If this option is omitted, the path given by the command
        %   'tempdir' is used as directory.
        % ----------------------------------------------------------------------
        % OUTPUT
        % [obj]
        % Object instance of class globalICP.
        % ----------------------------------------------------------------------
        % EXAMPLES
        % 1 Minimal working example with 6 point clouds.
        %
        %   % Create globalICP object
        %   icp = globalICP('OutputFolder', 'D:\temp');
        %
        %   % Add point clouds to object from plain text files
        %   % (Added point clouds are saved as mat files, e.g. LionScan1Approx.mat)
        %   icp.addPC('LionScan1Approx.xyz');
        %   icp.addPC('LionScan2Approx.xyz');
        %   icp.addPC('LionScan3Approx.xyz');
        %   icp.addPC('LionScan4Approx.xyz');
        %   icp.addPC('LionScan5Approx.xyz');
        %   icp.addPC('LionScan6Approx.xyz');
        %
        %   % Plot all point clouds BEFORE ICP (each in a different random color)
        %   figure; icp.plot('Color', 'random');
        %   title('BEFORE ICP'); view(0,0);
        %
        %   % Run ICP!
        %   icp.runICP('PlaneSearchRadius', 2);
        %
        %   % Plot all point clouds AFTER ICP
        %   figure; icp.plot('Color', 'random');
        %   title('AFTER ICP'); view(0,0);
        %
        % 2 Continued: Demo of the methods 'loadPC' and 'exportPC'.
        %
        %   % Load fifth point cloud to workspace and plot
        %   pc = icp.loadPC(5);
        %   figure; pc.plot;
        %
        %   % Export final point clouds
        %   icp.exportPC(1, 'LionScan1.xyz');
        %   icp.exportPC(2, 'LionScan2.xyz');
        %   icp.exportPC(3, 'LionScan3.xyz');
        %   icp.exportPC(4, 'LionScan4.xyz');
        %   icp.exportPC(5, 'LionScan5.xyz');
        %   icp.exportPC(6, 'LionScan6.xyz');
        % ----------------------------------------------------------------------
        % philipp.glira@gmail.com
        % ----------------------------------------------------------------------

        % Input parsing --------------------------------------------------------

        p = inputParser;
        p.addParameter('OutputFolder', cd     , @ischar);
        p.addParameter('TempFolder'  , tempdir, @ischar);
        p.parse(varargin{:});
        p = p.Results;

        % Directories ----------------------------------------------------------

        if ~exist(p.OutputFolder, 'dir'), mkdir(p.OutputFolder), end
        obj.OutputFolder = p.OutputFolder;

        if ~exist(p.TempFolder, 'dir'), mkdir(p.TempFolder), end
        obj.TempFolder = p.TempFolder;

        end

    end

end


%% -- mat2PDB.m --
%
% this function creates a PDB from coordinate data. Represent all inputs as
% a structure field for it to be read. The output format is as given in
% online documentation (as of July 2012 when writing this program)
% http://www.wwpdb.org/documentation/format33/sect9.html#ATOM
%
% Make sure all data input is one-dimensional with the same length. If
% they are not the same length, the program ignores user input, states
% an error, and uses defaults. All string inputs should be in cell-format.
% Keep in mind the "element" and "charge" inputs are strings in
% cell-format, not numbers.
%
%
% -- required inputs (3) --
%
% input value        meaning
%
% input.X            orthagonal X coordinate data (angstroms)
% input.Y            orthagonal Y coordinate data (angstroms)
% input.Z            orthagonal Z coordinate data (angstroms)
%
% -- optional inputs (12): generates defaults when not user-specified --
%
% input value        meaning                           default value
%
% input.outfile      output file name                 "mat2PDB.pdb"
% input.recordName   output record name of atoms      "ATOM"
% input.atomNum      atom serial number                sequential number
% input.atomName     name of atoms                    "OW" (water oxygen)
% input.altLoc       alt. location indicator          " "
% input.resName      name of residue                  "SOL" (water)
%
% input.chainID      protein chain identifier         "A"
% input.resNum       residue sequence number           sequential number
% input.occupancy    occupancy factor                 "1.00"
% input.betaFactor   beta factor, temperature         "0.00"
% input.element      element symbol                   "O" (oxygen)
% input.charge       atomic charge                    " "
%
%
% -- example uses --
%
% % translates both X and Y coordinates of 3IJU.pdb by 5 angstroms
% PDBdata = pdb2mat('3IJU.pdb');
% PDBdata.X = PDBdata.X + 5;
% PDBdata.Y = PDBdata.Y + 5;
% mat2pdb(PDBdata)
%
% % make a PDB with 30 atoms in random places within a 10 angstrom box
% data.X = rand(1,20)*10;
% data.Y = rand(1,20)*10;
% data.Z = rand(1,20)*10;
% mat2pdb(data)
%
%

function mat2pdb(input)
%% review XYZ coordinate data

% coordinate data is required! Checking XYZ input
if ~isfield(input, 'X') || ~isfield(input, 'Y') || ~isfield(input, 'Z')
    fprintf('we need xyz coordinate data to make a PDB!!\n\texiting...\n');
    return;
end
X = input.X;
Y = input.Y;
Z = input.Z;
if length(X) ~= length(Y) || length(X) ~= length(Z)
    fprintf('xyz coordinate data is not of equal lengths!\n\texiting...\n');
    return;
end

%% review optional data inputs

% in case optional data data not given, fill in blanks
if ~isfield(input, 'outfile')
    input.outfile = 'mat2PDB.pdb';
end
if ~isfield(input, 'recordName')
    input.recordName = cell(1,length(X));
    input.recordName(1:end) = {'ATOM'};
end
if ~isfield(input, 'atomNum')
    input.atomNum = 1:length(X);
end
if ~isfield(input, 'atomName')
    input.atomName = cell(1,length(X));
    input.atomName(1:end) = {'OW'};
end
if ~isfield(input, 'altLoc')
    input.altLoc = cell(1,length(X));
    input.altLoc(1:end) = {' '};
end
if ~isfield(input, 'resName')
    input.resName = cell(1,length(X));
    input.resName(1:end) = {'SOL'};
end
if ~isfield(input, 'chainID')
    input.chainID = cell(1,length(X));
    input.chainID(1:end) = {'A'};
end
if ~isfield(input, 'resNum')
    input.resNum = 1:length(X);
end
if ~isfield(input, 'occupancy')
    input.occupancy = ones(1,length(X));
end
if ~isfield(input, 'betaFactor')
    input.betaFactor = zeros(1, length(X));
end
if ~isfield(input, 'element')
    input.element = cell(1,length(X));
    input.element(1:end) = {'O'};
end
if ~isfield(input, 'charge')
    input.charge = cell(1,length(X));
    input.charge(1:end) = {' '};
end

outfile    = input.outfile;
recordName = input.recordName;
atomNum    = input.atomNum;
atomName   = input.atomName;
altLoc     = input.altLoc;
resName    = input.resName;
chainID    = input.chainID;
resNum     = input.resNum;
occupancy  = input.occupancy;
betaFactor = input.betaFactor;
element    = input.element;
charge     = input.charge;

%% remove faulty inputs

if length(recordName) ~= length(X)
    fprintf('recordName input is not the correct length!\n\tignoring user input\n');
    recordName = cell(1,length(X));
    recordName(1:end) = {'ATOM'};
end
if length(atomNum) ~= length(X)
    fprintf('atom serial number input is not the correct length!\n\tignoring user input\n');
    atomNum = 1:length(X);
end
if length(atomName) ~= length(X)
    fprintf('atom name input is not the correct length!\n\tignoring user input\n');
    atomName = cell(1,length(X));
    atomName(1:end) = {'OW'};
end
if length(altLoc) ~= length(X)
    fprintf('alternate location input is not the correct length!\n\tignoring user input\n');
    altLoc = cell(1,length(X));
    altLoc(1:end) = {' '};
end
if length(resName) ~= length(X)
    fprintf('residue name input is not the correct length!\n\tignoring user input\n');
    resName = cell(1,length(X));
    resName(1:end) = {'SOL'};
end
if length(chainID) ~= length(X)
    fprintf('chain ID input is not the correct length!\n\tignoring user input\n');
    chainID = cell(1,length(X));
    chainID(1:end) = {'A'};
end
if length(resNum) ~= length(X)
    fprintf('residue number input is not the correct length!\n\tignoring user input\n');
    resNum = 1:length(X);
end
if length(occupancy) ~= length(X)
    fprintf('occupancy input is not the correct length!\n\tignoring user input\n');
    occupancy = ones(1,length(X));
end
if length(betaFactor) ~= length(X)
    fprintf('beta factor input is not the correct length!\n\tignoring user input\n');
    betaFactor = zeros(1, length(X));
end
if length(element) ~= length(X)
    fprintf('element symbol input is not the correct length!\n\tignoring user input\n');
    element = cell(1,length(X));
    element(1:end) = {'O'};
end
if length(charge) ~= length(X)
    fprintf('charge input is not the correct length!\n\tignoring user input\n');
    charge = cell(1,length(X));
    charge(1:end) = {' '};
end

% fix atomName spacing
for n = 1:length(atomName)
    atomName(n) = {sprintf('%-3s',cell2mat(atomName(n)))};
end

%% create PDB

% open file
fprintf('outputting PDB in file %s\n', outfile);
FILE = fopen(outfile, 'w');

% output data
for n = 1:length(atomNum)

    % standard PDB output line
    fprintf( FILE, '%-6s%5u%5s%1.1s%3s %1.1s%4u%12.3f%8.3f%8.3f%6.2f%6.2f%12s%2s\n', ...
        cell2mat(recordName(n)), atomNum(n), cell2mat(atomName(n)), ...
        cell2mat(altLoc(n)), cell2mat(resName(n)), cell2mat(chainID(n)), ...
        resNum(n), X(n), Y(n), Z(n), occupancy(n), betaFactor(n), ...
        cell2mat(element(n)), cell2mat(charge(n)));

    % output progress in terminal
    if ~mod(n,400)
        fprintf('   %6.2f%%', 100*n / length(atomNum));
        if ~mod(n, 4000)
            fprintf('\n');
        end
    end

end
fprintf( FILE, 'END\n');

% close file
fprintf('   %6.2f%%\n    done! closing file...\n', 100);

fclose(FILE);

end


%% HEAT2D_POOL runs the HEAT2D example interactively with MATLABPOOL.
%

%
%  Read a black and white image which will be our "initial condition".
%
  x = imread ( 'surfsup.tif' );
%
%  Display the image.
%
  figure ( 1 )
  imshow ( x )
%
%  Get 4 "labs" to work on the job.
%
  matlabpool open local 4
  y = heat2d_fun ( x );
  matlabpool close


function qrdemo (matrix_name)
%QRDEMO a simple demo of SuiteSparseQR
% This is the MATLAB equivalent of the qrdemo.cpp program.  It reads in either
% a single matrix or a set of matrices, held as files in Matrix Market format
% in the ../Matrix directory.
%
% Example
%   qrdemo
%   qrdemo ('../Matrix/young1c.mtx')
%
% See also spqr, spqr_solve, mldivide

%   Copyright 2008, Timothy A. Davis
%   http://www.cise.ufl.edu/research/sparse

if (nargin == 0)

    % try all matrices
    qrdemo ('../Matrix/a2.mtx') ;
    qrdemo ('../Matrix/r2.mtx') ;
    qrdemo ('../Matrix/a04.mtx') ;
    qrdemo ('../Matrix/a2.mtx') ;
    qrdemo ('../Matrix/west0067.mtx') ;
    qrdemo ('../Matrix/c2.mtx') ;
    qrdemo ('../Matrix/a0.mtx') ;
    qrdemo ('../Matrix/lfat5b.mtx') ;
    qrdemo ('../Matrix/bfwa62.mtx') ;
    qrdemo ('../Matrix/LFAT5.mtx') ;
    qrdemo ('../Matrix/b1_ss.mtx') ;
    qrdemo ('../Matrix/bcspwr01.mtx') ;
    qrdemo ('../Matrix/lpi_galenet.mtx') ;
    qrdemo ('../Matrix/lpi_itest6.mtx') ;
    qrdemo ('../Matrix/ash219.mtx') ;
    qrdemo ('../Matrix/a4.mtx') ;
    qrdemo ('../Matrix/s32.mtx') ;
    qrdemo ('../Matrix/c32.mtx') ;
    qrdemo ('../Matrix/lp_share1b.mtx') ;
    qrdemo ('../Matrix/a1.mtx') ;
    qrdemo ('../Matrix/GD06_theory.mtx') ;
    qrdemo ('../Matrix/GD01_b.mtx') ;
    qrdemo ('../Matrix/Tina_AskCal_perm.mtx') ;
    qrdemo ('../Matrix/Tina_AskCal.mtx') ;
    qrdemo ('../Matrix/GD98_a.mtx') ;
    qrdemo ('../Matrix/Ragusa16.mtx') ;
    qrdemo ('../Matrix/young1c.mtx') ;
    fprintf ('All tests passed\n') ;

else

    %---------------------------------------------------------------------------
    % turn off warnings
    %---------------------------------------------------------------------------

    s = warning ('query', 'all') ;
    warning ('off', 'MATLAB:singularMatrix') ;
    warning ('off', 'MATLAB:rankDeficientMatrix') ;

    % --------------------------------------------------------------------------
    % the MATLAB equivalent of qrdemo.cpp
    % --------------------------------------------------------------------------

    fprintf ('qrdemo %s\n', matrix_name) ;
    A = mread (matrix_name) ;
    [m n] = size (A) ;
    anorm = norm (A,1) ;
    fprintf ('Matrix %6d-by-%-6d nnz: %6d ', m, n, nnz(A)) ;
    B = ones (m,1) ;
    [X, info] = spqr_solve (A,B) ;
    rnk = info.rank_A_estimate ;
    rnorm = norm (A*X-B,1) ;
    xnorm = norm (X,1) ;
    if (m <= n && anorm > 0 && xnorm > 0)
        rnorm = rnorm / (anorm * xnorm) ;
    end
    fprintf ('residual: %8.1e rank: %6d', rnorm, rnk) ;

    %---------------------------------------------------------------------------
    % compare with MATLAB
    % --------------------------------------------------------------------------

    try
        if (m ~= n || rnk == min (m,n))
            X = A\B ;
        else
            % The matrix is square and rank deficient.  Rather than getting a
            % divide-by-zero, force MATLAB to use a sparse QR by appending on a
            % blank row, in an attempt to find a consistent solution.
            X = [A ; sparse(1,n)] \ [B ; 0] ;
            X = X (1:m,:) ;
        end
        rnorm_matlab = norm (A*X-B,1) ;
        xnorm = norm (X,1) ;
        if (m <= n && anorm > 0 && xnorm > 0)
            rnorm_matlab = rnorm_matlab / (anorm * xnorm) ;
        end
    catch                                                                   %#ok
        % the above will fail for complex matrices that are rectangular and/or
        % rank deficient
        rnorm_matlab = nan ;
    end

    % find the true rank; this is costly
    rank_exact = rank (full (A)) ;

    if (rnk ~= rank_exact)
        % This can happen for some matrices; rnk is just an estimate, not
        % guaranteed to be equal to the true rank.  This does not occur
        % for any matrix in the ../Matrix test set.
        fprintf (' ?\n ... rank estimate is not exact; true rank is %d\n', ...
            rank_exact) ;
        warning ('rank estimate is incorrect') ;                            %#ok
    elseif (m <= n && rnk == m)
        % A*x=b is a full-rank square or under-determined system which spqr
        % should solve with low relative residual.
        if (rnorm > 1e-12)
            fprintf (' ?\n ... spqr solution is poor\n') ;
            error ('qrdemo failed') ;
        else
            fprintf (' OK\n') ;
        end
    elseif (m > n && rnk == n)
        % A*x=b is a full-rank least-squares problem.  Both spqr and MATLAB
        % should find a similar residual.
        err = abs (rnorm - rnorm_matlab) / max (rnorm_matlab, 1) ;
        if (err > 1e-12)
            fprintf (' ?\n ... spqr solution is poor\n') ;
            error ('qrdemo failed') ;
        else
            fprintf (' OK\n') ;
        end
    else
        % A*x=b is not full-rank; any solution will do ...
        fprintf (' %8.1e OK\n', rnorm_matlab) ;
    end

    %---------------------------------------------------------------------------
    % restore warning status
    %---------------------------------------------------------------------------

    warning (s) ;

end


function handles = plotDataMatrix(hObject, handles)

plotDimensions = get(handles.lstPlotDimensions, 'Value');

FigureTitle = 'Data';
[handles, handles.figData] = openPlotFigure(hObject, handles, ...
    'Data Plot (Matrix)', FigureTitle);

% OLD --
%plotmatrix((handles.Data(plotDimensions, :))', ...
%    (handles.Data(plotDimensions, :))');
% -- OLD

plotmatrix((handles.Data(plotDimensions, :))');

% Avoid bug
% (plotmatrix takes away the title created by openPlotFigure)
title(FigureTitle)

hold off;

guidata(hObject, handles);


function init_axes3d(axes_handle, grid3d, withinterp, withpml)
chkarg(~isempty(axes_handle) && ishandle(axes_handle), '"axes_handle" should be handle.');
chkarg(istypesizeof(grid3d, 'Grid3d'), '"grid3d" should be instance of Grid3d.');
chkarg(istypesizeof(withinterp, 'logical'), '"withinterp" should be logical.');
chkarg(istypesizeof(withpml, 'logical'), '"withpml" should be logical.');

hold(axes_handle, 'on');

if withinterp
	lplot = grid3d.lplot(GT.prim, withinterp, withpml);
else
	lplot = grid3d.lvoxelbound(GT.prim, withpml);
end
axis(axes_handle, [lplot{Axis.x}([1 end]), lplot{Axis.y}([1 end]), lplot{Axis.z}([1 end])]);
daspect(axes_handle, [1 1 1]);  % axis(ha, 'image');
box(axes_handle, 'on');
view(axes_handle, -38.5, 16)

hr = rotate3d;
set(hr, 'Enable', 'on');
setAllowAxesRotate(hr, axes_handle, true);

axes_str = {char(Axis.x), char(Axis.y), char(Axis.z)};
[like2d, n] = is2dlike(grid3d.N);
[h, v] = cycle(n);
h_str = [char(h), '  (', char(hex2dec('00D7'))];
if grid3d.unitvalue < 1e5 && grid3d.unitvalue > 1e-3
	h_str = [h_str, num2str(grid3d.unitvalue), ')'];
else
	h_str = [h_str, num2str(grid3d.unitvalue, '%.2e'), ')'];
end
axes_str{h} = h_str;

rotations = [0 0 0];
if like2d
	rotations(v) = -eps;  % small perturbation to show label correctly
end

% set(axes_handle, 'FontSize', 18, 'FontWeight', 'Bold');
xlabel(axes_handle, axes_str(Axis.x), 'Rotation', rotations(Axis.x));
ylabel(axes_handle, axes_str(Axis.y), 'Rotation', rotations(Axis.y));
zlabel(axes_handle, axes_str(Axis.z), 'Rotation', rotations(Axis.z));

set(axes_handle, 'TickDir', 'out');

% L0 = scalar3d.gi.L0;
% dlu = scalar3d.gi.display_length_unit;
% dlu_scale = scalar3d.gi.dlu_scale;
% xlabel(strcat(AxisName(Xx), ' (', char(hex2dec('00D7')), ...  % 00D7 is a unicode character for the multiplication sign.
% 	num2str(L0*dlu_scale), dlu, ')'));
% ylabel(strcat(AxisName(Yy), ' (', char(hex2dec('00D7')), ...  % 00D7 is a unicode character for the multiplication sign.
% 	num2str(L0*dlu_scale), dlu, ')'));
% zlabel(strcat(AxisName(Zz), ' (', char(hex2dec('00D7')), ...  % 00D7 is a unicode character for the multiplication sign.
% 	num2str(L0*dlu_scale), dlu, ')'));
% title(plot_title);


function wt = wfbtremove(d,kk,wt,varargin)
%WFBTREMOVE Remove node(s) from the filterbank tree
%   Usage:  wt = wbftremove(d,kk,wt);
%           wt = wfbtremove(d,kk,wt,'force');
%
%   Input parameters:
%           d   : Level in the tree (0 - root).
%           kk  : Index of the node at level *d* (starting at 0) or array
%                 of indexes.
%           wt  : Wavelet filterbank tree structure (as returned from
%                 |wfbtinit|).
%
%   Output parameters:
%           wt : Modified filterbank structure.
%
%   `wfbtremove(d,kk,wt)` removes existing node at level *d* and index *kk*
%   from the filterbank tree structure *wt*. The function fails if the
%   node has any children (it is not a leaf node).
%
%   `wfbtremove(d,k,wt,'force')` does the same, but any childern of the
%   node are removed too.
%
%   Examples:
%   ---------
%
%   The following example shows magnitude frequency responses of filterbank
%   tree before and after prunning.:::
%
%      % Create a full filterbank tree usinf 'db10' basic filterbank.
%      wt1 = wfbtinit({'db10',4,'full'});
%      % Remove a subtree starting by root's high-pass filter. Force flag
%      % is used because we are removing a non-leaf node.
%      wt2 = wfbtremove(1,1,wt1,'force');
%
%      % Create identical filterbanks
%      [g1,a1] = wfbt2filterbank(wt1,'freq');
%      [g2,a2] = wfbt2filterbank(wt2,'freq');
%
%      % Plot the frequency responses
%      subplot(2,1,1);
%      filterbankfreqz(g1,a1,1024,'plot','posfreq','linabs');
%      subplot(2,1,2);
%      filterbankfreqz(g2,a2,1024,'plot','posfreq','linabs');
%
%

% AUTHOR: Zdenek Prusa

complainif_notenoughargs(nargin,3,'WFBTREMOVE');

definput.flags.force = {'noforce','force'};
flags=ltfatarghelper({},definput,varargin);

if isempty(wt.nodes)
   error('%s: Tree is empty.',mfilename);
end

for k=kk
   [nodeNo,nodeChildIdx] = depthIndex2NodeNo(d,k,wt);
   if(nodeNo==0)
       % removing root
       rootNo = find(wt.parents==0);
       % check for any children of the root
       if any(wt.children{rootNo}~=0) && ~flags.do_force
            error(['%s: Deleting root node. To delete the whole tree ',...
                   'use FORCE option.'],mfilename,d,k);
       else
           wt = nodeSubtreeDelete(rootNo,wt);
           continue;
       end
   end

   % check if node exists
   childrenIdx = find(wt.children{nodeNo}~=0);
   found = find(childrenIdx==nodeChildIdx,1);

   if(isempty(found))
        error('%s: Such node (depth=%d, idx=%d) does not exist.',mfilename,d,k);
   end

   nodeToDelete = wt.children{nodeNo}(nodeChildIdx);
   % Check if it is a leaf (terminal node)
   if any(wt.children{nodeToDelete}~=0) && ~flags.do_force
       error(['%s: Deleting a non-leaf node. To delete whole subtree use ',...
              'FORCE option.'],mfilename);
   else
       wt = nodeSubtreeDelete(nodeToDelete,wt);
   end
end


function varargout = eegsynth_tsv(filename, hdr)

% EEGSYNTH_TSV is called from FT_READ_EVENT to read the events from a tsv file
% written by the recordtrigger module. The .tsv file should also contain a
% synchronization trigger from the recordsignal module.
%
% Use as
%   hdr = events_tsv(filename)
%   evt = events_tsv(filename, hdr)
% to read the header or the event information. Note that when reading the header, the
% number of channels in the actual data is unknown.
%
% See https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/05-task-events.html
%
% See also FT_FILETYPE, FT_READ_HEADER, FT_READ_DATA, FT_READ_EVENT, QUALISYS_TSV, EVENTS_TSV, BIDS_TSV

% FIXME it might be that the events are one sample off, but I cannot be bothered
% checking that precisely at the moment of the initial implementation.

% Copyright (C) 2022, Robert Oostenveld
%
% 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$

needhdr = (nargin==1);
needevt = (nargin==2);

% read the table from file
t = readtable(filename, 'filetype', 'text', 'delimiter', '\t');

type = unique(t.event);
sync = type(endsWith(type, 'synchronize'));
assert(length(sync)==1, 'there should be exactly one type of trigger that ends with "synchronize"')
sync = sync{1};

% find the mapping between timestamps and samples
sel = strcmp(t.event, sync);
firstTimeStamp = t.timestamp(1);
sec = seconds(t.timestamp(sel) - firstTimeStamp);
smp = t.value(sel); % the "synchronize" triggers contain the sample number of the corresponding EEG file

% figure
% plot(sec, smp, '.')
% xlabel('seconds')
% ylabel('samples')

if needhdr
  % fit a first-order polynomial that expresses samples per timestamp
  p = polyfit(sec, smp, 1);
  samplesPerTimeStamp = p(1);

  % fit a first-order polynomial that expresses timestamps per sample
  p = polyfit(smp, sec, 1);

  % construct a dummy header
  hdr = [];
  hdr.nChans = 1;
  hdr.label = {'unknown'};
  hdr.nSamples = inf;
  hdr.nSamplesPre = 0;
  hdr.nTrials = 1;
  hdr.Fs = samplesPerTimeStamp;
  hdr.FirstTimeStamp = firstTimeStamp + seconds(polyval(p, 1));
  hdr.TimeStampPerSample  = samplesPerTimeStamp;

  % return the header
  varargout = {hdr};
end % if needhdr

if needevt
  % fit a first-order polynomial that expresses samples per timestamp
  p = polyfit(sec, smp, 1);

  % estimate the sample number from the timestamp for all other events
  sec = seconds(t.timestamp - firstTimeStamp);
  smp = round(polyval(p, sec)) - 1;

  event = struct;
  for i=1:numel(smp)
    event(i).type = t.event{i};
    event(i).value = t.value(i);
    event(i).sample = smp(i);
    event(i).duration = [];
    event(i).offset = [];
  end

  % return the events
  varargout = {event};
end % if needevt


function p = completeInitial(p)

if p.options.warmstart && any(isnan(p.x0))

    p_reduced = p;

    % Fix the given variables
    p_reduced.lb(~isnan(p.x0)) = p.x0(~isnan(p.x0));
    p_reduced.ub(~isnan(p.x0)) = p.x0(~isnan(p.x0));

    % Propagate these values a bit
    p_reduced = propagate_bounds_from_equalities(p_reduced);
    p_reduced = propagate_bounds_from_evaluations(p_reduced);
    p_reduced = propagate_bounds_from_equalities(p_reduced);

    % Keep only equalities and elementwise inerqualities (more?)
    p_reduced.F_struc = p.F_struc(1:p.K.f + p.K.l,:);
    p_reduced.K.q = 0;
    p_reduced.K.r = 0;
    p_reduced.K.p = 0;
    p_reduced.K.s = 0;

    % No objective
    p_reduced.c = p_reduced.c*0;
    p_reduced.Q = p_reduced.Q*0;

    % Kill nonlinearity information
    p_reduced.variabletype = p_reduced.variabletype*0;

    % Solve LP
    output = feval(p.solver.lpcall,p_reduced);
    if output.problem == 0
        p.x0 = output.Primal;
    end
end


function varargout = Imagesegmentation(varargin)
%% Written by ABIOYE SAMSON D.
% Email Address: samsung4christ@yahoo.com
% Phone No: +2348068724645
%%
% IMAGESEGMENTATION M-file for Imagesegmentation.fig
%      IMAGESEGMENTATION, by itself, creates a new IMAGESEGMENTATION or raises the existing
%      singleton*.
%
%      H = IMAGESEGMENTATION returns the handle to a new IMAGESEGMENTATION or the handle to
%      the existing singleton*.
%
%      IMAGESEGMENTATION('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in IMAGESEGMENTATION.M with the given input arguments.
%
%      IMAGESEGMENTATION('Property','Value',...) creates a new IMAGESEGMENTATION or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before Imagesegmentation_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to Imagesegmentation_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help Imagesegmentation

% Last Modified by GUIDE v2.5 27-Sep-2010 21:29:28

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @Imagesegmentation_OpeningFcn, ...
                   'gui_OutputFcn',  @Imagesegmentation_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before Imagesegmentation is made visible.
function Imagesegmentation_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to Imagesegmentation (see VARARGIN)

% Choose default command line output for Imagesegmentation
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes Imagesegmentation wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = Imagesegmentation_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filename path] = uigetfile('*.bmp;*.jpg;*.tif;','Open input image');
if filename~=0
    file = [path filename];
    orignalimg = imread(file);
    axes(handles.axes1);
    imshow(real(orignalimg));
else
    warndlg('Input image must be selected.','Warning');
end

% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
j=getImage(handles.axes1);
jr=imresize(j,[512 512]);
jg=rgb2gray(jr);
h=histeq(jg);
b=qtdecomp(h,.1);
s=full(b);
blocks=repmat(double(0),size(s));
for dim=[512 256 128 64 32 16 8 4 2 1];
numblocks=length(find(s==dim));
if (numblocks > 0)
values = repmat(double(1),[dim dim numblocks]);
values(2:dim,2:dim,:)=0;
blocks=qtsetblk(blocks,s,dim,values);
end
end
blocks(end,1:end)=1;
blocks(1:end,end)=1;
f=(blocks());
axes(handles.axes2);
imshow(f)

% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
uisave()

% --- Executes on button press in pushbutton4.
function pushbutton4_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton4 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
exit = questdlg('Are you sure you want to Exit now','Exit','Yes','No','');
switch exit
    case 'Yes'
        delete(gcf)
    case 'No'
        return
end

% --- Executes during object creation, after setting all properties.
function pushbutton2_CreateFcn(hObject, eventdata, handles)
% hObject    handle to pushbutton2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called


function scan_data = p10rd(ufilename,plotmode,verbose)
%P10RD Read Tencor P-10 surface profilometer data file
%
% SCAN_DATA = P10RD(UFILENAME,PLOTMODE,VERBOSE)
%
%P10RD reads the data from file UFILENAME.txt, and returns a 5-column
% array SCAN_DATA:
%  (:,1) is the horizontal position data in microns
%  (:,2) is the raw vertical profile data in microns
%  (:,3) is the levelled vertical profile data in microns
%  (:,4) is the Wav/A data (unscaled)
%  (:,5) is the Rough/A data (unscaled)
%
% Options:
% If VERBOSE == 0, no messages will be displayed.
% If VERBOSE == 1, the data summary will be displayed. (default)
% If VERBOSE == 2, the file header and data summary will be displayed.
% If PLOTMODE == 0, the data will not be displayed.
% if PLOTMODE == 1, the levelled data will be displayed in a new figure. (default)
% If PLOTMODE == 2, a second data plot with the raw data will be shown.
%
% If no input parameters are specified, the program is interactive, and the
% user will be prompted to enter a filename.
%
% NOTE: The function can only read ASCII text data files, not binary data files.
%  The name of the data file must have the extension ".txt", but you do not
%  need include the extension when specifying the file name.
%
% Examples:
%
%  If the data is stored in a text file called "mydata.txt", then:
%
%      p10rd mydata;
%
%  will load the file, plot the data, and print a summary. You can also use:
%
%      p10rd;
%
%  and you will be prompted for the file name. The command:
%
%      profile_data=p10rd('mydata',0,1);
%
%  will open the file mydata.txt, plot the data,
%   and save the data to the variable profile_data in the workspace
%   without printing anything in the command window.
%
%
% M.A. Hopcroft
%  mhopeng at gmail dot com
%
% The license governing use of this code is in the accompanying file
%  "license.txt".
%
versionstr='p10rd 1.3';

% MH Jul2013
% v1.3  add uifileget
% MH Sep2012
% v1.2  updates for modern matlab
% MH MAY2007
% v1.1  re-order input (verbose last)
%       filename w/ or w/o .txt
% MH OCT2006
% v1.0 out of beta
%
%#ok<*NBRAK>

% handle input arguments - set defaults
% default to verbose mode 1 (summary only)
if nargin < 3
    verbose = 1;
end

% default to plot mode 1 (levelled data only)
if nargin < 2
    plotmode = 1;
end

% get interactive if not being called by another program
if (nargout == 0)
    if (verbose >= 1 && nargin == 0)
        clc;
        fprintf(1, '\n\n  %s\n  %s\n\n', versionstr, 'Read in Tencor P-10 data files');
    end
end

%%%%
% open user's file
if nargin >= 1 % if the user already specified a file, use it
    userfilename=ufilename;

    % check to see if file exists
    cfid=fopen(userfilename);
    if cfid== -1
        % try with ".txt"
        userfilename=strcat(userfilename,'.txt');
        cfid=fopen(userfilename);
        if cfid== -1
            disp(pwd);
            fprintf(1,'ERROR: data file ["%s"] not found in current directory',userfilename);
            scan_data=[];
            return
        end
        fclose(cfid);
    end

else % if user did not specify the file name, ask for one
    [ufilename, ufilepath]=uigetfile('.txt','Select the Tencor P-10 data file');
    if isequal(ufilename,0)
        scan_data=[];
        return
    end
    userfilename=fullfile(ufilepath,ufilename);
    %userfilename=input(' Enter the name of the Dektak XT .csv file: ','s');
end

% open the file
userfile=fopen(userfilename);
[fpath, fname, fext]=fileparts(userfilename);

%%%%
% process the file header
% the first 5 lines are header information
% read them in and get some data: scan length, number of points, etc.
if verbose == 2
    fprintf(1,'\n\n %s\n %s %s\n\n %s\n\n', versionstr, 'Filename:', fname, 'File header:');
end

% additional linein statements should handle unix/DOS ASCII/ANSI problem
%  [note: investigate this further]

% line 1: filename and date
linein=fgetl(userfile);
if isempty(linein), linein=fgetl(userfile); end % spurious carriage returns?
if verbose == 2
    fprintf(1,' %s\n', linein);
end
scan_date=sscanf(linein,'* %*s %s',1);

% line 2: number of data points
linein=fgetl(userfile);
if isempty(linein), linein=fgetl(userfile); end % spurious carriage returns?
if verbose == 2
    fprintf(1,' %s\n', linein);
end
% %  because the bastards use tabs instead of spaces, we have to
% %   parse the line to isolate the number at the start of it
% lspace=0; % initialize
% for i=1:8
%     if isspace(linein(i))
%         lspace=i;
%         break
%     end
% end
% num_points=str2num(linein(1:lspace-1));
num_points=sscanf(linein,'%d',1);

% line 3: length of scan (um)
linein=fgetl(userfile); % line 3: length of scan (um)
if isempty(linein), linein=fgetl(userfile); end % spurious carriage returns?
if verbose == 2
    fprintf(1,' %s\n', linein);
end
scan_length=sscanf(linein,'%d',1);

%line 4: "A per Y count"
% (I believe this represents the minimum vertical resolution for the scan)
linein=fgetl(userfile);
if isempty(linein), linein=fgetl(userfile); end %spurious carriage returns?
if verbose == 2
    fprintf(1,' %s\n', linein);
end

%line 5: column headers
linein=fgetl(userfile);
if isempty(linein), linein=fgetl(userfile); end
if verbose == 2
    fprintf(1,' %s\n', linein);
end

%the position of the data points is now known
% the P-10 appears to add spurious data points, i.e. 700um scan, 702 data points
%  ignore step
% stepsize=scan_length/num_points;
%rstep=round(stepsize);
%if rstep-stepsize <= 0.005
%    stepsize=rstep; %the scan length is effectively lengthed slightly
%end

%%%%
% get data from file
%  data is formatted in 5 columns
%  column 1 is horizontal position in um
%  column 2 is the "raw data" in Angstroms
%  column 3 is the levelled data in Angstroms
%  column 4 is "Wav/A" ??
%  column 5 is "Rough/A" ?? surface roughness?

d=textscan(userfile,'%f %f %f %f %f',inf);
scan_data(:,1)=d{1};
scan_data(:,2)=d{2};
scan_data(:,3)=d{3};
scan_data(:,4)=d{4};
scan_data(:,5)=d{5};
count=size(scan_data,1);
sd=diff(scan_data(:,1));
if all(sd==sd(1))
    stepsize=sd(1);
else
    stepsize=scan_length/num_points;
end

% close the file
fclose(userfile);

%adjust data point number to be position
%scan_data(:,1)=scan_data(:,1).*stepsize;
%scale data to um from Angstroms
scan_data(:,2:5)=scan_data(:,2:5)./10000;

% plot
% plot the raw data
if plotmode >= 1

    figure;
    plot(scan_data(:,1),scan_data(:,2),'.-b');
    title(['p10rd: ' fname],'Interpreter','none','FontSize',16,'FontWeight','bold');
    xlabel('Scan Length (\mum)','FontSize',14);
    ylabel('Profile (\mum)','FontSize',14);
    grid on;

end

% plot the levelled data
if plotmode == 2

    hold on
    plot(scan_data(:,1),scan_data(:,3),'.-g');
    legend('Raw Data','Levelled Data');

end

%print summary data
if verbose >= 1

    fprintf(1,'\n');
    fprintf(1,' %s\n', 'Data Summary:');
    fprintf(1,'\n');
    fprintf(1,' %s %s\n', 'File name:', [fname fext]);
    if ~isempty(scan_date)
        fprintf(1,' %s %s\n','Scan Date:',scan_date);
    end

    fprintf(1,'\n');

    fprintf(1,' %s %i\n', 'Number of data points read:', count);
    fprintf(1,' %s %g %s\n', 'Scan Length:', scan_length, 'um');
    fprintf(1,' %s %d %s\n %s %d %s\n %s %g %s\n',...
        'Scan Start:', scan_data(1,1), 'um', 'Scan End:',...
        scan_data(end,1), 'um', 'Scan Step:', stepsize, 'um');

    fprintf(1,'\n');

end


%% REW_riverbank
% %{
imfolder = 'images\REW_riverbank';
im_n = 2;
imfile = cell(im_n,1);
imfile{1} = [imfolder '\' 'riverbank_01.jpg'];
imfile{2} = [imfolder '\' 'riverbank_02.jpg'];

im = cell(im_n,1);
for ii = 1:im_n
    im{ii} = imread(imfile{ii});
end

edge_list = [1,2];

imsize = zeros(im_n,3);

for ii = 1:im_n
    imsize(ii,:) = size(im{ii});
    if imsize(ii,1) > 720
        scale = 720/size(im{ii}, 1);
        im{ii} = imresize(im{ii}, scale);

        imsize(ii,:) = size(im{ii});
    end
end

mosaic = REW_mosaic( im, edge_list, 1, 'persp', 0, imfolder );
%}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Spherical Harmonic Modeling and Analysis Toolkit (SPHARM-MAT) is a 3D
% shape modeling and analysis toolkit.
% It is a software package developed at Shenlab in Center for Neuroimaging,
% Indiana University (SpharmMat@gmail.com, http://www.iupui.edu/~shenlab/)
% It is available to the scientific community as copyright freeware
% under the terms of the GNU General Public Licence.
%
% Copyright 2009, 2010, ShenLab, Center for Neuroimaging, Indiana University
%
% This file is part of SPHARM-MAT.
%
% SPHARM-MAT 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.
%
% SPHARM-MAT 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 SPHARM-MAT. If not, see <http://www.gnu.org/licenses/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function userdataHandle = initOptions(userdataHandle)

% Start initialization
% Not implemented: 'ParamQuad', 'ParamConf'
userdataHandle.keyword.list = {'ParamCALD', 'ParamPDM', 'ParamQuad', 'ParamConf', 'ExpLSF', 'ExpIRF', ...
    'AligSHREC', 'AligFOE', 'AligLandmark', 'ExpAlig', 't_map', 'PCA', 't_map+PCA', ...
    'PDM_stat', 'Import', 'DisplayRes', 'bim2gipl', 'fix2gipl', 'gipl2bim', 'smo2surf_para_meta', ...
    'surf_para_meta2smo', 'des2meta_coef', 'meta_coef2des', 'reg2procalign_meta', 'InHouse_Fix', ...
    'PDM_Fix', 'Config'};
userdataHandle.keyword.selected = '';

userdataHandle.mesh={'orig';'quad32';'quad64';'quad128';'quad256';'quad512';'icosa1';'icosa2'; ...
    'icosa3';'icosa4';'icosa5';'icosa6'};
userdataHandle.space={'object';'param';'both'};
userdataHandle.shade={'solid';'mesh';'both'};
userdataHandle.overlay={'none';'adc_paramap'};
userdataHandle.colormap={'jet';'hot';'summer';'cool';'autumn';'winter';'spring'};
userdataHandle.export={'screen';'png';'both'};

% CALD Parameterization
userdataHandle.ParamCALD.vars = {'MeshGridSize','MaxSPHARMDegree','Tolerance','Smoothing','Iteration', ...
        'LocalIteration','t_major','SelectDiagonal','OutDirectory'};
userdataHandle.ParamCALD.args = [1 1 1 1 1 1 10 10 200];  % Encode the number and type of each variables
userdataHandle.ParamCALD.inFilter = {...
    '*_bim.mat;*_fix.mat;*_obj.mat', 'Binary and Mesh Objects (*_bim.mat;*_fix.mat;*_obj.mat)'; ...
    '*_obj.mat','Mesh Objects (*_obj.mat)'; ...
    '*_bim.mat;*_fix.mat', 'Bianry Objects (*_bim.mat, *_fix.mat)'; ...
    '*.mat', 'All Objects (*.mat)' ...
    };
userdataHandle.ParamCALD.default={'50', '6', '2', '2', '100', '10', '', '','./'};

for i=1:length(userdataHandle.ParamCALD.vars)
    varName = sprintf('userdataHandle.ParamCALD.%s', userdataHandle.ParamCALD.vars{i});
    if userdataHandle.ParamCALD.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.ParamCALD.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.ParamCALD.default{%d});', varName, i);
        eval(strCC);
    end
end

% PDM Parameterization (GenParamMesh)
userdataHandle.ParamPDM.vars = {'iter', 'label', 'OutDirectory', 'others'};
userdataHandle.ParamPDM.args = [1 1 200 20];
userdataHandle.ParamPDM.inFilter = {'*.gipl;*.hdr', 'Bianry Objects (*.gipl, *hdr)'};
userdataHandle.ParamPDM.default = {'500','1','./',''};
userdataHandle.ParamPDM.path = '';
userdataHandle.ParamPDM.command = 'GenParaMesh';
userdataHandle.ParamPDM.exist = 0;

for i=1:length(userdataHandle.ParamPDM.vars)
    varName = sprintf('userdataHandle.ParamPDM.%s', userdataHandle.ParamPDM.vars{i});
    if userdataHandle.ParamPDM.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.ParamPDM.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.ParamPDM.default{%d});', varName, i);
        eval(strCC);
    end
end

% Parameterization using a similar method to Brechbuhler's methd
userdataHandle.ParamQuad.vars = {'NRS_step','OutDirectory'};
userdataHandle.ParamQuad.args = [1 200];  % Encode the number and type of each variables
userdataHandle.ParamQuad.inFilter = {'*_bim.mat;*_fix.mat', 'Bianry Objects (*_bim.mat, *_fix.mat)'; ...
   '*_obj.mat','Mesh Objects (*_obj.mat)'; '*.mat', 'All Objects (*.mat)'};
userdataHandle.ParamQuad.default={'2','./'};

for i=1:length(userdataHandle.ParamQuad.vars)
    varName = sprintf('userdataHandle.ParamQuad.%s', userdataHandle.ParamQuad.vars{i});
    if userdataHandle.ParamQuad.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.ParamQuad.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.ParamQuad.default{%d});', varName, i);
        eval(strCC);
    end
end

% Expansion in the sense of least mean square
userdataHandle.ExpLSF.vars = {'MaxSPHARMDegree','OutDirectory'};
userdataHandle.ExpLSF.args = [1 200];
userdataHandle.ExpLSF.inFilter = {'*_ini.mat;*_smo.mat', 'Parameterized Objects (*_ini.mat, *_smo.mat)'; '*.mat', 'All Objects (*.mat)'};
userdataHandle.ExpLSF.default = {'15', './'};

for i=1:length(userdataHandle.ExpLSF.vars)
    varName = sprintf('userdataHandle.ExpLSF.%s', userdataHandle.ExpLSF.vars{i});
    if userdataHandle.ExpLSF.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.ExpLSF.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.ExpLSF.default{%d});', varName, i);
        eval(strCC);
    end
end

% SHREC Alignment
userdataHandle.AligSHREC.vars = {'Template', 'MaxSPHARMDegree', 'GroupAlpha', 'NormalizeSize', ...
    'BaseRes', 'HierarchyStep', 'HierarchyDepth', 'Top_K', 'GammaRes', 'OutDirectory'};
userdataHandle.AligSHREC.args = [100 1 1 10 1 1 1 1 1 200];
userdataHandle.AligSHREC.inFilter = {'*_des.mat;*_prm.mat', 'SPHARM Descriptors (*_des.mat,*_prm.mat)'; '*.mat', 'All Objects (*.mat)'};
userdataHandle.AligSHREC.default = {'','12','100','','1','1','3','1','2','./'};

for i=1:length(userdataHandle.AligSHREC.vars)
    varName = sprintf('userdataHandle.AligSHREC.%s', userdataHandle.AligSHREC.vars{i});
    if userdataHandle.AligSHREC.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.AligSHREC.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.AligSHREC.default{%d});', varName, i);
        eval(strCC);
    end
end

% First order ellipsoid alignment
userdataHandle.AligFOE.vars = {'CPoint', 'NPole', 'MaxSPHARMDegree', 'OutDirectory'};
userdataHandle.AligFOE.args = [10 10 1 200];
userdataHandle.AligFOE.inFilter = {'*_des.mat', 'SPHARM Descriptors (*_des.mat)'; '*.mat', 'All Objects (*.mat)'};
userdataHandle.AligFOE.default = {'', '', '12', './'};

for i=1:length(userdataHandle.AligFOE.vars)
    varName = sprintf('userdataHandle.AligFOE.%s', userdataHandle.AligFOE.vars{i});
    if userdataHandle.AligFOE.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.AligFOE.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.AligFOE.default{%d});', varName, i);
        eval(strCC);
    end
end

% PDM expansion and alignment (ParaToSPHARMMesh)
userdataHandle.ExpAlig.vars = {'flipTemplate', 'subdivLevel', 'spharmDegree', ...
        'regTemplate', 'FinalFlip', 'OutDirectory', 'others'};
userdataHandle.ExpAlig.args = [100 1 1 100 1 200 20];
userdataHandle.ExpAlig.inFilter = {'*_surf.meta', 'Parameterized Objects (*_surf.meta)'};
userdataHandle.ExpAlig.default = {'','20','12','','0','./',''};
userdataHandle.ExpAlig.path = '';
userdataHandle.ExpAlig.command = 'ParaToSPHARMMesh';
userdataHandle.ExpAlig.exist = 0;

for i=1:length(userdataHandle.ExpAlig.vars)
    varName = sprintf('userdataHandle.ExpAlig.%s', userdataHandle.ExpAlig.vars{i});
    if userdataHandle.ExpAlig.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.ExpAlig.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.ExpAlig.default{%d});', varName, i);
        eval(strCC);
    end
end

% t-statistical analysis
userdataHandle.t_map.vars = {'Atlas', 'Smoothing_FWHM', 'EqualVariance', 'Signal', 'SampleMesh', 'OutputNamePrefix','OutDirectory','GroupIDs'};
userdataHandle.t_map.args = [100 1 10 10 10 10 200 10];
userdataHandle.t_map.inFilter = {'*.mat', 'Registered Objects (*.mat)'; '*.mat', 'All Objects (*.mat)'};
userdataHandle.t_map.default = {'./atlas.mat','5','','','','t_map','./','Ctrl,PT'};

for i=1:length(userdataHandle.t_map.vars)
    varName = sprintf('userdataHandle.t_map.%s', userdataHandle.t_map.vars{i});
    if userdataHandle.t_map.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.t_map.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.t_map.default{%d});', varName, i);
        eval(strCC);
    end
end

% PCA analysis
userdataHandle.PCA.vars = {'GroupID','OutputName', 'OutDirectory'};
userdataHandle.PCA.args = [10 10 200];
userdataHandle.PCA.inFilter = {'*.mat', 'Registered Objects (*.mat)'; '*.mat', 'All Objects (*.mat)'};
userdataHandle.PCA.default = {'All','PCA_stat.mat','./'};

for i=1:length(userdataHandle.PCA.vars)
    varName = sprintf('userdataHandle.PCA.%s', userdataHandle.PCA.vars{i});
    if userdataHandle.PCA.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.PCA.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.PCA.default{%d});', varName, i);
        eval(strCC);
    end
end

% Display T-stat maps
userdataHandle.res_t_map.vars = {'Threshold_p_value', 'Overlay','Colormap'};
userdataHandle.res_t_map.args = [1 10 10];
userdataHandle.res_t_map.inFilter = {'t_map_*.mat',  'T-Stat Results (t_map_*.mat)'; ...
    '*.mat', 'All Objects (*.mat)'};
userdataHandle.res_t_map.default = {'0.05', '', ''};

for i=1:length(userdataHandle.res_t_map.vars)
    varName = sprintf('userdataHandle.res_t_map.%s', userdataHandle.res_t_map.vars{i});
    if userdataHandle.res_t_map.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.res_t_map.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.res_t_map.default{%d});', varName, i);
        eval(strCC);
    end
end

% Display PCA results
userdataHandle.res_PCA.vars = {'Level','Sigma','Mesh','MaxSPHARMDegree'};
userdataHandle.res_PCA.args = [1 1 10 1];
userdataHandle.res_PCA.inFilter = {'PCA_*.mat',  'PCA Results (PCA_*.mat)'; ...
    '*.mat', 'All Objects (*.mat)'};
userdataHandle.res_PCA.default = {'4','3','','15'};

for i=1:length(userdataHandle.res_PCA.vars)
    varName = sprintf('userdataHandle.res_PCA.%s', userdataHandle.res_PCA.vars{i});
    if userdataHandle.res_PCA.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.res_PCA.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.res_PCA.default{%d});', varName, i);
        eval(strCC);
    end
end

% PDM topology fix (SegPostProcess)
userdataHandle.PDM_Fix.vars = {'space','OutDirectory', 'others'};
userdataHandle.PDM_Fix.args = [3 200 20];
userdataHandle.PDM_Fix.inFilter = {'*.gipl;*.hdr', 'Bianry Objects (*.gipl, *hdr)'};
userdataHandle.PDM_Fix.default = {'0.75,0.75,0.75','./',''};
userdataHandle.PDM_Fix.path = '';
userdataHandle.PDM_Fix.command = 'SegPostProcess';
userdataHandle.PDM_Fix.exist = 0;

for i=1:length(userdataHandle.PDM_Fix.vars)
    varName = sprintf('userdataHandle.PDM_Fix.%s', userdataHandle.PDM_Fix.vars{i});
    if userdataHandle.PDM_Fix.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.PDM_Fix.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.PDM_Fix.default{%d});', varName, i);
        eval(strCC);
    end
end

% InHouse topology fixing method
userdataHandle.InHouse_Fix.vars = {'Connectivity','Epsilon','OutDirectory'};
userdataHandle.InHouse_Fix.args = [10 1 200];
userdataHandle.InHouse_Fix.inFilter = {'*_bim.mat;*_fix.mat', 'Bianry Objects (*_bim.mat, *_fix.mat)'; ...
    '*.mat', 'All Objects (*.mat)'};
userdataHandle.InHouse_Fix.default = {'','1.5','./'};

for i=1:length(userdataHandle.InHouse_Fix.vars)
    varName = sprintf('userdataHandle.InHouse_Fix.%s', userdataHandle.InHouse_Fix.vars{i});
    if userdataHandle.InHouse_Fix.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.InHouse_Fix.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.InHouse_Fix.default{%d});', varName, i);
        eval(strCC);
    end
end

% System configuration
userdataHandle.Config.vars = {'PDM_path_pc','PDM_path_unix'};
userdataHandle.Config.args = [200,200];
userdataHandle.Config.default = {'./','./'};
userdataHandle.Config.filename = 'sysConfig.mat';

for i=1:length(userdataHandle.Config.vars)
    varName = sprintf('userdataHandle.Config.%s', userdataHandle.Config.vars{i});
    if userdataHandle.Config.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.Config.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.Config.default{%d});', varName, i);
        eval(strCC);
    end
end

userdataHandle.Config.loaded = 0;

if exist(fullfile(pwd, userdataHandle.Config.filename), 'file')
    load(fullfile(pwd, userdataHandle.Config.filename));
    if ispc
        PDM_path = PDM_path_pc;
    elseif isunix
        PDM_path = PDM_path_unix;
    end

    userdataHandle.Config.PDM_path_pc = PDM_path_pc;
    userdataHandle.Config.PDM_path_unix = PDM_path_unix;

    if exist('PDM_path','var')
        userdataHandle.Config.loaded = 1;
        userdataHandle.Config.PDM_path = PDM_path;
        userdataHandle.ParamPDM.path = PDM_path;
        userdataHandle.PDM_Fix.path = PDM_path;
        userdataHandle.ExpAlig.path = PDM_path;
%         userdataHandle.PDM_stat.path = PDM_path;
    end

    com1 = [PDM_path '/' userdataHandle.ParamPDM.command];
    com2 = [PDM_path '/' userdataHandle.ExpAlig.command];
%     com3 = [PDM_path '/' userdataHandle.PDM_stat.command];
    com4 = [PDM_path '/' userdataHandle.PDM_Fix.command];

    if ispc
        com1 = [PDM_path '/' userdataHandle.ParamPDM.command '.exe'];
        com2 = [PDM_path '/' userdataHandle.ExpAlig.command '.exe'];
        com4 = [PDM_path '/' userdataHandle.PDM_Fix.command '.exe'];
    end
    if exist(com1, 'file')
        userdataHandle.ParamPDM.exist =1;
    else
        userdataHandle.ParamPDM.exist =0;
    end
    if exist(com2, 'file')
        userdataHandle.ExpAlig.exist =1;
    else
        userdataHandle.ExpAlig.exist =0;
    end
    if exist(com4, 'file')
        userdataHandle.PDM_Fix.exist =1;
    else
        userdataHandle.PDM_Fix.exist =0;
    end
end

% Display objects
userdataHandle.DisplayObjs.vars = {'Space','Mesh','Shade','Overlay','Export','Degree','Template'};
userdataHandle.DisplayObjs.args = [10 10 10 10 10 1 100];
userdataHandle.DisplayObjs.inFilter = {...
    '*.mat', 'All Objects (*.mat)'; ...
    '*_bim.mat; *_fix.mat', 'Bianry Objects (*_bim.mat, *_fix.mat)'; ...
    '*_obj.mat', 'Mesh Objects (*_obj.mat)'; ...
    '*_ini.mat; *_smo.mat', 'Parameterized Objects (*_ini.mat, *_smo.mat)'; ...
    '*_des.mat', 'SPHARM Descriptors (*_des.mat)'; ...
    '*_reg.mat; *_nor.mat',  'Registered Objects (*_reg.mat, *_nor.mat)' ...
    };
userdataHandle.DisplayObjs.default = {'','','','','','',''};

for i=1:length(userdataHandle.DisplayObjs.vars)
    varName = sprintf('userdataHandle.DisplayObjs.%s', userdataHandle.DisplayObjs.vars{i});
    if userdataHandle.DisplayObjs.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.DisplayObjs.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.DisplayObjs.default{%d});', varName, i);
        eval(strCC);
    end
end

%  Scale objects
userdataHandle.ScaleObjs.vars = {'ScalingFactor','OutDirectory'};
userdataHandle.ScaleObjs.args = [100 200];
userdataHandle.ScaleObjs.inFilter = {'*_des.mat; *_prm.mat; *_reg.mat', 'SPHARM Descriptors (*_des.mat, *_prm.mat, *_reg.mat)'; ...
    '*_obj.mat; *_ini.mat; *_smo.mat',  'Meshed Objects (*_obj.mat, *_ini.mat, *_smo.mat)'; ...
    '*.mat', 'All Objects (*.mat)'};
userdataHandle.ScaleObjs.default = {'','./'};

for i=1:length(userdataHandle.ScaleObjs.vars)
    varName = sprintf('userdataHandle.ScaleObjs.%s', userdataHandle.ScaleObjs.vars{i});
    if userdataHandle.ScaleObjs.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.ScaleObjs.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.ScaleObjs.default{%d});', varName, i);
        eval(strCC);
    end
end

% Create average object
userdataHandle.AverageObjs.vars = {'OutputName','OutDirectory'};
userdataHandle.AverageObjs.args = [10 200];
userdataHandle.AverageObjs.inFilter = {'*_des.mat; *_prm.mat; *_reg.mat', 'SPHARM Descriptors (*_des.mat, *_prm.mat, *_reg.mat)'; ...
    '*.mat', 'All Objects (*.mat)'};
userdataHandle.AverageObjs.default = {'atlas.mat','./'};

for i=1:length(userdataHandle.AverageObjs.vars)
    varName = sprintf('userdataHandle.AverageObjs.%s', userdataHandle.AverageObjs.vars{i});
    if userdataHandle.AverageObjs.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.AverageObjs.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.AverageObjs.default{%d});', varName, i);
        eval(strCC);
    end
end

% Import objects
userdataHandle.Import.vars = {'ResampleFactor','OutDirectory'};
userdataHandle.Import.args = [1 200];
userdataHandle.Import.inFilter = {'*.stl', 'Mesh Objects (*.stl)'; ...
    '*.m', 'Surface-mesh Objects (*.m)'; ...
    '*.hdr; *.nii', 'Binary Analyze/NIfTI Objects (*.hdr, *.nii)'};% ...
%    '*.stl; *.m; *.hdr; *.nii', 'All Eligible Files (*.stl, *.m, *.hdr, *.nii)'};
userdataHandle.Import.default = {'1','./'};

for i=1:length(userdataHandle.Import.vars)
    varName = sprintf('userdataHandle.Import.%s', userdataHandle.Import.vars{i});
    if userdataHandle.Import.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.Import.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.Import.default{%d});', varName, i);
        eval(strCC);
    end
end

% Convert file formats
userdataHandle.bim2gipl.inFilter = {'*_bim.mat', 'Bianry Objects (*_bim.mat)'; ...
    '*.mat', 'All Objects (*.mat)'};
userdataHandle.bim2gipl.args=[200];
userdataHandle.bim2gipl.vars = {'OutDirectory'};
userdataHandle.bim2gipl.OutDirectory = './';

userdataHandle.fix2gipl.inFilter = {'*_fix.mat', 'Bianry Objects (*_fix.mat)'; ...
    '*.mat', 'All Objects (*.mat)'};
userdataHandle.fix2gipl.args=[200];
userdataHandle.fix2gipl.vars = {'OutDirectory'};
userdataHandle.fix2gipl.OutDirectory = './';

userdataHandle.gipl2bim.inFilter = {'*.gipl', 'Bianry Objects (*.gipl)'};
userdataHandle.gipl2bim.args=[200];
userdataHandle.gipl2bim.vars = {'OutDirectory'};
userdataHandle.gipl2bim.OutDirectory = './';

userdataHandle.smo2surf_para_meta.inFilter = {'*_smo.mat', 'Parameterized Objects (*_smo.mat)'};
userdataHandle.smo2surf_para_meta.args=[200];
userdataHandle.smo2surf_para_meta.vars = {'OutDirectory'};
userdataHandle.smo2surf_para_meta.OutDirectory = './';

userdataHandle.surf_para_meta2smo.inFilter = {'*_surf.meta;*_para.meta', 'Parameterized Objects (*_surf.meta, *_para.meta)'};
userdataHandle.surf_para_meta2smo.args=[200];
userdataHandle.surf_para_meta2smo.vars = {'OutDirectory'};
userdataHandle.surf_para_meta2smo.OutDirectory = './';

userdataHandle.des2meta_coef.inFilter = {'*_des.mat', 'SPHARM Descriptors (*_des.mat)'};
userdataHandle.des2meta_coef.args=[200];
userdataHandle.des2meta_coef.vars = {'OutDirectory'};
userdataHandle.des2meta_coef.OutDirectory = './';

userdataHandle.meta_coef2des.inFilter = {'*_surfSPHARM.meta;*_surfSPHARM.coef', 'SPHARM Descriptors (*_surfSPHARM.meta, *_surfSPHARM.coef)'};
userdataHandle.meta_coef2des.args=[200];
userdataHandle.meta_coef2des.vars = {'OutDirectory'};
userdataHandle.meta_coef2des.OutDirectory = './';

userdataHandle.ellalign_meta_coef2reg.inFilter = {'*_ellalign.meta;*_ellalign.coef', 'Registered SPHARM Descriptors (*_ellalign.meta, *_ellalign.coef)'};
userdataHandle.ellalign_meta_coef2reg.args=[200];
userdataHandle.ellalign_meta_coef2reg.vars = {'OutDirectory'};
userdataHandle.ellalign_meta_coef2reg.OutDirectory = './';

% reg2procalign_meta option (mesh selection)
userdataHandle.reg2procalign_meta.vars = {'SampleMesh','OutDirectory'};
userdataHandle.reg2procalign_meta.args = [10,200];
userdataHandle.reg2procalign_meta.inFilter = {'*_reg.mat;*_nor.mat', 'Registered Objects (*_reg.mat, *_nor.mat)'};
userdataHandle.reg2procalign_meta.default = {'','./'};

for i=1:length(userdataHandle.reg2procalign_meta.vars)
    varName = sprintf('userdataHandle.reg2procalign_meta.%s', userdataHandle.reg2procalign_meta.vars{i});
    if userdataHandle.reg2procalign_meta.args(i) < 10
        strCC = sprintf('%s=str2num(userdataHandle.reg2procalign_meta.default{%d});', varName, i);
        eval(strCC);
    else
        strCC = sprintf('%s=(userdataHandle.reg2procalign_meta.default{%d});', varName, i);
        eval(strCC);
    end
end

userdataHandle.others.inFilter = {'*.txt', 'List of Objects (*.txt)'};  %'t_map' 'PCA' 't_map+PCA'

return;


% For transforming the sparse adjacency matrices in 'DD' and 'NCI1' to dense
% in order to be read by torch.matio
% Note torch.matio does not support dense .mat

dataset = strvcat('DD', 'NCI1');
for ith_data = 1: size(dataset, 1)
    clear save_struct
    data = strcat(dataset(ith_data, :))
    dataname = strcat('../data/raw_data/', data, '.mat');
    load(dataname);
    X = eval(data);
    for i = 1: size(X, 2)
        am = full(X(i).am);
        l = X(i).nl.values;
        X(i).am = am;
    end
    save_struct.(data) = X;
    save(dataname, '-struct', 'save_struct', '-append');
end


function [E tempprot] = RemoveNegMeas(Epn, protocol)
% Removes negative or zero measurements from a set and returns a protocol
% with the corresponding elements removed to exclude the negative
% measurements from the fitting.
%
% Epn is the full set of measurements; E is that with the negative ones
% removed.
%
% protocol is the full protocol; tempprot is that with the entries
% corresponding to negative measurements removed.
%
% author: Daniel C Alexander (d.alexander@ucl.ac.uk)
%         Gary Hui Zhang (gary.zhang@ucl.ac.uk)
%

tempprot = protocol;
E = Epn;
if(min(Epn)<=0)
    posonly = find(Epn>0);
    E = Epn(posonly);
    nonposonly = setdiff([1:size(Epn,1)], posonly);
    tempprot.totalmeas = length(posonly);
    % find the b0 indices for the new protocol without the non-positive
    % measurements
    tempprot.b0_Indices = [];
    for i=1:length(protocol.b0_Indices)
        currentB = protocol.b0_Indices(i);
        index = find(nonposonly<=currentB, 1, 'last');
        if isempty(index)
            tempprot.b0_Indices = [tempprot.b0_Indices currentB];
        elseif (nonposonly(index) ~= currentB)
            currentB = currentB - index;
            tempprot.b0_Indices = [tempprot.b0_Indices currentB];
        end
    end
    tempprot.numZeros = length(tempprot.b0_Indices);
    if(strcmp(tempprot.pulseseq, 'PGSE') || strcmp(tempprot.pulseseq, 'STEAM'))
        tempprot.G = tempprot.G(posonly);
        tempprot.delta = tempprot.delta(posonly);
        tempprot.smalldel = tempprot.smalldel(posonly);
        tempprot.grad_dirs = tempprot.grad_dirs(posonly, :);
    else
        error('Need to adapt for other pulse sequences.');
    end
end

if length(tempprot.b0_Indices) == 0
    error('All b=0 measurements are negative');
end


function [Eft, Varft, lpyt, Eyt, Varyt] = gpmc_loopred(gp, x, y, varargin)
%GPMC_LOOPRED  Leave-one-out predictions with Gaussian Process MCMC approximation.
%
%  Description
%    [EFT, VARFT, LPYT, EYT, VARYT] = GPMC_LOOPRED(RECGP, X, Y, OPTIONS)
%    takes a Gaussian processes record structure RECGP (returned by
%    gp_mc) together with a matrix X of training inputs and vector
%    Y of training targets, and evaluates the leave-one-out
%    predictive distribution at inputs X and returns means EFT and
%    variances VARFT of latent variables, the logarithm of the
%    predictive densities PYT, and the predictive means EYT and
%    variances VARYT of observations at input locations X.
%
%    OPTIONS is optional parameter-value pair
%      z      - optional observed quantity in triplet (x_i,y_i,z_i)
%               Some likelihoods may use this. For example, in case of
%               Poisson likelihood we have z_i=E_i, that is, expected value
%               for ith case.
%      is     - defines if importance sampling weighting is used 'on'
%               (default). If set to 'off', MCMC samples from the
%               full data posterior are used.
%
%    Given Gaussian likelihood or non-Gaussian likelihood and
%    latent method Laplace or EP, LOO-posterior given
%    hyperparameters is computed analytically or with analytic
%    approximation and LOO-posterior of the hyperparameters is
%    approximated using importance sampling. Optionally full data
%    posterior for hyperparameters can be used (by setting option
%    'is' to 'off'). Given non-Gaussian likelihood and latent
%    method MCMC, LOO-posterior of the hyperparameters and latent
%    values is approximated using importance sampling.
%
%  References:
%    Aki Vehtari and Jouko Lampinen (2002). Bayesian model
%    assessment and comparison using cross-validation predictive
%    densities. Neural Computation, 14(10):2439-2468.
%
%  See also
%   GP_LOOPRED, GP_MC, GP_PRED
%

% Copyright (c) 2012 Aki Vehtari

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

ip=inputParser;
ip.FunctionName = 'GPMC_LOOPRED';
ip.addRequired('gp',@isstruct);
ip.addRequired('x', @(x) ~isempty(x) && isreal(x) && all(isfinite(x(:))))
ip.addRequired('y', @(x) ~isempty(x) && isreal(x) && all(isfinite(x(:))))
ip.addParamValue('z', [], @(x) isreal(x) && all(isfinite(x(:))))
ip.addParamValue('is', 'on', @(x) ismember(x,{'on' 'off'}))
ip.parse(gp, x, y, varargin{:});
z=ip.Results.z;
is=ip.Results.is;

if isfield(gp,'meanf') && ~isempty(gp.meanf)
  error('GPMC_LOOPRED: Mean functions not yet supported');
end

nmc=size(gp.jitterSigma2,1);
[n,nin]=size(x);

if strcmp(gp.type, 'PIC_BLOCK') || strcmp(gp.type, 'PIC')
  ind = gp.tr_index;           % block indeces for training points
  gp = rmfield(gp,'tr_index');
end

for i1=1:nmc
  % compute leave-one-out predictions for each hyperparameter sample
  % if latent method is MCMC, then these samples are for latent values, too
  Gp = take_nth(gp,i1);
  switch gp.type
    case 'FULL'

    case {'FIC' 'CS+FIC'}
      % Reformat the inducing inputs
      u = reshape(Gp.X_u,length(Gp.X_u)/nin,nin);
      Gp.X_u = u;

    case {'PIC' 'PIC_BLOCK'}
      % Reformat the inducing inputs
      u = reshape(Gp.X_u,length(Gp.X_u)/nin,nin);
      Gp.X_u = u;
      Gp.tr_index = ind;
  end
  if nargout <= 3
    [Efts(:,i1), Varfts(:,i1), lpyts(:,i1)] = gp_loopred(Gp, x, y, 'z', z);
  else
    [Efts(:,i1), Varfts(:,i1), lpyts(:,i1), Eyts(:,i1), Varyts(:,i1)] = gp_loopred(Gp, x, y, 'z', z);
  end
end

if isequal(is,'off')
  w=1/nmc;
  lw=-log(nmc);
else
  % log importance sampling weights
  lw=-lpyts;
  % normalize weights
  for i2=1:n
    % this works even when lw have large magnitudes
    lw(i2,:)=lw(i2,:)-sumlogs(lw(i2,:));
  end
  % importance sampling weights
  w=exp(lw);
  % check the effective sample size
  m_eff=1./sum(w.^2,2);
  if min(m_eff)<n/10
    mn=sum(m_eff<(n/10));
    if mn==1
      warning(sprintf('For %d data point the effective sample size in IS is less than n/10',mn))
    else
      warning(sprintf('For %d data points the effective sample size in IS is less than n/10',mn))
    end
  end
end

% IS-LOO predictions
Eft = sum(Efts.*w, 2);
Varft = sum(Varfts.*w,2) + sum(bsxfun(@minus,Efts,Eft).^2.*w,2);
if nargout > 2
  lpyt = log(sum(exp(lpyts+lw),2)); % same as lpy=log(sum(exp(lpys).*w,2));
  if nargout > 3
    Eyt = sum(Eyts.*w,2);
    Varyt = sum(Varyts.*w,2) + sum(bsxfun(@minus,Eyts,Eyt).^2.*w,2);
  end
end


function Y = acos(X)
    % Symbolic inverse cosine.

    % Convert inputs to SymExpression
    % X = SymExpression(X);

    % construct the operation string
    sstr = ['ArcCos[' X.s ']'];

    % create a new object with the evaluated string
    Y = SymExpression(sstr);
end


%% Main script
clear all, close all;

%% Global options
GO_SHOW_CHANGE = true;	% Show the difference image (DI)
GO_SHOW_MASK = true;	% Show the change map (CM)
GO_SHOW_PRETTIFIED = true;	% Show the prettified detection results
GO_SHOW_ROC_CURVE = true;	% Plot the ROC curve

GO_BAND_PRE_NORM = false;	% Perform a band-wise pre-normalization on the inputs

GO_CONFIG_ROC = {};
GO_VERBOSE = true;
GO_SAVE_RESULTS = false;
GO_OUT_FILE_PATH = './results.xls';		% Path to save the results

% PAUSE MODES:
% -1: resume next iteration when all figures closed;
% -2: press any key to continue
GO_PAUSE_MODE = 1;

PAUSE_EACH_ITER_ = GO_SHOW_CHANGE | GO_SHOW_MASK | GO_SHOW_PRETTIFIED | GO_SHOW_ROC_CURVE;

%% Opt and configure the IMPORTANT ones
%{
	Available algorithms: CVA, DPCA, ImageDiff, ImageRatio, ImageRegr, IRMAD, MAD, PCAkMeans, PCDA

	Available datasets: AirChangeDataset, BernDataset, OSCDDataset, OttawaDataset, TaizhouDataset

	Available binaryzation algorithms: FixedThre, KMeans, OTSU

	Available metrics: AUC, FMeasure, Kappa, OA, Recall, UA
%}
ALG = 'MAD'
DATASET = 'TaizhouDataset'
THRE_ALG = 'KMeans'
METRICS = {'OA', 'UA', 'Recall', 'FMeasure', 'AUC', 'Kappa'}

CONFIG_ALG = {};
CONFIG_DATASET = {'D:\\data\\CD\\Taizhou'};
CONFIG_THRE_ALG = {};
CONFIG_METRICS = {{}, {}, {}, {}, {}, {}};

% Check it
if GO_SHOW_ROC_CURVE
    [~, loc] = ismember('AUC', METRICS);
    if loc == 0
        error('AUC was not included in the desired metrics');
    end
end

%% Construct objects
alg = Algorithms.(ALG)(CONFIG_ALG{:});
dataset = Datasets.(DATASET)(CONFIG_DATASET{:});
iterDS = Datasets.CDDIterator(dataset);
threAlg = ThreAlgs.(THRE_ALG)(CONFIG_THRE_ALG{:});
nMetrics = length(METRICS);
metrics = cell(1, nMetrics);
for ii = 1:nMetrics
    metrics{ii} = Metrics.(METRICS{ii})(CONFIG_METRICS{ii}{:});
end

%% Main loop
while(iterDS.hasNext())
    % Fetch data
    [t1, t2, ref] = iterDS.nextChunk();

    if GO_BAND_PRE_NORM
        % Perform a band-wise z-score normalization before any further
        % algorithm is applied
        fcnNorm = @Utilities.normMeanStd;
        [t1, t2] = deal(fcnNorm(double(t1)), fcnNorm(double(t2)));
    end

    % Make difference image
    DI = alg.detectChange(t1, t2);
    % Segment
    CM = threAlg.segment(DI);
    % Measure
    cellfun(@(obj) obj.update(CM, ref, DI), metrics);

    if GO_VERBOSE
        for ii = 1:nMetrics
            m = metrics{ii};
            fprintf('type: %s\n', METRICS{ii});
            fprintf('\tnewest: %f\n', m.val(end));
            fprintf('\taverage: %f\n', m.avg);
        end
        fprintf('\n')
    end

    if PAUSE_EACH_ITER_
        handles = [];
        if GO_SHOW_CHANGE
            figure('Name', 'Change Map'),
            chns = size(DI, 3);
            if  chns ~= 1 && chns ~=3
                imshow(Utilities.normMinMax(Utilities.mergeAvg(DI)));
            else
                imshow(Utilities.normMinMax(DI));
            end
            handles = [handles, gcf];
        end

        if GO_SHOW_MASK
            figure('Name', 'Change Mask'),
            imshow(CM);
            handles = [handles, gcf];
        end

        if GO_SHOW_PRETTIFIED
            figure('Name', 'Prettified Change Map'),
            imshow(Utilities.pretty(DI, CM, ref));
            handles = [handles, gcf];
        end

        if GO_SHOW_ROC_CURVE
            if ~exist('aucer', 'var')
                aucer = metrics{loc};
            end
            fig = aucer.plotROC(GO_CONFIG_ROC{:});
            handles = [handles, fig];
        end

        if (iterDS.hasNext())
            if GO_PAUSE_MODE == 1
                for h = handles
                    waitfor(h);
                end
            elseif GO_PAUSE_MODE == 2
                pause
            else
                ;
            end
        end
    end
end

%% Collate and save results
results = struct('name', alg.algName, 'threAlg', threAlg.algName, 'dataset', DATASET);
for ii = 1:nMetrics
    results.(METRICS{ii}) = metrics{ii}.avg;
end

if GO_SAVE_RESULTS
    [~, ~, ext] = fileparts(GO_OUT_FILE_PATH);
    switch ext
        case '.mat'
            save(GO_OUT_FILE_PATH, 'results');
        case {'.xls', '.xlsx'}
            writetable(struct2table(results), GO_OUT_FILE_PATH);
        otherwise
            error('Unsupported type of file');
    end
end


function [fragments, junctions, neighbor_data, seg, avg_seg_colors, ...
    polyfragments, poly_params] = seg2fragments(seg, img, min_area, order)
%
% [fragments, junctions, neighbor_data, new_seg, avg_seg_colors, ...
%  <polyfragments>, <poly_params>] = seg2fragments(seg, img, min_area, <order>)
%
%  Finds the boundary fragments for an oversegmentation of an image:
%
%  (1) Takes in an over-segmentation labeling (with labels 1:N),
%  (2) Fills any pixels with a label of zero with the neighboring label
%      that has the most similar color value in the original RGB color
%      image 'img',
%  (3) Cleans up segments which have a single pixel jutting diagonally off
%      of a corner somewhere, by reassigning these offending pixels to the
%      neighboring segment with the most similar color (as in (2)).
%  (4) Breaks diagonal-only connected segments into two new segments.
%  (5) Merges segments that are too small with a neighbor with the most
%      similar average color, and
%  (6) Chains fragments along the boundaries between segments, stopping at
%      junctions and image borders.
%
%  Returns the fragments as a cell array of [Mx2] matrices which contain
%  the M (x,y) coordinates of of each fragment's constituent elements, the
%  fragment neighbor information (see below for details), and the new
%  (filled-in / merged) segmentation.
%
%  'neighbor_data' is a struct with two fields:
%   - 'junction_fragmentlist': a list which contains for each junction an
%                              array of indices of the fragments that meet
%                              there
%   - 'fragment_junctionlist': a list which contains for each fragment the
%                              indices of the junctions which bound it
%   - 'fragment_segments': a list which contains for each fragment the ID
%                          numbers of the segments found to the left and
%                          right of that fragment, stored [left right].
%   - 'segment_fragments': a list which contains for each segment the index
%                          of the fragments that border it
%
%  Thus, the indices of fragment i's neighbors on one end can be found by:
%    junction_fragmentlist{fragment_junctionlist{i}(1)}
%
%  If requested, also fits polynomials of degree 'order' to each fragment
%  and returns those as well (and their parameters).
%

% DEPENDENCIES:
%  - RGB2Lab.m
%  - cracks2fragments.m
%  - fill_in_segmentation.m
%  - fit_curves.m
%    - fit_poly_to_fragment.m
%  - remove_small_segments.m
%  - seg2cracks.m
% [- drawedges.m (will use it if available, not a problem if not)]

[nrows, ncols] = size(seg);

% Convert the image to Lab space so that color distances used below are
% more meaningful
if ~isempty(img)
    img_lab = RGB2Lab(img);
end

while (any(seg(:)==0))
    seg = fill_in_segmentation(img, seg, 0, 4);
end

num_segments = max(seg(:));

% Find locations where there's a pixel jutting off diagonally from  a
% corner of a segment.  We want to remove those and attach them to the
% nearest-colored 4-connected neighbor.
% Note: this is actually redundant since this would also be covered below,
% but it's much faster to remove the simple singleton stragglers like this
% first (since it requires fewer calls to bwselect).
% stragglers = find( seg~=seg(:,[2:end end]) & seg~=seg(:,[1 1:end-1]) & ...
%     seg~=seg([2:end end],:) & seg~=seg([1 1:end-1],:) );
% if(any(stragglers(:)))
%     corner_neighbor_offsets = [-1-nrows -1+nrows 1-nrows 1+nrows];
%
%     for(i=1:length(stragglers))
%         % if the straggler was diagonnally connecting >=2 larger pieces of
%         % this segment, we need to re-label all but one of them to avoid
%         % inadvertantly splitting a segment into multiple pieces by
%         % removing the straggler
%         [y,x] = ind2sub([nrows ncols], stragglers(i));
%         corner_x = x + [-1 1 1 -1];
%         corner_y = y + [-1 -1 1 1];
%         out_of_bounds = find(corner_x<1 | corner_x>ncols | corner_y<1 | corner_y>nrows);
%         corner_x(out_of_bounds) = [];
%         corner_y(out_of_bounds) = [];
%         corner_neighbors = sub2ind([nrows ncols], corner_y, corner_x);
%         to_relabel = find( seg(corner_neighbors)==seg(stragglers(i)) );
%         if(length(to_relabel)>=2)
%             bw_img = seg==seg(stragglers(i));
%             for(j = 1:length(to_relabel))
%                 num_segments = num_segments+1;
%                 seg(bwselect(bw_img,corner_x(to_relabel(j)),corner_y(to_relabel(j)),4)) = num_segments;
%             end
%         end
%     end
%
%     % Now actually get rid of the stragglers by setting them to zero and
%     % filling them in:
%     seg(stragglers) = 0;
%     seg = fill_in_segmentation(img, seg, 0, 4);
%
% end

% Convert the segmentation to a crack image.  Note that we need this for
% the next step, even if we have to end up re-doing it later if small
% segments get removed.
cracks = seg2cracks(seg);

% Find locations where a single segment narrows to a singe-pixel diagonal
% connection.  We want to split such locations into two segments.
down_right_splits = find(cracks==15 & seg==seg([2:end end],[2:end end]));
down_left_splits  = find(cracks==15 & seg(:,[2:end end])==seg([2:end end],:));
[r,c] = ind2sub([nrows ncols], down_right_splits);
for(i=1:length(down_right_splits))
    % Need to set _both_ of the resulting segments after the split to new
    % ID numbers to avoid inadvertantly forming a non-contiguous segment
    % later... (argh, twice as many bwselect calls!)
    temp = seg==seg(down_right_splits(i));
    num_segments = num_segments+1;
    seg(bwselect(temp,c(i),r(i),4)) = num_segments;
    num_segments = num_segments+1;
    seg(bwselect(temp,c(i)+1,r(i)+1,4)) = num_segments;
end
[r,c] = ind2sub([nrows ncols], down_left_splits);
for(i=1:length(down_left_splits))
    temp = seg==seg(r(i),c(i)+1);
    num_segments = num_segments+1;
    seg(bwselect(temp,c(i)+1,r(i),4)) = num_segments;
    num_segments = num_segments+1;
    seg(bwselect(temp,c(i),r(i)+1,4)) = num_segments;
end

if(nargin < 3 || isempty(min_area))
    min_area = 0;
end

if min_area > 0
    [seg, avg_seg_colors] = remove_small_segments(seg, img_lab, min_area);
end

% Assuming any segments were removed, we'll need to update the crack info
cracks = seg2cracks(seg);

try
    [fragments, junctions, neighbor_data] = cracks2fragments(cracks, seg);
catch
    disp('warning: no isolation check');
    [fragments, junctions, neighbor_data] = cracks2fragments(cracks, seg, 0);
end

if(nargout>=5 || nargout==0)
    if(nargin < 4)
        order = 3;
    end

    [polyfragments, poly_params] = fit_curves(fragments, order);
end

if(nargout==0)
    figure(gcf)
    subplot 121, hold off
    imagesc(img), axis image, hold on
    title('Segment Borders')

    subplot 122, hold off
    imagesc(img), axis image, hold on
    title(['Polynomial Fits to Fragments (order=' num2str(order)])

    if(exist('file', 'drawedges'))
        subplot 121, drawedges(fragments, 'rand');
        subplot 122, drawedges(polyfragments, 'rand');
    else
        subplot 121
        for(i=1:length(fragments))
            plot(fragments{i}(:,1), fragments{i}(:,2), 'r', 'LineWidth', 2);
        end
        subplot 122
        for(i=1:length(polyfragments))
            plot(polyfragments{i}(:,1), polyfragments{i}(:,2), 'r', 'LineWidth', 2);
        end
    end
end