function ir = sofa_get_data_fir(sofa,idx)
%SOFA_GET_DATA_FIR returns a FIR data matrix from a SOFA file or struct
%
%   Usage: ir = sofa_get_data_fir(sofa,[idx])
%
%   Input parameters:
%       sofa    - impulse response data set (SOFA struct/file)
%       idx     - index of the single impulse responses that should be returned.
%                 idx could be a single value, then only one impulse response
%                 will be returned, or it can be a vector then all impulse
%                 responses for the corresponding index positions will be
%                 returned (default: return all impulse responses)
%
%   Output parameters:
%       ir      - impulse response (M,2,N), where
%                   M ... number of impulse responses
%                   N ... samples
%
%   SOFA_GET_DATA_FIR(sofa,idx) returns impulse response of the given
%   SOFA file or struct, specified by idx. If no idx is specified all data
%   contained in sofa is returned.
%   For the struct the SOFA file has to loaded before with SOFAload().
%   For a description of the SOFA file format see: https://sofaconventions.org
%
%   See also: sofa_get_data_fire, sofa_get_header, get_ir, SOFAload

%*****************************************************************************
% The MIT License (MIT)                                                      *
%                                                                            *
% Copyright (c) 2010-2019 SFS Toolbox Developers                             *
%                                                                            *
% Permission is hereby granted,  free of charge,  to any person  obtaining a *
% copy of this software and associated documentation files (the "Software"), *
% to deal in the Software without  restriction, including without limitation *
% the rights  to use, copy, modify, merge,  publish, distribute, sublicense, *
% and/or  sell copies of  the Software,  and to permit  persons to whom  the *
% Software is furnished to do so, subject to the following conditions:       *
%                                                                            *
% The above copyright notice and this permission notice shall be included in *
% all copies or substantial portions of the Software.                        *
%                                                                            *
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
% IMPLIED, INCLUDING BUT  NOT LIMITED TO THE  WARRANTIES OF MERCHANTABILITY, *
% FITNESS  FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL *
% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
% LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT  OR OTHERWISE, ARISING *
% FROM,  OUT OF  OR IN  CONNECTION  WITH THE  SOFTWARE OR  THE USE  OR OTHER *
% DEALINGS IN THE SOFTWARE.                                                  *
%                                                                            *
% The SFS Toolbox  allows to simulate and  investigate sound field synthesis *
% methods like wave field synthesis or higher order ambisonics.              *
%                                                                            *
% https://sfs.readthedocs.io                            sfstoolbox@gmail.com *
%*****************************************************************************

%% ===== Checking of input  parameters ==================================
nargmin = 1;
nargmax = 2;
narginchk(nargmin,nargmax)
if nargin==nargmax-1
    idx = [];
else
    isargvector(idx);
end

%% ===== Computation ====================================================
if length(idx)==0
    if sofa_is_file(sofa)
        sofa = SOFAload(sofa);
    end
    ir = sofa.Data.IR;
else
    header = sofa_get_header(sofa);
    if sofa_is_file(sofa)
        ir = zeros(length(idx),2,header.API.N);
        for ii=1:length(idx)
            tmp = SOFAload(sofa,[idx(ii) 1]);
            ir(ii,:,:) = tmp.Data.IR;
        end
    else
        ir = sofa.Data.IR(idx,:,:);
    end
end


function [inside] = ft_inside_vol(pos, vol)

% FT_INSIDE_VOL locates dipole locations inside/outside the source
% compartment of a volume conductor model.
%
% [inside] = ft_inside_vol(pos, vol, ...)
%
% where the input should be
%   pos      Nx3 matrix with dipole positions
%   vol      structure with volume conductor model
% and the output is
%   inside   list of dipoles inside the brain compartment
%            (1=inside, 0=outisde)
%
% Additional optional input arguments should be given in key value pairs
% and can include
%   <none>

% Copyright (C) 2003-2007, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
% 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: ft_inside_vol.m 2885 2011-02-16 09:41:58Z roboos $

% determine the type of volume conduction model
switch ft_voltype(vol)

  % single-sphere or multiple concentric spheres
  case {'singlesphere' 'concentric'}
    if ~isfield(vol, 'source')
      % locate the innermost compartment and remember it
      [dum, vol.source] = min(vol.r);
    end
    if isfield(vol, 'o')
      % shift dipole positions toward origin of sphere
      tmp = pos - repmat(vol.o, size(pos,1), 1);
    else
      tmp = pos;
    end
    distance = sqrt(sum(tmp.^2, 2))-vol.r(vol.source);
    % positive if outside, negative if inside
    inside   = distance<0;

    % multi-sphere volume conductor model
  case 'multisphere'

    % nspheres = size(vol.r,1);
    % ndipoles = size(pos,1);
    % inside = zeros(ndipoles,1);
    % for sph=1:nspheres
    % for dip=1:ndipoles
    %   if inside(dip)
    %     % the dipole has already been detected in one of the other spheres
    %     continue
    %   end
    %   inside(dip) = (norm(pos(dip,:) - vol.o(sph,:)) <= vol.r(sph));
    % end
    % end
    % outside = find(inside==0);
    % inside  = find(inside==1);

    % this is a much faster implementation
    nspheres = size(vol.r,1);
    ndipoles = size(pos,1);
    inside = zeros(ndipoles,1);
    for sph=1:nspheres
      % temporary shift dipole positions toward origin
      if isfield(vol, 'o')
        tmp = pos - repmat(vol.o(sph,:), [ndipoles 1]);
      else
        tmp = pos;
      end
      flag = (sqrt(sum(tmp.^2,2)) <= vol.r(sph));
      inside = inside + flag;
    end
    inside  = inside>0;

    % realistic BEM volume conductor model
  case {'bem', 'dipoli', 'bemcp', 'asa', 'avo', 'nolte', 'neuromag'}
    if ~isfield(vol, 'source')
      % locate the innermost compartment and remember it
      vol.source = find_innermost_boundary(vol.bnd);
    end
    % use the specified source compartment
    pnt = vol.bnd(vol.source).pnt;
    tri = vol.bnd(vol.source).tri;
    % determine the dipole positions that are inside the brain compartment
    inside  = bounding_mesh(pos, pnt, tri);

    % unrecognized volume conductor model
  otherwise
    error('unrecognized volume conductor model');
end

% ensure that these are column vectors
inside(find(isnan(inside(:)))) = 0;
inside  = logical(inside(:));


% Jiao Xianjun (putaoshu@msn.com; putaoshu@gmail.com)
% multi_rtl_sdr_split_scanner.m
% Frequency band scanning via multiple rtl-sdr dongles. Each dongle for each sub-band to speedup!
% A script of project: https://github.com/JiaoXianjun/multi-rtl-sdr-calibration

