function filteredOutS = sitkWrapper(sitkLibPath, scan3M, filterType, paramS)
%function filteredOutS = sitkWrapper(sitkLibPath, scan3M, filterType, paramS, planC)
%Calculate image filters using the Simple ITK Python Library
%--------------------------------------------------------------------------
%sitkLibPath - location of sitk python wrappscan to be filtered
%description - Short description string if desired.
%filterType - name of sitk filter
%             Supported options: 'GradientImageFilter','HistogramMatchingImageFilter',...
%             'LaplacianRecursiveGaussianImageFilter',...
%             'N4BiasFieldCorrectionImageFilter',
%             'N4BiasAndHistogramCorrectionImageFilter'.
%paramS: parameters required to calculate the filter
%planC: to convert scan back to cerr
%--------------------------------------------------------------------------
% example usage:
% filterType = 'GradientImageFilter';
% paramS.useImageSpacing = false;
% paramS.useImageDirection = true;
% sitkLibPath = 'C:\Python34\Lib\site-packages\SimpleITK\';
% planC = loadPlanC(cerrFileName,tempdir);
% planC = updatePlanFields(planC);
% % Quality assure
% planC = quality_assure_planC(cerrFileName,planC);
% indexS = planC{end};
%  % Get Scan
%  scanNum  =1;
%  scanM = double(planC{indexS.scan}(scanNum).scanArray) ...
%      - planC{indexS.scan}(scanNum).scanInfo(1).CTOffset;%
%
% sitkWrapper(sitkLibPath, scanM, filterType, paramS)
%
%
% Rutu Pandya, Dec, 16 2019.
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR 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 CERR.

% import python module SimpleITK
sitkModule = 'SimpleITK';
numpyModule = 'numpy';
%p = pyenv;

P = py.sys.path;
currentPath = pwd;
cd(sitkLibPath);
sitkFileName = fullfile(sitkLibPath,sitkModule);
numpyFileName = fullfile(sitkLibPath,numpyModule);

try
    if count(P,numpyFileName) == 0
        insert(P,int32(0),numpyFileName);
    end
    np = py.importlib.import_module(numpyModule);
    if count(P,sitkFileName) == 0
        insert(P,int32(0),sitkFileName);
    end
    sitk = py.importlib.import_module(sitkModule);
catch
    disp('SimpleITK module could not be imported, check the path');
end

cd(currentPath);

%origScanSize = size(scanM);
% visualize original scan
%slc = 50;
%figure, imagesc(scanM(:,:,50)), title('orig Image')

% % convert scan to numpy array and integer
% scanPy = py.numpy.array(scanM(:).');
% scanPy = scanPy.astype(py.numpy.int64);
%
% % get original shape of the scan
% origShape = py.numpy.array(size(scanM));
% origShape = origShape.astype(py.numpy.int64);

switch filterType
    case 'GradientImageFilter'
        % paramS inputs needed:
        % useImageSpacing (bool), true by default
        % useImageDirection (bool), true by default

        % convert scan to numpy array and integer
        scanPy = np.array(scan3M);
        scanPy = scanPy.astype(py.numpy.float32);

        % get original shape of the scan
        %origShape = py.numpy.array(size(scanM));
        %origShape = origShape.astype(py.numpy.int64);

        % reshape numpy array to original shape
        %scanPy = reshape(scanPy,origShape);

        % Get image from the array
        itkimg = sitk.GetImageFromArray(scanPy);

        % calculate gradient
        gradient = sitk.GradientImageFilter();

        if(paramS.useImageSpacing == false)
            gradient.SetUseImageSpacing(paramS.useImageSpacing);
        end
        if(paramS.useImageDirection == false)
            gradient.SetUseImageDirection(paramS.useImageDirection);
        end
        gradImg = gradient.Execute(itkimg);

        % extract numpy array from resulting image
        npGradImg = sitk.GetArrayFromImage(gradImg);

        % convert resulting numpy array to matlab array in required shape
        %dblGradResultM = double(py.array.array('d',py.numpy.nditer(npGradImg)));
        %gradMatM = reshape(dblGradResultM,[3,origScanSize]);
        gradMatM = double(npGradImg);
        gradMatM = permute(gradMatM,[2,3,4,1]);

        %             %visualize
        %             size(gradMatM)
        %             figure, imagesc(gradMatM(:,:,50,1))
        %             figure, imagesc(gradMatM(:,:,50,2))
        %             figure, imagesc(gradMatM(:,:,50,3))

        filteredOutS.xGradient = gradMatM(:,:,:,1);
        filteredOutS.yGradient = gradMatM(:,:,:,2);
        filteredOutS.zGradient = gradMatM(:,:,:,3);

    case 'LaplacianRecursiveGaussianImageFilter'

        % convert scan to numpy array and integer
        % scanPy = py.numpy.array(scanM(:).');
        scanPy = np.array(scan3M);
        scanPy = scanPy.astype(py.numpy.float32);

        % get original shape of the scan
        %origShape = py.numpy.array(size(scanM));
        %origShape = origShape.astype(py.numpy.int64);

        % reshape numpy array to original shape
        %scanPy = reshape(scanPy,origShape);

        % Get image from the array
        itkimg = sitk.GetImageFromArray(scanPy);

        % Set Image spacing
        zSpacing = paramS.VoxelSize_mm.val(3);
        xSpacing = paramS.VoxelSize_mm.val(1);
        ySpacing = paramS.VoxelSize_mm.val(2);
        itkimg.SetSpacing([zSpacing, ySpacing, xSpacing]);

        % calculate gradient
        logRecursiveFilt = sitk.LaplacianRecursiveGaussianImageFilter();

        logRecursiveFilt.SetNormalizeAcrossScale(true)

        sigmaVal = paramS.Sigma_mm.val;
        logRecursiveFilt.SetSigma(sigmaVal);

        % Execute the filter
        logImg = logRecursiveFilt.Execute(itkimg);

        % extract numpy array from resulting image
        npLogImg = sitk.GetArrayFromImage(logImg);

        % convert resulting numpy array to matlab array in required shape
        %dblLogResultM = double(py.array.array('d',py.numpy.nditer(npLogImg)));
        %logMatM = reshape(dblLogResultM,origScanSize);

        logMatM = double(npLogImg);

        filteredOutS.logImg3M = logMatM;

    case 'HistogramMatchingImageFilter'
        % paramS inputs needed:
        % numHistLevel (int), paramS.numMatchPts (int),
        % ThresholdAtMeanIntensityOn (bool),
        % refImgPath (char vector)

        % convert scan to numpy array and integer
        scan3M = permute(scan3M,[3,1,2]);
        scanPy = np.array(scan3M);
        scanPy = scanPy.astype(py.numpy.float32);

        % get original shape of the scan
        %origShape = py.numpy.array(size(scanM(:)'));
        %origShape = origShape.astype(py.numpy.int64);

        % reshape numpy array to original shape
        %scanPy = reshape(scanPy,origShape);

        % Get image from the array

        srcItkImg = sitk.GetImageFromArray(scanPy);

        %             srcItkImg = py.SimpleITK.ReadImage('E:\data\TumorAware_MR\nrrdScanFormat.nrrd');

        % get ref image
        maskImgPath = fullfile(getCERRPath,'ModelImplementationLibrary/SegmentationModels/referenceImages');
        if isfield(paramS,'refImg') && ~isempty(paramS.refImg.val)
            [refPath,~,~,] = fileparts(paramS.refImg.val);
            if isempty(refPath)
                maskImgPath = fullfile(maskImgPath,paramS.refImg.val);
            else
                maskImgPath = paramS.refImg.val;
            end
            refItkImg = sitk.ReadImage(maskImgPath);
            refItkImg = sitk.Cast(refItkImg,py.SimpleITK.sitkFloat32);

            %Adjust to RTOG-compliant orientation
            %maskPy = sitk.GetArrayFromImage(refItkImg);
            %mask3M = single(maskPy);
            %mask3M = flip(flip(permute(mask3M,[2,3,1]),1),3); % flip y and z dims to convert from RAS to CERR coordinate system
            %mask3M = permute(mask3M,[3,1,2]);
            %scanRefPy = np.array(mask3M);
            %scanRefPy = scanRefPy.astype(py.numpy.float32);
            %refItkImg1 = sitk.GetImageFromArray(scanRefPy);

            %mask3M = flip(flip(mask3M,1),2);
            %mask3M = flip(mask3M,3);
            %maskPy = np.array(mask3M);
            %refItkImg = py.extra.GetImageFromArray(maskPy);
        elseif isfield(paramS,'refImgMat') && ~isempty(paramS.refImgMat.val)
            maskPy = np.array(paramS.refImgMat.val);
            maskPy = maskPy.astype(py.numpy.float32);
            % Get image from the array
            refItkImg = sitk.GetImageFromArray(maskPy);
        else
            error('Reference image not specified for histogram matching')
        end

        %refNumElems = int64(py.numpy.prod(refScanPy.shape));
        %refShape = py.numpy.array([1,refNumElems]);
        %refScanPy = refScanPy.astype(py.numpy.int64);
        % reshape numpy array to original shape
        %refScanPy = reshape(refScanPy,refShape);

        %refItkImg = py.SimpleITK.reshape(refItkImg, scanPy);
        % execute Histogram Matching
        matcher = sitk.HistogramMatchingImageFilter();
        matcher.SetNumberOfHistogramLevels(uint32(paramS.numHistLevel.val));
        matcher.SetNumberOfMatchPoints(uint32(paramS.numMatchPts.val));
        matcher.SetThresholdAtMeanIntensity(false)
        if paramS.thresholdAtMeanIntensityOn.val
            matcher.SetThresholdAtMeanIntensity(true);
        end
        matchedImg = matcher.Execute(srcItkImg,refItkImg);

        % extract numpy array from resulting image
        npHistImg = sitk.GetArrayFromImage(matchedImg);

        % convert resulting numpy array to matlab array in required shape
        %dblHistResultM = double(py.array.array('d',py.numpy.nditer(npHistImg)));
        %histMatM = reshape(dblHistResultM,[origScanSize(1),origScanSize(2),origScanSize(3)]);
        histMatM = double(npHistImg);

        filteredOutS.histMatchedImage = permute(histMatM,[2,3,1]);

        %             %visualize
        %             size(histMatM)
        %             figure, imagesc(histMatM(:,:,slc,1))
        %             figure, imagesc(histMatM(:,:,slc,2))
        %             figure, imagesc(histMatM(:,:,slc,3))

    case 'N4BiasFieldCorrectionImageFilter'

        % Convert to sitk image
        scan3M = permute(scan3M,[3,1,2]);
        scanPy = np.array(scan3M);
        scanPy = scanPy.astype(py.numpy.float32);
        srcItkImg = sitk.GetImageFromArray(scanPy);

        % Get mask
        if isfield(paramS,'maskImg') && ~isempty(paramS.maskImg.val)
            maskImgPath = fullfile(paramS.maskImg.val);
            maskImg = sitk.ReadImage(maskImgPath);
            maskImg = sitk.Cast(maskImg,py.SimpleITK.sitkFloat32);
            %Adjust to RTOG-compliant orientation
            maskPy = sitk.GetArrayFromImage(maskImg);
            mask3M = single(maskPy);
            mask3M = permute(mask3M,[2,3,1]);
            mask3M = flip(flip(mask3M,1),2);
            mask3M = flip(mask3M,3);
            maskPy = np.array(mask3M);
            maskImg = sitk.GetImageFromArray(maskPy);
        else
            %Use defaults
            %maskImg = py.SimpleITK.OtsuThreshold(srcItkImg,...
            %    uint8(0),uint8(1),uint32(200));
            maskImg = [];
        end

        corrector = sitk.N4BiasFieldCorrectionImageFilter();

        % Get optional parameters
        if isfield(paramS,'shrinkFactor') && paramS.shrinkFactor.val > 1
            shrink = paramS.shrinkFactor.val;
            srcItkImg = sitk.Shrink(srcItkImg,...
                shrink*srcItkImg.GetDimension());
            maskImg = sitk.Shrink(maskImg,...
                shrink*srcItkImg.GetDimension());
        end

        if isfield(paramS,'numFittingLevels')
            numFitLevels = paramS.numFittingLevels.val;
        else
            numFitLevels = 4;
        end

        if isfield(paramS,'numIterations')
            numIterationsV = paramS.numIterations.val; %Vector of values per fit level
            maxIterations = int32(numIterationsV);
            corrector.SetMaximumNumberOfIterations(maxIterations);
        end

        % Apply bias correction
        if ~isempty(maskImg)
            outImg = corrector.Execute(srcItkImg, maskImg);
        else
            outImg = corrector.Execute(srcItkImg);
        end

        logBiasFieldImg = corrector.GetLogBiasFieldAsImage(srcItkImg);

        % Convert to matlab array
        npLogBiasFieldImg = sitk.GetArrayFromImage(logBiasFieldImg);
        logBiasFieldImg3M = double(npLogBiasFieldImg);

        correctedImageFullResolution = scan3M ./ exp(logBiasFieldImg3M);

        filteredOutS.biasCorrectedImage = permute(correctedImageFullResolution,[2,3,1]);

        %if isfield(paramS,'shrinkFactor') && paramS.shrinkFactor.val > 1
        %  npCorrectedImg = py.extra.GetArrayFromImage(outImg);
        %  correctedImgShrunk3M = double(npCorrectedImg);
        %end

    case 'N4BiasAndHistogramCorrectionImageFilter'
        filteredOutS = sitkWrapper(sitkLibPath, scan3M, ...
            'N4BiasFieldCorrectionImageFilter', paramS);
        correctedScan3M = filteredOutS.biasCorrectedImage;
        filteredOutS = sitkWrapper(sitkLibPath, correctedScan3M, ...
            'HistogramMatchingImageFilter', paramS);

    otherwise

        msgStr = [filterType,' not defined. Add it to sitkWrapper.m'];
        error(msgStr)
end


%                                                            y = bwdpr1(Lden, b)
% BWDPR1  Solves "PROD_k L(pk,betak)' * y = b", where
%     L(p,beta) = eye(n) + tril(p*beta',-1).
%
% **********  INTERNAL FUNCTION OF SEDUMI **********
%
% See also sedumi, dpr1fact, fwdpr1

function y = bwdpr1(Lden, b) %#ok
%
% This file is part of SeDuMi 1.1 by Imre Polik and Oleksandr Romanko
% Copyright (C) 2005 McMaster University, Hamilton, CANADA  (since 1.1)
%
% Copyright (C) 2001 Jos F. Sturm (up to 1.05R5)
%   Dept. Econometrics & O.R., Tilburg University, the Netherlands.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% Affiliation SeDuMi 1.03 and 1.04Beta (2000):
%   Dept. Quantitative Economics, Maastricht University, the Netherlands.
%
% Affiliations up to SeDuMi 1.02 (AUG1998):
%   CRL, McMaster University, Canada.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
% 02110-1301, USA
%

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


function trl = ft_trialfun_realtime(cfg)

% FT_TRIALFUN_REALTIME can be used to segment a continuous stream of
% data in real-time. Trials are defined as [begsample endsample offset
% condition]
%
% The configuration structure can contain the following specifications
%   cfg.minsample  = the last sample number that was already considered (passed from rt_process)
%   cfg.blocksize  = in seconds. In case of events, offset is with respect to the trigger.
%   cfg.offset     = the offset wrt the 0 point. In case of no events, offset is wrt
%                    prevSample. E.g., [-0.9 1] will read 1 second blocks with
%                    0.9 second overlap
%   cfg.bufferdata = {'first' 'last'}. If 'last' then only the last block of
%                    interest is read. Otherwise, all well-defined blocks are read (default = 'first')

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

if ~isfield(cfg,'minsample'),   cfg.minsample = 0;        end
if ~isfield(cfg,'blocksize'),   cfg.blocksize = 0.1;  end
if ~isfield(cfg,'offset'),      cfg.offset = 0; end
if ~isfield(cfg,'bufferdata'),  cfg.bufferdata = 'first'; end
if ~isfield(cfg,'triggers'),    cfg.triggers = [];        end

% blocksize and offset in terms of samples
cfg.blocksize = round(cfg.blocksize * cfg.hdr.Fs);
cfg.offset = round(cfg.offset * cfg.hdr.Fs);

% retrieve trials of interest
if isempty(cfg.event) % asynchronous mode
  trl = trialfun_asynchronous(cfg);
else % synchronous mode
  trl = trialfun_synchronous(cfg);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function trl = trialfun_asynchronous(cfg)

trl = [];

prevSample = cfg.minsample;

if strcmp(cfg.bufferdata, 'last') % only get last block

  % begsample starts blocksize samples before the end
  begsample  = cfg.hdr.nSamples*cfg.hdr.nTrials - cfg.blocksize;

  % begsample should be offset samples away from the previous read
  if begsample >= (prevSample + cfg.offset)

    endsample  = cfg.hdr.nSamples*cfg.hdr.nTrials;

    if begsample < endsample && begsample > 0
      trl = [begsample endsample 0 nan];
    end
  end

else % get all blocks

  while true

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

    % if newsamples exceeds the offset plus length specified in blocksize
    if newsamples >= (cfg.offset+cfg.blocksize)

      % we do not consider samples < 1
      begsample  = max(1,prevSample+cfg.offset);
      endsample  = max(1,prevSample+cfg.offset+cfg.blocksize);

      if begsample < endsample && endsample <= cfg.hdr.nSamples*cfg.hdr.nTrials
        trl = [trl; [begsample endsample 0 nan]];
      end
      prevSample = endsample;

    else
      break;
    end
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function trl = trialfun_synchronous(cfg)

trl = [];

% process all events
for j=1:length(cfg.event)

  if isempty(cfg.triggers)
    curtrig = cfg.event(j).value;
  else
    [m1,curtrig] = ismember(cfg.event(j).value,cfg.triggers);
  end

  if isempty(curtrig), curtrig = nan; end

  if isempty(cfg.triggers) || (~isempty(m1) && m1)
    % catched a trigger of interest

    % we do not consider samples < 1
    begsample = max(1,cfg.event(j).sample + cfg.offset);
    endsample = max(1,begsample + cfg.blocksize);

    trl = [trl; [begsample endsample cfg.offset curtrig]];

  end
end


%
%       HDR Toolbox demo 3:
%	   1) Load "CS_Warwick.hdr" HDR image
%	   2) Change the mapping from Longitude Latitude to Cube Map
%	   3) Show the new HDR image using gamma encoding
%	   4) Write the cube map on the disk
%	   5) Write on the disk each face of the cube map ready for OpenGL or
%	   Direct3D
%
%       Author: Francesco Banterle
%       Copyright June 2012 (c)
%
%

