function scalar = array2scalar(F_array, grid, ge, ft, axis, osc, physQ, intercept)

chkarg(istypesizeof(grid, 'Grid2d') || istypesizeof(grid, 'Grid3d'), ...
	'"grid" should be instance of Grid2d or Grid3d.');
chkarg(istypesizeof(ge, 'GT'), '"ge" should be instance of GT.');
chkarg(istypesizeof(ft, 'FT'), '"ft" should be instance of FT.');
chkarg(istypesizeof(axis, 'Axis'), '"axis" should be instance of Axis.');
chkarg(istypesizeof(osc, 'Oscillation'), '"osc" should be instance of Oscillation.');
chkarg(istypesizeof(physQ, 'PhysQ'), '"physQ" should be instance of PhysQ.');

is3D = true;
if istypesizeof(grid, 'Grid2d')
	is3D = false;
end

if ft == FT.e
    gt = ge;  % grid type for E-field
else  % ft == FT.h
    gt = alter(ge);  % grid type for H-field
end

gt_array = gt(ones(1, Axis.count));
gt_array(axis) = alter(gt);

if is3D
	grid3d = grid;
	chkarg(istypesizeof(F_array, 'arbitrary', grid3d.N), '"F_array" should be %d-by-%d-by-%d array.', grid3d.Ncell{:});

	V = F_array;
	for w = Axis.elems
		V = attach_extra_F(V, ft, gt_array(w), axis, grid3d.bc(w), w, grid3d.kBloch(w)*grid3d.L(w));
	end

	scalar = Scalar3d(V, grid3d, gt_array, osc, physQ, [physQ.symbol, '_', char(axis)]);
else  % grid is Grid2d
	if nargin < 7  % no intercept
		intercept = NaN;
	end
	chkarg(istypesizeof(intercept, 'real'), '"intercept" should be real.');  % NaN is real

	grid2d = grid;
	chkarg(istypesizeof(F_array, 'arbitrary', grid2d.N), '"F_array" should be %d-by-%d array.', grid2d.Ncell{:});

	gt_array = gt_array(grid2d.axis);

	if axis == grid2d.axis(Dir.h)
		axis_temp = Axis.x;
	elseif axis == grid2d.axis(Dir.v)
		axis_temp = Axis.y;
	else  % axis == grid2d.normal_axis
		axis_temp = Axis.z;
	end

	C = F_array;
	C = attach_extra_F(C, ft, gt_array(Dir.h), axis_temp, grid2d.bc(Dir.h), Axis.x, grid2d.kBloch(Dir.h)*grid2d.L(Dir.h));  % treat C as 3D array with one element in 3rd dimension
	C = attach_extra_F(C, ft, gt_array(Dir.v), axis_temp, grid2d.bc(Dir.v), Axis.y, grid2d.kBloch(Dir.v)*grid2d.L(Dir.v));  % treat C as 3D array with one element in 3rd dimension

	scalar = Scalar2d(C, grid2d, gt_array, osc, physQ, [physQ.symbol, '_', char(axis)], intercept);
end

function Fw_array = attach_extra_F(Fw_array, ft, gt, w, bc_v, v, kvLv)
% Augment the Fw array with ghost boundary elements in the v-axis.
% Surprisingly, this function combines attach_extra_E() and attach_extra_H().

% chkarg(istypesizeof(Fw_array, 'complex', [0 0 0]), '"Fw_array" should be 3D array with complex elements.');
chkarg(istypesizeof(ft, 'FT'), '"ft" should be instance of FT.');
chkarg(istypesizeof(gt, 'GT'), '"gt" should be instance of GT.');
chkarg(istypesizeof(w, 'Axis'), '"w" should be instance of Axis.');
chkarg(istypesizeof(bc_v, 'BC'), '"bc_v" should be instance of BC.');
chkarg(istypesizeof(v, 'Axis'), '"v" should be instance of Axis.');
chkarg(istypesizeof(kvLv, 'real'), '"kvLv" should be real.');

ind_n = {':',':',':'};
ind_p = {':',':',':'};
Nv = size(Fw_array, int(v));
if gt == GT.prim
	if bc_v == BC.p
		ind_p{v} = 1;
		Fw_array = cat(int(v), Fw_array, Fw_array(ind_p{:})*exp(-1i*kvLv));
	else  % bc_v == BC.e or BC.m
		% At the ghost point tangential primary fields are always zero, so
		% normal dual fields are also zero.
		size_extra = size(Fw_array);
		size_extra(v) = 1;
		Fw_array = cat(int(v), Fw_array, zeros(size_extra));
	end
else  % gt == GT.dual
	if bc_v == BC.p
		ind_n{v} = Nv;
		ind_p{v} = 1;
		Fw_array = cat(int(v), Fw_array(ind_n{:})*exp(1i*kvLv), Fw_array, Fw_array(ind_p{:})*exp(-1i*kvLv));
	else  % bc_v == BC.e or BC.m
		ind_n{v} = 1;
		ind_p{v} = Nv;
		ft_match_bc = (ft == FT.e && bc_v == BC.e) || (ft == FT.h && bc_v == BC.m);
		if (v ~= w && ft_match_bc) || (v == w && ~ft_match_bc)
			Fw_array = cat(int(v), -Fw_array(ind_n{:}), Fw_array, Fw_array(ind_p{:}));
		else  % (v == w && ft_match_bc) || (v ~= w && ~ft_match_bc)
			Fw_array = cat(int(v), Fw_array(ind_n{:}), Fw_array, Fw_array(ind_p{:}));
		end
	end
end


function [header,tracks] = trk_read(filePath)
%TRK_READ - Load TrackVis .trk files
%TrackVis displays and saves .trk files in LPS orientation. After import, this
%function attempts to reorient the fibers to match the orientation of the
%original volume data.
%
% Syntax: [header,tracks] = trk_read(filePath)
%
% Inputs:
%    filePath - Full path to .trk file [char]
%
% Outputs:
%    header - Header information from .trk file [struc]
%    tracks - Track data structure array [1 x nTracks]
%      nPoints - # of points in each streamline
%      matrix  - XYZ coordinates (in mm) and associated scalars [nPoints x 3+nScalars]
%      props   - Properties of the whole tract (ex: length)
%
% Example:
%    exDir           = '/path/to/along-tract-stats/example';
%    subDir          = fullfile(exDir, 'subject1');
%    trkPath         = fullfile(subDir, 'CST_L.trk');
%    [header tracks] = trk_read(trkPath);
%
% Other m-files required: none
% Subfunctions: get_header
% MAT-files required: none
%
% See also: http://www.trackvis.org/docs/?subsect=fileformat
%           http://github.com/johncolby/along-tract-stats/wiki/orientation

% Author: John Colby (johncolby@ucla.edu)
% UCLA Developmental Cognitive Neuroimaging Group (Sowell Lab)
% Mar 2010

% Parse in header
fid    = fopen(filePath, 'r');
header = get_header(fid);

% Check for byte order
if header.hdr_size~=1000
    fclose(fid);
    fid    = fopen(filePath, 'r', 'b'); % Big endian for old PPCs
    header = get_header(fid);
end

if header.hdr_size~=1000, error('Header length is wrong'), end

% Check orientation
[maxX, ix] = max(abs(header.image_orientation_patient(1:3)));
[maxY, iy] = max(abs(header.image_orientation_patient(4:6)));
% Martin: Bugfix here when image_orientation_patient is empty...
if maxX == 0 && maxY == 0
    ix = 1;
    iy = 2;
    iz = 3;
else
    iz = 1:3;
    iz([ix iy]) = [];
end

% Fix volume dimensions to match the reported orientation.
header.dim        = header.dim([ix iy iz]);
header.voxel_size = header.voxel_size([ix iy iz]);

% Parse in body
if header.n_count > 0
	max_n_trks = header.n_count;
else
	% Unknown number of tracks; we'll just have to read until we run out.
	max_n_trks = inf;
end

% It's impossible to preallocate the "tracks" variable because we don't
% know the number of points on each curve ahead of time; we find out by
% reading the file.  The line below suppresses preallocation warnings.
%#ok<*AGROW>

iTrk = 1;
while iTrk <= max_n_trks
	pts = fread(fid, 1, 'int');
	if feof(fid)
		break;
	end
    tracks(iTrk).nPoints = pts;
    tracks(iTrk).matrix  = fread(fid, [3+header.n_scalars, tracks(iTrk).nPoints], '*float')';
    if header.n_properties
        tracks(iTrk).props = fread(fid, header.n_properties, '*float');
    end

    % Modify orientation of tracks (always LPS) to match orientation of volume
    coords = tracks(iTrk).matrix(:,1:3);
    coords = coords(:,[ix iy iz]);
    if header.image_orientation_patient(ix) < 0
        coords(:,ix) = header.dim(ix)*header.voxel_size(ix) - coords(:,ix);
    end
    if header.image_orientation_patient(3+iy) < 0
        coords(:,iy) = header.dim(iy)*header.voxel_size(iy) - coords(:,iy);
    end
    tracks(iTrk).matrix(:,1:3) = coords;
	iTrk = iTrk + 1;
end

if header.n_count == 0
	header.n_count = length(tracks);
end

fclose(fid);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function header = get_header(fid)

header.id_string                 = fread(fid, 6, '*char')';
header.dim                       = fread(fid, 3, 'short')';
header.voxel_size                = fread(fid, 3, 'float')';
header.origin                    = fread(fid, 3, 'float')';
header.n_scalars                 = fread(fid, 1, 'short')';
header.scalar_name               = fread(fid, [20,10], '*char')';
header.n_properties              = fread(fid, 1, 'short')';
header.property_name             = fread(fid, [20,10], '*char')';
header.vox_to_ras                = fread(fid, [4,4], 'float')';
header.reserved                  = fread(fid, 444, '*char');
header.voxel_order               = fread(fid, 4, '*char')';
header.pad2                      = fread(fid, 4, '*char')';
header.image_orientation_patient = fread(fid, 6, 'float')';
header.pad1                      = fread(fid, 2, '*char')';
header.invert_x                  = fread(fid, 1, 'uchar');
header.invert_y                  = fread(fid, 1, 'uchar');
header.invert_z                  = fread(fid, 1, 'uchar');
header.swap_xy                   = fread(fid, 1, 'uchar');
header.swap_yz                   = fread(fid, 1, 'uchar');
header.swap_zx                   = fread(fid, 1, 'uchar');
header.n_count                   = fread(fid, 1, 'int')';
header.version                   = fread(fid, 1, 'int')';
header.hdr_size                  = fread(fid, 1, 'int')';


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Released under the MIT License.
% If you use this code, please cite the following paper:
% Mahmoud Afifi, Abdelrahman Abdelhamed, Abdullah Abuolaim, Abhijith
% Punnappurath, and Michael S Brown. CIE XYZ Net: Unprocessing Images for
% Low-Level Computer Vision Tasks. arXiv preprint, 2020.
%
% Author: Mahmoud Afifi | Email: mafifi@eecs.yorku.ca, m.3afifi@gmail.com
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% demo with operators
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Please adjust pp_code/postprocessing.m with your custom functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clc
clear
close all