% Assume that you have installed rtl-sdr
% (http://sdr.osmocom.org/trac/wiki/rtl-sdr) and have those native utilities run correctly already.

% For example, you have multiple dongles, please run multiple rtl_tcp in multiple shell respectively as:
% rtl_tcp -p 1234 -d 0
% rtl_tcp -p 1235 -d 1
% rtl_tcp -p 1236 -d 2
% ...

% Then run this script in MATLAB.

% ATTENTION! In some computer, every time before you run this script, maybe you need to terminate multiple rtl_tcp and re-launch them again.
% ATTENTION! Please reduce number of inspected points by reducing frequency range or increasing step size, if your computer hasn't enough memory installed. Because all signlas are stored firstly before processing.

% Change following parameters as you need:

% Number of dongles you have connected to your computer
num_dongle = 1; % more dongles, much faster.

% Beginning of the band you are interested in
start_freq = 502e6; % for test
% start_freq = 935e6; % Beginning of Primary GSM-900 Band downlink
% start_freq = (1575.42-15)*1e6; % GPS L1
% start_freq = (1207.14-30)*1e6; % COMPASS B2I
% start_freq = (1561.098-30)*1e6; % COMPASS B1I
% start_freq = 1.14e9; % Beginning of GNSS(GPS/GLONASS/COMPASS/Galileo) Band

% End of the band you are interested in
end_freq = 702e6; % for test
% end_freq = 960e6; % End of Primary GSM-900 Band downlink
% end_freq = (1575.42+30)*1e6; % GPS L1
% end_freq = (1207.14+30)*1e6; % COMPASS B2I
% end_freq = (1561.098+30)*1e6; % COMPASS B1I
% end_freq = 1.63e9; % Beginning of GNSS(GPS/GLONASS/COMPASS/Galileo) Band

freq_step = 0.5e6; % less step, higher resolution, narrower FIR bandwidth, slower speed

observe_time = 0.2; % observation time at each frequency point. ensure it can capture your signal!

RBW = freq_step; % Resolution Bandwidth each time we inspect

gain = 20; % If this is larger than 0, the fixed gain will be set to dongles

% use high sampling rate and FIR to improve estimation accuracy
sample_rate = 2.048e6; % sampling rate of dongles

coef_order = (2^(ceil(log2(sample_rate/RBW))))-1;
coef_order = min(coef_order, 127);
coef_order = max(coef_order, 31);
coef = fir1(coef_order, RBW/sample_rate);
% freqz(coef, 1, 1024);

num_samples = observe_time*sample_rate;

clf;
close all;

% construct freq set for each dongle
freq_orig = start_freq:freq_step:end_freq;
num_freq_per_sub_band = ceil(length(freq_orig)/num_dongle);
num_pad = num_freq_per_sub_band*num_dongle - length(freq_orig);
freq = [freq_orig freq_orig(end)+(1:num_pad).*freq_step];
freq = vec2mat(freq, num_freq_per_sub_band);

real_count = zeros(1, num_dongle);
s_all = uint8( zeros(2*num_samples, num_freq_per_sub_band*num_dongle) );
decimate_ratio = floor(sample_rate/(2*RBW));

% check if previous tce objects existed. if so clear them
if ~isempty(who('tcp_obj'))
    for i=1:length(tcp_obj)
        fclose(tcp_obj{i});
        delete(tcp_obj{i});
    end
    clear tcp_obj;
end

% construct tcp objects
tcp_obj = cell(1, num_dongle);
for i=1:num_dongle
    tcp_obj{i} = tcpip('127.0.0.1', 1233+i); % for dongle i
end

% set some parameters to tcp objects, and open them.
for i=1:num_dongle
    set(tcp_obj{i}, 'InputBufferSize', 8*2*num_samples);
    set(tcp_obj{i}, 'Timeout', 60);
end
for i=1:num_dongle
    fopen(tcp_obj{i});
end

% set gain
for i=1:num_dongle
    set_gain_tcp(tcp_obj{i}, gain*10); %be careful, in rtl_sdr the 10x is done inside C program, but in rtl_tcp the 10x has to be done here.
end

% set sampling rate
for i=1:num_dongle
    set_rate_tcp(tcp_obj{i}, sample_rate);
end

% set different start freq to different dongle
for i=1:num_dongle
    set_freq_tcp(tcp_obj{i}, freq(i,1));
end

% read and discard to flush
for i=1:num_dongle
    fread(tcp_obj{i}, 8*2*num_samples, 'uint8');
end

% capture samples of all frequencies firstly!
tic;
for freq_idx = 1:num_freq_per_sub_band
    while 1 % read data at current frequency until success
        for i=1:num_dongle
            set_freq_tcp(tcp_obj{i}, freq(i, freq_idx)); % set different frequency to different dongle
        end
        for i=1:num_dongle
            [s_all(:, freq_idx + (i-1)*num_freq_per_sub_band), real_count(i)] = fread(tcp_obj{i}, 2*num_samples, 'uint8'); % gather data from different dongles to s_all
        end

        if sum(real_count-(2*num_samples)) ~= 0
            disp(num2str([idx 2*num_samples, real_count]));
        else
            break;
        end
    end
end
e = toc;
ideal_time_cost = observe_time*num_freq_per_sub_band;

% close TCP
for i=1:num_dongle
    fclose(tcp_obj{i});
end
for i=1:num_dongle
    delete(tcp_obj{i});
end
clear tcp_obj;

disp('Scanning done!');
disp(['actual time cost ' num2str(e) ' ideal cost ' num2str(ideal_time_cost) ' efficiency(ideal/actual) ' num2str(ideal_time_cost/e)]);
disp(' ');
disp('Begin process ...');

% generate power spectrum
tic;
r = raw2iq( double( s_all ) ); % remove DC. complex number constructed.
r_flt = filter(coef, 1, r);% filter target band out
power_spectrum = mean(abs(r_flt(1:decimate_ratio:end, :)).^2, 1);% get averaged power
e1 = toc;
disp(['time cost ' num2str(e1) ' scan/process ' num2str(e/e1)]);
disp(['total time cost ' num2str(e1+e)]);

% plot power spectrum (converted to dB)
freq_linear = freq';
freq_linear = freq_linear(:)';
figure;
format_string = {'b.-', 'r.-', 'k.-', 'm.-'};
for i=1:num_dongle
    plot(freq(i,:).*1e-6, 10.*log10(power_spectrum( (i-1)*num_freq_per_sub_band+1: i*num_freq_per_sub_band)), format_string{i}); hold on;
end

legend_string = cell(1, num_dongle);
for i=1:num_dongle
    legend_string{i} = ['dongle ' num2str(i)];
end
legend(legend_string);

filename = ['split_scan_' num2str(start_freq) '_' num2str(end_freq) '_gain' num2str(gain) '_' num2str(num_dongle) 'dongles.mat'];
save(filename, 'power_spectrum', 'start_freq', 'end_freq', 'freq_step', 'observe_time', 'RBW', 'gain', 'sample_rate', 'coef', 'freq');


function fg = dtiXformFibersToMrVista(handles, fgNum, scale)
%
% fg = dtiXformFibersToMrVista(handles, [fiberGroupNum], [scale])
%
% Uses the xformVAnatToAcpc (see dtiXformVanatCompute) to convert the specified
% fiber group (ac-pc coords) to mrVista vAnatomy coords.
%
% HISTORY:
% 2004.05.03 RFD (bob@white.stanford.edu) wrote it.

if(~exist('fgNum','var') | isempty(fgNum))
    fgNum = handles.curFiberGroup;
end
if(~exist('scale','var') | isempty(scale))
    scale = [1 1 1];
end
if(length(scale(:))<3)
    scale = repmat(scale(1),1,3);
end

fg = handles.fiberGroups(fgNum);
xform = diag([scale 1])*inv(handles.xformVAnatToAcpc);
fg = dtiXformFiberCoords(fg, xform);
if(~isempty(fg.seeds))
  fg.seeds = mrAnatXformCoords(xform, fg.seeds);
end
return;


function N = spm_ecat2nifti(fname,opts)
% Import ECAT 7 images from CTI PET scanners
% FORMAT N = spm_ecat2nifti(fname)
% fname    - name of ECAT file
% opts     - options structure
%
% N        - NIfTI object (written in current directory)
%__________________________________________________________________________
% Copyright (C) 2005-2015 Wellcome Trust Centre for Neuroimaging

% John Ashburner & Roger Gunn
% $Id: spm_ecat2nifti.m 6315 2015-01-23 17:09:06Z guillaume $

if nargin==1
    opts = struct('ext',spm_file_ext);
else
    if opts.ext(1) ~= '.', opts.ext = ['.' opts.ext]; end
end

fp = fopen(fname,'r','ieee-be');
if fp == -1,
    error(['Can''t open "' fname '".']);
end

mh = ECAT7_mheader(fp);
if ~strcmp(mh.MAGIC_NUMBER,'MATRIX70v') &&...
        ~strcmp(mh.MAGIC_NUMBER,'MATRIX71v') &&...
        ~strcmp(mh.MAGIC_NUMBER,'MATRIX72v')
    fclose(fp);
    error(['"' fname '" does not appear to be ECAT 7 format.']);
end

if mh.FILE_TYPE ~= 7
    fclose(fp);
    error(['"' fname '" does not appear to be an image file.']);
end

list    = s7_matlist(fp);
matches = find((list(:,4) == 1) | (list(:,4) == 2));
llist   = list(matches,:);

for i=1:size(llist,1)
    sh(i) = ECAT7_sheader(fp,llist(i,2));
end
fclose(fp);

for i=1:size(llist,1)
    dim      = [sh(i).X_DIMENSION sh(i).Y_DIMENSION sh(i).Z_DIMENSION];
    dtype    = [4 1];
    off      = 512*llist(i,2);
    scale    = sh(i).SCALE_FACTOR*mh.ECAT_CALIBRATION_FACTOR;
    inter    = 0;
    dati     = file_array(fname,dim,dtype,off,scale,inter);

    dircos   = diag([-1 -1 -1]);
    step     = ([sh(i).X_PIXEL_SIZE sh(i).Y_PIXEL_SIZE sh(i).Z_PIXEL_SIZE]*10);
    start    = -(dim(1:3)'/2).*step';
    mat      = [[dircos*diag(step) dircos*start] ; [0 0 0 1]];

    matnum   = sprintf('%.8x',list(i,1));
    nam      = spm_file(fname,'basename');
    fnameo   = fullfile(pwd,[nam '_' matnum opts.ext]);
    dato     = file_array(fnameo,dim,[4 spm_platform('bigend')],0,scale,inter);

    N        = nifti;
    N.dat    = dato;
    N.mat    = mat;
    N.mat0   = mat;
    N.mat_intent  = 'aligned';
    N.mat0_intent = 'scanner';
    N.descrip     = sh(i).ANNOTATION;
    N.timing = struct('toffset',sh(i).FRAME_START_TIME/1000,'tspace',sh(i).FRAME_DURATION/1000);
    create(N);
    for j=1:dim(3)
        N.dat(:,:,j) = dati(:,:,j);
    end
    N.extras     = struct('mh',mh,'sh',sh(i));
end

%==========================================================================
% function list = s7_matlist(fp)
%==========================================================================
function list = s7_matlist(fp)
%S7_MATLIST List the available matrixes in an ECAT 7 file.
%   LIST = S7_MATLIST(FP) lists the available matrixes
%   in the file specified by FP.
%
%   Columns in LIST:
%       1 - Matrix identifier.
%       2 - Matrix subheader record number
%       3 - Last record number of matrix data block.
%       4 - Matrix status:
%           1 - exists - rw
%           2 - exists - ro
%           3 - matrix deleted
%

% I believe fp should be opened with:
%     fp = fopen(filename,'r','ieee-be');

fseek(fp,512,'bof');
block = fread(fp,128,'int');
if size(block,1) ~= 128
    list = [];
    return;
end
block = reshape(block,4,32);
list  = [];
while block(2,1) ~= 2
    if block(1,1)+block(4,1) ~= 31
        list = []; return;
    end
    list = [list block(:,2:32)];

    fseek(fp,512*(block(2,1)-1),'bof');
    block = fread(fp,128,'int');
    if size(block,1) ~= 128, list = []; return; end
    block = reshape(block,4,32);
end
list = [list block(:,2:(block(4,1)+1))];
list = list';

%==========================================================================
% function SHEADER=ECAT7_sheader(fid,record)
%==========================================================================
function SHEADER=ECAT7_sheader(fid,record)
%
% Sub header read routine for ECAT 7 image files
%
% Roger Gunn, 260298
off                     = (record-1)*512;
status                  = fseek(fid, off,'bof');
data_type               = fread(fid,1,'uint16',0);
num_dimensions          = fread(fid,1,'uint16',0);
x_dimension             = fread(fid,1,'uint16',0);
y_dimension             = fread(fid,1,'uint16',0);
z_dimension             = fread(fid,1,'uint16',0);
x_offset                = fread(fid,1,'float32',0);
y_offset                = fread(fid,1,'float32',0);
z_offset                = fread(fid,1,'float32',0);
recon_zoom              = fread(fid,1,'float32',0);
scale_factor            = fread(fid,1,'float32',0);
image_min               = fread(fid,1,'int16',0);
image_max               = fread(fid,1,'int16',0);
x_pixel_size            = fread(fid,1,'float32',0);
y_pixel_size            = fread(fid,1,'float32',0);
z_pixel_size            = fread(fid,1,'float32',0);
frame_duration          = fread(fid,1,'uint32',0);
frame_start_time        = fread(fid,1,'uint32',0);
filter_code             = fread(fid,1,'uint16',0);
x_resolution            = fread(fid,1,'float32',0);
y_resolution            = fread(fid,1,'float32',0);
z_resolution            = fread(fid,1,'float32',0);
num_r_elements          = fread(fid,1,'float32',0);
num_angles              = fread(fid,1,'float32',0);
z_rotation_angle        = fread(fid,1,'float32',0);
decay_corr_fctr         = fread(fid,1,'float32',0);
corrections_applied     = fread(fid,1,'uint32',0);
gate_duration           = fread(fid,1,'uint32',0);
r_wave_offset           = fread(fid,1,'uint32',0);
num_accepted_beats      = fread(fid,1,'uint32',0);
filter_cutoff_frequency = fread(fid,1,'float32',0);
filter_resolution       = fread(fid,1,'float32',0);
filter_ramp_slope       = fread(fid,1,'float32',0);
filter_order            = fread(fid,1,'uint16',0);
filter_scatter_fraction = fread(fid,1,'float32',0);
filter_scatter_slope    = fread(fid,1,'float32',0);
annotation              = fread(fid,40,'char',0);
mt_1_1                  = fread(fid,1,'float32',0);
mt_1_2                  = fread(fid,1,'float32',0);
mt_1_3                  = fread(fid,1,'float32',0);
mt_2_1                  = fread(fid,1,'float32',0);
mt_2_2                  = fread(fid,1,'float32',0);
mt_2_3                  = fread(fid,1,'float32',0);
mt_3_1                  = fread(fid,1,'float32',0);
mt_3_2                  = fread(fid,1,'float32',0);
mt_3_3                  = fread(fid,1,'float32',0);
rfilter_cutoff          = fread(fid,1,'float32',0);
rfilter_resolution      = fread(fid,1,'float32',0);
rfilter_code            = fread(fid,1,'uint16',0);
rfilter_order           = fread(fid,1,'uint16',0);
zfilter_cutoff          = fread(fid,1,'float32',0);
zfilter_resolution      = fread(fid,1,'float32',0);
zfilter_code            = fread(fid,1,'uint16',0);
zfilter_order           = fread(fid,1,'uint16',0);
mt_4_1                  = fread(fid,1,'float32',0);
mt_4_2                  = fread(fid,1,'float32',0);
mt_4_3                  = fread(fid,1,'float32',0);
scatter_type            = fread(fid,1,'uint16',0);
recon_type              = fread(fid,1,'uint16',0);
recon_views             = fread(fid,1,'uint16',0);
fill                    = fread(fid,1,'uint16',0);
annotation              = deblank(char(annotation.*(annotation>0))');

SHEADER = struct('DATA_TYPE', data_type, ...
    'NUM_DIMENSIONS', num_dimensions, ...
    'X_DIMENSION', x_dimension, ...
    'Y_DIMENSION', y_dimension, ...
    'Z_DIMENSION', z_dimension, ...
    'X_OFFSET', x_offset, ...
    'Y_OFFSET', y_offset, ...
    'Z_OFFSET', z_offset, ...
    'RECON_ZOOM', recon_zoom, ...
    'SCALE_FACTOR', scale_factor, ...
    'IMAGE_MIN', image_min, ...
    'IMAGE_MAX', image_max, ...
    'X_PIXEL_SIZE', x_pixel_size, ...
    'Y_PIXEL_SIZE', y_pixel_size, ...
    'Z_PIXEL_SIZE', z_pixel_size, ...
    'FRAME_DURATION', frame_duration, ...
    'FRAME_START_TIME', frame_start_time, ...
    'FILTER_CODE', filter_code, ...
    'X_RESOLUTION', x_resolution, ...
    'Y_RESOLUTION', y_resolution, ...
    'Z_RESOLUTION', z_resolution, ...
    'NUM_R_ELEMENTS', num_r_elements, ...
    'NUM_ANGLES', num_angles, ...
    'Z_ROTATION_ANGLE', z_rotation_angle, ...
    'DECAY_CORR_FCTR', decay_corr_fctr, ...
    'CORRECTIONS_APPLIED', corrections_applied, ...
    'GATE_DURATION', gate_duration, ...
    'R_WAVE_OFFSET', r_wave_offset, ...
    'NUM_ACCEPTED_BEATS', num_accepted_beats, ...
    'FILTER_CUTOFF_FREQUENCY', filter_cutoff_frequency, ...
    'FILTER_RESOLUTION', filter_resolution, ...
    'FILTER_RAMP_SLOPE', filter_ramp_slope, ...
    'FILTER_ORDER', filter_order, ...
    'FILTER_SCATTER_CORRECTION', filter_scatter_fraction, ...
    'FILTER_SCATTER_SLOPE', filter_scatter_slope, ...
    'ANNOTATION', annotation, ...
    'MT_1_1', mt_1_1, ...
    'MT_1_2', mt_1_2, ...
    'MT_1_3', mt_1_3, ...
    'MT_2_1', mt_2_1, ...
    'MT_2_2', mt_2_2, ...
    'MT_2_3', mt_2_3, ...
    'MT_3_1', mt_3_1, ...
    'MT_3_2', mt_3_2, ...
    'MT_3_3', mt_3_3, ...
    'RFILTER_CUTOFF', rfilter_cutoff, ...
    'RFILTER_RESOLUTION', rfilter_resolution, ...
    'RFILTER_CODE', rfilter_code, ...
    'RFILTER_ORDER', rfilter_order, ...
    'ZFILTER_CUTOFF', zfilter_cutoff, ...
    'ZFILTER_RESOLUTION', zfilter_resolution, ...
    'ZFILTER_CODE', zfilter_code, ...
    'ZFILTER_ORDER', zfilter_order, ...
    'MT_4_1', mt_4_1, ...
    'MT_4_2', mt_4_2, ...
    'MT_4_3', mt_4_3, ...
    'SCATTER_TYPE', scatter_type, ...
    'RECON_TYPE', recon_type, ...
    'RECON_VIEWS', recon_views, ...
    'FILL', fill);

%==========================================================================
% function [MHEADER]=ECAT7_mheader(fid)
%==========================================================================
function [MHEADER]=ECAT7_mheader(fid)
%
% Main header read routine for ECAT 7 image files
%
% Roger Gunn, 260298

status                  = fseek(fid, 0,'bof');
magic_number            = fread(fid,14,'char',0);
original_file_name      = fread(fid,32,'char',0);
sw_version              = fread(fid,1,'uint16',0);
system_type             = fread(fid,1,'uint16',0);
file_type               = fread(fid,1,'uint16',0);
serial_number           = fread(fid,10,'char',0);
scan_start_time         = fread(fid,1,'uint32',0);
isotope_name            = fread(fid,8,'char',0);
isotope_halflife        = fread(fid,1,'float32',0);
radiopharmaceutical     = fread(fid,32,'char',0);
gantry_tilt             = fread(fid,1,'float32',0);
gantry_rotation         = fread(fid,1,'float32',0);
bed_elevation           = fread(fid,1,'float32',0);
intrinsic_tilt           = fread(fid,1,'float32',0);
wobble_speed             = fread(fid,1,'uint16',0);
transm_source_type       = fread(fid,1,'uint16',0);
distance_scanned         = fread(fid,1,'float32',0);
transaxial_fov           = fread(fid,1,'float32',0);
angular_compression      = fread(fid,1,'uint16',0);
coin_samp_mode           = fread(fid,1,'uint16',0);
axial_samp_mode          = fread(fid,1,'uint16',0);
ecat_calibration_factor  = fread(fid,1,'float32',0);
calibration_units        = fread(fid,1,'uint16',0);
calibration_units_type   = fread(fid,1,'uint16',0);
compression_code         = fread(fid,1,'uint16',0);
study_type               = fread(fid,12,'char',0);
patient_id               = fread(fid,16,'char',0);
patient_name             = fread(fid,32,'char',0);
patient_sex              = fread(fid,1,'char',0);
patient_dexterity        = fread(fid,1,'char',0);
patient_age              = fread(fid,1,'float32',0);
patient_height           = fread(fid,1,'float32',0);
patient_weight           = fread(fid,1,'float32',0);
patient_birth_date       = fread(fid,1,'uint32',0);
physician_name           = fread(fid,32,'char',0);
operator_name            = fread(fid,32,'char',0);
study_description        = fread(fid,32,'char',0);
acquisition_type         = fread(fid,1,'uint16',0);
patient_orientation      = fread(fid,1,'uint16',0);
facility_name            = fread(fid,20,'char',0);
num_planes               = fread(fid,1,'uint16',0);
num_frames               = fread(fid,1,'uint16',0);
num_gates                = fread(fid,1,'uint16',0);
num_bed_pos              = fread(fid,1,'uint16',0);
init_bed_position        = fread(fid,1,'float32',0);
bed_position = zeros(15,1);
for bed=1:15
    tmp = fread(fid,1,'float32',0);
    if ~isempty(tmp), bed_position(bed) = tmp; end
end
plane_separation         = fread(fid,1,'float32',0);
lwr_sctr_thres           = fread(fid,1,'uint16',0);
lwr_true_thres           = fread(fid,1,'uint16',0);
upr_true_thres           = fread(fid,1,'uint16',0);
user_process_code        = fread(fid,10,'char',0);
acquisition_mode         = fread(fid,1,'uint16',0);
bin_size                 = fread(fid,1,'float32',0);
branching_fraction       = fread(fid,1,'float32',0);
dose_start_time          = fread(fid,1,'uint32',0);
dosage                   = fread(fid,1,'float32',0);
well_counter_corr_factor = fread(fid,1,'float32',0);
data_units               = fread(fid,32,'char',0);
septa_state              = fread(fid,1,'uint16',0);
fill                     = fread(fid,1,'uint16',0);

magic_number             = deblank(char(magic_number.*(magic_number>32))');
original_file_name       = deblank(char(original_file_name.*(original_file_name>0))');
serial_number            = deblank(char(serial_number.*(serial_number>0))');
isotope_name             = deblank(char(isotope_name.*(isotope_name>0))');
radiopharmaceutical      = deblank(char(radiopharmaceutical.*(radiopharmaceutical>0))');
study_type               = deblank(char(study_type.*(study_type>0))');
patient_id               = deblank(char(patient_id.*(patient_id>0))');
patient_name             = deblank(char(patient_name.*(patient_name>0))');
patient_sex              = deblank(char(patient_sex.*(patient_sex>0))');
patient_dexterity        = deblank(char(patient_dexterity.*(patient_dexterity>0))');
physician_name           = deblank(char(physician_name.*(physician_name>0))');
operator_name            = deblank(char(operator_name.*(operator_name>0))');
study_description        = deblank(char(study_description.*(study_description>0))');
facility_name            = deblank(char(facility_name.*(facility_name>0))');
user_process_code        = deblank(char(user_process_code.*(user_process_code>0))');
data_units               = deblank(char(data_units.*(data_units>0))');

MHEADER = struct('MAGIC_NUMBER', magic_number, ...
    'ORIGINAL_FILE_NAME', original_file_name, ...
    'SW_VERSION', sw_version, ...
    'SYSTEM_TYPE', system_type, ...
    'FILE_TYPE', file_type, ...
    'SERIAL_NUMBER', serial_number, ...
    'SCAN_START_TIME', scan_start_time, ...
    'ISOTOPE_NAME', isotope_name, ...
    'ISOTOPE_HALFLIFE', isotope_halflife, ...
    'RADIOPHARMACEUTICAL', radiopharmaceutical, ...
    'GANTRY_TILT', gantry_tilt, ...
    'GANTRY_ROTATION', gantry_rotation, ...
    'BED_ELEVATION', bed_elevation, ...
    'INTRINSIC_TILT', intrinsic_tilt, ...
    'WOBBLE_SPEED', wobble_speed, ...
    'TRANSM_SOURCE_TYPE', transm_source_type, ...
    'DISTANCE_SCANNED', distance_scanned, ...
    'TRANSAXIAL_FOV', transaxial_fov, ...
    'ANGULAR_COMPRESSION', angular_compression, ...
    'COIN_SAMP_MODE', coin_samp_mode, ...
    'AXIAL_SAMP_MODE', axial_samp_mode, ...
    'ECAT_CALIBRATION_FACTOR', ecat_calibration_factor, ...
    'CALIBRATION_UNITS', calibration_units, ...
    'CALIBRATION_UNITS_TYPE', calibration_units_type, ...
    'COMPRESSION_CODE', compression_code, ...
    'STUDY_TYPE', study_type, ...
    'PATIENT_ID', patient_id, ...
    'PATIENT_NAME', patient_name, ...
    'PATIENT_SEX', patient_sex, ...
    'PATIENT_DEXTERITY', patient_dexterity, ...
    'PATIENT_AGE', patient_age, ...
    'PATIENT_HEIGHT', patient_height, ...
    'PATIENT_WEIGHT', patient_weight, ...
    'PATIENT_BIRTH_DATE', patient_birth_date, ...
    'PHYSICIAN_NAME', physician_name, ...
    'OPERATOR_NAME', operator_name, ...
    'STUDY_DESCRIPTION', study_description, ...
    'ACQUISITION_TYPE', acquisition_type, ...
    'PATIENT_ORIENTATION', patient_orientation, ...
    'FACILITY_NAME', facility_name, ...
    'NUM_PLANES', num_planes, ...
    'NUM_FRAMES', num_frames, ...
    'NUM_GATES', num_gates, ...
    'NUM_BED_POS', num_bed_pos, ...
    'INIT_BED_POSITION', init_bed_position, ...
    'BED_POSITION', bed_position, ...
    'PLANE_SEPARATION', plane_separation, ...
    'LWR_SCTR_THRES', lwr_sctr_thres, ...
    'LWR_TRUE_THRES', lwr_true_thres, ...
    'UPR_TRUE_THRES', upr_true_thres, ...
    'USER_PROCESS_CODE', user_process_code, ...
    'ACQUISITION_MODE', acquisition_mode, ...
    'BIN_SIZE', bin_size, ...
    'BRANCHING_FRACTION', branching_fraction, ...
    'DOSE_START_TIME', dose_start_time, ...
    'DOSAGE', dosage, ...
    'WELL_COUNTER_CORR_FACTOR', well_counter_corr_factor, ...
    'DATA_UNITS', data_units, ...
    'SEPTA_STATE', septa_state, ...
    'FILL', fill);


function sourceLoc = dba_anatmodel(ind, sScout, CortexMat, srcType)
%
% Compute sources locations for deep structures
%
% Yohan Attal - HM-TC project 2013

disp = 0;

switch srcType
    case 'surf'
        sourceLoc = CortexMat.Vertices(ind,:);

    case 'vol'
        [ind_s, I_ind] = sort(ind);
        vertTmp = CortexMat.Vertices(sScout.Vertices,:);
        tessTmp.Vertices = vertTmp(I_ind,:);
        iFaces = sum(ismember(CortexMat.Faces, ind_s),2)==3;
        tessTmp.Faces = CortexMat.Faces(iFaces,:);
        for iv=1:numel(tessTmp.Faces)
            tessTmp.Faces(iv) = find(ind_s==tessTmp.Faces(iv));
        end
        sourceLoc = dba_vol_grids(tessTmp);
end
if disp && isequal(srcType,'vol')
    figure('color','w'); hold on; pp = patch(tessTmp);
    set(pp, 'FaceColor', [0 0 1] , 'FaceAlpha', .5, 'EdgeAlpha', 0)
    plot3(sourceLoc(:,1), sourceLoc(:,2),sourceLoc(:,3),'ro')
end
end


function TestEnhanceNet()
addpath('local');

dnn_files{1} = 'nnet/EnhanceRegression.noCMN.DeltaByEqn.MbSize40.U28539.771-LSTM-2048-771.L2_3E-4.LR_3E-3/nnet.itr37.LR1E-5.CV2453.828.mat';
dnn_files{2} = 'nnet/EnhanceRegression.noCMN.DeltaByEqn.MbSize20.U28539.771-LSTM-2048-771.L2_3E-4.LR_1E-4/nnet.itr62.LR4.97E-8.CV2439.245.mat';
dnn_files{3} = 'nnet/EnhanceGaussian.noCMN.init1.expDecay.Decay0.999.DeltaByEqn.MbSize40.U28539.771-LSTM-2048-771.L2_0.LR_3E-3/nnet.itr26.LR3.62E-5.CV756.273.mat';
IsMaskNet = [0 0 0];

testset = 2;
T60 = [0.01 0.3 0.6];
noise = {'buccaneer2', 'pink', 'm109', 'hfchannel', 'factory2', 'factory1', 'destroyerops', 'babble', 'volvo', 'leopard', 'buccaneer1', 'destroyerengine', 'f16', 'machinegun', 'white'};
% noise = {'f16', 'machinegun', 'white'};
SNR = [10 0 -10];
DEBUG = 0;
measures = {'PESQ', 'FWSEQ', 'CD', 'IS', 'LLR', 'WSS'};
useGPU = 0;

for t60_i = 2%:length(T60)
    for n_i = 12%:length(noise)
        for s_i = 3%:length(SNR)
            TestEnhanceNetByCategory(dnn_files, testset, T60(t60_i), noise{n_i}, SNR(s_i), IsMaskNet, measures, useGPU, DEBUG)
        end
    end
end

end


% TEST_CNNSKETCH2IMAGERETRIEVAL  Code to evaluate (not train) the methods presented in the paper:
% F. Radenovic, G. Tolias, O. Chum, Deep Shape Matching, ECCV 2018
%
% Authors: F. Radenovic, G. Tolias, O. Chum. 2018.

clear;

%---------------------------------------------------------------------
% Set data folder and testing parameters
%---------------------------------------------------------------------

% Set data folder, change if you have downloaded the data somewhere else
data_root = fullfile(get_root_cnnimageretrieval(), 'data');
% Check, and, if necessary, download test data (Flickr15 sketch dataset), and fine-tuned networks
download_test_sketch(data_root);

% Set test options
test_dataset = 'flickr15k_sketch';  % dataset to evaluate on
test_imdim = 227;  % choose test image dimensionality
use_mirror = 1; % use mirror representation, otherwise use only original image
use_ms = 1; % use multi-scale representation, otherwise use single-scale
use_gpu = [1]; % use GPUs (array of GPUIDs), if empty use CPU

% Choose ECCV18 fine-tuned CNN network
network_file = fullfile(data_root, 'networks', 'retrieval-SfM-30k', 'retrievalSfM30k-edgemac-vgg.mat');

% After running the training script train_cnnsketch2imageretrieval.m you can evaluate fine-tuned network
% network_file = fullfile(data_root, 'networks', 'exp', 'vgg_edgefilter_mac_test', 'net-epoch-20');

%---------------------------------------------------------------------
% Set dependent variables
%---------------------------------------------------------------------

% Prepare function for desc extraction
if ~use_ms
    descfun = @(x, y, z) cnn_vecms_sketch (x, y, z, 1, use_mirror);
else
    descfun = @(x, y, z) cnn_vecms_sketch (x, y, z, [1, 1/sqrt(2), sqrt(2), 1/2, 2], use_mirror);
end

%---------------------------------------------------------------------
% Testing
%---------------------------------------------------------------------
[~, network_name, ~] = fileparts(network_file);
fprintf('>> %s: Evaluating CNN image retrieval...\n', network_name);

% Load pre-trained edge detector
fprintf('>> Loading Dollar edge detector toolbox and model...\n');
emodel = load_edgedetector(data_root);

% Load pre-trained CNN network
fprintf('>> Loading CNN model...\n');
load(network_file);
net = dagnn.DagNN.loadobj(net);

% prepare GPUs if necessary
numGpus = numel(use_gpu);
if numGpus, fprintf('>> Preparing GPU(s)...\n'); end
if numGpus > 1
    % check parallel pool integrity as it could have timed out
    pool = gcp('nocreate');
    if ~isempty(pool) && pool.NumWorkers ~= numGpus
        delete(pool);
    end
    pool = gcp('nocreate');
    if isempty(pool)
        parpool('local', numGpus);
    end
end
if numGpus >= 1
    if numGpus == 1
        gpuinfo = gpuDevice(use_gpu);
        net.move('gpu');
        fprintf('>>>> Running on GPU %s with Index %d\n', gpuinfo.Name, gpuinfo.Index);
    else
        spmd
            gpuinfo = gpuDevice(use_gpu(labindex));
            fprintf('>>>> Running on GPU %s with Index %d\n', gpuinfo.Name, gpuinfo.Index);
        end
    end
end

% extract and evaluate
fprintf('>> %s: Processing test dataset...\n', test_dataset);
cfg = configdataset (test_dataset, fullfile(data_root, 'test/')); % config file for the dataset

fprintf('>> %s: Extracting CNN descriptors for db images...\n', test_dataset);
vecs = cell(1, cfg.n);
if numGpus <= 1
    progressbar(0);
    for i = 1:cfg.n
        vecs{i} = descfun(imresizemaxd(imread(cfg.im_fname(cfg, i)), test_imdim), net, emodel);
        progressbar(i/cfg.n);
    end
else
    time = tic;
    parfor i = 1:cfg.n
        if strcmp(net.device, 'cpu'), net.move('gpu'); end
        vecs{i} = descfun(imresizemaxd(imread(cfg.im_fname(cfg, i)), test_imdim), net, emodel);
    end
    fprintf('>>>> done in %s\n', htime(toc(time)));
end
vecs = cell2mat(vecs);

fprintf('>> %s: Extracting CNN descriptors for query images...\n', test_dataset);
qvecs = cell(1, cfg.nq);
if numGpus <= 1
    progressbar(0);
    for i = 1:cfg.nq
        qvecs{i} = descfun(imresizemaxd(imread(cfg.qim_fname(cfg, i)), test_imdim), net, 0);
        progressbar(i/cfg.nq);
    end
else
    time = tic;
    parfor i = 1:cfg.nq
        if strcmp(net.device, 'cpu'), net.move('gpu'); end
        qvecs{i} = descfun(imresizemaxd(imread(cfg.qim_fname(cfg, i)), test_imdim), net, 0);
    end
    fprintf('>>>> done in %s\n', htime(toc(time)));
end
qvecs = cell2mat(qvecs);

fprintf('>> %s: Retrieval...\n', test_dataset);
sim = vecs'*qvecs;
[sim, ranks] = sort(sim, 'descend');
map = compute_map (ranks, cfg.gnd);
fprintf('>> %s: mAP = %.4f\n', test_dataset, map);


function [p] = mesh_open(p)

% mesh_open - calls functions to read a triangulation file
%
% Usage: [p] = mesh_open(p)
%
% p is a parameter structure (see eeg_toolbox_defaults for
% more details). In this function, it should contain at least
% the following string fields:
%
%       p.mesh.path - the directory location of the file to load
%       p.mesh.file - the name of the file to load
%       p.mesh.type - the file format:
%
%      'emse'
%      'brainstorm'
%      'ascii' or 'freesurfer_ascii' for *.asc/.tri files
%      'freesurfer_surf' for freesurfer binary surface
%      'freesurfer_curv' for freesurfer binary curvature
%      'freesurfer_overlay' for freesurfer binary overlay (.w)
%
% The last two file types are associated with the current cortex,
% if it contains the same number of vertices (eg, load 'freesurfer_surf'
% first, then 'freesurfer_curv' or 'freesurfer_overlay').
%
% The file formats supported here are described in more detail
% at their respective websites:
%
%       FreeSurfer: http://surfer.nmr.mgh.harvard.edu
%       EMSE:       http://www.sourcesignal.com
%       BrainStorm: http://neuroimage.usc.edu/brainstorm
%
% The return structure creates or updates p.mesh.data, which
% contains cell arrays:
%
%       p.mesh.data.meshtype     type of surface, strings
%       p.mesh.data.vertices     Mx3 (x,y,z) vertices
%       p.mesh.data.faces        Mx3 vertex indices
%       p.mesh.data.Cdata        scalar overlay, M vert x N overlays
%
% For example, having loaded a scalp and an inner skull mesh,
% p.mesh.data.meshtype could be:
%
%       p.mesh.data.meshtype{1} = 'scalp'
%       p.mesh.data.meshtype{2} = 'inner skull'
%
% To plot the data returned, see mesh_plot or try
%
% Hpatch = patch('Vertices',p.mesh.data.vertices{1}',...
%                'Faces',p.mesh.data.faces{1},...
%                'Property','PropertyValue',...);
%

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:57 $

% Licence:  GNU GPL, no express or implied warranties
% History:  02/2002 Darren.Weber_at_radiology.ucsf.edu
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

fprintf('\nMESH_OPEN...\n'); tic;

if ~exist('p','var'),
 [p] = eeg_toolbox_defaults;
  fprintf('...creating default p structure.\n');
end

[path,name,ext] = fileparts(strcat(p.mesh.path,filesep,p.mesh.file));
file = fullfile(path,[name ext]);

if exist(file) ~= 2,
  msg = sprintf('\n\n...file does not exist:\n\t%s\n',file);
  error(msg);
end

type = lower(p.mesh.type);

switch type,

  case 'emse',

    fprintf('...loading EMSE mesh from:\n\t%s\n',file);

    % Get EMSE .wfr data (in meters)
    options = {'vertex','face'};
    [vertices,faces,edges,meshtype] = mesh_emse2matlab(file,options);

    vertex_matrix = [vertices.x; vertices.y; vertices.z]';
    face_matrix = [faces.vertex1;faces.vertex2;faces.vertex3]';

    % Rotate 90 degrees around Z for EMSE data
    vertex_matrix = Rz(vertex_matrix,90,'degrees');

    % Is this a new or replacement mesh?
    [p.mesh.current,meshExists] = mesh_check(p,meshtype);

    p.mesh.data.meshtype{p.mesh.current}    = meshtype;
    p.mesh.data.vertices{p.mesh.current}    = vertex_matrix;
    p.mesh.data.faces{p.mesh.current}       = face_matrix;
    p.mesh.data.lapmat{p.mesh.current}      = [];
    p.mesh.data.lapint{p.mesh.current}      = [];
    p.mesh.data.timeseries{p.mesh.current}  = [];
    p.mesh.data.Cdata{p.mesh.current}       = [];

  case 'brainstorm',

    fprintf('...loading BrainStorm data from:\n\t%s\n',file);
    load(file);

    p.mesh.data = [];

    for i=1:size(Comment,2),
      if isempty(Comment{i}), continue; end
      fprintf('...converting tesselation: %s\n',Comment{i});
      p.mesh.data.meshtype{i}   = Comment{i};
      p.mesh.data.vertices{i}   = Vertices{i}';  % transpose Vertices
      p.mesh.data.faces{i}      = Faces{i};
      p.mesh.data.lapmat{i}     = [];
      p.mesh.data.lapint{i}     = [];
      p.mesh.data.timeseries{i} = [];
      p.mesh.data.Cdata{i}      = [];
      p.mesh.current = i;
    end

  case {'ascii','freesurfer_ascii'},

    fprintf('...loading ASCII or FreeSurfer data from:\n\t%s\n',file);

    % Get Freesurfer data
    if findstr(file,'.tri'),
      [vertex_matrix,face_matrix] = freesurfer_read_tri(file);
    else
      [vertex_matrix,face_matrix] = freesurfer_read_ascii(file);
    end

    fprintf('...converting surface coordinates (mm to meters)\n');
    vertex_matrix = vertex_matrix ./ 1000;

    meshtype = freesurfer_meshtype(file); % see function below

    [p.mesh.current,meshExists] = mesh_check(p,meshtype);

    p.mesh.data.meshtype{p.mesh.current}   = meshtype;
    p.mesh.data.vertices{p.mesh.current}   = vertex_matrix;
    p.mesh.data.faces{p.mesh.current}      = face_matrix;
    p.mesh.data.lapmat{p.mesh.current}     = [];
    p.mesh.data.lapint{p.mesh.current}     = [];
    p.mesh.data.timeseries{p.mesh.current} = [];
    p.mesh.data.Cdata{p.mesh.current}      = [];

  case 'freesurfer_surf',

    fprintf('...loading FreeSurfer binary surface from:\n\t%s\n',file);

    meshtype = freesurfer_meshtype(file); % see function below

    [p.mesh.current,meshExists] = mesh_check(p,meshtype);

    [vertex_matrix, face_matrix] = freesurfer_read_surf(file);

    fprintf('...converting surface coordinates (mm to meters)\n');
    vertex_matrix = vertex_matrix ./ 1000;

    p.mesh.data.meshtype{p.mesh.current}   = meshtype;
    p.mesh.data.vertices{p.mesh.current}   = vertex_matrix;
    p.mesh.data.faces{p.mesh.current}      = face_matrix;
    p.mesh.data.lapmat{p.mesh.current}     = [];
    p.mesh.data.lapint{p.mesh.current}     = [];
    p.mesh.data.timeseries{p.mesh.current} = [];
    p.mesh.data.Cdata{p.mesh.current}      = [];

  case 'freesurfer_curv',

    fprintf('...loading FreeSurfer binary curvature from:\n\t%s\n',file);

    [curv, Nfaces] = freesurfer_read_curv(file);

    allocated = 0;
    for meshN = 1:length(p.mesh.data.meshtype),

      type = p.mesh.data.meshtype{meshN};

      if size(p.mesh.data.vertices{meshN},1) == size(curv,1),
        fprintf('...allocating overlay to Cdata for ''%s'' surface.\n',type);
        p.mesh.data.Cdata{meshN} = curv;
        p.mesh.current = meshN;
        allocated = 1;
      end

    end
    if allocated < 1,
      fprintf('...failed to allocate curvature to any surface, incompatible Nfaces!\n');
    end

  case 'freesurfer_overlay',

    fprintf('...loading FreeSurfer binary overlay from:\n\t%s\n',file);

    [w,vert] = freesurfer_read_wfile(file);

    Nvert = length(vert); clear vert;

    allocated = 0;
    for meshN = 1:length(p.mesh.data.meshtype),

      type = p.mesh.data.meshtype{meshN};

      if size(p.mesh.data.vertices{meshN},1) == Nvert,
        fprintf('...allocating overlay to Cdata for ''%s'' surface.\n',type);
        p.mesh.data.Cdata{meshN} = w;
        p.mesh.current = meshN;
        allocated = 1;
      end

    end
    if allocated < 1,
      fprintf('...failed to allocate overlay to any surface, incompatible vertices!\n');
    end

  otherwise,
    fprintf('...mesh format: %s\n', p.mesh.type);
    fprintf('...sorry, cannot load this data format at present.\n');
    return;
end

t=toc; fprintf('...done (%5.2f sec).\n\n',t);

return


function [Channel] = elec_3dspace2brainstorm(filename,N,bsfile)

% elec_3dspace2brainstorm - Convert NeuroScan 3Dspace ascii to brainstorm file
%
% The ascii file format is that of NeuroScan 3Dspace export files.  Each row
% of the file comprises an electrode label, an electrode type code, and
% the x,y,z coordinates (cm).  Each field is separated by spaces.  See
% ELEC_LOAD for more information.
%
% Useage: Channel = elec_3dspace2brainstorm(filename,[N],[brainstormfile])
%
% where:    file = 'path\filename' with format described in ELEC_LOAD
%
%           N is how many electrodes to load (rows of 3Dspace file, 129 default).
%
% Result:   Channel is an array of structures.  The fields are:
%
%           Loc     - a 3x2 matrix of electrode coordinates (x,y,z in rows).
%                     BrainStorm (x,y,z meters) = 3Dspace (x,y,z cm) / 100.
%           Orient  - a corresponding matrix of sensor orientations (MEG);
%                     all zero for EEG.
%           Weight  - a vector of relative or absolute weights (eg, amplification);
%                     all ones for this routine.
%           Type    - a character string, 'EEG' in this case.
%           Name    - a charater string indicating the electrode name.
%           Comment - a charater string indicating the reference electrode.  Empty
%                     for active electrodes and 'EEG REF' for reference electrode.
%
% See brainstorm website at http://neuroimage.usc.edu/, including a
% download pdf file describing the brainstorm database formats.
%

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:54 $

% Licence:  GNU GPL, no express or implied warranties
% History:  20/05/2002, Darren.Weber_at_radiology.ucsf.edu
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if ~exist('N', 'var'), N = 129;
elseif isempty(N),     N = 129;
end

file = char(filename);

[elec,type,X,Y,Z] = elec_load(file,[],[],[],[],N);

tic;

fprintf('\nELEC_3DSPACE2BRAINSTORM...\n');
fprintf('...Converting to brainstorm structure.\n');

elecindex = find(type == 69);
Ee = elec(elecindex);
Xe = X(elecindex) ./ 100;   % 3Dspace is cm, BrainStorm is m
Ye = Y(elecindex) ./ 100;
Ze = Z(elecindex) ./ 100;

reftype = ones(size(type)) * 120;
refindex = find(type == reftype);
Eref = elec(refindex);
Xref = X(refindex) ./ 100;   % 3Dspace is cm, BrainStorm is m
Yref = Y(refindex) ./ 100;
Zref = Z(refindex) ./ 100;

for i=1:length(elecindex),
    Channel(i).Loc = [[Xe(i) Ye(i) Ze(i)]',[Xref Yref Zref]'];
    Channel(i).Orient = [];     % used for MEG rather than EEG
    Channel(i).Weight = 1;      % Like Amplification
    Channel(i).Type = 'EEG';
    Channel(i).Name = char(Ee(i));
    Channel(i).Comment = '';
end
Channel(i+1).Loc = [[Xref Yref Zref]',[Xref Yref Zref]'];
Channel(i+1).Orient = [];
Channel(i+1).Weight = 1;
Channel(i+1).Type = 'EEG';
Channel(i+1).Name = char(Eref);
Channel(i+1).Comment = 'EEG REF';

if ~exist('bsfile', 'var'),
    bsfile = 'channel';
elseif isempty(bsfile),
    bsfile = 'channel';
end

if findstr('.mat',bsfile),
    bsfile = strrep(bsfile,'.mat','');
end

fprintf('...saving BrainStorm channel data to:\n\t%s.mat\n',bsfile);
save(bsfile, 'Channel');

t = toc; fprintf('...done (%6.2f sec).\n\n',t);

return


function DCM = spm_dcm_erp_data(DCM,ERP)
% prepares structures for forward model(EEG, MEG and LFP)
% FORMAT DCM = spm_dcm_erp_data(DCM,ERP)
% DCM  - DCM structure
% ERP  - switch to average over trials (default)
%
% requires
%
%    DCM.xY.Dfile        - data file
%    DCM.options.trials  - trial codes
%    DCM.options.Tdcm    - Peri-stimulus time window
%    DCM.options.D       - Down-sampling
%    DCM.options.han     - Hanning
%    DCM.options.h       - Order of (DCT) detrending
%
% sets
%    DCM.xY.modality - 'MEG','EEG' or 'LFP'
%    DCM.xY.Time     - Time [ms] data
%    DCM.xY.pst      - Time [ms] of down-sampled data
%    DCM.xY.dt       - sampling in seconds (s)
%    DCM.xY.y        - cell array of trial-specific response {[ns x nc]}
%    DCM.xY.It       - Indices of (ns) time bins
%    DCM.xY.Ic       - Indices of (nc) good channels
%    DCM.xY.name     - names of (nc) channels
%    DCM.xY.scale    - scalefactor applied to raw data
%    DCM.xY.coor2D   - 2D coordinates for plotting
%    DCM.xY.X0       - (DCT) confounds
%    DCM.xY.R        - Residual forming matrix (with hanning)
%    DCM.xY.Hz       - Frequency bins (for Wavelet transform)
%    DCM.options.h
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_dcm_erp_data.m 7749 2019-12-05 17:05:46Z guillaume $

% Set defaults and Get D filename
%--------------------------------------------------------------------------
try
    Dfile = DCM.xY.Dfile;
catch
    errordlg('Please specify data and trials');
    error('')
end

% options
%==========================================================================

% order of drift terms
%--------------------------------------------------------------------------
if nargin < 2, ERP = 1;                         end
try, han  = DCM.options.han; catch, han   = 0;  end
try, h    = DCM.options.h;   catch, h     = 1;  end
try
    DT    = DCM.options.D;
catch
    errordlg('Please specify down sampling');
    error('')
end
try
    trial = DCM.options.trials;
catch
    errordlg('please specify trials');
    error('')
end

% load D
%--------------------------------------------------------------------------
try
    D = spm_eeg_load(Dfile);
catch
    try
        [dum,f]      = fileparts(Dfile);
        D            = spm_eeg_load(f);
        DCM.xY.Dfile = fullfile(pwd,f);
    catch
        try
            [f,p]        = uigetfile('*.mat','please select data file');
            name         = fullfile(p,f);
            D            = spm_eeg_load(name);
            DCM.xY.Dfile = fullfile(name);
        catch
            warndlg([Dfile ' could not be found'])
            return
        end
    end
end

% get time-frequency data if appropriate
%--------------------------------------------------------------------------
if isequal(D.transformtype, 'TF')
    DCM = spm_dcm_ind_data(DCM);
    return;
end

% indices of EEG channel (excluding bad channels) and peristimulus times
%--------------------------------------------------------------------------
if ~isfield(DCM.xY, 'modality')
    [mod, list] = modality(D, 0, 1);
    if isequal(mod, 'Multimodal')
        qstr    = 'Only one modality can be modelled at a time';
        if numel(list) < 4

            % Pretty dialog box
            %--------------------------------------------------------------
            options = [];
            options.Default = list{1};
            options.Interpreter = 'none';
            DCM.xY.modality = questdlg(qstr, 'Select modality', list{:}, options);

        else

            % can accommodate more buttons
            %--------------------------------------------------------------
            ind = menu(qstr, list);
            DCM.xY.modality = list{ind};
        end
    else
        DCM.xY.modality = mod;
    end
end

% good channels
%--------------------------------------------------------------------------
Ic = D.indchantype(DCM.xY.modality,'GOOD');
if isempty(Ic)
    warndlg('No good channels in these data');
    return
end

Nc            = length(Ic);               % number of channels
DCM.xY.name   = D.chanlabels(Ic);         % channel names
DCM.xY.Ic     = Ic;                       % channel indices
DCM.xY.Time   = time(D, [], 'ms');        % PST (ms)
DCM.xY.dt     = 1/D.fsample;              % time bins
DCM.xY.coor2D = D.coor2D(Ic);             % coordinates (topographic)

% time window
%--------------------------------------------------------------------------
try

    % time window and bins for modelling
    %----------------------------------------------------------------------
    T1          = DCM.options.Tdcm(1);
    T2          = DCM.options.Tdcm(2);
    [dum, T1]   = min(abs(DCM.xY.Time - T1));
    [dum, T2]   = min(abs(DCM.xY.Time - T2));

    % Time [ms] of down-sampled data
    %----------------------------------------------------------------------
    It          = (T1:DT:T2)';
    Ns          = length(It);                % number of samples
    DCM.xY.pst  = DCM.xY.Time(It);           % Down-sampled PST
    DCM.xY.dt   = DT/D.fsample;              % sampling in seconds
    DCM.xY.It   = It;                        % Indices of time bins

catch
    errordlg('Please specify time window');
    error('')
end

% confounds - DCT:
%--------------------------------------------------------------------------
if h == 0
    X0 = sparse(Ns,1);
else
    X0 = spm_dctmtx(Ns,h);
end
R      = speye(Ns) - X0*X0';

% hanning (omit second residualization for very long time-series)
%--------------------------------------------------------------------------
if han
    if Ns < 2048
        R = R*sparse(diag(spm_hanning(Ns)))*R;
    else
        R = sparse(diag(spm_hanning(Ns)))*R;
    end
end

% get trial averages - ERP
%--------------------------------------------------------------------------
cond  = D.condlist;
for i = 1:length(trial)

    % trial indices
    %----------------------------------------------------------------------
    c            = D.indtrial(cond(trial(i)), 'GOOD');
    Nt           = length(c);
    DCM.xY.nt(i) = Nt;

    % ERP
    %----------------------------------------------------------------------
    if ERP
        Y     = zeros(Ns,Nc);
        for j = 1:Nt
            Y = Y + R*D(Ic,It,c(j))';
        end
        DCM.xY.y{i} = Y/Nt;

    % all trials
    %----------------------------------------------------------------------
    else
        Y     = zeros(Ns,Nc,Nt);
        for j = 1:Nt
            Y(:,:,j) = R*D(Ic,It,c(j))';
        end
        DCM.xY.y{i} = Y;
    end

end

% condition units of measurement
%--------------------------------------------------------------------------
DCM.xY.code  = cond(trial);
DCM.xY.scale = 1;
DCM.xY.X0    = X0;
DCM.xY.R     = R;


% DEPRECATED...
%
% Author: Javier Lopez-Calderon
% Center for Mind and Brain
% University of California, Davis,
% Davis, CA
% 2009

function EEG = checkzerolat(EEG)
nepoch = EEG.trials;
if isempty(EEG.epoch)
      fprintf('\nWARNING: checkzerolat() only works for epoched datasets. This call was ignored.\n')
      return
end
for i=1:nepoch
      latcell  =  cell2mat(EEG.epoch(i).eventlatency);
      [v, indx] = min(abs(latcell));
      EEG.epoch(i).eventlatency = num2cell(latcell - latcell(indx));
end

auxtimes  = EEG.times;
[v, indx]  = min(abs(auxtimes));
EEG.times = auxtimes - auxtimes(indx);
EEG.xmin  = min(EEG.times)/1000;
EEG.xmax  = max(EEG.times)/1000;
EEG.srate = round(EEG.srate);
EEG = eeg_checkset( EEG );

if EEG.times(1)~=auxtimes(1)
      msg = ['\nWarning: zero time-locked stimulus latency values were not found.\n'...
      'Therefore, ERPLAB adjusted latency values at EEG.epoch.eventlatency, EEG.times, EEG.xmin,and EEG.xmax.\n\n'];
      fprintf(msg);
      fprintf('Time range is now [%.3f  %.3f] sec.\n', EEG.min, EEG.max )
else
      fprintf('Zero latencies OK.\n')
end


function main_image = PTKGetMainRegionExcludingBorder(threshold_image, minimum_region_volume_mm3, reporting)
    % PTKGetMainRegionExcludingBorder. Finds the largest connected region in a
    % binary 3D volume, excluding any regions which touch the borders in the
    % first and second dimensions.
    %
    % Syntax:
    %     main_image = PTKGetMainRegionExcludingBorder(threshold_image, reporting)
    %
    % Inputs:
    %     threshold_image - a binary 3D volume as a PTKImage.
    %
    %     minimum_region_volume_mm3 (optional) - ignore any regions below this
    %         threshold
    %
    %     reporting (optional) - an object implementing CoreReportingInterface
    %                             for reporting progress and warnings
    %
    % Outputs:
    %     main_image - a PTKImage binary volume of the found region
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    if ~isa(threshold_image, 'PTKImage')
        error('Requires a PTKImage as input');
    end

    if nargin < 2 || isempty(minimum_region_volume_mm3)
        minimum_region_volume_mm3 = 0;
    end

    if nargin < 3
        reporting = CoreReportingDefault;
    end

    reporting.ShowProgress('Finding lung region');

    bordered_image = true(threshold_image.ImageSize + [2 2 2]);
    bordered_image(2:end-1, 2:end-1, 2:end-1) = threshold_image.RawImage;
    bordered_image(2:end-1, 2:end-1, 1) = false;
    bordered_image(2:end-1, 2:end-1, end) = false;

    image_opening_params_mm = [0, 2, 4, 6];
    image_opening_index = 1;
    still_searching = true;

    while still_searching

        [results, CC] = OpenAndGetRegions(bordered_image, image_opening_params_mm(image_opening_index), threshold_image.VoxelSize, minimum_region_volume_mm3, reporting);

        if numel(results) > 0 || image_opening_index == numel(image_opening_params_mm)
            still_searching = false;
        else
            image_opening_index = image_opening_index + 1;
        end
    end

    if numel(results) == 0
        main_image = [];
        reporting.Error('PTKGetMainRegionExcludingBorder:NoRegionFound', 'No region could be found');
    end

    if numel(results) > 1
        % If more than one region was found (after excluding boundary-touching
        % regions), then check if they are disconnected left and right lungs
        bounding_boxes = regionprops(CC, 'BoundingBox');
        bb_1 = bounding_boxes(results(1)).BoundingBox;
        bb_1 = bb_1([2,1,3,5,4,6]); % Bounding box is [xyz] but Matlab indices are [yxz]
        bb_2 = bounding_boxes(results(2)).BoundingBox;
        bb_2 = bb_2([2,1,3,5,4,6]); % Bounding box is [xyz] but Matlab indices are [yxz]
        image_centre = round(size(bordered_image)/2);

        image_centre_j = image_centre(2);

        if threshold_image.IsCT
            centre_offset = 0;
        else
            % Allow some leeway for MRI images where the lung boundaries may not be so
            % clear
            centre_offset = 10;
        end

        use_both_regions = false;
        if (bb_1(2) >= image_centre_j - centre_offset) && (bb_2(5) < image_centre_j + centre_offset)
            reporting.LogVerbose('I appear to have found 2 disconnected lungs. I am connecting them.');
            use_both_regions = true;
        end

        if (bb_2(2) >= image_centre_j - centre_offset) && (bb_1(5) < image_centre_j + centre_offset)
            reporting.LogVerbose('I appear to have found 2 disconnected lungs. I am connecting them.');
            use_both_regions = true;
        end
    else
        use_both_regions = false;
    end

    bordered_image(:) = false;
    bordered_image(CC.PixelIdxList{results(1)}) = true;
    if use_both_regions
        bordered_image(CC.PixelIdxList{results(2)}) = true;
    end

    main_image = threshold_image.BlankCopy;
    main_image.ChangeRawImage(bordered_image(2:end-1, 2:end-1, 2:end-1));
end

function [results, CC] = OpenAndGetRegions(bordered_image_input, opening_mm, voxel_size, minimum_region_volume_mm3, reporting)

    bordered_image = bordered_image_input;
    if opening_mm > 0
        ball_element = CoreImageUtilities.CreateBallStructuralElement(voxel_size, opening_mm);
        bordered_image = imopen(bordered_image_input > 0, ball_element);
    end

    % Borders are marked as segmented - this ensures all components
    % touching the border are connected and allows us to eliminate them
    % when extracting the lung

    % Obtain connected component matrix
    CC = bwconncomp(bordered_image, 26);

    % Find largest region
    num_pixels = cellfun(@numel, CC.PixelIdxList);
    [sorted_largest_areas, sorted_largest_areas_indices] = sort(num_pixels, 'descend');

    % Remove regions that are below the volume threshold
    pixel_volume = prod(voxel_size);
    sorted_largest_areas_indices = sorted_largest_areas_indices(pixel_volume*sorted_largest_areas >= minimum_region_volume_mm3);

    result_index = 1;
    results = [];
    index_in_sorted_array = 1;
    while (result_index < 3 && index_in_sorted_array <= length(sorted_largest_areas_indices))
        current_region_being_checked = sorted_largest_areas_indices(index_in_sorted_array);
        bordered_image(:) = false;
        bordered_image(CC.PixelIdxList{current_region_being_checked}) = true;
        if (bordered_image(1) || bordered_image(end))
            % This region is connected to the edge
%             reporting.ShowMessage('PTKGetMainRegionExcludingBorder:LargestROIConnectedToExterior', 'The largest region connected with the edge of the volume. I''m assuming this region is outside the body so choosing the next largest region');
        else
            results(result_index) = current_region_being_checked;
            result_index = result_index + 1;
        end
        index_in_sorted_array = index_in_sorted_array + 1;
    end
end


 function y = ir_imfilter_many(x, psf, varargin)
%function y = ir_imfilter_many(x, psf, varargin)
%|
%| as of 2015-04-12, octave's imfilter can handle only 2D input
%| whereas matlab can handle 3D inputs
%| this is a kludge to deal with that.
%|
%| 2015-04-12, Jeff Fessler, University of Michigan

if nargin < 2, ir_usage, end

if ~ir_is_octave || ndims(x) == ndims(psf)
	y = imfilter(x, psf, varargin{:}); % matlab or usual sizes
return
end

% hereafter for octave with unequal sizes

if ndims(x) == 3 && ndims(psf) == 2
	tmp = imfilter(x(:,:,1), psf, varargin{:});
	nz = size(x,3);
	y = zeros([size(tmp) nz]);
	y(:,:,1) = tmp;
	for iz = 2:nz
		y(:,:,iz) = imfilter(x(:,:,iz), psf, varargin{:});
	end
return
end

pr size(x)
pr size(psf)
fail('imfilter in octave does not support such sizes, nor does my kludge')


function [D,Ds,hdr,p,coords,X,Y,Z] = tor_3d(varargin)
% :Usage:
% ::
%
%    [D,Ds,hdr,p,coords,X,Y,Z] = tor_3d(varargin)
%
% made to use single_subj_T1.img from SPM99
%
% :Options:
%
%   **'data':**
%        followed by image data, must also use 'hdr'; data is full image volume
%
%   **'hdr':**
%        followed by hdr structure (use read_hdr)
%
%   **'coords':**
%        3 element row vector of x,y,z coordinates at which to cut away
%
%   **'figure':**
%        create a new figure to plot on
%
%   **'whichcuts':**
%        followed by incisions; choices are x y z w (whole)
%
%        example:'whichcuts','xyz' (xyz is default)
%        order of output handles (p(i)) is 'wyzx'
%
%        New: Special methods:
%          - 'coronal slice right'
%          - 'coronal slice left'
%          - 'coronal slice'
%
%   **'filename':**
%        followed by filename of image data to load, in single quotes
%
%        should be analyze img format, without the .img extension
%
%        cluster imaging assumes neurological orientation, but should work anyway.
%
%   **'revx':**
%        reverse x cut direction, so cut in from left instead of right
%
%   **'topmm':**
%        topmm = varargin{i+1};
%
%   **'intensity_threshold':**
%        percentile of data above which is considered in-object
%        higher = more sparse object
%
% :Outputs:
%
%   **D:**
%        img data
%
%   **Ds:**
%        smoothed data
%
%   **hdr:**
%        header
%
%   **p:**
%        image handles
%
%   **coords:**
%        coordinates
%
%   **X, Y, Z:**
%        are the millimeter, origin centered reference frame for the head isosurface
%
% :Examples:
% ::
%
%    [D,Ds,hdr,p,coords] = tor_3d('figure','data',D,'hdr',hdr,'whichcuts','yzx');
%    [D,Ds,hdr,p,coords] = tor_3d('figure');
%    [D,Ds,hdr,headhandle,coords] = tor_3d('whichcuts','z', 'coords', [-Inf
%    -Inf Inf], 'filename', 'T1_face_exemplar', 'intensity_threshold', 80); set(gcf, 'Color', 'w'); axis on
%
%    % Special slice example:
%    [D,Ds,hdr,handle,coords]  = tor_3d('whichcuts', 'coronal slice right', 'coords', [0 12 0], 'topmm', 100);
%    lightRestoreSingle
%    set(handle(1), 'FaceColor', [.5 .5 .5])
%
% ..
%    Made by Tor Wager, 10/3/2001 last modified 10/19/01
% ..

% ..
%    Set up arguments and default values
% ..

[D,Ds,hdr] = deal([]);
p = zeros(1,2);
coords = [0 0 0];
whichcuts = 'xyz';
filename = 'spm2_single_subj_T1_scalped'; 'single_subj_T1';    % default structural image to use
topmm = 60;                     % image only this high in mm to avoid image distortions above head.
bottommm = nan;                 % bottom cutoff in mm
dolight = 1;
revx = 0;
intensity_threshold = [];

for i = 1:nargin
    if isstr(varargin{i})
        switch varargin{i}
        case 'data', D = varargin{i+1};
        case 'hdr', hdr = varargin{i+1};
        case 'coords', coords = varargin{i+1};
        case 'figure', h3dfig = figure; set(h3dfig,'Tag','myFig');
            colormap(gray(100)),set(gcf,'Color','k'),axis off,set(gcf,'Position',[184   115   672   543])
        case 'whichcuts',whichcuts = varargin{i+1};
        case 'filename',filename = varargin{i+1};
        case 'nolight', dolight = 0;
        case 'revx', revx = 1;
        case 'topmm', topmm = varargin{i+1};
        case 'bottommm', bottommm = varargin{i+1};

        case 'intensity_threshold', intensity_threshold = varargin{i + 1};

        end
    end
end

%------------------------------------------------------------------------------
% Load the image file, if necessary
% Get origin and voxel size
%------------------------------------------------------------------------------
if isempty(D)

    if isa(D, 'fmri_data'), D = []; end % empty fmri_data object

    if ~exist(filename, 'file')
        fullpath = which([filename '.img']);
    else
        fullpath = filename;
    end

    if isempty(fullpath), error(['Cannot find file: ' filename '.img']);
    else disp(['Loading structural image: ' fullpath]);drawnow
    end
    [array,hdr] = readim2(filename);
    % rotate 270 degrees so that front of head is positive y
    % (works with canonical SPM images, at least, so this orientation is ok.)
    for i = 1:size(array,3)
        D(:,:,i) = rot90(rot90(rot90((array(:,:,i)))));
    end

    VV = spm_vol(fullpath);
    origin = VV.mat(1:3, 4);
    voxsize = (diag(VV.mat(1:3, 1:3)));

elseif isa(D, 'fmri_data')

    mymat = D.volInfo.mat;
    origin = mymat(1:3, 4);
    voxsize = (diag(mymat(1:3, 1:3)));
    array = reconstruct_image(D);

    % rotate 270 degrees so that front of head is positive y
    % (works with canonical SPM images, at least, so this orientation is ok.)
    D = [];
    for i = 1:size(array,3)
        D(:,:,i) = rot90(rot90(rot90((array(:,:,i)))));
    end

else
    error('Use no ''data'' argument for default surface, or enter ''data'' followed by fmri_data object')
end

if isempty(Ds)
    Ds = smooth3(D);
end

%------------------------------------------------------------------------------
% Define X Y Z coordinates of head data
%------------------------------------------------------------------------------
% Define X, Y, Z relative to the origin, so head will be centered on origin
% Multiply by voxel size in header so that coordinates are in mm from the origin
% Make sure origin is set properly in header for this to work accurately.

% NOTE: spm5 no longer sets things in origin, apparently, so use spm_vol
% to get origin

[M N P] = size(D);
%[X Y Z] = meshgrid(((1:N)-hdr.origin(1))*hdr.xsize, ((1:M)-hdr.origin(2))*hdr.ysize, ((1:P)-hdr.origin(3))*hdr.zsize);
[X Y Z] = meshgrid(((1:N)*voxsize(1)+origin(1)), ((1:M)*voxsize(2)+origin(2)), ((1:P)*voxsize(3)+origin(3)));

% define threshold
if isempty(intensity_threshold)
    surface_threshold = mean(D(:));  % original way, pre-2009
else
    surface_threshold = prctile(D(:), intensity_threshold);  %mean(mean(mean(D)));
end

%------------------------------------------------------------------------------
% Make patches for cutaway
%------------------------------------------------------------------------------
index = 1;

if strcmp(whichcuts, 'coronal slice right')
    % Special methods
    [p(index),p(index+1)] = imagePatch(X,Y,Z,D,Ds,[0 nan coords(2)-2 coords(2) bottommm topmm], surface_threshold);

elseif strcmp(whichcuts, 'coronal slice left')
    [p(index),p(index+1)] = imagePatch(X,Y,Z,D,Ds,[nan 0 coords(2)-10 coords(2) bottommm topmm], surface_threshold);

elseif strcmp(whichcuts, 'coronal slice')
    [p(index),p(index+1)] = imagePatch(X,Y,Z,D,Ds,[nan nan coords(2)-10 coords(2) bottommm topmm], surface_threshold);

else

    if any(whichcuts == 'w')
        [p(index),p(index+1)] = imagePatch(X,Y,Z,D,Ds,[nan nan nan nan bottommm topmm], surface_threshold);          % whole head
        index = index + 2;
    end

    % xyz inset cutaway - seems to work only if x does not come first
    if any(whichcuts == 'y')
        [p(index),p(index+1)] = imagePatch(X,Y,Z,D,Ds,[nan nan nan coords(2) bottommm topmm], surface_threshold);
        index = index + 2;
    end
    if any(whichcuts == 'z')
        [p(index),p(index+1)] = imagePatch(X,Y,Z,D,Ds,[nan nan nan nan bottommm coords(3)], surface_threshold);
        index = index + 2;
    end
    if any(whichcuts == 'x')
        if revx, [p(index),p(index+1)] = imagePatch(X,Y,Z,D,Ds,[coords(1) nan nan nan bottommm topmm], surface_threshold);
        else [p(index),p(index+1)] = imagePatch(X,Y,Z,D,Ds,[nan coords(1) nan nan bottommm topmm], surface_threshold);
        end
        index = index + 2;
    end

end

%------------------------------------------------------------------------------
% Set lighting conditions
%------------------------------------------------------------------------------
if dolight && length(p) > 1
    myLight = standardMRIlighting('full',p(1:2));
elseif dolight
    myLight = standardMRIlighting('full',p);
end

if length(p) > 2, standardMRIlighting('reflectance',p(3:4)); end
if length(p) > 4, standardMRIlighting('reflectance',p(5:6)); end

% set(myLight,'Tag','myLight')  % done in stMRIlighting.

rotate3d off
	%------------------------------------------------------------------------------
    % set callback to light follow the camera
	%------------------------------------------------------------------------------
	if exist('lightFollowView') == 2
        set(gcf, 'WindowButtonUpFcn', 'lightFollowView');
    else
        warning('Cannot find lightFollowView.m to set light position.')
    end

%------------------------------------------------------------------------------
% Sub-function for imaging patch
%------------------------------------------------------------------------------
function [p1,p2] = imagePatch(X,Y,Z,D,Ds,inValues, surface_threshold)

    if isempty(inValues)
        inValues = [nan nan nan nan nan nan];
    end

    if isempty(X) | isempty(Y) | isempty(Z)
        % no xyz coordinates
        FV2 = isosurface(Ds,surface_threshold);
        IS2 = isocaps(D,surface_threshold);

        % Draw figure patches
        try
            p1 = patch(FV2,'FaceColor',[.8,.5,.4],'EdgeColor','none','FaceAlpha',1,'SpecularExponent',200,'SpecularStrength',.2);
            p2 = patch(IS2,'FaceColor','interp','EdgeColor','none','FaceAlpha',1);
        catch
            p1 = patch(FV2,'FaceColor',[1,.75,.65],'EdgeColor','none','SpecularExponent',200,'SpecularStrength',.2);
            p2 = patch(IS2,'FaceColor','interp','EdgeColor','none');
        end

    else

        % Define subvolume for cutaway view
        [x y z A] = subvolume(X,Y,Z,D,inValues);
        [x y z As] = subvolume(X,Y,Z,Ds,inValues);
        FV2 = isosurface(x,y,z,As,surface_threshold);
        IS2 = isocaps(x,y,z,A,surface_threshold);

        % Draw figure patches
        try
            p1 = patch(FV2,'FaceColor',[.8,.5,.4],'EdgeColor','none','FaceAlpha',1,'SpecularExponent',200,'SpecularStrength',.2);
            p2 = patch(IS2,'FaceColor','interp','EdgeColor','none','FaceAlpha',1);
        catch
            p1 = patch(FV2,'FaceColor',[.8,.5,.4],'EdgeColor','none','FaceAlpha',1,'SpecularExponent',200,'SpecularStrength',.2);
            p2 = patch(IS2,'FaceColor','interp','EdgeColor','none');
        end
        % isonormals(A,p1)
    end

    drawnow
    return


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   MoveJ:
%   Caution. The global variable robot should be loaded
%   with a valid robot arm.
%   Example: MoveJ(pos_b_rec, 'v1000', 'z100', gripper, wobj0);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Copyright (C) 2012, by Arturo Gil Aparicio
%
% This file is part of ARTE (A Robotics Toolbox for Education).
%
% ARTE is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% ARTE 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with ARTE.  If not, see <http://www.gnu.org/licenses/>.
function MoveJ(robtarget, speeddata, zonedata, gripper, Wobj)

global configuration robot

fprintf('\nCall to MoveJ');

%obtain current joint coordinates
q_current = robot.q;

%Ttool, transformation from the robot's end to the TCP
Ttool = transform_to_homogeneous(gripper(2:end));

%compute target joint coordinates, from the inverse kinematics
%select desired joint values by using conf data from robtarget
%select configuration
conf = get_conf_data(robtarget);
Ttotal = transform_to_homogeneous(robtarget);

%T = Ttotal*inv(Ttool);
T = Ttotal/Ttool;

%Obtain solutions from inversekinematic function
q_final=inversekinematic(robot, T, robot.q);

%select one of the solutions of the inverse kinematic problem
% solution according to configuration and language.
% The conf vector defines the quadrants of the joints [theta1 theta4 theta6 thetax]
% =[cf1 cf4 cf6 cfx]. Where the x angle is zero in this implementation.
q_final=select_configuration(robot, q_final, conf);
%(q_final*180/pi)'

speed = obtain_joint_speed(robot, speeddata);
%when fine is specified, the radius is zero, otherwise,
%the radius represents a sphere around the target where the
%movement is changed to the next target
radius = obtain_zone_data(zonedata);

%find time to perform movement
[actual_speed, tmax]=synchronize(q_current, q_final, speed, robot.accelmax);

%in this case, if the total time for the movement is lower than the
%configuration.delta_time time then 10 points are interpolated
if tmax <= configuration.delta_time
    t = [0:tmax/10:tmax]';
else
    %local time for the planning, normal case
    t = [0:configuration.delta_time:tmax]';
end

if radius==0
    %compute a smooth trajectory in q and qd
    %in this case, the final speed is zero
    [q, qd, qdd] = compute_joint_trajectory_indep(robot, q_current, q_final, robot.qd, zeros(1,robot.DOF), t);
else
    %in this case, the final speed is selected as the speed selected by the
    %variable speeddata
    [q, qd, qdd] = compute_joint_trajectory_indep(robot, q_current, q_final, robot.qd, actual_speed, t);
end
%finds the first joint coordinates that are inside a radius r of the target
%point
index = find_first_in_zone_data(robot, q, T, radius);

%the robot performs the movement until the index found. The coordinates, joint speed and acceleratin
%are stored and used in the planning of the next point
robot.q=q(:,index);
robot.qd=qd(:,index);
robot.qdd=qdd(:,index);

%store all the trajectory for plotting
%the joint trajectories, speeds and acceleration of susequent movements are
%store here
%robot.q_vector=[robot.q_vector q(:, 1:index)];
%robot.qd_vector=[robot.qd_vector qd(:, 1:index)];
%robot.qdd_vector=[robot.qdd_vector qdd(:, 1:index)];

robot.q_vector = q(:, 1:index);
robot.qd_vector = qd(:, 1:index);
robot.qdd_vector = qdd(:, 1:index);

%a global time for the planning is computed.
%in this way, the total trajectory of different movements can be plotted
if length(robot.time)==0
    tend = 0;
else
    tend = robot.time(end);
end
t = t + tend;
%store total time
robot.time=t(1:index)';

%Test whether there are joints outside mechanical limits
test_joint_limits(robot);

%Plot position, velocity and acceleration
%plot_joint_data(robot);
%Now, animate the robot in 3D
animate(robot, q);

%Plot the trajectory
pp = zeros(3,size(q,2));
for i=1:size(q,2),
    T=directkinematic(robot, q(:,i));
    %pp=[pp T(1:3,4)];
    pp(1:3,i)=T(1:3,4);
end
plot3(pp(1,:),pp(2,:),pp(3,:), 'k', 'LineWidth', 2)


function [planar] = constructplanargrad(cfg, grad)

% CONSTRUCTPLANARGRAD constructs a planar gradiometer array from an axial gradiometer
% definition. This can be used to compute the planar field gradient for a known
% (estimated) source configuration.
%
% Use as
%   [grad_planar] = constructplanargrad(cfg, grad_axial)
%
% Where cfg contains the following configuration details
%   cfg.baseline_axial   = number (default is 5)
%   cfg.baseline_planar  = number (default is 0.5)
%   cfg.planaraxial      = 'no' or 'yes' (default)
%
% The option planaraxial='yes' specifies that the planar gradiometers
% should consist of axial gradiometers, to make them comparable with
% Ole Jensens planar gradient computation. If planaraxial='no', the
% planar gradiometers will be more or less similar to the Neuromag
% system.
%
% The input grad can be a CTF type axial gradiometer definition, but
% just as well be a magnetometer definition. This function only assumes
% that
%   grad.coilpos
%   grad.coilori
%   grad.label
% exist and that the first Nlabel channels in pnt and ori should be
% used to compute the position of the coils in the planar gradiometer
% channels.

% Copyright (C) 2004, 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$

if ~isfield(cfg, 'planaraxial'),     cfg.planaraxial = 'yes';   end
if ~isfield(cfg, 'baseline_axial'),  cfg.baseline_axial  = 5;   end
if ~isfield(cfg, 'baseline_planar'), cfg.baseline_planar = 0.5; end

Nchan = length(grad.label);

% these will hold all the coil positions
lo_posx = zeros(Nchan,3);
lo_negx = zeros(Nchan,3);
lo_posy = zeros(Nchan,3);
lo_negy = zeros(Nchan,3);
hi_posx = zeros(Nchan,3);
hi_negx = zeros(Nchan,3);
hi_posy = zeros(Nchan,3);
hi_negy = zeros(Nchan,3);

for chan=1:Nchan
  % Attach a local coordinate system to this gradiometer:
  %   the origin at the location of its bottom coil
  %   the z-axis pointing outwards from the head
  %   the x-axis pointing horizontal w.r.t. the head
  %   the y-axis pointing vertical, i.e. approximately towards the vertex
  this_o = grad.chanpos(chan,:);
  this_z = grad.chanori(chan,:);
  this_z = this_z / norm(this_z);
  this_x = cross([0 0 1], this_z);
  if all(this_x==0)
    this_x = [1 0 0];
  else
    this_x = this_x / norm(this_x);
  end
  this_y = cross(this_z, this_x);

  % compute the position of all the 8 coils per channel
  lo_posx(chan,:) = this_o + (cfg.baseline_planar/2) * this_x;
  lo_negx(chan,:) = this_o - (cfg.baseline_planar/2) * this_x;
  lo_posy(chan,:) = this_o + (cfg.baseline_planar/2) * this_y;
  lo_negy(chan,:) = this_o - (cfg.baseline_planar/2) * this_y;
  hi_posx(chan,:) = lo_posx(chan,:) + cfg.baseline_axial * this_z;
  hi_negx(chan,:) = lo_negx(chan,:) + cfg.baseline_axial * this_z;
  hi_posy(chan,:) = lo_posy(chan,:) + cfg.baseline_axial * this_z;
  hi_negy(chan,:) = lo_negy(chan,:) + cfg.baseline_axial * this_z;
end

% start with an empty planar gradiometer definition
planar = [];

if strcmp(cfg.planaraxial, 'yes')
  % combine all the 8 coils into a single sensor
  planar.coilpos = [
    lo_posx
    lo_negx
    lo_posy
    lo_negy
    hi_posx
    hi_negx
    hi_posy
    hi_negy
  ];

  % the orientation of all the coils of a single sensor should be the same
  planar.coilori = [
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
  ];

  e = eye(Nchan);
  z = zeros(Nchan);

  % the linear combination matrix should be 2*Nchan x 8*Nchan
  planar.tra = [
    e -e  z  z -e  e  z  z    % this is for the horizontal gradients
    z  z  e -e  z  z -e  e    % this is for the vertical gradients
  ];

else
  % combine only the 4 lower coils into a single sensor
  planar.coilpos = [
    posx
    negx
    posy
    negy
  ];

  % the orientation of all the coils of a single gradiometer should be the same
  planar.coilori = [
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
    grad.coilori(1:Nchan,:)
  ];

  e = eye(Nchan);
  z = zeros(Nchan);

  % the linear combination matrix should be 2*Nchan x 4*Nchan
  planar.tra = [
    e -e  z  z    % this is for the horizontal gradients
    z  z  e -e    % this is for the vertical gradients
  ];

end

for chan=1:Nchan
  planar.label{chan      } = [grad.label{chan} '_dH'];
  planar.label{chan+Nchan} = [grad.label{chan} '_dV'];
end

planar.label = planar.label(:);
planar.tra   = planar.tra / cfg.baseline_planar;
planar.chanpos = [grad.chanpos; grad.chanpos];
planar.chanori = [grad.chanori; grad.chanori];

try
  planar.unit  = grad.unit;
end

% add information about the version of this function to the configuration
cfg.version.name = mfilename('fullpath');
cfg.version.id   = '$Id$';

% rememember the exact configuration details in the output
planar.cfg = cfg;


function [net_matching] = init_siamese_model()
% this file implements the matching network
% By Xin Li, 11-27-2017

net_matching = dagnn.DagNN();
    net_matching.addLayer('xcorr', XCorr(), ...
                 {'w_feat', 'x_feat'}, ...
                 {'m_score'}, ...
                 {});
net_matching.move('gpu');

end


% REREF - convert common reference EEG data to some other common reference
%           or to average reference
% Usage:
%   >> Dataout = reref(data);  % convert all channels to average reference
%   >> [Dataout Chanlocs] = reref(data, refchan, 'key', 'val');
%                              % convert data to new reference with options
% Inputs:
%   data - 2-D or 3-D data matrix (chans,frames*epochs)
%   refchan  - reference channel number(s). There are three possibilities:
%          1) [] -  compute average reference
%          2) [X]: re-reference to channel X
%          2) [X Y Z ...]: re-reference to the average of channel X Y Z ...
%
% Optional inputs:
%   'exclude'    - [integer array] channel indices to exclude from re-referencing
%                  (e.g., event marker channels, etc.)
%   'keepref'    - ['on'|'off'] keep reference channel in output (only usable
%                  when there are several references).
%   'elocs'      - Current data electrode location structure (e.g., EEG.chanlocs).
%   'refloc'     - Reference channel location single element structure or cell array
%                  {'label' theta radius} containing the name and polar coordinates
%                  of the current channel. Including this entry means that
%                  this channel will be included (reconstructed) in the
%                  output.
%
% Outputs:
%   Dataout     - Input data converted to the new reference
%   Chanlocs    - Updated channel locations structure
%
% Notes: 1) The average reference calculation implements two methods
%           (see www.egi.com/Technotes/AverageReference.pdf)
%            V'i = (Vi-Vref) - sum(Vi-Vref)/number_of_electrodes
%
% Authors: Arnaud Delorme, SCCN/INC/UCSD, La Jolla, 2009-
%          previous version: Arnaud Delorme & Scott Makeig, 1999-2002

% Deprecated inputs:
% These inputs are still accepted but not processed. The function returns
% accurate results irrespective of the entry of these options.
%   'refstate  ' - ['common'|'averef'|[indices]] Current reference condition,
%                  ('averef') = average reference; ('common' or 0) = common
%                  reference. [indices] designate the current reference channel
%                  or channels if present in the data {default: 'common'}
%   'method'     - ['standard'|'withref'] Do not ('standard') or do ('withref')
%                  include reference channel data in output {def: 'standard'}.
%                  Note: Option 'withref' not possible when multiple ref channel
%                  indices are given as argument to 'refstate' (below).
%
% ICA inputs:
% These inputs are still accepted but not the ICA conversion is now
% performed from within POP_REREF
%   'icaweights' - ICA weight matrix. Note: If this is ICA weights*sphere,
%                  then the 'icasphere' input below should be [] or identity.
%   'icasphere'  - ICA sphere matrix (if any)
%   'icachansind' - Indices of the channels used in ICA decomposition
%
% Outputs:
%   Wout        - ICA weight matrix (former icaweights*icasphere)
%                 converted to new data reference
%   Sout        - ICA sphere matrix converted to an identity matrix
%   ICAinds     - New indices of channels used in ICA decomposition
%   meandata    - (1,dataframes) means removed from each data point
%
%        2) In conversion of the weight matrix to a new reference
%           where WS = Wts*Sph  and  ica_act = WS*data, then
%              data = inv(WS)*ica_act;
%           If R*data are the re-referenced data,
%              R*data= R*inv(WS)*ica_act;
%           And Wout = inv(R*inv(WS));
%           Now, Sout = eye(length(ICAinds));
%           The re-referenced ICA component maps are now the
%           columns of inv(Wout), and the icasphere matrix, Sout,
%           is an identity matrix. Note: INV -> PINV when
%           PCA dimension reduction is used during ICA decomposition.

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

% 12/16/99 Corrected denomiator on the suggestion of Ian Nimmo-Smith, Cambridge UK
% 01-25-02 reformated help & license -ad

function [data, Elocs, morechans, W, S, icachansind, meandata] = reref(data, ref, varargin)

if nargin<1
  help reref
  return
end
if nargin < 2
    ref = [];
end

% check inputs
% ------------
g = finputcheck(varargin, { 'icaweight'   'real'    []          [];
                            'icaweights'  'real'    []          [];
                            'icasphere'   'real'    []          [];
                            'icachansind' 'integer'    []       [];
                            'interpchan'  {''}      []          [];
                            'method'     'string'  { 'standard','withref' }  'standard';
                            'refstate'   { 'string','integer' } { { 'common','averef' } [1 size(data,1)] }     'common'; % ot used but kept for backward compatib.
                            'exclude'    'integer' [1 size(data,1)]          [];
                            'refloc'     { 'cell','struct' }  { [] [] }   {};
                            'keepref'    'string'  {'on','off' }             'off';
                            'elocs'      {'integer','struct'}  []            [] });
if ischar(g), error(g); end
if ~isempty(g.icaweight)
    g.icaweights = g.icaweight;
end
if ~isempty(g.icaweights)
    if isempty(g.icachansind),
        g.icachansind = [1:size(g.icaweights,2)];
        disp('Warning: reref() output has changed slightly since EEGLAB 5.02');
        disp('         the 4th output argument is the indices of channels used for ICA instead');
        disp('         of the mean reference value (which is now output argument 5)');
    end
end
if ischar(ref), ref = { ref }; end
if iscell(ref), ref = eeg_chaninds(g.elocs, ref); end
if ~isempty(ref)
    if ref > size(data,1)
        error('reference channel index out of range');
    end
end

[dim1, dim2, dim3] = size(data);
data = reshape(data, dim1, dim2*dim3);

% single reference not present in the data
% add it as blank data channel at the end
% ----------------------------------------
if ~isempty(g.refloc) == 1
    if ~isempty(g.elocs)
        if iscell(g.refloc)
            data(end+1,:) = 0;
            g.elocs(end+1).labels = g.refloc{1};
            g.elocs(end  ).theta  = g.refloc{2};
            g.elocs(end  ).radius = g.refloc{3};
        else
            data(end+length(g.refloc),:) = 0;
            for iLocs = 1:length(g.refloc)
                g.elocs(end+1).labels = g.refloc(iLocs).labels;
                fieldloc = fieldnames(g.elocs);
                for ind = 1:length(fieldloc)
                    g.elocs(end) = setfield(g.elocs(end), fieldloc{ind}, getfield(g.refloc(iLocs), fieldloc{ind}));
                end
            end
        end
    end
    [dim1 dim2 dim3] = size(data);
end

% exclude some channels
% ---------------------
chansin   = setdiff_bc([1:dim1], g.exclude);
nchansin  = length(chansin);

% return mean data
% ----------------
if nargout > 4
    meandata = sum(data(chansin,2))/nchansin;
end

% generate rereferencing matrix
% -----------------------------
if 0 % alternate code - should work exactly the same
    if isempty(ref)
        ref=chansin; % average reference
    end % if
    chansout=chansin;
    data(chansout,:)=data(chansout,:)-ones(nchansin,1)*mean(data(ref,:),1);
else
    if ~isempty(ref) % not average reference
        refmatrix = eye(nchansin); % begin with identity matrix
        tmpref = ref;
        for index = length(g.exclude):-1:1
            tmpref(find(g.exclude(index) < tmpref)) = tmpref(find(g.exclude(index) < tmpref))-1;
        end
        for index = 1:length(tmpref)
            refmatrix(:,tmpref(index)) = refmatrix(:,tmpref(index))-1/length(tmpref);
        end
    else % compute average reference
        refmatrix = eye(nchansin)-ones(nchansin)*1/nchansin;
    end
    chansout = chansin;
    data(chansout,:) = refmatrix*data(chansin,:);
end

% change reference in elocs structure
% -----------------------------------
if ~isempty(g.elocs)
    if isempty(ref)
        for ind = chansin
            g.elocs(ind).ref = 'average';
        end
    else
        reftxt = { g.elocs(ref).labels };
        if length(reftxt) == 1, reftxt = reftxt{1};
        else
            reftxt = cellfun(@(x)([x ' ']), reftxt, 'uniformoutput', false);
            reftxt = [ reftxt{:} ];
        end
        for ind = chansin
            g.elocs(ind).ref = reftxt;
        end
    end
end

% remove reference
% ----------------
morechans = [];
if strcmpi(g.keepref, 'off')
    data(ref,:) = [];
    if ~isempty(g.elocs)
        morechans = g.elocs(ref);
        g.elocs(ref) = [];
    end
end

data = reshape(data, size(data,1), dim2, dim3);

% treat optional ica parameters
% -----------------------------
W = []; S = []; icachansind = [];
if ~isempty(g.icaweights)
    disp('Warning: This function does not process ICA array anymore, use the pop_reref function instead');
end
Elocs = g.elocs;


% ------------------------------------------------------------------------
%        Get ROI reference-space locations and region annotations
% ------------------------------------------------------------------------

%% SET FILE LOCATIONS OF TRANSFORM AND ROIS

% file location of transform and transformed image
transform_location =         'C:\Drive\Histology\for tutorial - sample data\SS096_done\processed\transformations\SS096_1_1_transform_data';
transformed_slice_location = 'C:\Drive\Histology\for tutorial - sample data\SS096_done\processed\transformations\SS096_1_1_transformed.tif';

% file location of ROIs (image / array of the same size as the reference ie 800 x 1140)
roi_location = 'C:\Drive\Histology\for tutorial - sample data\SS096_1_1_ROIs.tif';

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

% plane used to view ROI ('coronal' -- most common, 'sagittal', 'transverse')
plane = 'coronal';

% Synthetic ROIs for testing
% rois = zeros(800,1140,'uint8');
% rois(250:300, 600:610) = 200; rois(480:500, 200:210) = 200;
% imwrite(rois,roi_location)
%
% Using a set of x and y coordinates from the ImageJ function Analyze Particles to generate an ROI image
% roi_array = zeros(800,1140,'uint8');
% roi_array_values = csvread('C:\ROI_files\cfos_cells.csv', 1, 5);
% y = roi_array_values(:, 1);
% x = roi_array_values(:, 2);
%
% for i = 1:length(roi_array_values)-1
%     roi_array(x(i),y(i)) = 200;
% end

%% LOAD THE DATA

% load the transformed slice image
transformed_slice_image = imread(transformed_slice_location);

% load the transform from the transform file
transform_data = load(transform_location);
transform_data = transform_data.save_transform;

% get the actual transformation from slice to atlas
slice_to_atlas_transform = transform_data.transform;

% get the position within the atlas data of the transformed slice
slice_num = transform_data.allen_location{1};
slice_angle = transform_data.allen_location{2};

% load the rois
rois = imread(roi_location);

% if the rois come from a transformed roi image of non-contiguous roi
% pixels (e.g. an ROI pixel for each neuron), then run this line to ensure
% a one-to-one mapping between ROIs in the original and transformed images:
% rois = uint8(imregionalmax(rois));

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

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

%% GET REFERENCE-SPACE LOCATIONS AND REGION ANNOTATIONS FOR EACH ROI

% I will do this for every *pixel* in the roi image with nonzero value,
% but this code can be modified, e.g. to do it by clusters of pixels

% show the transformed ROI, together with the transformed image
figure; imshow(imfuse(rois, transformed_slice_image));
title('transformed slice image, fused with ROIs')

% make sure the rois are in a properly size image
assert(size(rois,1)==800&size(rois,2)==1140&size(rois,3)==1,'roi image is not the right size');

% initialize array of locations (AP, DV, ML relative to bregma) in reference space
% and the correponding region annotations
roi_location = zeros(sum(rois(:)>0),3);
roi_annotation = cell(sum(rois(:)>0),3);

% get location and annotation for every roi pixel
[pixels_row, pixels_column] = find(rois>0);

% generate other necessary values
bregma = allenCCFbregma(); % bregma position in reference data space

atlas_resolution = 0.010; % mm
ref_size = size(squeeze(av_plot(1,:,:)));
offset_map = get_offset_map(slice_angle, ref_size);

% loop through every pixel to get ROI locations and region annotations
for pixel = 1:length(pixels_row)

    % get the offset from the AP value at the centre of the slice, due to
    % off-from-coronal angling
    offset = offset_map(pixels_row(pixel),pixels_column(pixel));

    % use this and the slice number to get the AP, DV, and ML coordinates
    if strcmp(plane,'coronal')
        ap = -(slice_num-bregma(1)+offset)*atlas_resolution;
        dv = (pixels_row(pixel)-bregma(2))*atlas_resolution;
        ml = (pixels_column(pixel)-bregma(3))*atlas_resolution;
    elseif strcmp(plane,'sagittal')
        ml = -(slice_num-bregma(3)+offset)*atlas_resolution;
        dv = (pixels_row(pixel)-bregma(2))*atlas_resolution;
        ap = -(pixels_column(pixel)-bregma(1))*atlas_resolution;
    elseif strcmp(plane,'transverse')
        dv = -(slice_num-bregma(2)+offset)*atlas_resolution;
        ml = (pixels_row(pixel)-bregma(3))*atlas_resolution;
        ap = -(pixels_column(pixel)-bregma(1))*atlas_resolution;
    end

    roi_location(pixel,:) = [ap dv ml];

    % finally, find the annotation, name, and acronym of the current ROI pixel
    ann = av_plot(slice_num+offset,pixels_row(pixel),pixels_column(pixel));
    name = st.safe_name{ann};
    acr = st.acronym{ann};

    roi_annotation{pixel,1} = ann;
    roi_annotation{pixel,2} = name;
    roi_annotation{pixel,3} = acr;

end

 roi_table = table(roi_annotation(:,2),roi_annotation(:,3), ...
                    roi_location(:,1),roi_location(:,2),roi_location(:,3), roi_annotation(:,1), ...
     'VariableNames', {'name', 'acronym', 'AP_location', 'DV_location', 'ML_location', 'avIndex'});

 disp(roi_table(1:10,:))

% now, use roi_locations and roi_annotations for your further analyses