clear all;

disp('1) Load "CS_Warwick.hdr" HDR image');
img = hdrimread('demos/CS_Warwick.hdr');

disp('2) Change the mapping from Longitude Latitude to Cube Map');
imgOut = ChangeMapping(img, 'LongitudeLatitude', 'CubeMap');

disp('3) Visualization of the new HDR image using gamma encoding');
ldr = GammaTMO(imgOut, 2.2, 0.0, 1);

disp('4) Write the cube map on the disk');
hdrimwrite(imgOut, 'demos/output/CS_Warwick_CUBE_MAP_format.hdr');

disp('5) Write each face of the cube map on the disk');
CrossCutter(imgOut, 'demos/output/CS_Warwick_CM', 'hdr');


function plotData(x, y)
%PLOTDATA Plots the data points x and y into a new figure
%   PLOTDATA(x,y) plots the data points and gives the figure axes labels of
%   population and profit.

% ====================== YOUR CODE HERE ======================
% Instructions: Plot the training data into a figure using the
%               "figure" and "plot" commands. Set the axes labels using
%               the "xlabel" and "ylabel" commands. Assume the
%               population and revenue data have been passed in
%               as the x and y arguments of this function.
%
% Hint: You can use the 'rx' option with plot to have the markers
%       appear as red crosses. Furthermore, you can make the
%       markers larger by using plot(..., 'rx', 'MarkerSize', 10);

figure; % open a new figure window

plot(x, y, 'rx', 'MarkerSize', 10);      % Plot the data
ylabel('Profit in $10,000s');            % Set the y-axis label
xlabel('Population of City in 10,000s'); % Set the x-axis label

% ============================================================

end