filename = fullfile('..','images','a0280-IMG_0854.JPG');

device = 'gpu';

load(fullfile('models','model_sRGB-XYZ-sRGB.mat'));
           %|res1|I-res1|XYZ|RGB|res2|RGB+res2
pp_method = 'none|none|denoise+deblur|none|none';
%post-processing methods: denoise, deblur, dehaze, editdetails,
% exposure-fusion, transfer-colors, chrom-adapt, super-res
%The order is: localLayer|sRGB-localLayer|CIE XYZ|sRGB|localLayer

show = 1;

save_output = 1;

opt = [];  %extra options, if needed

if save_output == 1
    out_dir = fullfile('..','results');
    if exist(out_dir, 'dir') == 0
        mkdir(out_dir);
    end
end

image = im2double(imread(filename));

if length(size(image)) ~= 3
    error('cannot deal with grayscale images');
end

fprintf('processing image %s...\n', filename);

[~,name,~] = fileparts(filename);

tasks = strsplit(pp_method,'|');

output_XYZ = applyLocalMapping(nets.local_sRGB, image, ...
    'to-xyz', device, tasks{1}, opt);

output_XYZ = applyGlobalMapping(nets.global_sRGB, output_XYZ,device, ...
    tasks{2}, opt);

if strcmpi(tasks{3},'none') == 0
    output_XYZ = postprocessing(output_XYZ,tasks{3},opt);
end

output_sRGB = applyGlobalMapping(nets.global_XYZ, output_XYZ,device, ...
    tasks{4}, opt);

output_sRGB = applyLocalMapping(nets.local_XYZ, output_sRGB, ...
    'to-srgb', device, tasks{5}, opt);

output_sRGB(output_sRGB>1) = 1;
output_sRGB(output_sRGB<0) = 0;

if save_output == 1
    imwrite(output_sRGB,fullfile(out_dir, [name '_result.png']));
end

if show == 1
    subplot(1,2,1);imshow(image);  title('input');
    subplot(1,2,2);imshow(output_sRGB);  title('result');
    linkaxes
end


function g = modelLogLikeGradients(model)

% MODELLOGLIKEGRADIENTS Compute a model's gradients wrt log likelihood.
% FORMAT
% DESC is a wrapper function to compute the gradients of the log
% likelihood of a given model.
% ARG model : the model for which likelihoods are computed.
% RETURN g : teh gradients of the likelihood with respect to the
% parameters.
%
% SEEALSO : modelCreate
%
% COPYRIGHT : Neil D. Lawrence, 2006, 2005

% MLTOOLS

fhandle = str2func([model.type 'LogLikeGradients']);
g = fhandle(model);

if isfield(model, 'paramGroups')
  g = g*model.paramGroups;
end


function [rf, info] = readrfvnmr(filename,verbosity)

% RF = READRFVNMR(FILENAME) reads a Varian VNMR format RF pulse
% description in FILENAME and generates an RF matrix with 3 columns
% specifying angle, magnitude, and duration.
%
% FILENAME can be in working directory, ~/vnmrsys/shapelib, or
% $vnmrsystem/shapelib and can be specified with or with trailing .RF

% Author: L. Martyn Klassen
% Copyright 2003 Robarts Research Institute
% This program is copyrighted worldwide by the Robarts Research
% Institute.  Any distribution, copying or redistribution is expressly
% forbidden.
% Created: April 17, 2003 14:22
% Modified: N/A

if nargin < 2
   verbosity = 0;
   if nargin < 1
      error('READRFVNMR requires RF file name.');
   end
end

% info defaults to an empty structure
info = struct;

% Get the vnmrsystem path
[status, vnmrpath] = unix('echo $vnmrsystem');
if status == 0
   % Strip end-of-line character
   vnmrpath = vnmrpath(1:end-1);
else
   % Make a guess - good for RRI
   vnmrpath = '/vnmr';
end

fid = findfile(filename, vnmrpath);
if fid < 0
   % Check if user forgot .RF or .rf ending
   orgfilename = filename;
   filename = [orgfilename '.RF'];
   fid = findfile(filename, vnmrpath);
   if fid < 0
      filename = [orgfilename '.rf'];
      fid = findfile(filename, vnmrpath);
      if fid < 0
         error('READRFVNMR unable to find %s', orgfilename);
      end
   end
end

if verbosity > 0
   % Report what file was actually opened for reading
   disp(sprintf('READRFVNMR reading file %s', fopen(fid)));
end

% Get the first line of the file
fileline = fgets(fid);
linenumber = 1;
rf = zeros(3,0);
while ischar(fileline)
   % Strip out any comment indicated by #
   idxcomment = strfind(fileline,'#');
   if ~isempty(idxcomment)
      % Look for information normally stored in header
      % It must be commented so we don't need to do this every line
      idx = strfind(fileline, 'VERSION');
      if ~isempty(idx)
         info.version = sscanf(fileline(idx+7:end), '%s', 1);
      end
      idx = strfind(fileline, 'TYPE');
      if ~isempty(idx)
         info.type = sscanf(fileline(idx+4:end), '%s', 1);
      end
      idx = strfind(fileline, 'MODULATION');
      if ~isempty(idx)
         info.modulation = sscanf(fileline(idx+10:end), '%s', 1);
      end
      idx = strfind(fileline, 'EXCITEWIDTH');
      if ~isempty(idx)
         info.excitewidth = sscanf(fileline(idx+11:end), '%f', 1);
      end
      idx = strfind(fileline, 'INVERTWIDTH');
      if ~isempty(idx)
         info.invertwidth = sscanf(fileline(idx+11:end), '%f', 1);
      end
      idx = strfind(fileline, 'INTEGRAL');
      if ~isempty(idx)
         info.integral = sscanf(fileline(idx+8:end), '%f', 1);
      end
      idx = strfind(fileline, 'RF_FRACTION');
      if ~isempty(idx)
         info.aref = sscanf(fileline(idx+11:end), '%f', 1);
      end
      idx = strfind(fileline, 'AREF');
      if ~isempty(idx)
         info.aref = sscanf(fileline(idx+4:end), '%f', 1);
      end
      idx = strfind(fileline, 'b1excite');
      if ~isempty(idx)
         info.b1excite = sscanf(fileline(idx+8:end), '%f', 1);
      end
      idx = strfind(fileline, 'b1invert');
      if ~isempty(idx)
         info.b1invert = sscanf(fileline(idx+8:end), '%f', 1);
      end

      % Strip out everything after the comment indicator
      fileline = fileline(1:idxcomment(1));
   end

   % Kill the last character: end-of-line or #
   fileline(end) = [];

   % If the line is empty skip it
   if ~isempty(fileline)
      % if it blank then skip
      if any(fileline ~= ' ')
         [A,count, errmsg, nextindex] = sscanf(fileline, '%f', inf);

         % If read failed, output the error
         if ~isempty(errmsg)
            fclose(fid)
            error('READRFVNMR failed with read error: %s', errmsg);
         end

         % Each line is to contain 3 and only 3 numbers
         if (count > 0) & (count ~= 3)
            fclose(fid);
            error('READRFVNMR malformed line number %d', linenumber);
         end

         % Store the read values into rf array
         rf(:,linenumber) = A;
         linenumber = linenumber + 1;
      end
   end
   % Get the next line
   fileline = fgets(fid);
end
fclose(fid);

% Add a default aref value if not found
if ~isfield(info, 'aref')
   info.aref = 0.5;
end

% Switch from row to column orientation
rf = rf';
return

function fid = findfile(filename, vnmrpath)
% Search local, user vnmrsys, and global vnmrsys for RF file
fid = fopen(filename, 'r');
if fid < 0
   orgfilename = filename;
   filename = ['~/vnmrsys/shapelib/' orgfilename];
   fid = fopen(filename, 'r');
   if fid < 0
      filename = [vnmrpath '/shapelib/' orgfilename];
      fid = fopen(filename, 'r');
   end
end
return


% pop_rejcont() - reject continuous portions of data based on spectrum
%                 thresholding. First, contiguous data epochs are extracted
%                 and a standard spectrum thresholding algorithm is
%                 applied. Regions of contiguous epochs larger than a
%                 specified size are then labeled as artifactual.
%
% Usage:
%   >> pop_rejcont( INEEG ) % pop-up interative window mode
%   >> [OUTEEG, selectedregions] = pop_rejcont( INEEG, 'key', 'val');
%
% Inputs:
%   INEEG      - input dataset
%
% Optional inputs:
%  'elecrange'   - [integer array] electrode indices {Default: all electrodes}
%  'epochlength' - [float] epoch length in seconds {Default: 0.5 s}
%  'overlap'     - [float] epoch overlap in seconds {Default: 0.25 s}
%  'freqlimit'   - [min max] frequency range too consider for thresholding
%                  Default is [35 128] Hz.
%  'threshold'   - [float] frequency upper threshold in dB {Default: 10}
%  'contiguous'  - [integer] number of contiguous epochs necessary to
%                  label a region as artifactual {Default: 4 }
%  'addlength'   - [float] once a region of contiguous epochs has been labeled
%                  as artifact, additional trailing neighboring regions on
%                  each side may also be added {Default: 0.25 s}
%  'eegplot'     - ['on'|'off'] plot rejected portions of data in a eegplot
%                  window. Default is 'off'.
%  'onlyreturnselection'  - ['on'|'off'] this option when set to 'on' only
%                  return the selected regions and does not remove them
%                  from the datasets. This allow to perform quick
%                  optimization of the rejected portions of data.
%  'precompstruct' - [struct] structure containing precomputed spectrum (see
%                  Outputs) to be used instead of computing the spectrum.
%  'verbose'       - ['on'|'off'] display information. Default is 'off'.
%  'taper'         - ['none'|'hamming'] taper to use before FFT. Default is
%                    'none' for backward compatibility but 'hamming' is
%                    recommended.
%
% Outputs:
%   OUTEEG          - output dataset with updated joint probability array
%   selectedregions - frames indices of rejected electrodes. Array of n x 2
%                     n being the number of regions and 2 for the beginning
%                     and end of each region.
%   precompstruct   - structure containing precomputed data. This structure
%                     contains the spectrum, the frequencies and the EEGLAB
%                     dataset used as input with epochs extracted.
%
% Author: Arnaud Delorme, CERCO, UPS/CNRS, 2009-
%
% Example:
% EEG = pop_rejcont(EEG, 'elecrange',[1:32] ,'freqlimit',[20 40] ,'threshold',...
%    10,'epochlength',0.5,'contiguous',4,'addlength',0.25, 'taper', 'hamming');
%
% See also: eegthresh()

% Copyright (C) 2009 Arnaud Delorme, CERCO, UPS/CNRS
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [EEG selectedregions precompstruct com ] = pop_rejcont(EEG, varargin);

com = '';
if nargin < 1
    help pop_rejcont;
    return;
end;

if nargin < 2
    firstelec = 'EXG1';                % first non EEG channel
    % take all scalp electrodes
    % -------------------------
    if ~isempty(EEG.chanlocs)
        tmpchanlocs = EEG.chanlocs;
        indelec = strmatch( firstelec, { tmpchanlocs.labels });

        if isempty(indelec), elecrange = 1:EEG.nbchan;
        else                 elecrange = 1:(indelec-1);
        end;
    else
        elecrange = 1:EEG.nbchan;
    end;
    elecrange = deblank(vararg2str(elecrange));
    %elecrange = elecrange(2:end-1);

%     promptstr = { 'Channel range' ...
%                   'Frequency range (Hz)' ...
%                   'Frequency threshold in dB' ...
%                   'Epoch segment length (s)' ...
%                   'Minimum number of contiguous epochs' ...
%                   'Add trails before and after regions (s)' ...
%                   };
%     initstr = { elecrange '20 40' '10' '0.5' '4' '0.25' };
%     result = inputdlg2(promptstr, 'Reject portions of continuous data - pop_rejcont', 1, initstr);
    uilist = { { 'style' 'text' 'string' 'Channel range' } ...
               { 'style' 'edit' 'string' elecrange } ...
               { 'style' 'text' 'string' 'Frequency range (Hz)' } ...
               { 'style' 'edit' 'string' '20 40' } ...
               { 'style' 'text' 'string' 'Frequency threshold in dB' } ...
               { 'style' 'edit' 'string' '10' } ...
               { 'style' 'text' 'string' 'Epoch segment length (s)' } ...
               { 'style' 'edit' 'string' '0.5' } ...
               { 'style' 'text' 'string' 'Minimum number of contiguous epochs' } ...
               { 'style' 'edit' 'string' '4' } ...
               { 'style' 'text' 'string' 'Add trails before and after regions (s)' } ...
               { 'style' 'edit' 'string' '0.25' } ...
               { 'style' 'text' 'string' 'Use hanning window before computing FFT' } ...
               { 'style' 'checkbox' 'string' '' 'value' 1 } ...
                  };
    geom = { [2 1] [2 1] [2 1] [2 1] [2 1] [2 1] [2 1] };
    result = inputgui('uilist', uilist, 'geometry', geom);
    if length( result ) == 0 return; end;

    options = { 'elecrange'     str2num(result{1}) ...
                'freqlimit'     str2num(result{2}) ...
                'threshold'     str2double(result{3}) ...
                'epochlength'   str2double(result{4}) ...
                'contiguous'    str2double(result{5}) ...
                'addlength'     str2double(result{6}) ...
                'taper'         fastif(result{7}, 'hamming', 'none') };
else
    options = varargin;
end;

opt = finputcheck(options, { 'threshold'     { 'real';'cell' }  []    10;
                             'freqlimit'     { 'real';'cell' }  []    [35 128];
                             'elecrange'     'real'   []    [1:EEG.nbchan];
                             'rejectori'     'real'   []    [];
                             'contiguous'    'real'   []    4;
                             'addlength'     'real'   []    0.25;
                             'precompstruct' 'struct' []    struct([]);
                             'eegplot'       'string' { 'on';'off' } 'off';
                             'onlyreturnselection' 'string' { 'on';'off' } 'off';
                             'verbose'       'string' { 'on';'off' } 'on';
                             'taper'         'string' { 'none' 'hamming' } 'none';
                             'overlap'       'real'   []    0.25;
                             'epochlength'   'real'   []    0.5 }, 'pop_rejcont');
if isstr(opt), error(opt); end;
if ~iscell(opt.threshold) && length(opt.threshold) == 2 && ...
    iscell(opt.freqlimit) && length(opt.freqlimit) == 2
    opt.threshold = { opt.threshold(1) opt.threshold(2) };
end;
if ~iscell(opt.threshold), opt.threshold = { opt.threshold }; end;
if ~iscell(opt.freqlimit), opt.freqlimit = { opt.freqlimit }; end;

%EEG.event = [];
grouplen  = opt.contiguous/2*opt.epochlength*EEG.srate+1; % maximum number of points for grouping regions
color     = [ 0 0.9 0];             % color of rejection window