%-----------------------------------------------------------------------
% Job saved on 19-Jan-2014 14:08:03 by cfg_util (rev $Rev: 7703 $)
% spm SPM - SPM12b (beta)
% cfg_basicio BasicIO - Unknown
%-----------------------------------------------------------------------
matlabbatch{1}.spm.meeg.source.headmodel.val = 1;
matlabbatch{1}.spm.meeg.source.headmodel.comment = '';
matlabbatch{1}.spm.meeg.source.headmodel.meshing.meshes.template = 1;
matlabbatch{1}.spm.meeg.source.headmodel.meshing.meshres = 2;
matlabbatch{1}.spm.meeg.source.headmodel.coregistration.coregspecify.useheadshape = 0;
matlabbatch{1}.spm.meeg.source.headmodel.forward.eeg = 'EEG BEM';
matlabbatch{1}.spm.meeg.source.headmodel.forward.meg = 'Single Shell';
matlabbatch{2}.spm.tools.beamforming.data.D(1) = cfg_dep('M/EEG head model specification: M/EEG dataset(s) with a forward model', substruct('.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}), substruct('.','D'));
matlabbatch{2}.spm.tools.beamforming.data.val = 1;
matlabbatch{2}.spm.tools.beamforming.data.gradsource = 'inv';
matlabbatch{2}.spm.tools.beamforming.data.space = 'MNI-aligned';
matlabbatch{2}.spm.tools.beamforming.data.overwrite = 1;
matlabbatch{3}.spm.tools.beamforming.sources.BF(1) = cfg_dep('Prepare data: BF.mat file', substruct('.','val', '{}',{2}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}), substruct('.','BF'));
matlabbatch{3}.spm.tools.beamforming.sources.reduce_rank = [2 3];
matlabbatch{3}.spm.tools.beamforming.sources.keep3d = 1;
matlabbatch{3}.spm.tools.beamforming.sources.plugin.mesh.orient = 'original';
matlabbatch{3}.spm.tools.beamforming.sources.plugin.mesh.fdownsample = 1;
matlabbatch{3}.spm.tools.beamforming.sources.plugin.mesh.flip = false;
matlabbatch{3}.spm.tools.beamforming.sources.visualise = 1;
matlabbatch{4}.spm.tools.beamforming.features.BF(1) = cfg_dep('Define sources: BF.mat file', substruct('.','val', '{}',{3}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}), substruct('.','BF'));
matlabbatch{4}.spm.tools.beamforming.features.whatconditions.all = 1;
matlabbatch{4}.spm.tools.beamforming.features.woi = [-Inf Inf];
matlabbatch{4}.spm.tools.beamforming.features.modality = {'MEG'};
matlabbatch{4}.spm.tools.beamforming.features.fuse = 'no';
matlabbatch{4}.spm.tools.beamforming.features.plugin.cov.foi = [0 Inf];
matlabbatch{4}.spm.tools.beamforming.features.plugin.cov.taper = 'none';
matlabbatch{4}.spm.tools.beamforming.features.regularisation.manual.lambda = 1;
matlabbatch{4}.spm.tools.beamforming.features.bootstrap = false;
matlabbatch{5}.spm.tools.beamforming.inverse.BF(1) = cfg_dep('Covariance features: BF.mat file', substruct('.','val', '{}',{4}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}), substruct('.','BF'));
matlabbatch{5}.spm.tools.beamforming.inverse.plugin.eloreta.regularisation = 0.05;
matlabbatch{6}.spm.tools.beamforming.output.BF(1) = cfg_dep('Inverse solution: BF.mat file', substruct('.','val', '{}',{5}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}), substruct('.','BF'));
matlabbatch{6}.spm.tools.beamforming.output.plugin.image_power.whatconditions.all = 1;
matlabbatch{6}.spm.tools.beamforming.output.plugin.image_power.sametrials = false;
matlabbatch{6}.spm.tools.beamforming.output.plugin.image_power.contrast = 1;
matlabbatch{6}.spm.tools.beamforming.output.plugin.image_power.result = 'singleimage';
matlabbatch{6}.spm.tools.beamforming.output.plugin.image_power.scale = 2;
matlabbatch{6}.spm.tools.beamforming.output.plugin.image_power.powermethod = 'trace';
matlabbatch{6}.spm.tools.beamforming.output.plugin.image_power.modality = 'MEG';
matlabbatch{7}.spm.tools.beamforming.write.BF(1) = cfg_dep('Output: BF.mat file', substruct('.','val', '{}',{6}, '.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}), substruct('.','BF'));
matlabbatch{7}.spm.tools.beamforming.write.plugin.gifti.normalise = 'no';
matlabbatch{7}.spm.tools.beamforming.write.plugin.gifti.space = 'mni';
matlabbatch{7}.spm.tools.beamforming.write.plugin.gifti.visualise = 2;


function [TruePositives, FalseNegatives] = testAromaticAADegradation(model, microbeID, biomassReaction, database)
% Performs an FVA and reports those AromaticAA pathway end reactions (exchange reactions)
% that can carry flux in the model and should carry flux according to
% data (true positives) and those AromaticAA pathway end reactions that
% cannot carry flux in 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 aromatic amino acid
% degradation products
% that can be secreted by the model and in comnparative genomic data.
% FalseNegatives    Cell array of strings listing all aromatic amino acid
% degradation products
% that cannot be secreted by the model but should be secreted according to comparative genomic data.
%
% .. Author:
%      Almut Heinken, Dec 2017
%                     March  2022 - changed code to string-matching to make
%                     it more robust

global CBT_LP_SOLVER
if isempty(CBT_LP_SOLVER)
    initCobraToolbox
end

% read aromatic amino acid degradation product table
dataTable = readInputTableForPipeline('AromaticAATable.txt');

corrRxns = {'Phenylpropanoate','EX_pppn(e)';'4-Hydroxyphenylpropanoate','EX_r34hpp(e)';'Indolepropionate','EX_ind3ppa(e)';'Isocaproate','EX_isocapr(e)'};

TruePositives = {};  % true positives (uptake in vitro and in silico)
FalseNegatives = {};  % false negatives (uptake in vitro not in silico)

% find microbe index in data table
mInd = find(strcmp(dataTable(:,1), microbeID));
if isempty(mInd)
    warning(['Microbe "', microbeID, '" not found in aromatic amino acid degradation data file.'])
else
    % perform FVA to identify uptake metabolites
    % 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(maxFlux > 1e-6);
    else
        flux = {};
    end

    % which reaction should carry flux according to in vitro data
    for i=2:size(dataTable,2)
        rxn={};
        if contains(version,'(R202') % for Matlab R2020a and newer
            if dataTable{mInd,i}==1
                rxn = corrRxns{find(strcmp(corrRxns(:,1),dataTable{1,i})),2};
            end
        else
            if strcmp(dataTable{mInd,i},'1')
                rxn = corrRxns{find(strcmp(corrRxns(:,1),dataTable{1,i})),2};
            end
        end
        if ~isempty(rxn)
            % add any that are not in model/not carrying flux to the false negatives
            if ~isempty(intersect(rxn,flux))
                TruePositives = union(TruePositives,rxn);
            else
                FalseNegatives=union(FalseNegatives,rxn);
            end
        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


clear; clc;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Add dependencies
dir_lib_caffe = './fast-rcnn/caffe-fast-rcnn/matlab/caffe/';
dir_lib_frcn = './fast-rcnn/matlab/';
dir_lib_edgebox = './edges/';
dir_lib_ptoolbox = './toolbox/';

addpath(genpath(dir_lib_caffe));
addpath(genpath(dir_lib_frcn));
addpath(genpath(dir_lib_edgebox));
addpath(genpath(dir_lib_ptoolbox));

% Set directories
dir_data = './data/';
file_input_img = [dir_data, 'input_img.jpg'];

file_model_edgebox = [dir_lib_edgebox, 'models/forest/modelBsds.mat'];
file_def_frcn = './models/fashion_detector.prototxt';
file_net_frcn = './models/fashion_detector.caffemodel';

dir_results = './results/';
file_output_bbox = [dir_results, 'bbox_img.mat'];

% Set hyper-parameters
flag_visualize = true;
size_img_max = 227;
id_category = 1; % '1' represents upper-body clothes, '2' represents lower-body clothes, '3' represents full-body clothes

% Initialize EdgeBox model
model_edgebox = load(file_model_edgebox);
model_edgebox = model_edgebox.model;
model_edgebox.opts.multiscale = 0;
model_edgebox.opts.sharpen = 2;
model_edgebox.opts.nThreads = 4;

opts_edgebox = edgeBoxes;
opts_edgebox.alpha = .65;      % step size of sliding window search
opts_edgebox.beta  = .65;      % nms threshold for object proposals
opts_edgebox.minScore = .01;   % min score of boxes to detect
opts_edgebox.maxBoxes = 1e4;   % max number of boxes to detect

% Initialize fast R-CNN model
tic;
use_gpu = true;
model_frcn = fast_rcnn_load_net(file_def_frcn, file_net_frcn, use_gpu);
disp('### Initialization completed: ');
toc;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Read image
img_cur = imread(file_input_img);
height_img = size(img_cur, 1);
width_img = size(img_cur, 2);
channel_img = size(img_cur, 3);

% Resize image for speed-up
if max([height_img, width_img]) > size_img_max
	ratio = size_img_max ./ max([height_img, width_img]);
	img_resized = imresize(img_cur, ratio);
else
	ratio = 1;
	img_resized = img_cur;
end

% Generate object proposals using EdgeBox
tic;
try
	proposals_cur = edgeBoxes(img_resized, model_edgebox, opts_edgebox);
catch
	continue;
	warning('!!! error generating object proposals');
end
proposals_cur = proposals_cur(:, 1:4); % only keep coordinates
proposals_cur(:, 3:4) = proposals_cur(:, 1:2) + proposals_cur(:, 3:4); % convert [x, y, w, h] to [x1, y1, x2, y2]
proposals_cur = single(proposals_cur) + 1; % account for the 0-based indexing in EdgeBox
disp('### EdgeBox completed : ');
toc;

% Sanity check proposals
if isempty(proposals_cur)
	continue;
	warning('!!! no proposal generated');
end

% Detecting clothes using fast R-CNN
tic;
try
	bbox_pred = fast_rcnn_im_detect(model_frcn, img_resized, proposals_cur);
catch
	continue;
	warning('!!! error running fast R-CNN');
end
disp('### Fast R-CNN completed: ');
toc;

% Transform bounding box back into original coordinates w.r.t input image
bbox_img = cell(3, 1);
for id_category = 1:3
	bbox_img{id_category}(:, 1:4) = bbox_pred{id_category}(:, 1:4) ./ ratio;
	bbox_img{id_category}(:, 5) = bbox_pred{id_category}(:, 5);
end

% Visualize the most salient detection results for upper-body clothes, lower-body clothes and full-body clothes respectively
if flag_visualize
	figure(1);
	subplot(1, 3, 1); showboxes(img_cur, bbox_img{1}(1, :)); title('Upper-body Clothes');
	subplot(1, 3, 2); showboxes(img_cur, bbox_img{2}(1, :)); title('Lower-body Clothes');
	subplot(1, 3, 3); showboxes(img_cur, bbox_img{3}(1, :)); title('Full-body Clothes');
end

% Save bounding box outputs
save(file_output_bbox, 'img_cur', 'bbox_img', '-v7.3');


classdef geodata
    %   GEODATA: Geographical data class
    %   Handles geographical data describing coastlines or other features in
    %   the form of a shapefile and topobathy in the form of a DEM
    %   Copyright (C) 2018  Keith Roberts & William Pringle
    %
    %   The following inputs (with default values) are available for the
    %   geodata method:
    %     defval = 0; % placeholder value if arg is not passed.
    %     addOptional(p,'bbox',defval);
    %     addOptional(p,'shp',defval);
    %     addOptional(p,'h0',defval);
    %     addOptional(p,'dem',defval);
    %     addOptional(p,'backupdem',defval);
    %     addOptional(p,'fp',defval);
    %     addOptional(p,'weirs',defval);
    %     addOptional(p,'pslg',defval);
    %     addOptional(p,'boubox',defval);
    %     addOptional(p,'window',defval);
    %
    %   This program is free software: you can redistribute it and/or modify
    %   it under the terms of the GNU General Public License as published by
    %   the Free Software Foundation, either version 3 of the License, or
    %   (at your option) any later version.
    %
    %   This program is distributed in the hope that it will be useful,
    %   but WITHOUT ANY WARRANTY; without even the implied warranty of
    %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    %   GNU General Public License for more details.
    %
    %   You should have received a copy of the GNU General Public License
    %   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    properties
        bbox  % bounding coordinates
        boubox % bbox coordinates as a CCW polygon
        mainland % mainland boundary.
        outer % outer boundary.
        inner % island boundary(ies)
        mainlandb % height of mainland
        innerb    % height of inner
        mainlandb_type % type of mainland (lake or river or ocean)
        innerb_type    % type of inner (lake or river or ocean)
        weirs % weir crestlines
        weirPfix % boundaries of weir
        weirEgfix % edges of weir
        ibconn_pts % cell-array of paired weir nodes
        inpoly_flip % reverse the notion of "in"
        contourfile %  cell-array of shapefile
        demfile % filename of dem
        BACKUPdemfile % filename of dem
        h0 % min. edgelength (meters)
        window  % smoothing window on boundary (default 5 points)
        fp % deprecated but kept for backwards capability
        Fb % linear gridded interpolant of DEM
        Fb2 % linear gridded interpolant of backup DEM
        x0y0 % bottom left of structure grid or position (0,0)
        pslg % piecewise liner straight line graph
        spacing = 2.0 ; %Relative spacing along polygon, large effect on computational efficiency of signed distance.
        gridspace
        shapefile_3d % if the shapefile has a height attribute
    end

    methods

        function obj = geodata(varargin)
            % Class constructor to parse NetCDF DEM data, NaN-delimited vector,
            % or shapefile that defines polygonal boundary of meshing
            % domain.
            % options
            %addOptional(p,'bbox',defval);
            %addOptional(p,'shp',defval);
            %addOptional(p,'h0',defval);
            %addOptional(p,'dem',defval);
            %addOptional(p,'backupdem',defval);
            %addOptional(p,'fp',defval);
            %addOptional(p,'weirs',defval);
            %addOptional(p,'pslg',defval);
            %addOptional(p,'boubox',defval);

            % Check for m_map dir
            M_MAP_EXISTS=0 ;
            if exist('m_proj','file')==2
              M_MAP_EXISTS=1 ;
            end
            if M_MAP_EXISTS~=1
              error('Where''s m_map? Please read the user guide')
            end

            % Check for utilties dir
            UTIL_DIR_EXISTS=0  ;
            if exist('inpoly.m','file')
              UTIL_DIR_EXISTS=1;
            end
            if UTIL_DIR_EXISTS~=1
              error('Where''s the utilities directory? Please read the user guide')
            end

            % Check for dataset dir
            DATASET_DIR_EXISTS=0 ;
            if exist('datasets','dir')==7
                DATASET_DIR_EXISTS=1 ;
            end
            if DATASET_DIR_EXISTS~=1
                warning('We suggest you to place your files in a directory called "datasets". Please read the user guide')
            end

            p = inputParser;

            defval = 0; % placeholder value if arg is not passed.
            % add name/value pairs
            addOptional(p,'bbox',defval);
            addOptional(p,'shp',defval);
            addOptional(p,'h0',defval);
            addOptional(p,'dem',defval);
            addOptional(p,'backupdem',defval);
            addOptional(p,'fp',defval);
            addOptional(p,'weirs',defval);
            addOptional(p,'pslg',defval);
            addOptional(p,'boubox',defval);
            addOptional(p,'window',defval);
            addOptional(p,'shapefile_3d',defval);

            % parse the inputs
            parse(p,varargin{:});
            % store the inputs as a struct
            inp=p.Results;
            % get the fieldnames of the edge functions
            fields = fieldnames(inp);
            % loop through and determine which args were passed.
            % also, assign reasonable default values if some options were
            % not assigned.
            obj.boubox = [] ;
            for i = 1 : numel(fields)
                type = fields{i};
                switch type
                    % parse aux options first
                    case('bbox')
                        obj.bbox = inp.(fields{i});
                        if any(obj.bbox ~=0)
                            obj.bbox = inp.(fields{i});
                            %elseif ~ischar(inp.(fields{contains(fields,'dem')}))
                            %    error('No bbox specified!');
                        end
                    case('h0')
                        obj.h0= inp.(fields{i});
                        if obj.h0 ~=0
                            obj.h0 = inp.(fields{i});
                        else
                            error('No h0 specified!');
                        end
                    case('shp')
                        obj.contourfile = inp.(fields{i});
                        if ~iscell(obj.contourfile) && ~ischar(obj.contourfile)
                            obj.contourfile = [];
                        end
                    case('dem')
                        obj.demfile= inp.(fields{i});
                        if obj.demfile ~=0
                            obj.demfile = inp.(fields{i});
                        else
                            obj.demfile = [];
                        end
                    case('backupdem')
                        obj.BACKUPdemfile= inp.(fields{i});
                        if obj.BACKUPdemfile ~=0
                            obj.BACKUPdemfile = inp.(fields{i});
                        else
                            obj.BACKUPdemfile = [];
                        end
                    case('fp')
                        obj.fp= inp.(fields{i});
                        if obj.fp ~=0
                            obj.fp = inp.(fields{i});
                        end
                    case('outer')
                        obj.outer = inp.(fields{i});
                        if obj.outer(1) ~=0
                            obj.outer = inp.(fields{i});
                        end
                    case('pslg')
                        obj.pslg = inp.(fields{i});
                        if obj.pslg(1) ~=0
                            obj.pslg = inp.(fields{i});
                        else
                            obj.pslg = [];
                        end
                    case('mainland')
                        obj.mainland = inp.(fields{i});
                        if obj.mainland(1) ~=0
                            obj.mainland = inp.(fields{i});
                        end
                    case('inner')
                        obj.inner = inp.(fields{i});
                        if obj.inner(1) ~=0
                            obj.inner = inp.(fields{i});
                        end
                    case('boubox')
                        obj.boubox = inp.(fields{i}) ;
                    case('window')
                        obj.window = inp.(fields{i}) ;
                        if obj.window == 0
                            % Default value
                            obj.window = 5;
                        end
                    case('shapefile_3d')
                         obj.shapefile_3d = inp.(fields{i}) ;
                    case('weirs')
                        if ~iscell(inp.(fields{i})) && ~isstruct(inp.(fields{i})) && inp.(fields{i})==0, continue; end
                        if ~iscell(inp.(fields{i})) && ~isstruct(inp.(fields{i}))
                            error('Data for weirs must be in a cell-array or struct. Please see the user guide.');
                        end
                        obj.weirs = inp.(fields{i}) ;
                        noWeirs   = length(obj.weirs) ;
                        disp(['INFO: User has passed ',num2str(noWeirs),' weir crestlines.']) ;
                        obj.weirPfix = [] ; obj.weirEgfix = [] ;
                        if iscell(obj.weirs)
                            ss = obj.weirs{1}(1);
                        else
                            ss = obj.weirs(1).X(1);
                        end
                        if ss ~= 0
                            for ii = 1 : noWeirs
                                if iscell(obj.weirs)
                                    crestlines = obj.weirs{ii}(:,1:2) ;
                                    width      = obj.weirs{ii}(1,3)/111e3 ;
                                    weir_min_ele = obj.weirs{ii}(1,4)/111e3;
                                else
                                    crestlines = [obj.weirs(ii).X obj.weirs(ii).Y];
                                    width      = obj.weirs(ii).width/111e3 ;
                                    weir_min_ele = obj.weirs(ii).min_ele/111e3;
                                end
                                if width == 0
                                  error('Please specify non-zero width of weir in meters!');
                                end
                                % user-defined spacing along face of weir
                                if weir_min_ele ~= 0
                                    [tempPfix,tmpEgfix,obj.ibconn_pts{ii}] = GenerateWeirGeometry(crestlines,width,...
                                          weir_min_ele,0) ;
                                else
                                % by default spacing along face of weir is
                                % MIN_EL
                                    [tempPfix,tmpEgfix,obj.ibconn_pts{ii}] = GenerateWeirGeometry(crestlines,width,...
                                        2*(obj.h0/111e3),0) ;
                                end
                                [tmpEgfix]=renumberEdges(tmpEgfix) ;
                                weirLength(ii) = length(tempPfix) ;
                                if ii~=1
                                    tmpEgfix = tmpEgfix + length(obj.weirPfix) ;
                                end
                                obj.weirPfix = [obj.weirPfix; tempPfix] ;
                                obj.weirEgfix = [obj.weirEgfix; tmpEgfix] ;
                            end
                        end
                end
            end
            % Basic error handling should go here.
            % if not bbox and no dem, you're outta luck
            if size(obj.bbox,1) == 1 && isempty(obj.demfile) && isempty(obj.pslg)
                error('No DEM supplied and no bbox supplied, sorry pal');
            end
            obj.gridspace    = abs(obj.h0)/111e3; %point spacing along polygon,
            % Get bbox information from demfile if not supplied
            if size(obj.bbox,1) == 1 && isempty(obj.pslg)
                obj = ParseDEM(obj,'bbox');
            end

            if obj.bbox == 0
                error('No bbox supplied. If you are using the pslg option then you need to supply a bbox.')
            elseif size(obj.bbox,1) == 2
                % Typical square bbox type
                % Make the bounding box 5 x 2 matrix in clockwise order
                obj.boubox = bbox_to_bou(obj.bbox);
            else
                % Handle non-square bbox type regions
                obj.boubox = obj.bbox;
                if ~isnan(obj.boubox(end,1))
                    obj.boubox(end+1,:) = [NaN NaN];
                end
                obj.bbox = [min(obj.boubox(:,1)) max(obj.boubox(:,1))
                    min(obj.boubox(:,2)) max(obj.boubox(:,2))] ;
            end

            obj = ParseShoreline(obj) ;

            % kjr Add the weir faux islands to the inner geometry
            if ~isempty(obj.weirPfix)
                idx = [0; cumsum(weirLength)']+1 ;
                tmp = [] ;
                for ii = 1 : noWeirs
                    tmp =  [tmp;
                        [obj.weirPfix(idx(ii):idx(ii+1)-1,:)
                        obj.weirPfix(idx(ii),:)]
                        NaN NaN] ;
                end
                obj.inner = [obj.inner ; NaN NaN ;  tmp ] ;
            end

            % Ensure inpoly flip is correct
            obj = check_connectedness_inpoly(obj);

            disp(['Read in meshing boundary: ',obj.contourfile]);

            if obj.BACKUPdemfile~=0
                obj = ParseDEM(obj,'BackUp') ;
            end

            obj = ParseDEM(obj) ;

        end

        function obj = ParseShoreline(obj)
            % Read in the geometric meshing boundary information from a
            % ESRI-shapefile
            if ~isempty(obj.contourfile)
                if ~iscell(obj.contourfile)
                    obj.contourfile = {obj.contourfile};
                end

                polygon_struct = Read_shapefile( obj.contourfile, [], ...
                    obj.bbox, obj.gridspace, obj.boubox, 0, obj.shapefile_3d);

                % Unpack data from function Read_Shapefile()s
                obj.outer     = polygon_struct.outer;
                obj.mainland  = polygon_struct.mainland;
                obj.inner     = polygon_struct.inner;
                obj.mainlandb = polygon_struct.mainlandb;
                obj.innerb    = polygon_struct.innerb;
                obj.mainlandb_type = polygon_struct.mainlandb_type;
                obj.innerb_type    = polygon_struct.innerb_type;

                % Read in the geometric meshing boundary information from a
                % NaN-delimited vector.
            elseif ~isempty(obj.pslg)

                % Handle the case for user defined mesh boundary information
                polygon_struct = Read_shapefile( [], obj.pslg, ...
                    obj.bbox, obj.gridspace, obj.boubox, 0, obj.shapefile_3d);

                % Unpack data from function Read_Shapefile()s
                obj.outer     = polygon_struct.outer;
                obj.mainland  = polygon_struct.mainland;
                obj.inner     = polygon_struct.inner;
                obj.mainlandb = polygon_struct.mainlandb;
                obj.innerb    = polygon_struct.innerb;
                obj.mainlandb_type = polygon_struct.mainlandb_type;
                obj.innerb_type    = polygon_struct.innerb_type;

            else
                % set outer to the boubox
                obj.outer = obj.boubox;
            end
            obj = ClassifyShoreline(obj) ;
        end

        function obj = ClassifyShoreline(obj)
            % Helper function to...
            % 1) Read the data from supplied file
            % 2) Classify segments as either inner, outer, or mainland.
            % 3) Ensure point spacing is adequate to support mesh sizes
            %    and ensure computational efficiency when calculating the
            %    signed distance function.

            % Check if no mainland segments, set outer
            % to the boubox.
            if isempty(obj.mainland)
                obj.outer = [ ];
                obj.outer = obj.boubox;
            end

            % Make sure the shoreline components have spacing of
            % gridspace/spacing
            [la,lo] = my_interpm(obj.outer(:,2),obj.outer(:,1),...
                obj.gridspace/obj.spacing);
            obj.outer = [];  obj.outer(:,1) = lo; obj.outer(:,2) = la;
            outerbox = obj.outer(1:find(isnan(obj.outer(:,1)),1,'first'),:);

            if ~isempty(obj.mainland)
                [la,lo] = my_interpm(obj.mainland(:,2),obj.mainland(:,1),...
                    obj.gridspace/obj.spacing);
                obj.mainland = []; obj.mainland(:,1) = lo; obj.mainland(:,2) = la;
            end

            if ~isempty(obj.inner)
                [la,lo]=my_interpm(obj.inner(:,2),obj.inner(:,1),...
                    obj.gridspace/obj.spacing);
                obj.inner = []; obj.inner(:,1) = lo; obj.inner(:,2) = la;
            end
            clearvars lo la

            % Smooth the coastline (apply moving average filter).
            if obj.window > 1
                disp(['Smoothing coastline with ' ...
                    num2str(obj.window) ' point window'])
                if ~isempty(obj.outer)
                    obj.outer = smooth_coastline(obj.outer,obj.window,0);
                end
                if ~isempty(obj.mainland)
                    obj.mainland = smooth_coastline(obj.mainland,obj.window,0);
                end
                if ~isempty(obj.inner)
                    obj.inner = smooth_coastline(obj.inner,obj.window,0);
                end
            else
                disp('No smoothing of coastline enabled')
            end

            % KJR: Coarsen portions of outer, mainland
            % and inner outside bbox.
            iboubox = bbox_to_bou(obj.bbox);
            iboubox(:,1) = 1.10*iboubox(:,1)+(1-1.10)*mean(iboubox(1:end-1,1));
            iboubox(:,2) = 1.10*iboubox(:,2)+(1-1.10)*mean(iboubox(1:end-1,2));

            % Coarsen outer
            obj.outer = coarsen_polygon(obj.outer,iboubox);

            % Coarsen inner and move parts that overlap with bounding box
            % to mainland
            if ~isempty(obj.inner)
                obj.inner = coarsen_polygon(obj.inner,iboubox);
            end

            % Coarsen mainland and remove parts that overlap with bounding
            % box (note this doesn't change the polygon used for inpoly,
            % only changes the distance function used for edgefx)
            if ~isempty(obj.mainland)
                obj.mainland = coarsen_polygon(obj.mainland,iboubox);
            end

        end

        function obj = ParseDEM(obj,varargin)
            % obj = ParseDEM(obj,varargin)
            % set 'BackUp' for reading backupdem
            % set 'bbox' for reading only bbox
            fname = obj.demfile ; backup = 0;
            if any(strcmp(varargin,'BackUp'))
                backup = 1;
                fname = obj.BACKUPdemfile ;
            end

            % Process the DEM for the meshing region.
            if ~isempty(fname)

                % Find name of x, y (one that has 1 dimensions)
                % z values (use one that has 2 dimensions)
                [xvn, yvn, zvn] = getdemvarnames(fname);

                % Read x and y
                x = double(ncread(fname,xvn));
                y = double(ncread(fname,yvn));

                if any(strcmp(varargin,'bbox'))
                    obj.bbox = [min(x) max(x); min(y) max(y)];
                    return;
                end

                modbox = [0 0];
                if obj.bbox(1,2) > 180 && obj.bbox(1,1) < 180 && min(x) < 0
                    % bbox straddles 180/-180 line
                    loop = 2;
                else
                    loop = 1;
                    if max(x) > 180
                        if obj.bbox(1,1) < 0; modbox(1) = 1; end
                        if obj.bbox(1,2) < 0; modbox(2) = 1; end
                    elseif min(x) < 0
                        if obj.bbox(1,1) > 180; modbox(1) = -1; end
                        if obj.bbox(1,2) > 180; modbox(2) = -1; end
                    end
                end
                J = find(y >= obj.bbox(2,1) & y <= obj.bbox(2,2));
                I = []; demz = [];
                for nn = 1:loop
                    bboxt = obj.bbox;
                    bboxt(1,:) =  bboxt(1,:) + modbox.*360;
                    if loop == 2
                        if nn == 1
                            bboxt(1,2) = 180;
                        else
                            bboxt(1,1) = -180;
                            bboxt(1,2) = bboxt(1,2) - 360;
                        end
                    end
                    It = find(x >= bboxt(1,1) & x <= bboxt(1,2));
                    I = [I; It];

                    % At this point, detect the memory footprint of the
                    % DEM subset and compute the required stride necessary
                    % to satisfy the memory requirements
                    if nn == 1
                        AVAILABLE_MEMORY=4; % 4 gb;
                        mult = (obj.bbox(1,2) - obj.bbox(1,1))/...
                                   (bboxt(1,2) - bboxt(1,1));
                        peak_mem = mult*length(I)*length(J)*4/1e9; % in GB assuming single
                        STRIDE_MEM = ceil(sqrt(peak_mem/AVAILABLE_MEMORY));
                        DEM_GRIDSPACE = (x(2)-x(1))*111e3; % in meters
                        STRIDE_H0 = ceil(obj.h0/DEM_GRIDSPACE); % skip # of DEM entires
                        STRIDE = max(STRIDE_H0, STRIDE_MEM);
                        if STRIDE > 1
                            if STRIDE_MEM > STRIDE_H0
                                warning(['DEM would occupy ',num2str(peak_mem),...
                                         'GB of RAM. DEM will be downsampled ' ...
                                         'by a stride of ' num2str(STRIDE)])
                            else
                                warning(['DEM will be downsampled by a stride ' ...
                                         'of ' num2str(STRIDE) ' to match h0'])
                            end
                        end

                    end
                    % grab only the portion that was requested
                    if STRIDE > 1 && STRIDE_MEM > STRIDE_H0
                        % with a stride to save memory
                        LX = length(It(1:STRIDE:end));
                        LY = length(J(1:STRIDE:end));
                        demzt = single(ncread(fname,zvn,[It(1) J(1)],...
                                       [LX LY],[STRIDE,STRIDE]));
                    else
                        % faster to read in with no stride if not memory
                        % bound
                        demzt = single(ncread(fname,zvn,[It(1) J(1)],...
                                       [length(It) length(J)]));
                        if STRIDE > 1
                            demzt = demzt(1:STRIDE:end,1:STRIDE:end);
                        end
                    end
                    if isempty(demz)
                        demz = demzt;
                    else
                        demz = cat(1,demz,demzt);
                    end
                end
                x = x(I(1:STRIDE:end)); y = y(J(1:STRIDE:end));
                if obj.bbox(1,2) > 180
                    x(x < 0) = x(x < 0) + 360;
                    [x1,IA] = unique(x);
                    if length(x) > length(x1)
                        x = x1; demz = demz(IA,:);
                    end
                end
                % handle DEMS from packed starting from the bottom left
                if y(2) < y(1)
                    y = flipud(y) ;
                    demz = fliplr(demz) ;
                end
                % Determine bottom left corner of DEM
                % (after possible flipping of DEM packing)
                obj.x0y0 = [x(1),y(1)];

                % check for any invalid values
                bad = isnan(demz);
                if sum(bad(:)) > 0 && ~backup
                    warning('ALERT: Invalid and/or missing DEM values detected..check DEM');
                    if ~isempty(obj.BACKUPdemfile)
                        disp('Replacing invalid values with back-up DEMfile');
                        [demx,demy] = ndgrid(x,y) ;
                        demz(bad) = obj.Fb2(demx(bad),demy(bad)) ;
                    else
                        % just replace it with NaNs
                        demz(bad) = NaN ;
                    end
                end

                % creating back up interpolant
                if backup
                    obj.Fb2   = griddedInterpolant({x,y},demz,...
                        'linear','nearest');
                    % clear data from memory
                    clear x y demz
                else
                    % main interpolant
                    if obj.BACKUPdemfile~=0
                        obj.Fb   = griddedInterpolant({x,y},demz,...
                            'linear','none'); % no extrapolation (so use Fb2)
                    else
                        obj.Fb   = griddedInterpolant({x,y},demz,...
                            'linear','nearest');
                    end
                    % clear data from memory
                    clear x y demz
                end

                disp(['Read in demfile ',fname]);
            end

            % Handle the case of no dem
            if isempty(obj.x0y0)
                obj.x0y0 = [obj.bbox(1,1), obj.bbox(2,1)];
            end

            function [xvn, yvn, zvn] = getdemvarnames(fname)
                % Define well-known variables for longitude and latitude
                % coordinates in Digital Elevation Model NetCDF file (CF
                % compliant).
                xvn = []; yvn = []; zvn = [];
                wkv_x = {'x','Longitude','longitude','lon'} ;
                wkv_y = {'y','Latitude', 'latitude','lat'} ;
                finfo = ncinfo(fname);
                for ii = 1:length(finfo.Variables)
                    if ~isempty(xvn) && ~isempty(yvn) && ~isempty(zvn); break; end
                    if length(finfo.Variables(ii).Size) == 1
                        if isempty(xvn) && ...
                                any(strcmp(finfo.Variables(ii).Name,wkv_x))
                            xvn = finfo.Variables(ii).Name;
                        end
                        if isempty(yvn) && ...
                                any(strcmp(finfo.Variables(ii).Name,wkv_y))
                            yvn = finfo.Variables(ii).Name;
                        end
                    elseif length(finfo.Variables(ii).Size) == 2
                        if isempty(zvn)
                            zvn = finfo.Variables(ii).Name;
                        end
                    end
                end
                if isempty(xvn)
                    error('Could not locate x coordinate in DEM') ;
                end
                if isempty(yvn)
                    error('Could not locate y coordinate in DEM') ;
                end
                if isempty(zvn)
                    error('Could not locate z coordinate in DEM') ;
                end
            end

        end

        function obj = check_connectedness_inpoly(obj)
            % Check for connected polygons and if not connected,
            %  whether to flip the inpoly result to ensure meshing
            %  on the coastal side of the polygon.

            obj.inpoly_flip = 0;
            % return if outer polygon is connected
            shpEnd = find(isnan(obj.outer(:,1)));
            [~,loc] = max(diff(shpEnd));
            shpEnd = vertcat(0,shpEnd); loc = loc+1;
            if abs(sum(obj.outer(shpEnd(loc)+1,:)) - ...
                    sum(obj.outer(shpEnd(loc+1)-1,:))) > eps
                disp('Warning: Shapefile is unconnected... continuing anyway')
            end

            % check for inpoly goodness read the GSHHS checker
            ps = Read_shapefile( {'GSHHS_l_L1'}, [], ...
                obj.bbox, obj.gridspace, obj.boubox, 0, 0 );

            % make a "fake" tester grid
            x = linspace(obj.bbox(1,1),obj.bbox(1,2),100);
            y = linspace(obj.bbox(2,1),obj.bbox(2,2),100);
            edges = Get_poly_edges( [ps.outer; ps.inner] );
            in_Test = inpoly([x',y'],[ps.outer; ps.inner],edges);
            polytester = [obj.outer; obj.inner];
            edges = Get_poly_edges( polytester );
            in_Shpf = inpoly([x',y'],polytester,edges);
            % if more than half of thepoints disagree between Test and Shpf
            % lets flip the inpoly
            if length(find(xor(in_Shpf,in_Test))) > 50
                obj.inpoly_flip = 1;
                disp(['Shapefile inpoly is inconsistent ' ...
                    'with GHSSS test file, flipping the inpoly test'])
            end

            % if flooplaind meshing, flip the inpoly test
            if obj.fp
                obj.inpoly_flip = mod(1,obj.inpoly_flip);
            end
        end

        function obj = close(obj)
            % Clips the mainland segment with the boubox.
            % Performs a breadth-first search given a seed position
            % of the piecewise-straight line graph (PSLG) that is used to define the meshing boundary.
            % This returns back an updated geodata class instance with the outer boundary clipped with the boubox.
            % kjr,und,chl 2018

            if isempty(obj.Fb)
                warning('ALERT: Meshing boundary is not a polygon!')
                warning('ALERT: DEM is required to clip line segment with polygon')
                seed=input('Enter coordinate of seed location to clip: ');
            else
                % Guess seed location: submerged portion of domain within
                % bbox?
                [demx,demy] = ndgrid(obj.x0y0(1):obj.h0/111e3:obj.bbox(1,2), ...
                    obj.x0y0(2):obj.h0/111e3:obj.bbox(2,2));
                demz = obj.Fb(demx,demy);
                [idx]=find(demz(:) < -10) ; % find points deeper than -10 m below sea level
                allpts=[demx(:),demy(:)] ;
                cands = allpts(idx,:);
                if(isnan(obj.boubox(end,1)))
                    edges=Get_poly_edges(obj.boubox) ;
                    [in]=inpoly(cands,obj.boubox,edges) ; %  determine which of these points is in the domain
                else
                    [in]=inpoly(cands,obj.boubox) ;       %  determine which of these points is in the domain
                end
                cands2=cands(in,:) ;
                seed = cands2(50,:) ;
            end

            geom = [obj.mainland; obj.boubox] ;

            [NODE,PSLG]=getnan2(geom) ;

            [NODE2,PSLG2,PART2] = bfsgeo2(NODE,PSLG,seed) ;

            POLY = extdom_polygon(PSLG2(PART2{1},:),NODE2,-1) ;

            new_outer = cell2mat(POLY') ;

            [la,lo] = my_interpm(new_outer(:,2),new_outer(:,1),((obj.h0/2)/111e3))  ;

            new_outer = [lo la] ;

            obj.outer = new_outer ;

            % reset this to default
            obj.inpoly_flip = 0 ;
        end

        function obj = extractContour(obj,ilev)
            % Extract a geometric contour from the DEM at elevation ilev.
            % obj = extractContour(obj,ilev)
            %
            % Can use to get the mean sea level contour, e.g.;
            % gdat = geodata('pslg',0,'h0',min_el,'dem',dem); % make the dummy gdat for the dem extents;
            % lmsl = extractContour(gdat,0); %using the dummy gdat with dem info to get the 'lmsl' gdat with the 0-m contour.

            [node,edge] = ...
                getiso2( obj.Fb.GridVectors{1},obj.Fb.GridVectors{2},...
                double(obj.Fb.Values'),ilev) ;

            polyline = cell2mat(extdom_polygon(edge,node,-1,1,10)') ;

            obj = geodata('pslg',polyline,'bbox',obj.bbox,...
                          'h0',obj.h0,'dem',obj.demfile) ;

        end

        function plot(obj,type,projection,holdon)
            % plot(obj,type,projection,holdon)
            % Plot geodata class info
            %
            % Inputs:
            % obj  : geodata class object [required input]
            %
            % optional inputs =>....
            % type : i) 'shp' [default] - plots the shapelines (shoreline) only
            %       ii) 'dem' - plots the dem bathy in addition to shapelines
            %      iii) 'omega' - hatches the meshing domain in addition to plotting shapelines
            % projection : choose the projection type from m_map options
            %              (default is Mercator)
            % holdon : plot on a new (= 0 [default]) or existing (= 1) figure?

            if nargin == 1 || isempty(type)
                type = 'shp';
            end
            if nargin < 3 || isempty(projection)
                projection = 'Mercator';
            end
            if nargin < 4 || isempty(holdon)
                holdon = 0;
            end

            % plotting on new or existing figure?
            if ~holdon
                % setup the projection
                bufx = 0.2*(obj.bbox(1,2) - obj.bbox(1,1));
                bufy = 0.2*(obj.bbox(2,2) - obj.bbox(2,1));
                if ~isempty(regexp(projection,'ste'))
                    m_proj(projection,'lat',min(obj.bbox(2,:)),...
                        'long',mean(obj.bbox(1,:)),'radius',...
                        min(179.9,1.20*max(diff(obj.bbox(2,:)))));
                else
                    lmin = -180; lmax = +180;
                    if obj.bbox(1,2) > 180; lmax = 360; lmin = 0; end
                    lon1 = max(lmin,obj.bbox(1,1) - bufx);
                    lon2 = min(lmax,obj.bbox(1,2) + bufx);
                    lat1 = max(- 90,obj.bbox(2,1) - bufy);
                    lat2 = min(+ 90,obj.bbox(2,2) + bufy);
                    m_proj(projection,...
                           'long',[lon1, lon2],'lat',[lat1, lat2]);
                end
                % plot on new figure
                figure;
                colori = 'g-'; % set island color
                colorm = 'r-'; % set mainland color
            else
                colori = 'b-'; % set island color
                colorm = 'm-'; % set mainland color
            end
            hold on
            % select optional types
            switch type
                case('dem')
                    % interpolate DEM's bathy linearly onto our
                    % edgefunction grid (or a coarsened version of it for
                    % memory considerations)
                    mem = inf; stride = obj.h0/111e3;
                    while mem > 1
                        xx = obj.x0y0(1):stride:obj.bbox(1,2);
                        yy = obj.x0y0(2):stride:obj.bbox(2,2);
                        xs = whos('xx'); ys = whos('yy');
                        mem = xs.bytes*ys.bytes/1e9;
                        stride = stride*2;
                    end
                    [demx,demy] = ndgrid(xx,yy);
                    demz = obj.Fb(demx,demy);
                    m_fastscatter(demx(:),demy(:),demz(:));
                    cb = colorbar; ylabel(cb,'topo-bathy depth [m]')
                case('omega')
                    % hatch the meshing domain, Omega
                    [demx,demy] = ndgrid(obj.x0y0(1):obj.h0/111e3:obj.bbox(1,2), ...
                        obj.x0y0(2):obj.h0/111e3:obj.bbox(2,2));
                    edges = Get_poly_edges( [obj.outer; obj.inner] );
                    in = inpoly([demx(:),demy(:)],[obj.outer; obj.inner], edges);
                    long = demx(~in); lati = demy(~in);
                    m_hatch(obj.boubox(1:end-1,1),...
                        obj.boubox(1:end-1,2),'cross',45,0.05);
                    m_plot(long,lati,'.','Color','white')
            end
            if ~isempty(obj.mainland) && obj.mainland(1) ~= 0
                h1 = m_plot(obj.mainland(:,1),obj.mainland(:,2),...
                    colorm,'linewi',1); hold on;
            end
            if ~isempty(obj.inner) && obj.inner(1) ~= 0
                h2 = m_plot(obj.inner(:,1),obj.inner(:,2),...
                    colori,'linewi',1); hold on;
            end
            if ~isempty(obj.weirs)
                if isstruct(obj.weirs) ~= 0
                    for ii =1 : length(obj.weirs)
                        h3 = m_plot(obj.weirs.X,obj.weirs.Y,...
                            'm-','linewi',1); hold on;
                    end
                else
                    for ii =1 : length(obj.weirs)
                        h3 = m_plot(obj.weirs{ii}(:,1),obj.weirs{ii}(:,2),...
                            'm-','linewi',1); hold on;
                    end
                end
            end
            [la,lo] = my_interpm(obj.boubox(:,2),obj.boubox(:,1),...
                0.5*obj.h0/111e3);
            m_plot(lo,la,'k--','linewi',2);
            if ~holdon
                m_grid('xtick',10,'tickdir','out','yaxislocation','left','fontsize',10);
            end
            if exist('h1','var') && exist('h2','var') && exist('h3','var')
                legend([h1 h2,h3],{'mainland' 'inner' 'weirs'},'Location','NorthWest')
            elseif exist('h1','var') && exist('h2','var')
                legend([h1 h2],{'mainland' 'inner'},'Location','NorthWest')
            end
        end

    end

end


%%
% Copyright (c) 2019-present, Mahmoud Afifi
%
% This source code is licensed under the license found in the
% LICENSE file in the root directory of this source tree.
%
% Please, cite the following paper if you use this code:
%
% Mahmoud Afifi and Michael S. Brown. What else can fool deep learning?
% Addressing color constancy errors on deep neural network performance.
% ICCV, 2019
%
% Email: mafifi@eecs.yorku.ca | m.3afifi@gmail.com
%%

%%
% This demo generates ten images from each image in the  given path.
% Each generated file will be in the following format:
% originalName_WB_CS.ext, where originalName is the original filename, WB
% refers to white balance (WB) settings, and CS is the camera style.
% WB settings are:
%   - T: Tungsten WB [2850 Kelvin (K)]
%   - F: Fluorescent WB [3800K]
%   - D: Daylight WB [5500K]
%   - C: Cloudy WB [6500K]
%   - S: Shade WB [7500K]
% Camera styes are:
%   - AS: Adobe Standard
%   - CS: Camera Standard
% The generated images and a copy of the input image (optional) will be
% saved in the output directory (output_dir)

%%
clear;
clc;

use_GPU = 0; % to use GPU
datasetbase = fullfile('..','images'); % path of images directory
output_dir = fullfile('..','results'); % output directory (will contain
% generated images and copy of original images
NumOfImgs = 10; % should be less than or equal 10
saveOrig = true; % to save a copy of original images in output_dir

if exist(output_dir, 'dir') == 0
	mkdir(output_dir)
end

if NumOfImgs > 10
    error('Cannot generate more than 10 images for each input image');
end

imds = imageDatastore(datasetbase,'IncludeSubfolders' ,1);
images = {imds.Files{:}}'; % get all input filenames

if use_GPU==1
    load('synthWBmodel_GPU.mat'); % load WB_emulator GPU model
else
    load('synthWBmodel.mat'); % load WB_emulator CPU model
end

for i = 1 : length (images) % for each input image, do
    fprintf('processing image: %s...\n',images{i});
    imgin = images{i};
    I_in = imread(imgin); % read input image
    [~,name,ext] = fileparts(imgin);
    if saveOrig == true
        imwrite(I_in,fullfile(output_dir,... % save a copy of it in output dir
            sprintf('%s%s%s',name,'_original',ext)));
    end
    try
        % generate images with synthetic WB effects
        out = WB_emulator.generate_wb_srgb(I_in, NumOfImgs);
        if use_GPU==1 % if GPU is used,
            out = gather(out); % convert gpuArray to double tensor
        end
        for j =1 : size(out,4) % save generated images
            imwrite(out(:,:,:,j),fullfile(output_dir,...
                sprintf('%s%s%s',name,...
                WB_emulator.wb_photo_finishing{j},ext)));
        end
    catch
        fprintf('Error in image %s!\n', imgin);
    end
end


function [influenceM] = getGlobalInfluenceM(IM, structsV)
%function [influenceM] = getGlobalInfluenceM(IM, structsV)
%   Get the global influence matrix (dose(:) = influenceM * weights(:)),
%   for all given structures.  The output influenceM is sparse, and has
%   rowNums equal to the number of voxels in the plan.
%   The row coord is the same as would be gotten by retrieving the
%   structure mask:
%          [mask3D, planC] =getUniformStr(Str_Num, planC, optS);
%
%JOD, 17 Nov 03.
%JRA, 27 Feb 04, cleanup.
%JRA, 24 Mar 04, Supports multiple structs, preallocate inflM, kicked up
%                the speed some.
%JRA, 14 Apr 04, Added monteCarlo MCflag.
%JOD, 19 Dec 05, comment mods.
%JJW, 20 Jun 06, MCflag removed; added call of getSingleGlobalInfluenceM
%APA, 10 Oct 06, updated to make compatible with changed location of beamlets field
%
%Usage:
%   function [gInfluenceM] = getGlobalInfluenceM(IM, structsV);
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

if length(structsV) == 1

    % this function is fast, but it works only for one structure at a time
    [influenceM] = getSingleGlobalInfluenceM(IM, structsV);

else

   global planC;

   beamlets = [IM.beams(:).beamlets];

   %get indices of structures stored under beamlets
   structIndV = getAssociatedStr({beamlets(:,1).strUID});

   if ~all(ismember(structsV,structIndV))
       influenceM = [];
       error('Dose not computed on some of the input structures. Please compute dose on and try again')
       return;
   end

   numPBs = size(beamlets,2);

   %Find minimum number of nonzero elements that need to be put in influenceM.
   for structNum = structsV;
       strBmletInd = find(structNum==structIndV);
        count = 0;
        for i=1:length(beamlets(strBmletInd,:))
            count = count + length(beamlets(strBmletInd,i).influence);
        end
        nnzV(structNum) = count;
   end
    maxnnz = max(nnzV);

    %Pre-initalize influence matrix, greatly speeds things up.
    indexS = planC{end};
    numVoxels = prod(getUniformScanSize(planC{indexS.scan}(getStructureAssociatedScan(structsV(1)))));
    influenceM = spalloc(numVoxels, numPBs, maxnnz);

    %Make sure structsV is a row vector, used in below for loop.
    if size(structsV, 1) ~= 1
        structsV = structsV';
    end

    %Loop over beamlets.
    for PBNum = 1 : numPBs

        %For each requested structure, add the effect of this beamlet to inflM.
        %*** Loops are in this order to cut down on out of order inserts into
        %*** sparse influence matrix. Greatly increases speed. Leave it!
        for structNum = structsV

            strBmletInd = find(structNum==structIndV);

            if ~isempty(beamlets(strBmletInd,PBNum).influence)

                doseV     = double(beamlets(strBmletInd,PBNum).influence);
                indV      = beamlets(strBmletInd,PBNum).indexV;
                maxVal    = beamlets(strBmletInd,PBNum).maxInfluenceVal;
                sizeParam = beamlets(strBmletInd,PBNum).fullLength;

                if isfield(beamlets, 'lowDosePoints')
                    lowDosePoints = unpackLogicals(beamlets(strBmletInd,PBNum).lowDosePoints, size(indV));
                    doseScaledV(~lowDosePoints) = doseV(~lowDosePoints) * (maxVal / (2^8 -1));
                    doseScaledV(lowDosePoints) = doseV(lowDosePoints) * (maxVal / (2^8 -1) / (2^8 -1));
                else
                    doseScaledV = doseV * (maxVal / (2^8 -1));
                end

                influenceM(indV,PBNum) = doseScaledV(:);
                doseScaledV = [];

            end

        end

    end

end % if length(structsV)==1


function [any_scanevent_repaired, ons, dur, index] ...
    = tapas_physio_repair_scan_events_PHILIPS(ons, sqpar, verbose)
% repairs the temporal structure of the sequence of scan events
% (time-stamps when slice was acquired) by filling up holes of missing
% slice acquisition or volume acquisition starts
%
% USAGE
%   [any_scanevent_repaired, ons, dur, index] ...
%       = tapas_physio_repair_scan_events_PHILIPS(ons, sqpar, verbose)
%
% -------------------------------------------------------------------------
% INPUT:
%   ons         - ons_samples, as given by tapas_physio_read_physlog_PHILIPS_guess_scanevents.m
%   sqpar       - sequence timing parameters
%           .Nslices        - number of slices per volume in fMRI scan
%           .NslicesPerBeat - usually equals Nslices, unless you trigger
%                             with the heart beat
%           .TR             - repetition time in seconds
%           .Ndummies       - number of dummy volumes
%           .Nscans         - number of full volumes saved (volumes in nifti file,
%                             usually rows in your design matrix)
%
%   verbose   - create informative plots (1= yes, 0 = no)
%
% -------------------------------------------------------------------------
% OUTPUT:
%   any_scanevent_repaired - flag, if function changed ons (1=yes, 0=no)
%   ons         - ons_samples, corrected for missing slice and volume
%                 scan events
%
% Note: The temporal unit of the output ons & dur corresponds to the input,
% i.e. if acq_sliceevents is given in samples, the output unit will be 2 ms
% usually, NOT 1 second!
%
% -------------------------------------------------------------------------
% Lars Kasper, August 2011
% Copyright (C) 2013, Institute for Biomedical Engineering, ETH/Uni Zurich.
%
% This file is part of the PhysIO toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

thrmin = 1.5; % gap between slices, if spacing >thrmin*min(slicegap)
thrmax = 0.5; % gap is large, if gap > thrmax*max(slicegap)

%% repair scan events: some scan event triggers were missed so we have to
% fill up the holes
ons.acq_slice = ons.acq_slice_all(:);
dur.acq_slice = diff(ons.acq_slice);

%% =======================================================================
%% Find and remove gaps of one missing slice trigger within one volume scan of Nslices
index.hugegaps = find(dur.acq_slice>thrmax*max(dur.acq_slice));

%double gaps, think about it later...
index.doublegaps = setdiff(find(dur.acq_slice > (thrmin+1)*min(dur.acq_slice)),index.hugegaps);
if ~isempty(index.doublegaps)
    disp('There are double gaps or worse in scan events. I will not correct that!');
end

%one slice trigger missing in volume of NslicesPerBeat slices
index.gaps                  = find(dur.acq_slice>thrmin*min(dur.acq_slice) ...
                                & dur.acq_slice<(thrmin+1)*min(dur.acq_slice));
ons.acq_slice_gaps          = floor((ons.acq_slice(index.gaps)+ons.acq_slice(index.gaps+1))/2);
ons.acq_slice_filled_gaps   = sort([ons.acq_slice; ons.acq_slice_gaps]);

%% =======================================================================
%% gaps at beginning or end of Nslices-volume block still possible
dur.acq_most_slices = diff(ons.acq_slice_filled_gaps);

%indices of ons.acq_slice which belong to start of new volume
%ons.acq_vol=[1; find(dur.acq_most_slices>thrmin*min(dur.acq_most_slices))+1];

ind_vol = 1:sqpar.Nslices:length(ons.acq_slice_filled_gaps);%(length(ons.acq_slice_filled_gaps)-sqpar.Nslices*(Ndummies+Nscans)+1):sqpar.Nslices:length(ons.acq_slice_filled_gaps);
ons.acq_vol = ind_vol;%ons.acq_slice_filled_gaps(ind_vol);

%here we have scan volume blocks with e.g. N-1 slices, scan event trigger
%missed, e.g. for 3 slices: |||   ||  |||
index.gaps_startend_vol = find(diff(ons.acq_vol)<sqpar.NslicesPerBeat);

%OK till here
%is it |||   ||  ||| or |||  ||   ||| (larger gap before or after block
%which is too short?)
gapbefore   = ons.acq_slice_filled_gaps(ons.acq_vol(index.gaps_startend_vol))-ons.acq_slice_filled_gaps(ons.acq_vol(index.gaps_startend_vol)-1);
gapafter    = ons.acq_slice_filled_gaps(ons.acq_vol(index.gaps_startend_vol+1))-ons.acq_slice_filled_gaps(ons.acq_vol(index.gaps_startend_vol+1)-1);

ons.acq_slice_all = ons.acq_slice_filled_gaps;
ons.acq_slice_larger_gaps = [];
for i = 1:length(gapbefore)
    if (gapbefore(i) > gapafter(i))
        targetons=(ons.acq_vol(index.gaps_startend_vol(i)));
        ons.acq_slice_larger_gaps(i)=2*ons.acq_slice_filled_gaps(targetons)-ons.acq_slice_filled_gaps(targetons+1);
    else
        targetons=(ons.acq_vol(index.gaps_startend_vol(i)+1)-1);
        ons.acq_slice_larger_gaps(i)=2*ons.acq_slice_filled_gaps(targetons)-ons.acq_slice_filled_gaps(targetons-1);
    end
    ons.acq_slice_all=[ons.acq_slice_all; ons.acq_slice_larger_gaps(i)];
end

ons.acq_slice_all = sort(ons.acq_slice_all);
% END of filling up start/end slice triggers in volume
% update ons.acq_vol
dur.acq_slice_all = diff(ons.acq_slice_all);

%ons.acq_vol_all=[1; find(dur.acq_slice_all>thrmin*min(dur.acq_slice_all))+1];
ons.acq_vol_all = ons.acq_vol;

%1st volume added manually
ons.acq_vol_all = [ons.acq_slice_all(ons.acq_vol_all)];

any_scanevent_repaired = ~(length(ons.acq_slice)==length(ons.acq_slice_all) ...
    && length(ons.acq_vol)==length(ons.acq_vol_all));

if verbose && any_scanevent_repaired
    figh{1} = plot_fix_missing_scan_events(ons, ...
        dur, index);
end

end %repair_scan_events

%%========================================================================
%% auxiliary plot functions follow;

%%=========================================================================
%% plot fixing procedure in scantrigger-time-difference view
function fh = plot_fix_missing_scan_events(ons, dur, index)

fh = tapas_physio_get_default_fig_params();
set(fh,'Name','Read-In: Time-difference view between events: Fix missing scan events');
ax(1) = subplot(3,1,1);
hold off;
plot(1:length(dur.acq_slice),dur.acq_slice);
hold on;
plot(index.hugegaps,dur.acq_slice(index.hugegaps),'bo')
plot(index.doublegaps,dur.acq_slice(index.doublegaps),'go')
plot(index.gaps,dur.acq_slice(index.gaps),'kx')

title('As extracted from the logfile');
xlabel('scan event + 1');
ylabel('\Delta t (ms) from last event')
warning('off', 'MATLAB:legend:IgnoringExtraEntries');
legend(...
    'dur.acq_slice (time diff between scan events', ...
    'index.hugegaps (dur.acq\_slice>thrmax*max(dur.acq\_slice))', ...
    'index.doublegaps (dur.acq\_slice > (thrmin+1)*min(dur.acq\_slice), but no hugegap)', ...
    'index.gaps (roughly size of 2*sliceTR)'...
    );

ax(2) = subplot(3,1,2);
hold off;
plot(1:length(dur.acq_most_slices),dur.acq_most_slices);
hold on;
plot(ons.acq_vol,dur.acq_most_slices(ons.acq_vol),'bx')

title('After fixing the slice-trigger gaps within a volume');
xlabel('scan event + 1');
ylabel('\Delta t (ms) from last event')
legend(...
    'dur.acq\_most\_slices', ...
    'ons.acq\_vol');

ax(3) = subplot(3,1,3);
hold off;
plot(1:length(dur.acq_slice_all),dur.acq_slice_all);
hold on;
plot(ons.acq_vol_all,dur.acq_slice_all(ons.acq_vol),'bx')

legend(...
    'dur.acq\_slice\_all', ...
    'ons.acq\_vol\_all');

title('After inserting the slice triggers at the beginning or end of a volume');
xlabel('scan event + 1');
ylabel('\Delta t (ms) from last event')

linkaxes(ax,'x');
end


%% load param
param.net_def_dir = 'model/ResNet_3b_s16_f2r';
param.init_model = fullfile(pwd, 'output/ResNet_3b_s16/tot_wometa_1epoch'); %fullfile(pwd, 'output/ResNet-101L/1000000');
param.solverfile = 'solver_test.prototxt';
param.gpu_id = 0;
mins = 3;
maxs = 14;
%% init caffe solver
caffe.reset_all;
caffe_solver = caffe.get_solver(fullfile(param.net_def_dir, param.solverfile), param.gpu_id);
if ~isempty(param.init_model)
    assert(exist(param.init_model)==2, 'Cannot find caffemodel.');
    caffe_solver.use_caffemodel(param.init_model);
end
caffe_solver.set_phase('test');
num = length(featmap_trans);
cons = 0;
hit = 0;
sums = 0;
missed = cell(num, 1);
recall = 0;
for i = 1 : num
    ti = tic();
    drawnow;
    fprintf('Step 3 rpn:  %d/%d...', i, num);
    parsed(i) = detect_all_by_featmap( featmap_trans{i}, unique(min(scale{i}, 5)), param, caffe_solver, mins);
    toc(ti);
end
fprintf('Modify scale...')
for i = 1 : num
    s = max(size(imread(fullfile(param.test_root, list{i}))))/param.max_img;
    parsed(i).box(:,1:4) = parsed(i).box(:,1:4) * s;
    parsed(i).point = parsed(i).point * s;
end
fprintf('Done\n');


function [c, r, t, cpulse, acq_codes] = tapas_physio_read_physlogfiles_brainproducts(log_files, ...
    cardiac_modality, verbose)
% reads out physiological time series (ECG, PMU, resp belt) and timing vector for BrainProducts .eeg file
%
%   [cpulse, rpulse, t, c, acq_codes] = tapas_physio_read_physlogfiles_brainproducts(logfiles, ...
%                               verbose)
%
%
% IN    log_files
%       .cardiac        contains ECG or pulse oximeter time course
%                           for BrainProducts: usually the same as respiration
%       .respiration    contains breathing belt amplitude time course
%                           for BrainProducts: usually the same as cardiac
%       .sampling_interval  is ignored here, read from logfile
%
%   cardiac_modality
%                       'ecg1_filtered'     filtered 1st ECG channel signal
%                                           (Default)
%                       'ecg2_filtered'     filteered 2nd ECG channel
%                                           (sometimes less gradient artifacts)
%                       'ecg1_raw'          raw 1st ECG channel
%
%       verbose
%       .level              debugging plots are created if level >=3
%       .fig_handles        appended by handle to output figure
%
% OUT
%   r                   respiratory time series
%   c                   cardiac time series (ECG or pulse oximetry)
%   t                   vector of time points (in seconds)
%   cpulse              time events of R-wave peak in cardiac time series (seconds)
%                       for Biopac: usually empty, kept for compatibility
%   acq_codes           slice/volume start events marked by number <> 0
%                       for time points in t
% EXAMPLE
%   [ons_secs.cpulse, ons_secs.rpulse, ons_secs.t, ons_secs.c] =
%       tapas_physio_read_physlogfiles_GE(logfiles);
%
%   See also tapas_physio_main_create_regressors

% Author: Lars Kasper
% Created: 2017-01-27
% Copyright (C) 2017 Institute for Biomedical Engineering, ETH/Uni Zurich.
%
% This file is part of the PhysIO toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

%% user input

% volume trigger event
event_type = 'Response';
event_value = 'R128';

switch lower(cardiac_modality)
    case {'ecg','ecg1_filtered'}
        % chose one ecg channel (only for visualisation)
        ecg_ch = 1;
    case 'ecg2_filtered'
       % chose one ecg channel (only for visualisation)
        ecg_ch = 2;
end

% is ecg data flipped?
ecg_is_flipped = 1;

%% data

% read data and header info using field trip (included in SPM)
if ~exist('ft_read_header', 'file')
   pathSpm = fileparts(which('spm'));
   addpath(genpath(fullfile(pathSpm, 'external', 'fieldtrip')));
end

hdr = ft_read_header(log_files.cardiac);
data = ft_read_data(log_files.cardiac);

fs = hdr.Fs; % sampling frequency in Hz
N = hdr.nSamples; % number of samples
dt = 1/fs; % sampling interval in seconds
t = linspace(0,dt*(N-1), N); % time vector in seconds

fh = [];

% plot first 10 seconds of the raw data
fh(end+1,1) = tapas_physio_get_default_fig_params();
plot_end = 10 * fs;
plot(t(1:plot_end), data(:,(1:plot_end)));
xlabel('time in seconds');
ylabel(hdr.chanunit);
legend(hdr.label);

% extract ECG data
if ecg_is_flipped
    s = -data(ecg_ch,:);
else
    s = data(ecg_ch,:);
end

% plot first 10 seconds again for check
fh(end+1,1) = tapas_physio_get_default_fig_params();
plot_end = 10 * fs;
plot(t(1:plot_end), s(:,(1:plot_end)));
xlabel('time in seconds');
ylabel(hdr.chanunit{ecg_ch});
legend(hdr.label{ecg_ch});
%% events
% display all events in the data on the command line
cfg = [];
cfg.dataset = log_files.cardiac;
cfg.trialdef.eventtype  = '?';
ft_definetrial(cfg);

% define volume trigger
cfg.trialdef.eventtype = event_type;
cfg.trialdef.eventvalue = event_value;
cfg = ft_definetrial(cfg);
trigger_pos = cfg.trl(:,1);
n_trigger = length(trigger_pos);

% plot raw data and events
fh(end+1,1) = tapas_physio_get_default_fig_params();
max_value = max(s);
plot(t, s);
hold all;
stem(t(trigger_pos), max_value * ones(1,n_trigger));

% find segments
% compute the number of samples between each trigger (pos-1)
diff_trigger_pos = diff(trigger_pos);
% find the positons where a change is happening
diff_diff_trigger_pos = find(diff(diff_trigger_pos));
% add first and last event
start_segment = [1; diff_diff_trigger_pos(2:2:end)+1];
end_segment = [diff_diff_trigger_pos(1:2:end)+1; n_trigger];
% number of samples per trials
n_trial_samples = diff_trigger_pos(start_segment);
% position of start segment in samples
sample_start_segment = trigger_pos(start_segment);
% position of end segment in samples (not including the whole trial)
sample_end_segment = trigger_pos(end_segment);
% number of segments
n_segments = length(start_segment);
% number of trials per segment
n_trials = end_segment - start_segment + 1;
% TR per trial
TR_trials = n_trial_samples*dt;

% plot segments
stem(t(sample_start_segment), max_value * ones(1,n_segments), '--', 'LineWidth', 5);
stem(t(sample_end_segment), max_value * ones(1,n_segments), '--', 'LineWidth', 5);
legend('signal', 'all trigger', 'start segment', 'end segment');

%% load only first segment for sanity check
cfg = [];
cfg.dataset = log_files.cardiac;
cfg.trialdef.eventtype = event_type;
cfg.trialdef.eventvalue = event_value;
cfg.trialfun = 'ft_trialfun_segment';
cfg.trialdef.prestim = 0;
cfg.trialdef.poststim = TR_trials(1);
cfg.trialdef.segment_start = start_segment(1);
cfg.trialdef.segment_end = end_segment(1);
cfg = ft_definetrial(cfg);

% plot segments
fh(end+1,1) = tapas_physio_get_default_fig_params();
max_value = max(s);
plot(t, s);
hold all;
stem(t(cfg.trl(:,1)), max_value * ones(1,n_trials(1)));
stem(t(cfg.trl(:,2)), max_value * ones(1,n_trials(1)));
legend('signal', 'start trial', 'end trial');

%% save results
[~,name] = fileparts(file_name);
save_name = fullfile(file_path, [name, '_segments.mat']);
save(save_name, 'sample_start_segment', 'sample_end_segment', ...
    'n_segments', 'n_trials', 'TR_trials', 'start_segment', 'end_segment', ...
    'event_type', 'event_value', 'n_trial_samples', 'fs', ...
    'ecg_is_flipped', 'ecg_ch', 'file_path', 'file_name');