NEWEEG = EEG;
if isempty(opt.precompstruct)
    % compute power spectrum
    % ----------------------
    % average reference
    % NEWEEG.data(opt.elecrange,:) = NEWEEG.data(opt.elecrange,:)-repmat(mean(NEWEEG.data(opt.elecrange,:),1), [length(opt.elecrange) 1]);

    % only keep boundary events
    % -------------------------
    tmpevent = NEWEEG.event;
    if ~isempty(tmpevent)
        if isnumeric( tmpevent(1).type )
            NEWEEG.event = [];
        else
            boundEvent = strmatch('boundary', { tmpevent.type }, 'exact');
            NEWEEG.event = NEWEEG.event(boundEvent);
        end;
    end;

    [TMPNEWEEG] = eeg_regepochs(NEWEEG, opt.overlap, [0 opt.epochlength], NaN);
    %[TMPNEWEEG indices] = pop_rejspec(TMPNEWEEG, 1, [1:64], -100, 15, 30, 45, 0, 0);
    %rejepoch = find(indices);

    tmpdata = TMPNEWEEG.data;
    if strcmpi(opt.taper, 'hamming'),
        tmpdata = bsxfun(@times, tmpdata, hamming(size(TMPNEWEEG.data,2))');
    end;
    tmp   = fft(tmpdata, [], 2);
    freqs = linspace(0, TMPNEWEEG.srate/2, size(tmp,2)/2);
    freqspectrum = freqs(2:end); % remove DC (match the output of PSD)
    tmp   = tmp(:,2:size(tmp,2)/2,:);
    warning('off', 'MATLAB:log:logOfZero');
    tmpspec  = 10*log10(abs(tmp).^2);
    warning('on', 'MATLAB:log:logOfZero');
    tmpspec  = tmpspec - repmat( mean(tmpspec,3), [1 1 TMPNEWEEG.trials]);
    specdata = tmpspec;

    % compute mean spectrum
    % ---------------------
    meanspectrum = nan_mean(specdata(opt.elecrange, :, :), 1);
    precompstruct.spec  = meanspectrum;
    precompstruct.freqs = freqspectrum;
    precompstruct.EEG   = TMPNEWEEG;
else
    meanspectrum  = opt.precompstruct.spec;
    freqspectrum  = opt.precompstruct.freqs;
    TMPNEWEEG     = opt.precompstruct.EEG;
    precompstruct = opt.precompstruct;
end;

% apply threshold to average of all electrodes
% --------------------------------------------
rejepoch = [];
for iReject = 1:length(opt.threshold)
    threshold = opt.threshold{iReject};
    freqLim   = opt.freqlimit{iReject};
    if length(threshold) == 1, threshold = [ -100 threshold ]; end;
    [I1 tmpRejEpoch NS Erej] = eegthresh( meanspectrum, size(meanspectrum,2), 1, threshold(1), threshold(2), [freqspectrum(1) freqspectrum(end)], freqLim(1), freqLim(2));
    rejepoch = union_bc(rejepoch, tmpRejEpoch);
    if strcmpi(opt.verbose, 'on')
        fprintf('%d regions selected for rejection, threshold %3.2f-%3.2f dB, frequency limits %3.1f-%3.1f\n', length(tmpRejEpoch), threshold(1), threshold(2), freqLim(1), freqLim(2));
    end;
end;

% build the winrej array for eegplot
% ----------------------------------
winrej   = [];
if ~isempty(find(cellfun(@isempty, { TMPNEWEEG.event.epoch }) == 1))
    error('Some events are not associated with any epoch');
end;
tmpevent = TMPNEWEEG.event;
allepoch = [ tmpevent.epoch ];
if ~isempty(rejepoch)
    for index = 1:length(rejepoch)
        eventepoch = find( rejepoch(index) == allepoch );
        if strcmpi(TMPNEWEEG.event(eventepoch(1)).type, 'X')
            urevent = TMPNEWEEG.event(eventepoch(1)).urevent;
            lat     = TMPNEWEEG.urevent(urevent).latency;
            winrej  = [ winrej; lat lat+opt.epochlength*TMPNEWEEG.srate-1 color ]; %Erej(:,index)'];
        else
            error('Wrong type for epoch');
        end;
    end;
    winrej(:,6:6+length(opt.elecrange)-1) = 0;
end;

% remove isolated regions and merge others
% ----------------------------------------
merged = 0;
isolated = 0;
for index = size(winrej,1):-1:1
    if size(winrej,1) >= index && winrej(index,2) - winrej(index,1) > grouplen, winrej(index,:) = []; isolated = isolated + 1;
    elseif index == 1 && size(winrej,1) > 1 && winrej(index+1,1) - winrej(index,2) > grouplen, winrej(index,:) = []; isolated = isolated + 1;
    elseif index == size(winrej,1) && size(winrej,1) > 1 && winrej(index,1) - winrej(index-1,2) > grouplen, winrej(index,:) = []; isolated = isolated + 1;
    elseif index > 1 && size(winrej,1) > 1 && index < size(winrej,1) && winrej(index+1,1) - winrej(index,2) > grouplen && ...
            winrej(index,1) - winrej(index-1,2) > grouplen
        winrej(index,:) = [];
        isolated = isolated + 1;
    elseif index < size(winrej,1) && size(winrej,1) > 1 && winrej(index+1,1) - winrej(index,2) <= grouplen
        winrej(index,2) = winrej(index+1,2);
        winrej(index+1,:) = [];
        merged = merged + 1;
    end;
end;
if strcmpi(opt.verbose, 'on')
    fprintf('%d regions merged\n', merged);
    fprintf('%d regions removed\n', isolated);
end;

% add time before and after each region
% -------------------------------------
for index = 1:size(winrej,1)
    winrej(index,1) = max(1,         winrej(index,1)-opt.addlength*EEG.srate);
    winrej(index,2) = min(EEG.pnts,  winrej(index,2)+opt.addlength*EEG.srate);
end;

% plot result
% -----------
if ~isempty(winrej)
    selectedregions = winrej(:,1:2);
    if strcmpi(opt.onlyreturnselection, 'off')
        % merge with initial regions
        if ~isempty(opt.rejectori)
            winrej(:,3) = 1; % color
            for iRow = 1:size(opt.rejectori,1)
                winrej(end+1,1:2) = opt.rejectori(iRow,:);
                winrej(end  ,4)   = 1; % color
                winrej(end  ,5)   = 1; % color
            end;
        end;

        command = '[EEG LASTCOM] = pop_select(EEG, ''nopoint'', TMPREJ(:,1:2)); eegh(LASTCOM); [ALLEEG EEG CURRENTSET LASTCOM] = pop_newset(ALLEEG, EEG, CURRENTSET, ''study'', ~isempty(STUDY)+0); eegh(LASTCOM); eeglab redraw';
        if nargin < 2 || strcmpi(opt.eegplot, 'on')
            eegplot(NEWEEG.data(opt.elecrange,:), 'srate', NEWEEG.srate, 'winrej', winrej, 'command', command, 'events', EEG.event, 'winlength', 50);
            disp('Green is overlap');
            disp('Light blue is ORIGINAL rejection');
            disp('Yellow is AUTOMATIC rejection');
        else
            NEWEEG = pop_select(EEG, 'nopoint', round(selectedregions));
        end;
        EEG = NEWEEG;
    else
        EEG = [];
    end;
else
    selectedregions = [];
    if strcmpi(opt.verbose, 'on')
        disp('No region removed');
    end;
end;
if nargout > 3
    com = sprintf('EEG = pop_rejcont(EEG, %s);', vararg2str(options));
end;


% std_interp() - interpolate, if needed, a list of named data channels
%                for all datasets included in a STUDY. Currently assumes
%                that all channels have uniform locations across datasets.
%
% Usage:      >> [STUDY ALLEEG] = std_interp(STUDY, ALLEEG, chans, method);
%
% Inputs:
%     STUDY    - EEGLAB STUDY structure
%     ALLEEG   - EEGLAB vector containing all EEG dataset structures in the STUDY.
%     chans    - [Cell array] cell array of channel names (labels) to interpolate
%                into the data if they are missing from one of the datasets.
%     method   - [string] griddata() method to use for interpolation.
%                See  >> help eeg_interp() {default:'spherical'}
%
% Important limitation:
%     This function currently presuposes that all datasets have the same channel
%     locations (with various channels from a standard set possibly missing).
%     If this is not the case, the interpolation will not be performed.
%
% Output:
%     STUDY    - study structure.
%     ALLEEG   - updated datasets.
%
% Author: Arnaud Delorme, CERCO, CNRS, August 2006-
%
% See also: eeg_interp()

% Copyright (C) Arnaud Delorme, CERCO, 2006, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

% Deprecated:
%              - [chanlocs structure] channel location structure containing
%                a full channel structure (missing channels in the current
%                dataset are interpolated).

function [STUDY, ALLEEG] = std_interp(STUDY, ALLEEG, chans, method);

if nargin < 2
    help std_interp;
    return;
end;
if nargin < 3
    chans = [];
end;
if nargin < 4
    method = 'spherical';
end;

% union of all channel structures
% -------------------------------
alllocs = eeg_mergelocs(ALLEEG.chanlocs);

% check electrode names to interpolate
% ------------------------------------
if iscell(chans)
    alllabs = lower({ alllocs.labels });
    for index = 1:length(chans)
        tmpind = strmatch(lower(chans{index}), alllabs, 'exact');
        if isempty(tmpind)
            error( sprintf('Channel named ''%s'' not found in any dataset', chans{index}));
        end;
    end;
end;

% read all STUDY datasets and interpolate electrodes
% ---------------------------------------------------
for index = 1:length(STUDY.datasetinfo)
   tmpind  = STUDY.datasetinfo(index).index;
   tmplocs = ALLEEG(tmpind).chanlocs;

   % build electrode location structure for interpolation
   % ----------------------------------------------------
   [tmp tmp2 id1] = intersect({tmplocs.labels}, {alllocs.labels});
   if isempty(chans)
       interplocs = alllocs;
   elseif iscell(chans)
       [tmp tmp2 id2] = intersect( chans, {alllocs.labels});
       interplocs = alllocs(union(id1, id2));
   else
       interplocs = chans;
   end;

   if length(interplocs) ~= length(tmplocs)

       % search for position of electrode in backup structure
       % ----------------------------------------------
       extrachans = [];
       if isfield(ALLEEG(tmpind).chaninfo, 'nodatchans')
            if isfield(ALLEEG(tmpind).chaninfo.nodatchans, 'labels')
                extrachans = ALLEEG(tmpind).chaninfo.nodatchans;
            end;
       end;
       tmplabels = { tmplocs.labels };
       for i=1:length(interplocs)
           ind = strmatch( interplocs(i).labels, tmplabels, 'exact');
           if ~isempty(ind)
               interplocs(i) = tmplocs(ind); % this is necessary for polhemus
           elseif ~isempty(extrachans)
               ind = strmatch( interplocs(i).labels, { extrachans.labels }, 'exact');
               if ~isempty(ind)
                    fprintf('Found position of %s in chaninfo structure\n', interplocs(i).labels);
                    interplocs(i) = extrachans(ind);
               end;
           end;
       end;

        % perform interpolation
        % ---------------------
        EEG = eeg_retrieve(ALLEEG, index);
        EEG = eeg_checkset(EEG);
        EEG = eeg_interp(EEG, interplocs, method);
        EEG.saved = 'no';
        EEG = pop_saveset(EEG, 'savemode', 'resave');

        % update dataset in EEGLAB
        % ------------------------
        if isstr(ALLEEG(tmpind).data)
            tmpdata = ALLEEG(tmpind).data;
            [ ALLEEG EEG ] = eeg_store(ALLEEG, EEG, tmpind);
            ALLEEG(tmpind).data  = tmpdata;
            ALLEEG(tmpind).saved = 'yes';
            clear EEG;
        else
            [ ALLEEG EEG ] = eeg_store(ALLEEG, EEG, tmpind);
            ALLEEG(tmpind).saved = 'yes';
        end;
    else
        fprintf('No need for interpolation for dataset %d\n', tmpind);
    end;
end;

function checkchans(STUDY, ALLEEG)

    % Check to see if all the channels have the same coordinates
    % (check only the theta field)
    % ----------------------------------------------------------
    for index = 1:length(STUDY.datasetinfo)
       tmpind  = STUDY.datasetinfo(index).index;
       tmplocs = ALLEEG(tmpind).chanlocs;
       [tmp id1 id2] = intersect({tmplocs.labels}, {alllocs.labels});
       for ind = 1:length(id1)
           if tmplocs(id1(ind)).theta ~= alllocs(id2(ind)).theta

               % find datasets with different coordinates
               % ----------------------------------------
               for ind2 = 1:length(STUDY.datasetinfo)
                   tmplocs2 = ALLEEG(ind2).chanlocs;
                   tmpmatch = strmatch(alllocs(id2(ind)).labels, { tmplocs2.labels }, 'exact');
                   if ~isempty(tmpmatch)
                       if alllocs(id2(ind)).theta == tmplocs2(tmpmatch).theta
                           datind = ind2;
                           break;
                       end;
                   end;
               end;

               error(sprintf( [ 'Dataset %d and %d do not have the same channel location\n' ...
                   'for electrode ''%s''' ], datind, tmpind, tmplocs(id1(ind)).labels));
           end;
       end;
    end;


clear;
netStruct = load('../data/vgg16_cuhk_batch32_Rankloss_2:1:0.5_margin1_re/net-epoch-60.mat');
net = dagnn.DagNN.loadobj(netStruct.net);
clear netStruct;
net.mode = 'test' ;
net.move('gpu') ;
net.removeLayer('RankLoss');
net.conserveMemory = true;
im_mean = reshape(net.meta.normalization.averageImage,1,1,3);

load('../dataset/CUHK-PEDES-prepare/url_data.mat');
p = imdb.images.data(imdb.images.set==3);
ff = [];
%%------------------------------

for i = 1:numel(p)
    disp(i);
    str = p{i};
    im = imread(str);
    oim = im;
    f = getFeature2(net,oim,im_mean,'x0','fc1_1bn');
    f = sum(sum(f,1),2);
    f2 = getFeature2(net,fliplr(oim),im_mean,'x0','fc1_1bn');
    f2 = sum(sum(f2,1),2);
    f = f+f2;
    size4 = size(f,4);
    f = reshape(f,[],size4)';
    f = norm_zzd(f);
    ff = cat(1,ff,f);
end
save('./resnet_cuhk_img.mat','ff','-v7.3');
%}

ff = [];
load('../dataset/CUHK-PEDES-prepare/cuhk_word2.mat');
test_word = wordcnn(:,end-6155:end);

for i = 1:6156
    disp(i);
    content = test_word(:,i);
    len = numel(find(content>0));
    txtinput = zeros(len,7263,'single');
    for k=1:len
        txtinput(k,content(k))=1;
    end
    %transfer it to different location
    win = 57-len;
    input = zeros(56,7263,win,'single');
    for kk = 1:win
        input(kk:kk+len-1,:,kk) = txtinput;
    end
    input = reshape(input,1,56,7263,[]);
    f = getFeature2(net,input,[],'data2','fc5_2bn');
    f = sum(f,4);
    size4 = size(f,4);
    f = reshape(f,[],size4)';
    f = norm_zzd(f);
    ff = cat(1,ff,f);
end
save('./resnet_cuhk_txt.mat','ff','-v7.3');

evaluate;


% MAKE_TIMEWARP - Select a subset of epochs containing a given event sequence, and return
%                   a matrix of latencies for time warping the selected epochs to a common
%                   timebase in NEWTIMEF. Events in the given sequence may be further
%                   restricted to those with specified event field values.
% Usage:
%       >> timeWarp = make_timewarp(EEG, eventSequence, 'key1',value1,
%       'key2',value2,...);
%
% Inputs:
%   EEG                 - dataset structure
%   eventSequence       - cell array containing a sequence of event type strings.
%                         For example, to select epochs containing a 'movement Onset'
%                         event followed by a 'movement peak', use
%                            {'movement Onset' 'movement peak'}
%                         The output timeWarp matrix will contain the epoch latencies
%                         of the two events for each selected epoch.
%
% Optional inputs (in 'key', value format):
%   'baselineLatency'     - (ms) the minimum acceptable epoch latency for the first
%                         event in the sequence {default: 0}
%   'eventConditions'     - cell array specifying conditions on event fields.
%                         For example, for a sequence consisting of two
%                         events with (velocity) fields vx and vy, use
%                            {vx>0' 'vx>0 && vy<1'}
%                         To accept events unconditionally, use empty strings,
%                         for example {'vx>0','',''} {default: no conditions}
%  'maxSTDForAbsolute'    - (positive number of std. devs.) Remove epochs containing events
%                         whose latencies are more than this number of standard deviations
%                         from the mean in the selected epochs. {default: Inf -> no removal}
%  'maxSTDForRelative'    - (positive number of std. devs.) Remove epochs containing inter-event
%                         latency differences larger or smaller than this number of standard deviations
%                         from the mean in the selected epochs. {default: Inf -> no removal}
% Outputs:
%   timeWarp            - a structure with latencies (time-warp matrix with fields
%                          timeWarp.latencies - an (N, M) timewarp matrix for use in NEWTIMEF
%                           where    N = number of selected epochs containing the specified sequence,
%                                    M = number of events in specified event sequence.
%                          timeWarp.epochs - a (1, M) vector giving the index of epochs with the
%                              specified sequence. Only these epochs should be passed to NEWTIMEF.
%                          timeWarp.eventSequence - same as the 'eventSequence' input variable.
% Example:
%   % Create a timewarp matrix for a sequence of events, first an event of type 'movement Onset' followed by
%   % a 'movement peak' event, with event fields vx and vy:
%
%   >> timeWarp = make_timewarp(EEG, {'movement Onset' 'movement%   peak'},'baselineLatency', 0 ...
%                  ,'eventConditions', {'vx>0' 'vx>0 && vy<1'});
%
%   % To remove events with latencies more than 3 standard deviations from the mean OR 2 std. devs.
%   % from the mean inter-event difference:
%
%   >> timeWarp = make_timewarp(EEG, {'movement Onset' 'movement peak'},'baselineLatency', 0, ...
%                  'eventConditions', {'vx>0' 'vx>0 && vy<1'},'maxSTDForAbsolute', 3,'maxSTDForRelative', 2);
%
% Author: Nima Bigdely Shamlo, SCCN/INC/UCSD, 2008
% See also: SHOW_EVENTS, NEWTIMEF

% Copyright (C) Nima Bigdely Shamlo, SCCN/INC/UCSD, 2008
%
% 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.

function timeWarpStructure = make_timewarp(EEG, eventSequence, varargin)

inputKeyValues = finputcheck(varargin, ...
   {'baselineLatency'     'real'    []          0; ...
    'eventConditions'     'cell'    {}        {}  ; ...
    'maxSTDForAbsolute'        'real'    [0 Inf]          Inf; ...
    'maxSTDForRelative'        'real'    [0 Inf]         Inf...
    });

baselineLatency = [];
maxSTDForAbsolute = 0;
maxSTDForRelative = 0;
eventConditions = [];

% place key values into function workspace variables
inputKeyValuesFields = fieldnames(inputKeyValues);
for i=1:length(inputKeyValuesFields)
    eval([inputKeyValuesFields{i} '= inputKeyValues.' inputKeyValuesFields{i} ';']);
end

if length(eventConditions) < length(eventSequence)
    for i = (length(eventConditions)+1):length(eventSequence)
        eventConditions{i} = '';
    end
end

epochsIsAcceptable = ones(1, length(EEG.epoch));
for epochNumber = 1:length(EEG.epoch)
    eventNameID = 1;
    minimumLatency = baselineLatency;
    timeWarp{epochNumber} = [];
    while eventNameID <= length(eventSequence) % go tthrought event names and find the event that comes after a certain event with correct type and higher latency

        firstLatency = eventsOfCertainTypeAfterCertainLatencyInEpoch(EEG.epoch(epochNumber), eventSequence{eventNameID}, minimumLatency, eventConditions{eventNameID});
        if isempty(firstLatency) % means there were no events, so the epoch is not acceptable
            break;
        else
            timeWarp{epochNumber} = [timeWarp{epochNumber}; firstLatency];
            minimumLatency = firstLatency;
            eventNameID = eventNameID + 1;
        end
    end

    if length(timeWarp{epochNumber}) < length(eventSequence)
        epochsIsAcceptable(epochNumber) = false;
    end
end

acceptableEpochs = find(epochsIsAcceptable);

if isempty(acceptableEpochs)
    timeWarp = {}; % no epoch meet the criteria
else
    timeWarp = cell2mat(timeWarp(acceptableEpochs));

    rejectedEpochesBasedOnLateny = union_bc(rejectEventsBasedOnAbsoluteLatency(timeWarp), rejectEventsBasedOnRelativeLatency(timeWarp));
    timeWarp(:,rejectedEpochesBasedOnLateny) = [];
    acceptableEpochs(rejectedEpochesBasedOnLateny) = [];

end

% since latencies and accepted epochs always have to be together, we put them in one structure
timeWarpStructure.latencies = timeWarp'; % make it suitable for newtimef()

if isempty(timeWarpStructure.latencies) % when empty, it becomes a {} instead of [], so we change it to []
    timeWarpStructure.latencies = [];
end

timeWarpStructure.epochs = acceptableEpochs;
timeWarpStructure.eventSequence = eventSequence;

    function rejectedBasedOnLateny =  rejectEventsBasedOnRelativeLatency(timeWarp)
        % remeve epochs in which the time warped event is further than n
        % standard deviations to mean of latency distance between events
        timeWarpDiff =  diff(timeWarp);
        rejectedBasedOnLateny = [];
        for eventNumber = 1:size(timeWarpDiff, 1)
            rejectedBasedOnLateny = [rejectedBasedOnLateny find(abs(timeWarpDiff(eventNumber, :)-  mean(timeWarpDiff(eventNumber, :))) > maxSTDForRelative * std(timeWarpDiff(eventNumber, :)))];
        end
        rejectedEpochesBasedOnLateny = unique_bc(rejectedBasedOnLateny);
    end

    function rejectedBasedOnLateny =  rejectEventsBasedOnAbsoluteLatency(timeWarp)
        % remeve instances in which the time warped event is further than n
        % standard deviations to mean
        rejectedBasedOnLateny = [];
        for eventNumber = 1:size(timeWarp, 1)
            rejectedBasedOnLateny = [rejectedBasedOnLateny find(abs(timeWarp(eventNumber, :)-  mean(timeWarp(eventNumber, :))) >  maxSTDForAbsolute* std(timeWarp(eventNumber, :)))];
        end
        rejectedEpochesBasedOnLateny = unique_bc(rejectedBasedOnLateny);
    end

    function [firstLatency resultEventNumbers] = eventsOfCertainTypeAfterCertainLatencyInEpoch(epoch, certainEventType, certainLatency, certainCondition)
        resultEventNumbers = [];
        firstLatency = []; % first event latency that meets the critria
        for eventNumber = 1:length(epoch.eventtype)
%            if strcmp(certainEventType, epoch.eventtype(eventNumber)) && epoch.eventlatency{eventNumber} >= certainLatency && eventMeetsCondition(epoch, eventNumber, certainCondition)
             if  eventIsOfType(epoch.eventtype(eventNumber), certainEventType)  && epoch.eventlatency{eventNumber} >= certainLatency && eventMeetsCondition(epoch, eventNumber, certainCondition)
                resultEventNumbers = [resultEventNumbers eventNumber];

                if isempty(firstLatency)
                    firstLatency = epoch.eventlatency{eventNumber};
                end
            end
        end
    end

    function result = eventMeetsCondition(epoch, eventNumber, condition)
        if strcmp(condition,'') || strcmp(condition,'true')
            result = true;
        else

            % get the name thatis before themfor field in the epoch, then remove 'event' name
            epochField = fieldnames(epoch);
            for i=1:length(epochField)
                epochField{i} = strrep(epochField{i},'event',''); % remove event from the beginning of field names
                condition = strrep(condition, epochField{i}, ['cell2mat(epoch.event' epochField{i} '(' num2str(eventNumber) '))' ]);
            end

            result = eval(condition);
        end

    end

    function result = eventIsOfType(eventStr, types)
        % if events are numbers, turn them into strings before comparison
        if ischar(types)
            if iscell(eventStr) && isnumeric(cell2mat(eventStr))
                eventStr = num2str(cell2mat(eventStr));
            end

            result = strcmp(eventStr, types);
        else % it must be a cell of strs
            result = false;
            for i=1:length(types)
                result = result ||  strcmp(eventStr, types{i});
            end
        end
    end

end


function [TruePositives, FalseNegatives] = testDrugMetabolism(model, microbeID, biomassReaction, database)
% Performs an FVA and reports those drug metabolites (exchange reactions)
% that can be taken up and/or secreted by the model and should be secreted according to
% data (true positives) and those bile acid metabolites that cannot be secreted by
% the model but should be secreted according to in vitro data (false
% negatives).
%
% INPUT
% model             COBRA model structure
% microbeID         Microbe ID in carbon source data file
% biomassReaction   Biomass objective functions (low flux through BOF
%                   required in analysis)
% database          Structure containing rBioNet reaction and metabolite
%                   database
%
% OUTPUT
% TruePositives     Cell array of strings listing all drug metabolites
%                   (exchange reactions) that can be taken up and/or secreted by the model
%                   and in in vitro data.
% FalseNegatives    Cell array of strings listing all drug metabolites
%                   (exchange reactions) that cannot be taken up and/or secreted by the model
%                   but should be secreted according to in vitro data.
%
% .. Author:
%       Almut Heinken, April 2020
%                      March 2022 - changed code to string-matching to make
%                      it more robust

global CBT_LP_SOLVER
if isempty(CBT_LP_SOLVER)
    initCobraToolbox
end

% read drug metabolism table
dataTable = readInputTableForPipeline('drugTable.txt');

corrRxns = {'eALP','EX_r788(e)','EX_r406(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cALP','EX_r788(e)','EX_r406(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cAzNAD','EX_bzd(e)','EX_abz_ala_b(e)','EX_5asa(e)','EX_olsa(e)','EX_neopront(e)','EX_sanilamide(e)','EX_ssz(e)','EX_sulfp(e)','EX_tab(e)','EX_pront(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cAzNADP','EX_bzd(e)','EX_abz_ala_b(e)','EX_5asa(e)','EX_olsa(e)','EX_neopront(e)','EX_sanilamide(e)','EX_ssz(e)','EX_sulfp(e)','EX_tab(e)','EX_pront(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'eBGal','EX_gal(e)','EX_fru(e)','EX_lactl(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cBGal','EX_lactl(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cBRV','EX_brv(e)','EX_srv(e)','EX_bvu(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cCda','EX_dfduri(e)','EX_dfdcytd(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'eCda','EX_dfduri(e)','EX_dfdcytd(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cCgr','EX_digoxin(e)','EX_digitoxin(e)','EX_dihydro_digitoxin(e)','EX_dihydro_digoxin(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cCodA','EX_5fura(e)','EX_fcsn(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'eCodA','EX_5fura(e)','EX_fcsn(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cDpdNAD','EX_dh5fura(e)','EX_5fura(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cDpdNADP','EX_dh5fura(e)','EX_5fura(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'eDpdNADP','EX_dh5fura(e)','EX_5fura(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cHpd','EX_4hphac(e)','EX_pcresol(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'TdcA','EX_34dhphe(e)','EX_dopa(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'Dadh','EX_mtym(e)','EX_dopa(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cNAT','EX_5asa(e)','EX_isnzd(e)','EX_acisnzd(e)','EX_ac5asa(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'eNAT','EX_5asa(e)','EX_isnzd(e)','EX_acisnzd(e)','EX_ac5asa(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'eNit','EX_nzp(e)','EX_chlphncl(e)','EX_nchlphncl(e)','EX_7a_czp(e)','EX_anzp(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'cNit','EX_nzp(e)','EX_chlphncl(e)','EX_nchlphncl(e)','EX_7a_czp(e)','EX_anzp(e)','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','';'eUidA','EX_1hibup_S(e)','EX_1hibupglu_S(e)','EX_1hmdgluc(e)','EX_1ohmdz(e)','EX_2hatvacid(e)','EX_2hatvacidgluc(e)','EX_2hatvlac(e)','EX_2hatvlacgluc(e)','EX_2hibup_S(e)','EX_2hibupglu_S(e)','EX_2oh_cbz(e)','EX_2oh_cbz_glc(e)','EX_2oh_mtz(e)','EX_2oh_mtz_glc(e)','EX_3meacmp(e)','EX_3hibup_S(e)','EX_3hibupglu_S(e)','EX_3oh_cbz(e)','EX_3oh_cbz_glc(e)','EX_3oh_dlor(e)','EX_3oh_dlor_glc(e)','EX_3oh_mdea(e)','EX_3oh_mdea_glc(e)','EX_3oh_mxn(e)','EX_3oh_mxn_glc(e)','EX_4dh_tpno(e)','EX_4dh_tpno_1glc(e)','EX_4hmdgluc(e)','EX_4oh_dcf(e)','EX_4oh_dcf_glc(e)','EX_4oh_kp(e)','EX_4oh_kp_glc(e)','EX_4oh_levole(e)','EX_4oh_levole_glc(e)','EX_4oh_meth(e)','EX_4oh_meth_glc(e)','EX_4oh_propl(e)','EX_4oh_propl_glc(e)','EX_4oh_trz(e)','EX_4oh_trz_glc(e)','EX_4oh_vcz(e)','EX_4oh_vcz_glc(e)','EX_4ohmdz(e)','EX_5oh_sulfp(e)','EX_5oh_sulfp_glc(e)','EX_5ohfvs(e)','EX_5ohfvsglu(e)','EX_6bhglz(e)','EX_6bhglzglc(e)','EX_6ohfvs(e)','EX_6ohfvsglu(e)','EX_7bhglz(e)','EX_7bhglzglc(e)','EX_7oh_efv(e)','EX_7oh_efv_glc(e)','EX_814dioh_efv(e)','EX_814dioh_efv_glc(e)','EX_8oh_efv(e)','EX_8oh_efv_glc(e)','EX_ac_amn_b_gly(e)','EX_ac_amn_b_gly_glc(e)','EX_acmp(e)','EX_acmp_glc(e)','EX_acmpglu(e)','EX_alpz_4oh(e)','EX_alpz_4oh_glc(e)','EX_alpz_aoh(e)','EX_alpz_aoh_glc(e)','EX_am14(e)','EX_am14_glc(e)','EX_am1ccs(e)','EX_am1cglc(e)','EX_am5(e)','EX_am5_glc(e)','EX_am6(e)','EX_am6_glc(e)','EX_amio(e)','EX_amio_c(e)','EX_amio_c_glc(e)','EX_amio_glc(e)','EX_amn_b_gly(e)','EX_amn_b_gly_glc(e)','EX_amntd_m6(e)','EX_amntd_m6_glc(e)','EX_atvacid(e)','EX_atvacylgluc(e)','EX_atvethgluc(e)','EX_atvlac(e)','EX_atvlacgluc(e)','EX_bhpm(e)','EX_bhpm_glc(e)','EX_bilr_355(e)','EX_bilr_M10(e)','EX_bilr_M12(e)','EX_bilr_M14(e)','EX_bilr_M15(e)','EX_bilr_M16(e)','EX_bilr_M7(e)','EX_bsn(e)','EX_bsn_glc(e)','EX_bz(e)','EX_bz_glc(e)','EX_caribup_s(e)','EX_caribupglu_S(e)','EX_cbz(e)','EX_cbz_glc(e)','EX_cd6168(e)','EX_cd6168_glc(e)','EX_chlphncl(e)','EX_chlphncl_glc(e)','EX_clcxb(e)','EX_clcxb_c(e)','EX_clcxb_c_glc(e)','EX_clcxb_glc(e)','EX_clobi_c(e)','EX_clobi_glc(e)','EX_crvsm1(e)','EX_crvsm23(e)','EX_cvm1gluc(e)','EX_cvm23gluc(e)','EX_daa(e)','EX_daa_glc(e)','EX_dcf(e)','EX_dcf_glc(e)','EX_ddea(e)','EX_ddea_glc(e)','EX_des_astzl(e)','EX_des_astzl_glc(e)','EX_digoxin(e)','EX_digoxin_glc(e)','EX_dlb(e)','EX_dlb_glc(e)','EX_dnpz_5des(e)','EX_dnpz_6des(e)','EX_dnpz_m11(e)','EX_dnpz_m12(e)','EX_dnpz_m13(e)','EX_dnpz_m14(e)','EX_dnpz_m9(e)','EX_doh_etr(e)','EX_doh_etr_glc(e)','EX_doh_vcz(e)','EX_doh_vcz_glc(e)','EX_dxo(e)','EX_dxo_glc(e)','EX_efv(e)','EX_efv_glc(e)','EX_eltr(e)','EX_eltr_glc(e)','EX_eltr_m3(e)','EX_eltr_m4(e)','EX_eztmb(e)','EX_eztmb_glc(e)','EX_fvs(e)','EX_fvsgluc(e)','EX_fvstet(e)','EX_fvstetglu(e)','EX_glc3meacp(e)','EX_gltmn(e)','EX_gltmn_glc(e)','EX_gmfl(e)','EX_gmfl_glc(e)','EX_gmfl_mI(e)','EX_gmfl_mI_glc(e)','EX_gmfl_mII(e)','EX_gmfl_mII_glc(e)','EX_gmfl_mIII(e)','EX_gmfl_mIII_glc(e)','EX_gtacmp(e)','EX_hst(e)','EX_hst_3_glc(e)','EX_hst_3_s(e)','EX_hst_37_diglc(e)','EX_hst_3glc_7s(e)','EX_hst_7_glc(e)','EX_hst_7_s(e)','EX_hst_7glc_3s(e)','EX_ibup_S(e)','EX_ibupgluc(e)','EX_imn(e)','EX_imn_glc(e)','EX_inv(e)','EX_inv_m1(e)','EX_isosorbide_5mn(e)','EX_isosorbide_5mn_glc(e)','EX_kprofen(e)','EX_kprofen_glc(e)','EX_lst4exp(e)','EX_lstn(e)','EX_lstn1gluc(e)','EX_lstnm4(e)','EX_lstnm7(e)','EX_mdz(e)','EX_mdz_glc(e)','EX_mdzglc(e)','EX_miso(e)','EX_miso_glc(e)','EX_mrphn(e)','EX_mrphn_3glc(e)','EX_mrphn_6glc(e)','EX_mtz(e)','EX_mtz_glc(e)','EX_N_oh_phtn(e)','EX_N_oh_phtn_glc(e)','EX_nsldp_m5(e)','EX_nsldp_m5_glc(e)','EX_nverp(e)','EX_nverp_glc(e)','EX_odsm_egltmn(e)','EX_odsm_egltmn_glc(e)','EX_odsm_gltmn(e)','EX_odsm_gltmn_glc(e)','EX_oh_etr(e)','EX_oh_etr_glc(e)','EX_oh_pbl(e)','EX_oh_pbl_glc(e)','EX_phppa(e)','EX_phppa_glc(e)','EX_phtn_glc(e)','EX_prob(e)','EX_prob_glc(e)','EX_pront(e)','EX_pront_glc(e)','EX_propl(e)','EX_propl_glc(e)','EX_prx_mI(e)','EX_prx_mI_glc(e)','EX_prx_mII(e)','EX_prx_mII_glc(e)','EX_ptvst(e)','EX_ptvstgluc(e)','EX_pvs(e)','EX_pvsgluc(e)','EX_R_6oh_warf(e)','EX_R_6oh_warf_glc(e)','EX_R_7oh_warf(e)','EX_R_7oh_warf_glc(e)','EX_R_8oh_warf(e)','EX_R_8oh_warf_glc(e)','EX_r406(e)','EX_r406_glc(e)','EX_r529(e)','EX_r529_glc(e)','EX_rep(e)','EX_rep_glc(e)','EX_rpn_104557(e)','EX_rpn_104557_cb_glc(e)','EX_rpn_96990(e)','EX_rpn_96990_glc(e)','EX_rpn_oh(e)','EX_rpn_oh_glc(e)','EX_rsv(e)','EX_rsvgluc(e)','EX_S_4oh_warf(e)','EX_S_4oh_warf_glc(e)','EX_S_6oh_warf(e)','EX_S_6oh_warf_glc(e)','EX_sb_611855(e)','EX_sb_y(e)','EX_sch_488128(e)','EX_sch_57871(e)','EX_sch_57871_glc(e)','EX_sfnd_1689(e)','EX_sfnd_1689_glc(e)','EX_sftz(e)','EX_sftz_glc(e)','EX_simvgluc(e)','EX_smap(e)','EX_smap_glc(e)','EX_smvacid(e)','EX_sn38(e)','EX_sn38g(e)','EX_spz(e)','EX_spz_glc(e)','EX_spz_sfn(e)','EX_spz_sfn_glc(e)','EX_stg(e)','EX_stg_m3(e)','EX_stg_m4(e)','EX_tat(e)','EX_tgz(e)','EX_tgz_glc(e)','EX_thsacmp(e)','EX_tlf_a(e)','EX_tlf_a_1a(e)','EX_tlf_a_1b(e)','EX_tlf_a_1x(e)','EX_tlf_a_2(e)','EX_tlf_a_2a(e)','EX_tlf_a_3(e)','EX_tlf_a_4(e)','EX_tlf_a_m1(e)','EX_tlf_a_m2(e)','EX_tlf_a_m3(e)','EX_tlf_a_m4(e)','EX_tlf_a_m4a(e)','EX_tlf_a_m5(e)','EX_tlf_a_m5a(e)','EX_tlf_a_m5b(e)','EX_tlf_a_m6(e)','EX_tlf_a_m9(e)','EX_tlms(e)','EX_tlms_glc(e)','EX_tmacmp(e)','EX_tolcp(e)','EX_tolcp_ac(e)','EX_tolcp_ac_glc(e)','EX_tolcp_am(e)','EX_tolcp_am_glc(e)','EX_tolcp_glc(e)','EX_tpno_1glc_4g(e)','EX_tpno_4g(e)','EX_tpno_4glc(e)','EX_tpnoh(e)','EX_tsacmgluc(e)';'cUidA','EX_1hibup_S(e)','EX_1hibupglu_S(e)','EX_1hmdgluc(e)','EX_1ohmdz(e)','EX_2hatvacid(e)','EX_2hatvacidgluc(e)','EX_2hatvlac(e)','EX_2hatvlacgluc(e)','EX_2hibup_S(e)','EX_2hibupglu_S(e)','EX_2oh_cbz(e)','EX_2oh_cbz_glc(e)','EX_2oh_mtz(e)','EX_2oh_mtz_glc(e)','EX_3meacmp(e)','EX_3hibup_S(e)','EX_3hibupglu_S(e)','EX_3oh_cbz(e)','EX_3oh_cbz_glc(e)','EX_3oh_dlor(e)','EX_3oh_dlor_glc(e)','EX_3oh_mdea(e)','EX_3oh_mdea_glc(e)','EX_3oh_mxn(e)','EX_3oh_mxn_glc(e)','EX_4dh_tpno(e)','EX_4dh_tpno_1glc(e)','EX_4hmdgluc(e)','EX_4oh_dcf(e)','EX_4oh_dcf_glc(e)','EX_4oh_kp(e)','EX_4oh_kp_glc(e)','EX_4oh_levole(e)','EX_4oh_levole_glc(e)','EX_4oh_meth(e)','EX_4oh_meth_glc(e)','EX_4oh_propl(e)','EX_4oh_propl_glc(e)','EX_4oh_trz(e)','EX_4oh_trz_glc(e)','EX_4oh_vcz(e)','EX_4oh_vcz_glc(e)','EX_4ohmdz(e)','EX_5oh_sulfp(e)','EX_5oh_sulfp_glc(e)','EX_5ohfvs(e)','EX_5ohfvsglu(e)','EX_6bhglz(e)','EX_6bhglzglc(e)','EX_6ohfvs(e)','EX_6ohfvsglu(e)','EX_7bhglz(e)','EX_7bhglzglc(e)','EX_7oh_efv(e)','EX_7oh_efv_glc(e)','EX_814dioh_efv(e)','EX_814dioh_efv_glc(e)','EX_8oh_efv(e)','EX_8oh_efv_glc(e)','EX_ac_amn_b_gly(e)','EX_ac_amn_b_gly_glc(e)','EX_acmp(e)','EX_acmp_glc(e)','EX_acmpglu(e)','EX_alpz_4oh(e)','EX_alpz_4oh_glc(e)','EX_alpz_aoh(e)','EX_alpz_aoh_glc(e)','EX_am14(e)','EX_am14_glc(e)','EX_am1ccs(e)','EX_am1cglc(e)','EX_am5(e)','EX_am5_glc(e)','EX_am6(e)','EX_am6_glc(e)','EX_amio(e)','EX_amio_c(e)','EX_amio_c_glc(e)','EX_amio_glc(e)','EX_amn_b_gly(e)','EX_amn_b_gly_glc(e)','EX_amntd_m6(e)','EX_amntd_m6_glc(e)','EX_atvacid(e)','EX_atvacylgluc(e)','EX_atvethgluc(e)','EX_atvlac(e)','EX_atvlacgluc(e)','EX_bhpm(e)','EX_bhpm_glc(e)','EX_bilr_355(e)','EX_bilr_M10(e)','EX_bilr_M12(e)','EX_bilr_M14(e)','EX_bilr_M15(e)','EX_bilr_M16(e)','EX_bilr_M7(e)','EX_bsn(e)','EX_bsn_glc(e)','EX_bz(e)','EX_bz_glc(e)','EX_caribup_s(e)','EX_caribupglu_S(e)','EX_cbz(e)','EX_cbz_glc(e)','EX_cd6168(e)','EX_cd6168_glc(e)','EX_chlphncl(e)','EX_chlphncl_glc(e)','EX_clcxb(e)','EX_clcxb_c(e)','EX_clcxb_c_glc(e)','EX_clcxb_glc(e)','EX_clobi_c(e)','EX_clobi_glc(e)','EX_crvsm1(e)','EX_crvsm23(e)','EX_cvm1gluc(e)','EX_cvm23gluc(e)','EX_daa(e)','EX_daa_glc(e)','EX_dcf(e)','EX_dcf_glc(e)','EX_ddea(e)','EX_ddea_glc(e)','EX_des_astzl(e)','EX_des_astzl_glc(e)','EX_digoxin(e)','EX_digoxin_glc(e)','EX_dlb(e)','EX_dlb_glc(e)','EX_dnpz_5des(e)','EX_dnpz_6des(e)','EX_dnpz_m11(e)','EX_dnpz_m12(e)','EX_dnpz_m13(e)','EX_dnpz_m14(e)','EX_dnpz_m9(e)','EX_doh_etr(e)','EX_doh_etr_glc(e)','EX_doh_vcz(e)','EX_doh_vcz_glc(e)','EX_dxo(e)','EX_dxo_glc(e)','EX_efv(e)','EX_efv_glc(e)','EX_eltr(e)','EX_eltr_glc(e)','EX_eltr_m3(e)','EX_eltr_m4(e)','EX_eztmb(e)','EX_eztmb_glc(e)','EX_fvs(e)','EX_fvsgluc(e)','EX_fvstet(e)','EX_fvstetglu(e)','EX_glc3meacp(e)','EX_gltmn(e)','EX_gltmn_glc(e)','EX_gmfl(e)','EX_gmfl_glc(e)','EX_gmfl_mI(e)','EX_gmfl_mI_glc(e)','EX_gmfl_mII(e)','EX_gmfl_mII_glc(e)','EX_gmfl_mIII(e)','EX_gmfl_mIII_glc(e)','EX_gtacmp(e)','EX_hst(e)','EX_hst_3_glc(e)','EX_hst_3_s(e)','EX_hst_37_diglc(e)','EX_hst_3glc_7s(e)','EX_hst_7_glc(e)','EX_hst_7_s(e)','EX_hst_7glc_3s(e)','EX_ibup_S(e)','EX_ibupgluc(e)','EX_imn(e)','EX_imn_glc(e)','EX_inv(e)','EX_inv_m1(e)','EX_isosorbide_5mn(e)','EX_isosorbide_5mn_glc(e)','EX_kprofen(e)','EX_kprofen_glc(e)','EX_lst4exp(e)','EX_lstn(e)','EX_lstn1gluc(e)','EX_lstnm4(e)','EX_lstnm7(e)','EX_mdz(e)','EX_mdz_glc(e)','EX_mdzglc(e)','EX_miso(e)','EX_miso_glc(e)','EX_mrphn(e)','EX_mrphn_3glc(e)','EX_mrphn_6glc(e)','EX_mtz(e)','EX_mtz_glc(e)','EX_N_oh_phtn(e)','EX_N_oh_phtn_glc(e)','EX_nsldp_m5(e)','EX_nsldp_m5_glc(e)','EX_nverp(e)','EX_nverp_glc(e)','EX_odsm_egltmn(e)','EX_odsm_egltmn_glc(e)','EX_odsm_gltmn(e)','EX_odsm_gltmn_glc(e)','EX_oh_etr(e)','EX_oh_etr_glc(e)','EX_oh_pbl(e)','EX_oh_pbl_glc(e)','EX_phppa(e)','EX_phppa_glc(e)','EX_phtn_glc(e)','EX_prob(e)','EX_prob_glc(e)','EX_pront(e)','EX_pront_glc(e)','EX_propl(e)','EX_propl_glc(e)','EX_prx_mI(e)','EX_prx_mI_glc(e)','EX_prx_mII(e)','EX_prx_mII_glc(e)','EX_ptvst(e)','EX_ptvstgluc(e)','EX_pvs(e)','EX_pvsgluc(e)','EX_R_6oh_warf(e)','EX_R_6oh_warf_glc(e)','EX_R_7oh_warf(e)','EX_R_7oh_warf_glc(e)','EX_R_8oh_warf(e)','EX_R_8oh_warf_glc(e)','EX_r406(e)','EX_r406_glc(e)','EX_r529(e)','EX_r529_glc(e)','EX_rep(e)','EX_rep_glc(e)','EX_rpn_104557(e)','EX_rpn_104557_cb_glc(e)','EX_rpn_96990(e)','EX_rpn_96990_glc(e)','EX_rpn_oh(e)','EX_rpn_oh_glc(e)','EX_rsv(e)','EX_rsvgluc(e)','EX_S_4oh_warf(e)','EX_S_4oh_warf_glc(e)','EX_S_6oh_warf(e)','EX_S_6oh_warf_glc(e)','EX_sb_611855(e)','EX_sb_y(e)','EX_sch_488128(e)','EX_sch_57871(e)','EX_sch_57871_glc(e)','EX_sfnd_1689(e)','EX_sfnd_1689_glc(e)','EX_sftz(e)','EX_sftz_glc(e)','EX_simvgluc(e)','EX_smap(e)','EX_smap_glc(e)','EX_smvacid(e)','EX_sn38(e)','EX_sn38g(e)','EX_spz(e)','EX_spz_glc(e)','EX_spz_sfn(e)','EX_spz_sfn_glc(e)','EX_stg(e)','EX_stg_m3(e)','EX_stg_m4(e)','EX_tat(e)','EX_tgz(e)','EX_tgz_glc(e)','EX_thsacmp(e)','EX_tlf_a(e)','EX_tlf_a_1a(e)','EX_tlf_a_1b(e)','EX_tlf_a_1x(e)','EX_tlf_a_2(e)','EX_tlf_a_2a(e)','EX_tlf_a_3(e)','EX_tlf_a_4(e)','EX_tlf_a_m1(e)','EX_tlf_a_m2(e)','EX_tlf_a_m3(e)','EX_tlf_a_m4(e)','EX_tlf_a_m4a(e)','EX_tlf_a_m5(e)','EX_tlf_a_m5a(e)','EX_tlf_a_m5b(e)','EX_tlf_a_m6(e)','EX_tlf_a_m9(e)','EX_tlms(e)','EX_tlms_glc(e)','EX_tmacmp(e)','EX_tolcp(e)','EX_tolcp_ac(e)','EX_tolcp_ac_glc(e)','EX_tolcp_am(e)','EX_tolcp_am_glc(e)','EX_tolcp_glc(e)','EX_tpno_1glc_4g(e)','EX_tpno_4g(e)','EX_tpno_4glc(e)','EX_tpnoh(e)','EX_tsacmgluc(e)'};

TruePositives = {};
FalseNegatives = {};
% find microbe index in drug metabolism table
mInd = find(strcmp(dataTable(:,1), microbeID));
if isempty(mInd)
    warning(['Microbe "', microbeID, '" not found in drug data file.'])
else
    % perform FVA
    % set BOF
    if ~any(ismember(model.rxns, biomassReaction)) || nargin < 3
        error(['Biomass reaction "', biomassReaction, '" not found in model.'])
    end
    model = changeObjective(model, biomassReaction);
    % set a low lower bound for biomass
    %     model = changeRxnBounds(model, biomassReaction, 1e-3, 'l');
    % list exchange reactions
    exchanges = model.rxns(strncmp('EX_', model.rxns, 3));
    % open all exchanges
    model = changeRxnBounds(model, exchanges, -1000, 'l');
    model = changeRxnBounds(model, exchanges, 1000, 'u');

    % get the reactions to test
    rxns = {};
    for i=2:size(dataTable,2)
        if contains(version,'(R202') % for Matlab R2020a and newer
            if dataTable{mInd,i}==1
                findCorrRxns = find(strcmp(corrRxns(:,1),dataTable{1,i}));
                rxns = union(rxns,corrRxns(findCorrRxns,2:end));
            end
        else
            if strcmp(dataTable{mInd,i},'1')
                findCorrRxns = find(strcmp(corrRxns(:,1),dataTable{1,i}));
                rxns = union(rxns,corrRxns(findCorrRxns,2:end));
            end
        end
    end

    % flux variability analysis on reactions of interest
    rxns = unique(rxns);
    rxns = rxns(~cellfun('isempty', rxns));
    rxnsInModel=intersect(rxns,model.rxns);
    if ~isempty(rxnsInModel)
        currentDir=pwd;
        try
            [minFlux, maxFlux, ~, ~] = fastFVA(model, 0, 'max', 'ibm_cplex', ...
                rxnsInModel, 'S');
        catch
            warning('fastFVA could not run, so fluxVariability is instead used. Consider installing fastFVA for shorter computation times.');
            cd(currentDir)
            [minFlux, maxFlux] = fluxVariability(model, 0, 'max', rxnsInModel);
        end

        % active flux
        flux = rxnsInModel(minFlux < -1e-6);
        flux = union(flux,rxnsInModel(maxFlux > 1e-6));
    else
        flux = {};
    end
    % check all exchanges corresponding to drug uptake/secretion
    % in this case, all of them should be carrying flux
    for i=2:size(dataTable,2)
        findCorrRxns = [];
        if contains(version,'(R202') % for Matlab R2020a and newer
            if dataTable{mInd,i}==1
                findCorrRxns = find(strcmp(corrRxns(:,1),dataTable{1,i}));
            end
        else
            if strcmp(dataTable{mInd,i},'1')
                findCorrRxns = find(strcmp(corrRxns(:,1),dataTable{1,i}));
            end
        end
        if ~isempty(findCorrRxns)
            allEx = corrRxns(findCorrRxns,2:end);
            allEx = allEx(~cellfun(@isempty, allEx));

            TruePositives = union(TruePositives, intersect(allEx, flux));
            FalseNegatives = union(FalseNegatives, setdiff(allEx, flux));
        end
    end
end

% replace reaction IDs with metabolite names
if ~isempty(TruePositives)
    TruePositives = TruePositives(~cellfun(@isempty, TruePositives));
    TruePositives=strrep(TruePositives,'EX_','');
    TruePositives=strrep(TruePositives,'(e)','');

    for i=1:length(TruePositives)
        TruePositives{i}=database.metabolites{find(strcmp(database.metabolites(:,1),TruePositives{i})),2};
    end
end

% warn about false negatives
if ~isempty(FalseNegatives)
    FalseNegatives = FalseNegatives(~cellfun(@isempty, FalseNegatives));
    FalseNegatives=strrep(FalseNegatives,'EX_','');
    FalseNegatives=strrep(FalseNegatives,'(e)','');
    for i = 1:length(FalseNegatives)
        FalseNegatives{i}=database.metabolites{find(strcmp(database.metabolites(:,1),FalseNegatives{i})),2};
    end
end

end


function script_extract_vgg16_conv_features(image_set, voc_year, varargin)
% image_set: string with the PASCAL VOC imaget set name, e.g. 'test','trainval',...
% voc_year: string with the PASCAL VOC challenge year of the imaget set, e.g. '2007','2012',...
%
% This file is part of the code that implements the following ICCV2015 accepted paper:
% title: "Object detection via a multi-region & semantic segmentation-aware CNN model"
% authors: Spyros Gidaris, Nikos Komodakis
% institutation: Universite Paris Est, Ecole des Ponts ParisTech
% Technical report: http://arxiv.org/abs/1505.01749
% code: https://github.com/gidariss/mrcnn-object-detection
%
% AUTORIGHTS
% --------------------------------------------------------
% Copyright (c) 2015 Spyros Gidaris
%
% "Object detection via a multi-region & semantic segmentation-aware CNN model"
% Technical report: http://arxiv.org/abs/1505.01749
% Licensed under The MIT License [see LICENSE for details]
% ---------------------------------------------------------

ip = inputParser;
ip.addOptional('start',      1,   @isscalar); % index of the first image in the set from which it will start extracting the feature maps.
ip.addOptional('end',        0,   @isscalar); % index of the last image in the set till which it will extract the feature maps.
ip.addOptional('scales',   [480 576 688 874 1200], @ismatrix);
ip.addOptional('gpu_id',     0,  @isnumeric);
ip.addOptional('use_flips', false, @islogical);

ip.parse(varargin{:});
opts = ip.Results;

mean_pix         = [103.939, 116.779, 123.68];
net_files_dir    = fullfile(pwd,'data','vgg_pretrained_models');
net_def_file     = fullfile(net_files_dir,'vgg16_conv5_deploy.prototxt');
net_weights_file = fullfile(net_files_dir,'VGG_ILSVRC_16_Convolutional_Layers.caffemodel');
assert(exist(net_files_dir,'dir')>0);
assert(exist(net_def_file,'file')>0);
assert(exist(net_weights_file,'file')>0);

image_db  = load_image_dataset('image_set',image_set,...
    'voc_year',voc_year,'use_flips',opts.use_flips);

feat_cache_name          = 'VGG_ILSVRC_16_layers';
feat_cache_dir_parent    = fullfile(pwd, 'feat_cache');
feat_cache_dir_child     = fullfile(feat_cache_dir_parent, feat_cache_name);
feat_cache_dir_image_set = fullfile(feat_cache_dir_child, image_db.image_set_name);

mkdir_if_missing(feat_cache_dir_parent);
mkdir_if_missing(feat_cache_dir_child);
mkdir_if_missing(feat_cache_dir_image_set);

caffe_set_device( opts.gpu_id );
caffe.reset_all();
net = caffe_load_model( net_def_file, {net_weights_file});

extract_conv_features_all_images(net, image_db.image_paths, feat_cache_dir_image_set, ...
    'start',opts.start,'end',opts.end,'scales',opts.scales,'mean_pix',mean_pix);

caffe.reset_all();

end


function [img, fileinfo] = read_hdr(filename)

% load_hdr - loading a radiance RBGE file.
%
%   [img, fileinfo] = read_rle_rgbe(filename);
%
% Written by Lawrence A. Taplin (taplin@cis.rit.edu)
%
% Based loosely on the c-code RGBE implementation written by Bruce Walters
% http://www.graphics.cornell.edu/~bjw/rgbe.html
%
% function to read a run length encoded RGBE picture file and header. This does
% not work if the image is not RLE!!!

do_rescale = 0;

% check if the image is in classical image (eg. TIFF) format
if ~strcmp(filename(end-2:end), 'hdr')
    img = double(imread(filename));
    if do_rescale
        img = rescale(img);
    end
    fileinfo = [];
    return;
end

tic

%open the file
fid = fopen(filename,'r');

if fid<0
    error(['File not found:' filename '.']);
end

%read the magic number
tline = fgetl(fid);
if length(tline)<3 | tline(1:2) ~= '#?'
    error('invalid header');
end
fileinfo.identifier = tline(3:end);

%read the header variables into a structure
tline = fgetl(fid);
while ~isempty(tline)
    %find and set the variable name
    n = strfind(tline,'=');
    if ~isempty(n) % skip stuff I don't understand
        vname = lower(tline(1:n(1)-1));
        vval = tline(n+1:end);
        fileinfo = setfield(fileinfo,vname,tline(n+1:end));
        fprintf('Variable = %s, Value = %s\n',vname, vval);
    end
    %read the next line
    tline = fgetl(fid);
end

%set the resolution variables
tline = fgetl(fid);
fileinfo.Ysign = tline(1);
[fileinfo.height,count,errmsg,nextindex] = sscanf(tline(4:end),'%d',1);
fileinfo.Xsign = tline(nextindex+4);
[fileinfo.width,count,errmsg,nextindex] = sscanf(tline(nextindex+7:end),'%d',1);
fprintf('resolution: %s\n',tline);

%allocate space for the scan line data
img = zeros(fileinfo.height, fileinfo.width, 3);

%read the scanline data
if fileinfo.format == '32-bit_rle_rgbe';
    fprintf('Decoding RLE Data stream\n');
end

%read the remaining data
[data, count] = fread(fid,inf,'uint8');
fclose(fid);

scanline_width = fileinfo.width;
num_scanlines = fileinfo.height;

if ((scanline_width < 8)|(scanline_width > 32767))
    % run length encoding is not allowed so read flat
    img = rgbe2float(reshape(data,fileinfo.width,fileinfo.height,4));
    return;
end

scanline_buffer = repmat(uint8(0),scanline_width,4);
dp = 1; %set the data pointer to the begining of the read data

% read in each successive scanline */
for scanline=1:num_scanlines
    %     if mod(scanline,fix(num_scanlines/100))==0
    %         fprintf('scanline = %d\n',scanline);
    %     end
    %
    if (data(dp) ~= 2) | (data(dp+1) ~= 2)% | (bitget(data(dp+2),8)~=1)
        error('this file is not run length encoded');
    end

    if (bitshift(data(dp+2),8)+data(dp+3))~=scanline_width % -128
        error('wrong scanline width');
    end

    dp = dp+4;

    % read each of the four channels read the scanline into the buffer
    for i=1:4
        ptr = 1;
        while(ptr <= scanline_width)
            if (data(dp) > 128) % a run of the same value
                count = data(dp)-128;
                if ((count == 0)|(count-1 > scanline_width - ptr))
                    warning('bad scanline data');
                end
                scanline_buffer(ptr:ptr+count-1,i) = data(dp+1);
                dp = dp+2;
                ptr = ptr+count;
            else % a non-run
                count = data(dp);
                dp = dp+1;
                if ((count == 0)|(count-1 > scanline_width - ptr))
                    warning('bad scanline data');
                end
                scanline_buffer(ptr:ptr+count-1,i) = data(dp:dp+count-1);
                ptr = ptr+count;
                dp = dp+count;
            end
        end
    end

    % now convert data from buffer into floats
    img(scanline,:,:) = rgbe2float(scanline_buffer);
end

toc

% rescale to 0-1
if do_rescale
    a = min(img(:));
    b = max(img(:));
    img = (img-a)/(b-a);
end

% standard conversion from float pixels to rgbe pixels
% the last dimension is assumed to be color
function [rgbe] = float2rgbe(rgb)
s = size(rgb);
rgb = reshape(rgb,prod(s)/3,3);
rgbe = reshape(repmat(uint8(0),[s(1:end-1),4]),prod(s)/3,4);
v = max(rgb,[],2); %find max rgb
l = find(v>1e-32); %find non zero pixel list
rgbe(l,4) = uint8(round(128.5+log(v)/log(2))); %find E
rgbe(l,1:3) = uint8(rgb(l,1:3)./repmat(2.^(double(rgbe(l,4))-128-8),1,3)); %find rgb multiplier
reshape(rgbe,[s(1:end-1),4]); %reshape back to original dimensions

% standard conversion from rgbe to float pixels */
% note: Ward uses ldexp(col+0.5,exp-(128+8)).  However we wanted pixels */
%       in the range [0,1] to map back into the range [0,1].            */
function [rgb] = rgbe2float(rgbe)
s = size(rgbe);
rgbe = reshape(rgbe,prod(s)/4,4);
rgb = zeros(prod(s)/4,3);
l = find(rgbe(:,4)>0); %nonzero pixel list
rgb(l,:) = double(rgbe(l,1:3)).*repmat(2.^(double(rgbe(l,4))-128-8),1,3);
rgb = reshape(rgb,[s(1:end-1),3]);