function [tmpS study] = dicomrt_d2c_SPECT(SPECTInitS,study)
% dicomrt_d2c_SPECT(SPECTInitS,study)
%
% converts the passed PET Cell to CERR structure.
% SPECTInitS is the initialized CERR structure representing PET scan.
%
% study is the actual PET Cell with following structure
%         PETCell{1} = PET_Scan_Info;
%         PETCell{2} = PET_Scan;
%         PETCell{3} = xVec;
%         PETCell{4} = yVec;
%         PETCell{5} = sort(ZSlice);
%
% Created DK

tmpS.scanArray            = study{2};
tmpS.scanType             = 'NM';
tmpS.scanInfo             = SPECTInitS;
tmpS.uniformScanInfo      = '';
tmpS.scanArraySuperior    = '';
tmpS.scanArrayInferior    = '';
tmpS.scanUID              = createUID('SCAN');

[tags study]=dicomrt_d2c_SPECTcoordsystem(study);

type = 'NM';
info = study{1};
xmesh = study{3};
ymesh = study{4};
zmesh = study{5};
% Scan info
for i=1:length(study{5}) % loop through the number of slices
    % it would be possible to retrive dimensions from the CT images info
    % however for consistency we get ct_xmesh ct_ymesh and ct_zmesh already calculated

    % Fill SPECTInitS
    SPECTInitS(i).imageNumber            = i;
    SPECTInitS(i).imageType              = type;
    SPECTInitS(i).patientName            = [info.PatientName.FamilyName];
    try
        SPECTInitS(i).patientName            = [SPECTInitS(i).patientName,' ', ...
            info.PatientName.GivenName]; % may be not present in anonymized studies
    end
    SPECTInitS(i).scanType               = info.ImageType;
    SPECTInitS(i).grid1Units             = tags.grid1Units;
    SPECTInitS(i).grid2Units             = tags.grid2Units;
    SPECTInitS(i).numberRepresentation   = 'TWO''S COMPLEMENT INTEGER';                 % LEAVE FOR NOW
    SPECTInitS(i).bytesPerPixel          = 2;                                           % LEAVE FOR NOW
    SPECTInitS(i).numberOfDimensions     = length(info.PixelSpacing);
    SPECTInitS(i).sizeOfDimension1       = double(info.Rows);
    SPECTInitS(i).sizeOfDimension2       = double(info.Columns);
    SPECTInitS(i).zValue                 = zmesh(i);
    SPECTInitS(i).xOffset                = tags.xOffset;
    SPECTInitS(i).yOffset                = tags.yOffset;
    SPECTInitS(i).CTOffset               = 0;
    SPECTInitS(i).sliceThickness         = info.SliceThickness.*0.1;
    try
        SPECTInitS(i).siteOfInterest         = info.StudyDescription;
    catch
        SPECTInitS(i).siteOfInterest         = info.StudyID;
    end

    try
        SPECTInitS(i).scanDescription        = info.StudyDescription;
    catch
        SPECTInitS(i).scanDescription        = info.StudyID;
    end

    SPECTInitS(i).scannerType            = info.Manufacturer;
    SPECTInitS(i).scanFileName           = info.Filename;
    try
        SPECTInitS(i).headInOut              = tags.hio;
    end
    try
        SPECTInitS(i).positionInScan         = tags.pos;
    end

    SPECTInitS(i).scanNumber             = info.InstanceNumber;

    try
        SPECTInitS(i).scanDate           = info.ImageDate;
    catch
        SPECTInitS(i).scanDate           ='';
    end
    SPECTInitS(i).transferProtocol       = 'DICOM';
    SPECTInitS(i).DICOMHeaders           = info;
    try
        SPECTInitS(i).PatientAge               = info.PatientAge;
    end
    try
        SPECTInitS(i).PatientWeight            = info.PatientWeight;
    end

    SPECTInitS(i).RadiopharmaceuticalInformationSequence  = info.RadiopharmaceuticalInformationSequence;
    SPECTInitS(i).PatientOrientationCodeSequence          = info.PatientOrientationCodeSequence ;
    SPECTInitS(i).PatientGantryRelationshipCodeSequence   = info.PatientGantryRelationshipCodeSequence;
end

% Update nimages
tags.nimages = size(info,2); % number of PET images

% Writing CERR scan data
tmpS.scanInfo             = SPECTInitS;


function check_shape(shape,value,argname,funcname)
% Check whether a given value can be assigned to a field of a given shape.
% check_type(ShapeString,Value,ArgumentName,FunctionName)
%
% This function throws an error message if the check fails.
%
% In:
%   ShapeString : a string that identifies the type of the argument (as in deduce_shape).
%
%   Value : the value to check
%
%   ArgumentName : name of the affected argument, for diagnostic messages.
%
%   FunctionName : name of the function that defines the argument.
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2014-02-26

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

switch shape
    case 'scalar'
        if any(size(value) > 1)
            error('BCILAB:arg:shapecheck','The value assigned to %s in %s must be scalar, but was: %s.',argname,funcname,hlp_tostring(value,1000)); end
    case 'empty'
        if ~isempty(value)
            error('BCILAB:arg:shapecheck','The value assigned to %s in %s must be empty, but was: %s.',argname,funcname,hlp_tostring(value,1000)); end
    case 'row'
        if size(value,1) > 1
            error('BCILAB:arg:shapecheck','The value assigned to %s in %s must be a row vector, but was: %s.',argname,funcname,hlp_tostring(value,1000)); end
    case 'column'
        if size(value,2) > 1
            error('BCILAB:arg:shapecheck','The value assigned to %s in %s must be a column vector, but was: %s.',argname,funcname,hlp_tostring(value,1000)); end
    case 'matrix'
        if ndims(value) > 2 %#ok<ISMAT>
            error('BCILAB:arg:shapecheck','The value assigned to %s in %s must be a matrix, but was: %s.',argname,funcname,hlp_tostring(value,1000)); end
end


% This file is part of the project NILM-Eval (https://github.com/beckel/nilm-eval).
% Licence: GPL 2.0 (http://www.gnu.org/licenses/gpl-2.0.html)
% Copyright: ETH Zurich, 2014
% Author: Romano Cicchetti

warning off MATLAB:dispatcher:nameConflict

addpath(genpath('algorithms'));
addpath(genpath('config'));
addpath(genpath('data_access'));
addpath(genpath('framework'));
% some conflict with 'legend' plotting function :(
% addpath(genpath('lib/bnt'));
addpath(genpath('lib/lightspeed'));
addpath(genpath('lib/proxTV-1.0'));
addpath(genpath('lib/spectralClustering'));
addpath(genpath('lib/TVDIP'));
addpath(genpath('lib/YAMLMatlab_0.4.3'));
addpath(genpath('plot'));
addpath('projects/');
addpath('projects/buildsys/');
addpath('projects/buildsys/images/');
addpath(genpath('util'));

set(0,'DefaultTextFontname', 'Times New Roman');
set(0,'DefaultTextFontSize', 9);
set(0,'DefaultAxesFontName', 'Times New Roman');
set(0,'DefaultAxesFontSize', 9);


function [ readerobj ] = open_iceye_reader( filename )
%OPEN_ICEYE_READER Intiates a reader object for ICEYE SLC HDF5 file format.
%
% Written by: Tim Cox, NRL.  Based on the CSM/NISAR reader by Wade Schwartzkopf, NGA/IDT
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

%% Open HDF5
fid=H5F.open(filename, 'H5F_ACC_RDONLY', 'H5P_DEFAULT');
meta=meta2sicd_iceye(fid);

% Open HDF objects for reading real and imaginary pixels
dset_id(1) = H5D.open(fid,'s_i');
dspace_id(1) = H5D.get_space(dset_id(1));
[~, datasize{1}] = H5S.get_simple_extent_dims(dspace_id(1));
dset_id(2) = H5D.open(fid,'s_q');
dspace_id(2) = H5D.get_space(dset_id(2));
[~, datasize{2}] = H5S.get_simple_extent_dims(dspace_id(2));

if strcmpi(h5read(filename,'/look_side'),'left')
    symmetry=[0 1 1];
else
    symmetry=[0 0 1];
end

%% Define object methods
readerobj = chipfun2readerobj(@chipper_iceye, datasize{1}); %real/imag are the same size
readerobj.get_meta=@() meta;
readerobj.close=@() close_hdf;

    function out = chipper_iceye(varargin)
        [dim1range,dim2range,subsample]=check_chipper_args(datasize{1}, varargin{:});
        tempargs=reorient_chipper_args(symmetry, datasize{1}([2 1]), dim1range, dim2range, subsample);
        [dim1range,dim2range,subsample]=deal(tempargs{:});
        offset=[dim2range(1) dim1range(1)]-1;
        subsample([1 2]) = subsample([2 1]);
        slabsize=ceil(([diff(dim2range) diff(dim1range)]+1)./subsample);
        H5S.select_hyperslab(dspace_id(1),'H5S_SELECT_SET',...
            offset,subsample,slabsize,ones(size(offset)));
        memspacei_id = H5S.create_simple(length(slabsize),slabsize,slabsize);
        temp_out_real=H5D.read(dset_id(1),'H5ML_DEFAULT',memspacei_id,dspace_id(1),'H5P_DEFAULT');
        H5S.select_hyperslab(dspace_id(2),'H5S_SELECT_SET',...
            offset,subsample,slabsize,ones(size(offset)));
        memspaceq_id = H5S.create_simple(length(slabsize),slabsize,slabsize);
        temp_out_imag=H5D.read(dset_id(2),'H5ML_DEFAULT',memspaceq_id,dspace_id(2),'H5P_DEFAULT');

        H5S.close(memspacei_id);
        H5S.close(memspaceq_id);
        out=reorient_chipper_data(symmetry, complex(temp_out_real,temp_out_imag));
    end

    function close_hdf()
        H5S.close(dspace_id(1));
        H5D.close(dset_id(1));
        H5S.close(dspace_id(2));
        H5D.close(dset_id(2));
        H5F.close(fid);
    end

end

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


function varargout = bbGt( action, varargin )
% Bounding box (bb) annotations struct, evaluation and sampling routines.
%
% bbGt gives access to two types of routines:
% (1) Data structure for storing bb image annotations.
% (2) Routines for evaluating the Pascal criteria for object detection.
%
% The bb annotation stores bb for objects of interest with additional
% information per object, such as occlusion information. The underlying
% data structure is simply a Matlab stuct array, one struct per object.
% This annotation format is an alternative to the annotation format used
% for the PASCAL object challenges (in addition routines for loading PASCAL
% format data are provided, see bbLoad()).
%
% Each object struct has the following fields:
%  lbl  - a string label describing object type (eg: 'pedestrian')
%  bb   - [l t w h]: bb indicating predicted object extent
%  occ  - 0/1 value indicating if bb is occluded
%  bbv  - [l t w h]: bb indicating visible region (may be [0 0 0 0])
%  ign  - 0/1 value indicating bb was marked as ignore
%  ang  - [0-360] orientation of bb in degrees
%
% Note: although orientation (angle) is stored for each bb, for now it is
% not being used during evaluation or sampling.
%
% bbGt contains a number of utility functions, accessed using:
%  outputs = bbGt( 'action', inputs );
% The list of functions and help for each is given below. Also, help on
% individual subfunctions can be accessed by: "help bbGt>action".
%
%%% (1) Data structure for storing bb image annotations.
% Create annotation of n empty objects.
%   objs = bbGt( 'create', [n] );
% Save bb annotation to text file.
%   objs = bbGt( 'bbSave', objs, fName )
% Load bb annotation from text file and filter.
%   [objs,bbs] = bbGt( 'bbLoad', fName, [pLoad] )
% Get object property 'name' (in a standard array).
%   vals = bbGt( 'get', objs, name )
% Set object property 'name' (with a standard array).
%   objs = bbGt( 'set', objs, name, vals )
% Draw an ellipse for each labeled object.
%   hs = draw( objs, pDraw )
%
%%% (2) Routines for evaluating the Pascal criteria for object detection.
% Get all corresponding files in given directories.
%   [fs,fs0] = bbGt('getFiles', dirs, [f0], [f1] )
% Copy corresponding files into given directories.
%   fs = bbGt( 'copyFiles', fs, dirs )
% Load all ground truth and detection bbs in given directories.
%   [gt0,dt0] = bbGt( 'loadAll', gtDir, [dtDir], [pLoad] )
% Evaluates detections against ground truth data.
%   [gt,dt] = bbGt( 'evalRes', gt0, dt0, [thr], [mul] )
% Display evaluation results for given image.
%   [hs,hImg] = bbGt( 'showRes' I, gt, dt, varargin )
% Compute ROC or PR based on outputs of evalRes on multiple images.
%   [xs,ys,ref] = bbGt( 'compRoc', gt, dt, roc, ref )
% Extract true or false positives or negatives for visualization.
%   [Is,scores,imgIds] = bbGt( 'cropRes', gt, dt, imFs, varargin )
% Computes (modified) overlap area between pairs of bbs.
%   oa = bbGt( 'compOas', dt, gt, [ig] )
% Optimized version of compOas for a single pair of bbs.
%   oa = bbGt( 'compOa', dt, gt, ig )
%
% USAGE
%  varargout = bbGt( action, varargin );
%
% INPUTS
%  action     - string specifying action
%  varargin   - depends on action, see above
%
% OUTPUTS
%  varargout  - depends on action, see above
%
% EXAMPLE
%
% See also bbApply, bbLabeler, bbGt>create, bbGt>bbSave, bbGt>bbLoad,
% bbGt>get, bbGt>set, bbGt>draw, bbGt>getFiles, bbGt>copyFiles,
% bbGt>loadAll, bbGt>evalRes, bbGt>showRes,  bbGt>compRoc, bbGt>cropRes,
% bbGt>compOas, bbGt>compOa
%
% Piotr's Computer Vision Matlab Toolbox      Version 3.26
% Copyright 2014 Piotr Dollar.  [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see external/bsd.txt]

%#ok<*DEFNU>
varargout = cell(1,max(1,nargout));
[varargout{:}] = feval(action,varargin{:});
end

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

function objs = create( n )
% Create annotation of n empty objects.
%
% USAGE
%  objs = bbGt( 'create', [n] )
%
% INPUTS
%  n      - [1] number of objects to create
%
% OUTPUTS
%  objs   - annotation of n 'empty' objects
%
% EXAMPLE
%  objs = bbGt('create')
%
% See also bbGt
o=struct('lbl','','bb',[0 0 0 0],'occ',0,'bbv',[0 0 0 0],'ign',0,'ang',0);
if(nargin<1 || n==1), objs=o; return; end; objs=o(ones(n,1));
end

function objs = bbSave( objs, fName )
% Save bb annotation to text file.
%
% USAGE
%  objs = bbGt( 'bbSave', objs, fName )
%
% INPUTS
%  objs   - objects to save
%  fName  - name of text file
%
% OUTPUTS
%  objs   - objects to save
%
% EXAMPLE
%
% See also bbGt, bbGt>bbLoad
vers=3; fid=fopen(fName,'w'); assert(fid>0);
fprintf(fid,'%% bbGt version=%i\n',vers);
objs=set(objs,'bb',round(get(objs,'bb')));
objs=set(objs,'bbv',round(get(objs,'bbv')));
objs=set(objs,'ang',round(get(objs,'ang')));
for i=1:length(objs)
  o=objs(i); bb=o.bb; bbv=o.bbv;
  fprintf(fid,['%s' repmat(' %i',1,11) '\n'],o.lbl,...
    bb,o.occ,bbv,o.ign,o.ang);
end
fclose(fid);
end

function [objs,bbs] = bbLoad( fName, varargin )
% Load bb annotation from text file and filter.
%
% FORMAT: Specify 'format' to indicate the format of the ground truth.
% format=0 is the default format (created by bbSave/bbLabeler). format=1 is
% the PASCAL VOC format. Loading ground truth in this format requires
% 'VOCcode/' to be in directory path. It's part of VOCdevkit available from
% the PASCAL VOC: http://pascallin.ecs.soton.ac.uk/challenges/VOC/. Objects
% labeled as either 'truncated' or 'occluded' using the PASCAL definitions
% have the 'occ' flag set to true. Objects labeled as 'difficult' have the
% 'ign' flag set to true. 'class' is used for 'lbl'. format=2 is the
% ImageNet detection format and requires the ImageNet Dev Kit.
%
% FILTERING: After loading, the objects can be filtered. First, only
% objects with lbl in lbls or ilbls or returned. For each object, obj.ign
% is set to 1 if it was already at 1, if its label was in ilbls, or if any
% object property is outside of the specified range. The ignore flag is
% used during training and testing so that objects with certain properties
% (such as very small or heavily occluded objects) are excluded. The range
% for each property is a two element vector, [0 inf] by default; a property
% value v is inside the range if v>=rng(1) && v<=rng(2). Tested properties
% include height (h), width (w), area (a), aspect ratio (ar), orientation
% (o), extent x-coordinate (x), extent y-coordinate (y), and fraction
% visible (v). The last property is computed as the visible object area
% divided by the total area, except if o.occ==0, in which case v=1, or
% all(o.bbv==o.bb), which indicates the object may be barely visible, in
% which case v=0 (note that v~=1 in this case).
%
% RETURN: In addition to outputting the objs, bbLoad() can return the
% corresponding bounding boxes (bbs) in an [nx5] array where each row is of
% the form [x y w h ignore], [x y w h] is the bb and ignore=obj.ign. For
% oriented bbs, the extent of the bb is returned, where the extent is the
% smallest axis aligned bb containing the oriented bb. If the oriented bb
% was labeled as a rectangle as opposed to an ellipse, the tightest bb will
% usually increase slightly in size due to the corners of the rectangle
% sticking out beyond the ellipse bounds. The 'ellipse' flag controls how
% an oriented bb is converted to a regular bb. Specifically, set ellipse=1
% if an ellipse tightly delineates the object and 0 if a rectangle does.
% Finally, if 'squarify' is not empty the (non-ignore) bbs are converted to
% a fixed aspect ratio using bbs=bbApply('squarify',bbs,squarify{:}).
%
% USAGE
%  [objs,bbs] = bbGt( 'bbLoad', fName, [pLoad] )
%
% INPUTS
%  fName    - name of text file
%  pLoad    - parameters (struct or name/value pairs)
%   .format   - [0] gt format 0:default, 1:PASCAL, 2:ImageNet
%   .ellipse  - [1] controls how oriented bb is converted to regular bb
%   .squarify - [] controls optional reshaping of bbs to fixed aspect ratio
%   .lbls     - [] return objs with these labels (or [] to return all)
%   .ilbls    - [] return objs with these labels but set to ignore
%   .hRng     - [] range of acceptable obj heights
%   .wRng     - [] range of acceptable obj widths
%   .aRng     - [] range of acceptable obj areas
%   .arRng    - [] range of acceptable obj aspect ratios
%   .oRng     - [] range of acceptable obj orientations (angles)
%   .xRng     - [] range of x coordinates of bb extent
%   .yRng     - [] range of y coordinates of bb extent
%   .vRng     - [] range of acceptable obj occlusion levels
%
% OUTPUTS
%  objs     - loaded objects
%  bbs      - [nx5] array containg ground truth bbs [x y w h ignore]
%
% EXAMPLE
%
% See also bbGt, bbGt>bbSave

% get parameters
df={'format',0,'ellipse',1,'squarify',[],'lbls',[],'ilbls',[],'hRng',[],...
  'wRng',[],'aRng',[],'arRng',[],'oRng',[],'xRng',[],'yRng',[],'vRng',[]};
[format,ellipse,sqr,lbls,ilbls,hRng,wRng,aRng,arRng,oRng,xRng,yRng,vRng]...
  = getPrmDflt(varargin,df,1);

% load objs
if( format==0 )
  % load objs stored in default format
  fId=fopen(fName);
  if(fId==-1), error(['unable to open file: ' fName]); end; v=0;
  try v=textscan(fId,'%% bbGt version=%d'); v=v{1}; catch, end %#ok<CTCH>
  if(isempty(v)), v=0; end
  % read in annotation (m is number of fields for given version v)
  if(all(v~=[0 1 2 3])), error('Unknown version %i.',v); end
  frmt='%s %d %d %d %d %d %d %d %d %d %d %d';
  ms=[10 10 11 12]; m=ms(v+1); frmt=frmt(1:2+(m-1)*3);
  in=textscan(fId,frmt); for i=2:m, in{i}=double(in{i}); end; fclose(fId);
  % create objs struct from read in fields
  n=length(in{1}); objs=create(n);
  for i=1:n, objs(i).lbl=in{1}{i}; objs(i).occ=in{6}(i); end
  bb=[in{2} in{3} in{4} in{5}]; bbv=[in{7} in{8} in{9} in{10}];
  for i=1:n, objs(i).bb=bb(i,:); objs(i).bbv=bbv(i,:); end
  if(m>=11), for i=1:n, objs(i).ign=in{11}(i); end; end
  if(m>=12), for i=1:n, objs(i).ang=in{12}(i); end; end
elseif( format==1 )
  % load objs stored in PASCAL VOC format
  if(exist('PASreadrecord.m','file')~=2)
    error('bbLoad() requires the PASCAL VOC code.'); end
  os=PASreadrecord(fName); os=os.objects;
  n=length(os); objs=create(n);
  if(~isfield(os,'occluded')), for i=1:n, os(i).occluded=0; end; end
  for i=1:n
    bb=os(i).bbox; bb(3)=bb(3)-bb(1); bb(4)=bb(4)-bb(2); objs(i).bb=bb;
    objs(i).lbl=os(i).class; objs(i).ign=os(i).difficult;
    objs(i).occ=os(i).occluded || os(i).truncated;
    if(objs(i).occ), objs(i).bbv=bb; end
  end
elseif( format==2 )
  if(exist('VOCreadxml.m','file')~=2)
    error('bbLoad() requires the ImageNet dev code.'); end
  os=VOCreadxml(fName); os=os.annotation;
  if(isfield(os,'object')), os=os.object; else os=[]; end
  n=length(os); objs=create(n);
  for i=1:n
    bb=os(i).bndbox; bb=str2double({bb.xmin bb.ymin bb.xmax bb.ymax});
    bb(3)=bb(3)-bb(1); bb(4)=bb(4)-bb(2); objs(i).bb=bb;
    objs(i).lbl=os(i).name;
  end
else error('bbLoad() unknown format: %i',format);
end

% only keep objects whose lbl is in lbls or ilbls
if(~isempty(lbls) || ~isempty(ilbls)), K=true(n,1);
  for i=1:n, K(i)=any(strcmp(objs(i).lbl,[lbls ilbls])); end
  objs=objs(K); n=length(objs);
end

% filter objs (set ignore flags)
for i=1:n, objs(i).ang=mod(objs(i).ang,360); end
if(~isempty(ilbls)), for i=1:n, v=objs(i).lbl;
    objs(i).ign = objs(i).ign || any(strcmp(v,ilbls)); end; end
if(~isempty(xRng)),  for i=1:n, v=objs(i).bb(1);
    objs(i).ign = objs(i).ign || v<xRng(1) || v>xRng(2); end; end
if(~isempty(xRng)),  for i=1:n, v=objs(i).bb(1)+objs(i).bb(3);
    objs(i).ign = objs(i).ign || v<xRng(1) || v>xRng(2); end; end
if(~isempty(yRng)),  for i=1:n, v=objs(i).bb(2);
    objs(i).ign = objs(i).ign || v<yRng(1) || v>yRng(2); end; end
if(~isempty(yRng)),  for i=1:n, v=objs(i).bb(2)+objs(i).bb(4);
    objs(i).ign = objs(i).ign || v<yRng(1) || v>yRng(2); end; end
if(~isempty(wRng)),  for i=1:n, v=objs(i).bb(3);
    objs(i).ign = objs(i).ign || v<wRng(1) || v>wRng(2); end; end
if(~isempty(hRng)),  for i=1:n, v=objs(i).bb(4);
    objs(i).ign = objs(i).ign || v<hRng(1) || v>hRng(2); end; end
if(~isempty(oRng)),  for i=1:n, v=objs(i).ang; if(v>180), v=v-360; end
    objs(i).ign = objs(i).ign || v<oRng(1) || v>oRng(2); end; end
if(~isempty(aRng)),  for i=1:n, v=objs(i).bb(3)*objs(i).bb(4);
    objs(i).ign = objs(i).ign || v<aRng(1) || v>aRng(2); end; end
if(~isempty(arRng)), for i=1:n, v=objs(i).bb(3)/objs(i).bb(4);
    objs(i).ign = objs(i).ign || v<arRng(1) || v>arRng(2); end; end
if(~isempty(vRng)),  for i=1:n, o=objs(i); bb=o.bb; bbv=o.bbv; %#ok<ALIGN>
    if(~o.occ || all(bbv==0)), v=1; elseif(all(bbv==bb)), v=0; else
      v=(bbv(3)*bbv(4))/(bb(3)*bb(4)); end
    objs(i).ign = objs(i).ign || v<vRng(1) || v>vRng(2); end
end

% finally get extent of each bounding box (not trivial if ang~=0)
if(nargout<=1), return; end; if(n==0), bbs=zeros(0,5); return; end
bbs=double([reshape([objs.bb],4,[]); [objs.ign]]'); ign=bbs(:,5)==1;
for i=1:n, bbs(i,1:4)=bbExtent(bbs(i,1:4),objs(i).ang,ellipse); end
if(~isempty(sqr)), bbs(~ign,:)=bbApply('squarify',bbs(~ign,:),sqr{:}); end

  function bb = bbExtent( bb, ang, ellipse )
    % get bb that fully contains given oriented bb
    if(~ang), return; end
    if( ellipse ) % get bb that encompases ellipse (tighter)
      x=bbApply('getCenter',bb); a=bb(4)/2; b=bb(3)/2; ang=ang-90;
      rx=(a*cosd(ang))^2+(b*sind(ang))^2; rx=abs(rx/sqrt(rx));
      ry=(a*sind(ang))^2+(b*cosd(ang))^2; ry=abs(ry/sqrt(ry));
      bb=[x(1)-rx x(2)-ry 2*rx 2*ry];
    else % get bb that encompases rectangle (looser)
      c=cosd(ang); s=sind(ang); R=[c -s; s c]; rs=bb(3:4)/2;
      x0=-rs(1); x1=rs(1); y0=-rs(2); y1=rs(2); pc=bb(1:2)+rs;
      p=[x0 y0; x1 y0; x1 y1; x0 y1]*R'+pc(ones(4,1),:);
      x0=min(p(:,1)); x1=max(p(:,1)); y0=min(p(:,2)); y1=max(p(:,2));
      bb=[x0 y0 x1-x0 y1-y0];
    end
  end
end

function vals = get( objs, name )
% Get object property 'name' (in a standard array).
%
% USAGE
%  vals = bbGt( 'get', objs, name )
%
% INPUTS
%  objs   - [nx1] struct array of objects
%  name   - property name ('lbl','bb','occ',etc.)
%
% OUTPUTS
%  vals   - [nxk] array of n values (k=1 or 4)
%
% EXAMPLE
%
% See also bbGt, bbGt>set
nObj=length(objs); if(nObj==0), vals=[]; return; end
switch name
  case 'lbl', vals={objs.lbl}';
  case 'bb',  vals=reshape([objs.bb]',4,[])';
  case 'occ', vals=[objs.occ]';
  case 'bbv', vals=reshape([objs.bbv]',4,[])';
  case 'ign', vals=[objs.ign]';
  case 'ang', vals=[objs.ang]';
  otherwise, error('unkown type %s',name);
end
end

function objs = set( objs, name, vals )
% Set object property 'name' (with a standard array).
%
% USAGE
%  objs = bbGt( 'set', objs, name, vals )
%
% INPUTS
%  objs   - [nx1] struct array of objects
%  name   - property name ('lbl','bb','occ',etc.)
%  vals   - [nxk] array of n values (k=1 or 4)
%
% OUTPUTS
%  objs   - [nx1] struct array of updated objects
%
% EXAMPLE
%
% See also bbGt, bbGt>get
nObj=length(objs);
switch name
  case 'lbl', for i=1:nObj, objs(i).lbl=vals{i}; end
  case 'bb',  for i=1:nObj, objs(i).bb=vals(i,:); end
  case 'occ', for i=1:nObj, objs(i).occ=vals(i); end
  case 'bbv', for i=1:nObj, objs(i).bbv=vals(i,:); end
  case 'ign', for i=1:nObj, objs(i).ign=vals(i); end
  case 'ang', for i=1:nObj, objs(i).ang=vals(i); end
  otherwise, error('unkown type %s',name);
end
end

function hs = draw( objs, varargin )
% Draw an ellipse for each labeled object.
%
% USAGE
%  hs = bbGt( 'draw', objs, pDraw )
%
% INPUTS
%  objs       - [nx1] struct array of objects
%  pDraw      - parameters (struct or name/value pairs)
%   .col        - ['g'] color or [nx1] array of colors
%   .lw         - [2] line width
%   .ls         - ['-'] line style
%
% OUTPUTS
%  hs     - [nx1] handles to drawn graphic objects
%
% EXAMPLE
%
% See also bbGt
dfs={'col',[],'lw',2,'ls','-'};
[col,lw,ls]=getPrmDflt(varargin,dfs,1);
n=length(objs); hold on; hs=zeros(n,4);
if(isempty(col)), if(n==1), col='g'; else col=hsv(n); end; end
tProp={'FontSize',10,'color','w','FontWeight','bold',...
  'VerticalAlignment','bottom'};
for i=1:n
  bb=objs(i).bb; ci=col(i,:);
  hs(i,1)=text(bb(1),bb(2),objs(i).lbl,tProp{:});
  x=bbApply('getCenter',bb); r=bb(3:4)/2; a=objs(i).ang/180*pi-pi/2;
  [hs(i,2),hs(i,3),hs(i,4)]=plotEllipse(x(2),x(1),r(2),r(1),a,ci,[],lw,ls);
end; hold off;
end

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

function [fs,fs0] = getFiles( dirs, f0, f1 )
% Get all corresponding files in given directories.
%
% The first dir in 'dirs' serves as the baseline dir. getFiles() returns
% all files in the baseline dir and all corresponding files in the
% remaining dirs to the files in the baseline dir, in the same order. Two
% files are in correspondence if they have the same base name (regardless
% of extension). For example, given a file named "name.jpg", a
% corresponding file may be named "name.txt" or "name.jpg.txt". Every file
% in the baseline dir must have a matching file in the remaining dirs.
%
% USAGE
%  [fs,fs0] = bbGt('getFiles', dirs, [f0], [f1] )
%
% INPUTS
%   dirs      - {1xm} list of m directories
%   f0        - [1] index of first file in baseline dir to use
%   f1        - [inf] index of last file in baseline dir to use
%
% OUTPUTS
%   fs        - {mxn} list of full file names in each dir
%   fs0       - {1xn} list of file names without path or extensions
%
% EXAMPLE
%
% See also bbGt

if(nargin<2 || isempty(f0)), f0=1; end
if(nargin<3 || isempty(f1)), f1=inf; end
m=length(dirs); assert(m>0); sep=filesep;

for d=1:m, dir1=dirs{d}; dir1(dir1=='\')=sep; dir1(dir1=='/')=sep;
  if(dir1(end)==sep), dir1(end)=[]; end; dirs{d}=dir1; end

[fs0,fs1] = getFiles0(dirs{1},f0,f1,sep);
n1=length(fs0); fs=cell(m,n1); fs(1,:)=fs1;
for d=2:m, fs(d,:)=getFiles1(dirs{d},fs0,sep); end

  function [fs0,fs1] = getFiles0( dir1, f0, f1, sep )
    % get fs1 in dir1 (and fs0 without path or extension)
    fs1=dir([dir1 sep '*']); fs1={fs1.name}; fs1=fs1(3:end);
    fs1=fs1(f0:min(f1,end)); fs0=fs1; n=length(fs0);
    if(n==0), error('No files found in baseline dir %s.',dir1); end
    for i=1:n, fs1{i}=[dir1 sep fs0{i}]; end
    n=length(fs0); for i=1:n, f=fs0{i};
      f(find(f=='.',1,'first'):end)=[]; fs0{i}=f; end
  end

  function fs1 = getFiles1( dir1, fs0, sep )
    % get fs1 in dir1 corresponding to fs0
    n=length(fs0); fs1=cell(1,n); i2=0; i1=0;
    fs2=dir(dir1); fs2={fs2.name}; n2=length(fs2);
    eMsg='''%s'' has no corresponding file in %s.';
    for i0=1:n, r=length(fs0{i0}); match=0;
      while(i2<n2), i2=i2+1; if(strcmpi(fs0{i0},fs2{i2}(1:min(end,r))))
          i1=i1+1; fs1{i1}=fs2{i2}; match=1; break; end; end
      if(~match), error(eMsg,fs0{i0},dir1); end
    end
    for i1=1:n, fs1{i1}=[dir1 sep fs1{i1}]; end
  end
end

function fs = copyFiles( fs, dirs )
% Copy corresponding files into given directories.
%
% Useful for splitting data into training, validation and testing sets.
% See also bbGt>getFiles for obtaining a set of corresponding files.
%
% USAGE
%  fs = bbGt( 'copyFiles', fs, dirs )
%
% INPUTS
%   fs        - {mxn} list of full file names in each dir
%   dirs      - {1xm} list of m target directories
%
% OUTPUTS
%   fs        - {mxn} list of full file names of copied files
%
% EXAMPLE
%
% See also bbGt, bbGt>getFiles
[m,n]=size(fs); assert(numel(dirs)==m); if(n==0), return; end
for d=1:m
  if(~exist(dirs{d},'dir')), mkdir(dirs{d}); end
  for i=1:n, f=fs{d,i}; j=[0 find(f=='/' | f=='\')]; j=j(end);
    fs{d,i}=[dirs{d} '/' f(j+1:end)]; copyfile(f,fs{d,i}); end
end
end

function [gt0,dt0] = loadAll( gtDir, dtDir, pLoad )
% Load all ground truth and detection bbs in given directories.
%
% Loads each ground truth (gt) annotation in gtDir and the corresponding
% detection (dt) in dtDir. gt and dt files must correspond according to
% getFiles(). Alternatively, dtDir may be a filename of a single text file
% that contains the detection results across all images.
%
% Each dt should be a text file where each row contains 5 numbers
% representing a bb (left/top/width/height/score). If dtDir is a text file,
% it should contain the detection results across the full set of images. In
% this case each row in the text file should have an extra leading column
% specifying the image id: (imgId/left/top/width/height/score).
%
% The output of this function can be used in bbGt>evalRes().
%
% USAGE
%  [gt0,dt0] = bbGt( 'loadAll', gtDir, [dtDir], [pLoad] )
%
% INPUTS
%  gtDir      - location of ground truth
%  dtDir      - [] optional location of detections
%  pLoad      - {} params for bbGt>bbLoad() (determine format/filtering)
%
% OUTPUTS
%  gt0        - {1xn} loaded ground truth bbs (each is a mx5 array of bbs)
%  dt0        - {1xn} loaded detections (each is a mx5 array of bbs)
%
% EXAMPLE
%
% See also bbGt, bbGt>getFiles, bbGt>evalRes

% get list of files
if(nargin<2), dtDir=[]; end
if(nargin<3), pLoad={}; end
if(isempty(dtDir)), fs=getFiles({gtDir}); gtFs=fs(1,:); else
  dtFile=length(dtDir)>4 && strcmp(dtDir(end-3:end),'.txt');
  if(dtFile), dirs={gtDir}; else dirs={gtDir,dtDir}; end
  fs=getFiles(dirs); gtFs=fs(1,:);
  if(dtFile), dtFs=dtDir; else dtFs=fs(2,:); end
end

% load ground truth
persistent keyPrv gtPrv; key={gtDir,pLoad}; n=length(gtFs);
if(isequal(key,keyPrv)), gt0=gtPrv; else gt0=cell(1,n);
  for i=1:n, [~,gt0{i}]=bbLoad(gtFs{i},pLoad); end
  gtPrv=gt0; keyPrv=key;
end

% load detections
if(isempty(dtDir) || nargout<=1), dt0=cell(0); return; end
if(iscell(dtFs)), dt0=cell(1,n);
  for i=1:n, dt1=load(dtFs{i},'-ascii');
    if(numel(dt1)==0), dt1=zeros(0,5); end; dt0{i}=dt1(:,1:5); end
else
  dt1=load(dtFs,'-ascii'); if(numel(dt1)==0), dt1=zeros(0,6); end
  ids=dt1(:,1); assert(max(ids)<=n);
  dt0=cell(1,n); for i=1:n, dt0{i}=dt1(ids==i,2:6); end
end

end

function [gt,dt] = evalRes( gt0, dt0, thr, mul )
% Evaluates detections against ground truth data.
%
% Uses modified Pascal criteria that allows for "ignore" regions. The
% Pascal criteria states that a ground truth bounding box (gtBb) and a
% detected bounding box (dtBb) match if their overlap area (oa):
%  oa(gtBb,dtBb) = area(intersect(gtBb,dtBb)) / area(union(gtBb,dtBb))
% is over a sufficient threshold (typically .5). In the modified criteria,
% the dtBb can match any subregion of a gtBb set to "ignore". Choosing
% gtBb' in gtBb that most closely matches dtBb can be done by using
% gtBb'=intersect(dtBb,gtBb). Computing oa(gtBb',dtBb) is equivalent to
%  oa'(gtBb,dtBb) = area(intersect(gtBb,dtBb)) / area(dtBb)
% For gtBb set to ignore the above formula for oa is used.
%
% Highest scoring detections are matched first. Matches to standard,
% (non-ignore) gtBb are preferred. Each dtBb and gtBb may be matched at
% most once, except for ignore-gtBb which can be matched multiple times.
% Unmatched dtBb are false-positives, unmatched gtBb are false-negatives.
% Each match between a dtBb and gtBb is a true-positive, except matches
% between dtBb and ignore-gtBb which do not affect the evaluation criteria.
%
% In addition to taking gt/dt results on a single image, evalRes() can take
% cell arrays of gt/dt bbs, in which case evaluation proceeds on each
% element. Use bbGt>loadAll() to load gt/dt for multiple images.
%
% Each gt/dt output row has a flag match that is either -1/0/1:
%  for gt: -1=ignore,  0=fn [unmatched],  1=tp [matched]
%  for dt: -1=ignore,  0=fp [unmatched],  1=tp [matched]
%
% USAGE
%  [gt, dt] = bbGt( 'evalRes', gt0, dt0, [thr], [mul] )
%
% INPUTS
%  gt0  - [mx5] ground truth array with rows [x y w h ignore]
%  dt0  - [nx5] detection results array with rows [x y w h score]
%  thr  - [.5] the threshold on oa for comparing two bbs
%  mul  - [0] if true allow multiple matches to each gt
%
% OUTPUTS
%  gt   - [mx5] ground truth results [x y w h match]
%  dt   - [nx6] detection results [x y w h score match]
%
% EXAMPLE
%
% See also bbGt, bbGt>compOas, bbGt>loadAll

% get parameters
if(nargin<3 || isempty(thr)), thr=.5; end
if(nargin<4 || isempty(mul)), mul=0; end

% if gt0 and dt0 are cell arrays run on each element in turn
if( iscell(gt0) && iscell(dt0) ), n=length(gt0);
  assert(length(dt0)==n); gt=cell(1,n); dt=gt;
  for i=1:n, [gt{i},dt{i}] = evalRes(gt0{i},dt0{i},thr,mul); end; return;
end

% check inputs
if(isempty(gt0)), gt0=zeros(0,5); end
if(isempty(dt0)), dt0=zeros(0,5); end
assert( size(dt0,2)==5 ); nd=size(dt0,1);
assert( size(gt0,2)==5 ); ng=size(gt0,1);

% sort dt highest score first, sort gt ignore last
[~,ord]=sort(dt0(:,5),'descend'); dt0=dt0(ord,:);
[~,ord]=sort(gt0(:,5),'ascend'); gt0=gt0(ord,:);
gt=gt0; gt(:,5)=-gt(:,5); dt=dt0; dt=[dt zeros(nd,1)];

% Attempt to match each (sorted) dt to each (sorted) gt
oa = compOas( dt(:,1:4), gt(:,1:4), gt(:,5)==-1 );
for d=1:nd
  bstOa=thr; bstg=0; bstm=0; % info about best match so far
  for g=1:ng
    % if this gt already matched, continue to next gt
    m=gt(g,5); if( m==1 && ~mul ), continue; end
    % if dt already matched, and on ignore gt, nothing more to do
    if( bstm~=0 && m==-1 ), break; end
    % compute overlap area, continue to next gt unless better match made
    if(oa(d,g)<bstOa), continue; end
    % match successful and best so far, store appropriately
    bstOa=oa(d,g); bstg=g; if(m==0), bstm=1; else bstm=-1; end
  end; g=bstg; m=bstm;
  % store type of match for both dt and gt
  if(m==-1), dt(d,6)=m; elseif(m==1), gt(g,5)=m; dt(d,6)=m; end
end

end

function [hs,hImg] = showRes( I, gt, dt, varargin )
% Display evaluation results for given image.
%
% USAGE
%  [hs,hImg] = bbGt( 'showRes', I, gt, dt, varargin )
%
% INPUTS
%  I          - image to display, image filename, or []
%  gt         - first output of evalRes()
%  dt         - second output of evalRes()
%  varargin   - additional parameters (struct or name/value pairs)
%   .evShow     - [1] if true show results of evaluation
%   .gtShow     - [1] if true show ground truth
%   .dtShow     - [1] if true show detections
%   .cols       - ['krg'] colors for ignore/mistake/correct
%   .gtLs       - ['-'] line style for gt bbs
%   .dtLs       - ['--'] line style for dt bbs
%   .lw         - [3] line width
%
% OUTPUTS
%  hs         - handles to bbs and text labels
%  hImg       - handle for image graphics object
%
% EXAMPLE
%
% See also bbGt, bbGt>evalRes
dfs={'evShow',1,'gtShow',1,'dtShow',1,'cols','krg',...
  'gtLs','-','dtLs','--','lw',3};
[evShow,gtShow,dtShow,cols,gtLs,dtLs,lw]=getPrmDflt(varargin,dfs,1);
% optionally display image
if(ischar(I)), I=imread(I); end
if(~isempty(I)), hImg=im(I,[],0); title(''); end
% display bbs with or w/o color coding based on output of evalRes
hold on; hs=cell(1,1000); k=0;
if( evShow )
  if(gtShow), for i=1:size(gt,1), k=k+1;
      hs{k}=bbApply('draw',gt(i,1:4),cols(gt(i,5)+2),lw,gtLs); end; end
  if(dtShow), for i=1:size(dt,1), k=k+1;
      hs{k}=bbApply('draw',dt(i,1:5),cols(dt(i,6)+2),lw,dtLs); end; end
else
  if(gtShow), k=k+1; hs{k}=bbApply('draw',gt(:,1:4),cols(3),lw,gtLs); end
  if(dtShow), k=k+1; hs{k}=bbApply('draw',dt(:,1:5),cols(3),lw,dtLs); end
end
hs=[hs{:}]; hold off;
end

function [xs,ys,score,ref] = compRoc( gt, dt, roc, ref )
% Compute ROC or PR based on outputs of evalRes on multiple images.
%
% ROC="Receiver operating characteristic"; PR="Precision Recall"
% Also computes result at reference points (ref):
%  which for ROC curves is the *detection* rate at reference *FPPI*
%  which for PR curves is the *precision* at reference *recall*
% Note, FPPI="false positive per image"
%
% USAGE
%  [xs,ys,score,ref] = bbGt( 'compRoc', gt, dt, roc, ref )
%
% INPUTS
%  gt         - {1xn} first output of evalRes() for each image
%  dt         - {1xn} second output of evalRes() for each image
%  roc        - [1] if 1 compue ROC else compute PR
%  ref        - [] reference points for ROC or PR curve
%
% OUTPUTS
%  xs         - x coords for curve: ROC->FPPI; PR->recall
%  ys         - y coords for curve: ROC->TP; PR->precision
%  score      - detection scores corresponding to each (x,y)
%  ref        - recall or precision at each reference point
%
% EXAMPLE
%
% See also bbGt, bbGt>evalRes

% get additional parameters
if(nargin<3 || isempty(roc)), roc=1; end
if(nargin<4 || isempty(ref)), ref=[]; end
% convert to single matrix, discard ignore bbs
nImg=length(gt); assert(length(dt)==nImg);
gt=cat(1,gt{:}); gt=gt(gt(:,5)~=-1,:);
dt=cat(1,dt{:}); dt=dt(dt(:,6)~=-1,:);
% compute results
if(size(dt,1)==0), xs=0; ys=0; score=0; ref=ref*0; return; end
m=length(ref); np=size(gt,1); score=dt(:,5); tp=dt(:,6);
[score,order]=sort(score,'descend'); tp=tp(order);
fp=double(tp~=1); fp=cumsum(fp); tp=cumsum(tp);
if( roc )
  xs=fp/nImg; ys=tp/np; xs1=[-inf; xs]; ys1=[0; ys];
  for i=1:m, j=find(xs1<=ref(i)); ref(i)=ys1(j(end)); end
else
  xs=tp/np; ys=tp./(fp+tp); xs1=[xs; inf]; ys1=[ys; 0];
  for i=1:m, j=find(xs1>=ref(i)); ref(i)=ys1(j(1)); end
end
end

function [Is,scores,imgIds] = cropRes( gt, dt, imFs, varargin )
% Extract true or false positives or negatives for visualization.
%
% USAGE
%  [Is,scores,imgIds] = bbGt( 'cropRes', gt, dt, imFs, varargin )
%
% INPUTS
%  gt         - {1xN} first output of evalRes() for each image
%  dt         - {1xN} second output of evalRes() for each image
%  imFs       - {1xN} name of each image
%  varargin   - additional parameters (struct or name/value pairs)
%   .dims       - ['REQ'] target dimensions for extracted windows
%   .pad        - [0] padding amount for cropping
%   .type       - ['fp'] one of: 'fp', 'fn', 'tp', 'dt'
%   .n          - [100] max number of windows to extract
%   .show       - [1] figure for displaying results (or 0)
%   .fStr       - ['%0.1f'] label{i}=num2str(score(i),fStr)
%   .embed      - [0] if true embed dt/gt bbs into cropped windows
%
% OUTPUTS
%  Is         - [dimsxn] extracted image windows
%  scores     - [1xn] detection score for each bb unless 'fn'
%  imgIds     - [1xn] image id for each cropped window
%
% EXAMPLE
%
% See also bbGt, bbGt>evalRes
dfs={'dims','REQ','pad',0,'type','fp','n',100,...
  'show',1,'fStr','%0.1f','embed',0};
[dims,pad,type,n,show,fStr,embed]=getPrmDflt(varargin,dfs,1);
N=length(imFs); assert(length(gt)==N && length(dt)==N);
% crop patches either in gt or dt according to type
switch type
  case 'fn', bbs=gt; keep=@(bbs) bbs(:,5)==0;
  case 'fp', bbs=dt; keep=@(bbs) bbs(:,6)==0;
  case 'tp', bbs=dt; keep=@(bbs) bbs(:,6)==1;
  case 'dt', bbs=dt; keep=@(bbs) bbs(:,6)>=0;
  otherwise, error('unknown type: %s',type);
end
% create ids that will map each bb to correct name
ms=zeros(1,N); for i=1:N, ms(i)=size(bbs{i},1); end; cms=[0 cumsum(ms)];
ids=zeros(1,sum(ms)); for i=1:N, ids(cms(i)+1:cms(i+1))=i; end
% flatten bbs and keep relevent subset
bbs=cat(1,bbs{:}); K=keep(bbs); bbs=bbs(K,:); ids=ids(K); n=min(n,sum(K));
% reorder bbs appropriately
if(~strcmp(type,'fn')), [~,ord]=sort(bbs(:,5),'descend'); else
  if(size(bbs,1)<n), ord=randperm(size(bbs,1)); else ord=1:n; end; end
bbs=bbs(ord(1:n),:); ids=ids(ord(1:n));
% extract patches from each image
if(n==0), Is=[]; scores=[]; imgIds=[]; return; end;
Is=cell(1,n); scores=zeros(1,n); imgIds=zeros(1,n);
if(any(pad>0)), dims1=dims.*(1+pad); rs=dims1./dims; dims=dims1; end
if(any(pad>0)), bbs=bbApply('resize',bbs,rs(1),rs(2)); end
for i=1:N
  locs=find(ids==i); if(isempty(locs)), continue; end; I=imread(imFs{i});
  if( embed )
    if(any(strcmp(type,{'fp','dt'}))), bbs1=gt{i};
    else bbs1=dt{i}(:,[1:4 6]); end
    I=bbApply('embed',I,bbs1(bbs1(:,5)==0,1:4),'col',[255 0 0]);
    I=bbApply('embed',I,bbs1(bbs1(:,5)==1,1:4),'col',[0 255 0]);
  end
  Is1=bbApply('crop',I,bbs(locs,1:4),'replicate',dims);
  for j=1:length(locs), Is{locs(j)}=Is1{j}; end;
  scores(locs)=bbs(locs,5); imgIds(locs)=i;
end; Is=cell2array(Is);
% optionally display
if(~show), return; end; figure(show); pMnt={'hasChn',size(Is1{1},3)>1};
if(isempty(fStr)), montage2(Is,pMnt); title(type); return; end
ls=cell(1,n); for i=1:n, ls{i}=int2str2(imgIds(i)); end
if(~strcmp(type,'fn'))
  for i=1:n, ls{i}=[ls{i} '/' num2str(scores(i),fStr)]; end; end
montage2(Is,[pMnt 'labels' {ls}]); title(type);
end

function oa = compOas( dt, gt, ig )
% Computes (modified) overlap area between pairs of bbs.
%
% Uses modified Pascal criteria with "ignore" regions. The overlap area
% (oa) of a ground truth (gt) and detected (dt) bb is defined as:
%  oa(gt,dt) = area(intersect(dt,dt)) / area(union(gt,dt))
% In the modified criteria, a gt bb may be marked as "ignore", in which
% case the dt bb can can match any subregion of the gt bb. Choosing gt' in
% gt that most closely matches dt can be done using gt'=intersect(dt,gt).
% Computing oa(gt',dt) is equivalent to:
%  oa'(gt,dt) = area(intersect(gt,dt)) / area(dt)
%
% USAGE
%  oa = bbGt( 'compOas', dt, gt, [ig] )
%
% INPUTS
%  dt       - [mx4] detected bbs
%  gt       - [nx4] gt bbs
%  ig       - [nx1] 0/1 ignore flags (0 by default)
%
% OUTPUTS
%  oas      - [m x n] overlap area between each gt and each dt bb
%
% EXAMPLE
%  dt=[0 0 10 10]; gt=[0 0 20 20];
%  oa0 = bbGt('compOas',dt,gt,0)
%  oa1 = bbGt('compOas',dt,gt,1)
%
% See also bbGt, bbGt>evalRes
m=size(dt,1); n=size(gt,1); oa=zeros(m,n);
if(nargin<3), ig=zeros(n,1); end
de=dt(:,[1 2])+dt(:,[3 4]); da=dt(:,3).*dt(:,4);
ge=gt(:,[1 2])+gt(:,[3 4]); ga=gt(:,3).*gt(:,4);
for i=1:m
  for j=1:n
    w=min(de(i,1),ge(j,1))-max(dt(i,1),gt(j,1)); if(w<=0), continue; end
    h=min(de(i,2),ge(j,2))-max(dt(i,2),gt(j,2)); if(h<=0), continue; end
    t=w*h; if(ig(j)), u=da(i); else u=da(i)+ga(j)-t; end; oa(i,j)=t/u;
  end
end
end

function oa = compOa( dt, gt, ig )
% Optimized version of compOas for a single pair of bbs.
%
% USAGE
%  oa = bbGt( 'compOa', dt, gt, ig )
%
% INPUTS
%  dt       - [1x4] detected bb
%  gt       - [1x4] gt bb
%  ig       - 0/1 ignore flag
%
% OUTPUTS
%  oa       - overlap area between gt and dt bb
%
% EXAMPLE
%  dt=[0 0 10 10]; gt=[0 0 20 20];
%  oa0 = bbGt('compOa',dt,gt,0)
%  oa1 = bbGt('compOa',dt,gt,1)
%
% See also bbGt, bbGt>compOas
w=min(dt(3)+dt(1),gt(3)+gt(1))-max(dt(1),gt(1)); if(w<=0),oa=0; return; end
h=min(dt(4)+dt(2),gt(4)+gt(2))-max(dt(2),gt(2)); if(h<=0),oa=0; return; end
i=w*h; if(ig),u=dt(3)*dt(4); else u=dt(3)*dt(4)+gt(3)*gt(4)-i; end; oa=i/u;
end


function X = metoffice_remove_bins(X,maskfile)

X(~metoffice_get_mask(maskfile),:) = [];


function reactions = similarity(formula,data,bar)
% Returns the reaction lines with similarities
%
% USAGE:
%
%    reactions = similarity(formula,data,bar)
%
% INPUTS:
%    formula:    reaction formula
%    data:       reaction list
%    bar:        `waitbar` exists then 1, else 0, default 1
%
% OUTPUT:
%    reactions:   numbers of rxn lines that share similarity
%
%
% .. Author: - Stefan G. Thorleifsson 2010
%
% .. rBioNet is published under GNU GENERAL PUBLIC LICENSE 3.0+
% .. Thorleifsson, S. G., Thiele, I., rBioNet: A COBRA toolbox extension for
% .. reconstructing high-quality biochemical networks, Bioinformatics, Accepted.
% .. rbionet@systemsbiology.is

if nargin < 3
    bar = 1;
end

comp = cell(1);
compd = cell(1);
reactions = [];

%Generate metabolite, compartment, coefficient and rev array
[met,coe,rev] = parseRxnFormula(formula);
S = length(met);
for n = 1:S
    k = regexpi(met{n},'\[');
    metab = met{n};
    comp{n} = metab(k+1);
    met{n} = metab(1:k-1);
end

Sdata = length(data);

if bar == 1
    showprogress(0/Sdata,'This may take a while. Checking reaction');
end

for i = 1:Sdata
    if bar == 1
        showprogress(i/Sdata);
    end

    [metd,coed,revd] = parseRxnFormula(data{i});
    %Sd = length(metd);

    if length(metd) == S % If reaction has equal number of metabolites.
        for n = 1:S %Create comparison array
            %k = regexpi(metd{n},'\[');
            %metab = metd{n};
            %compd{n} = metab(k+1);
            %metd{n} = metab(1:k-1);
            %
            compd{n} = regexprep(regexpi(metd{n},'\[.*?\]','match'),'\[*\]*','');
            metd{n} = metd{n}(1:regexp(metd{n},'\[','end')-1);

        end

        match = 0;
        for m = 1:S % Check every metabolite in met
            metab_match = 0;
            for l = 1:S %Check every metabolite in met
                if strcmp(met{m},metd{l})
                    metab_match = 1;
                end
            end
            if  metab_match == 0 % If metabolite dous not match
                break
            else
                match = match+1;
            end
        end

        if match == S
            reactions = [reactions i];
        end

    end

end


classdef AnnotationMarkersPlotter < handle
    properties (Access = private, Constant)
        markerColors = {[1 0 0],[1 1 0],[0 1 0], [0 0 1], [0 1 1], [1 105/255 180/255], [0.5 0 0.5], [0 0 0]};
        markerLineWidths = [1,1,4,1,1,1,1,1];
    end

    properties (Access = public)
        markerYRange = [-1 1];
        markerHandles;
        shouldShowMarkers = true;
    end

    methods
        function set.shouldShowMarkers(obj,visible)
            obj.setMarkersVisibility(visible);
            obj.shouldShowMarkers = visible;
        end
    end

    methods (Access = public)

        function plotMarkers(obj, markers, plotAxes)

            nMarkers = length(markers);
            obj.markerHandles = repmat(AnnotationMarkerHandle,1,nMarkers);

            for i = 1 : length(markers)
                marker = markers(i);
                color = obj.markerColors(marker.label);
                lineWidth = obj.markerLineWidths(marker.label);

                markerHandle = AnnotationMarkerHandle();

                markerHandle.lineHandle = line(plotAxes,[marker.sample, marker.sample],...
                    [obj.markerYRange(1) obj.markerYRange(2)],...
                    'Color',color{1},'LineWidth',lineWidth,...
                    'LineStyle','-');

                if ~isempty(marker.text)
                    textY = double((obj.markerYRange(1) + obj.markerYRange(2)) / 2);
                    textHandle = text(plotAxes,double(marker.sample),...
                        textY , marker.text,...
                        'Rotation',90);

                    set(textHandle, 'Clipping', 'on');
                    markerHandle.textHandle = textHandle;
                end

                obj.markerHandles(i) = markerHandle;
            end

            obj.setMarkersVisibility(obj.shouldShowMarkers);
        end

        function deleteMarkers(obj)

            for i = 1 : length(obj.markerHandles)
                markerHandle = obj.markerHandles(i);
                delete(markerHandle.lineHandle);
                delete(markerHandle.textHandle);
            end
            obj.markerHandles = [];
        end

        function setMarkersVisibility(obj,visible)
            visibleStr = Helper.GetOnOffString(visible);
            for i = 1 : length(obj.markerHandles)
                markerHandle = obj.markerHandles(i);
                markerHandle.visible = visibleStr;
            end
        end
    end

end


%% Template Matlab script to create an BIDS compatible electrodes.tsv file
% This example lists all required and optional fields.
% When adding additional metadata please use CamelCase
%
% DHermes, 2017
% modified Jaap van der Aar 30.11.18

% Writing json files relies on the JSONio library
% https://github.com/bids-standard/bids-matlab
%
% Make sure it is in the matab/octave path
try
    bids.bids_matlab_version;
catch
    warning('%s\n%s\n%s\n%s', ...
            'Writing the JSON file seems to have failed.', ...
            'Make sure that the following library is in the matlab/octave path:', ...
            'https://github.com/bids-standard/bids-matlab');
end

%%
clear;

this_dir = fileparts(mfilename('fullpath'));
root_dir = fullfile(this_dir, '..', filesep, '..');

project = 'templates';

sub_label = '01';
ses_label = '01';
task_label = 'LongExample';
run_label = '01';

name_spec.modality = 'ieeg';
name_spec.suffix = 'channels';
name_spec.ext = '.tsv';
name_spec.entities = struct('sub', sub_label, ...
                            'ses', ses_label, ...
                            'task', task_label, ...
                            'run', run_label);

% using the 'use_schema', true
% ensures that the entities will be in the correct order
bids_file = bids.File(name_spec, 'use_schema', true);

% Contrust the fullpath version of the filename
channels_tsv_name = fullfile(root_dir, project, bids_file.bids_path, bids_file.filename);

%% make a participants table and save

%% required columns
name = {'n/a'}; % Label of the channel, only contains letters and numbers. The label must
% correspond to _electrodes.tsv name and all ieeg type channels are required to have \
% a position. The reference channel name MUST be provided in the reference column

type = {'n/a'}; % Type of channel, see below for adequate keywords in this field

units = {'n/a'}; % Physical unit of the value represented in this channel, for example: V for Volt,
% specified according to the SI unit symbol and possibly prefix symbol (for example: mV, ?V),
% see the BIDS spec (section 15 Appendix V: Units) for guidelines for Units and Prefixes.

low_cutoff = [0]; % Frequencies used for the low pass filter applied to the
% channel in Hz. If no low pass filter was applied, use n/a. Note that
% anti-alias is a low pass filter, specify its frequencies here if applicable.

high_cutoff = [0]; % Frequencies used for the high pass filter applied to
% the channel in Hz. If no high pass filter applied, use n/a.

%% recommended columns:

reference = {'n/a'}; % Specification of the reference (for example: "mastoid", "ElectrodeName01",
% "intracranial", "CAR", "other", "n/a"). If the channel is not an electrode channel
% (for example: a microphone channel) use `n/a`.

group = {'n/a'}; % Which group of channels (grid/strip/probe) this channel belongs to.
% One group has one wire and noise can be shared. This can be a name or number.
% Note that any groups specified in `_electrodes.tsv` must match those present here.

%% optional columns

sampling_frequency = [0]; % Sampling rate of the channel in Hz.

description = {'n/a'}; % Brief free-text description of the channel, or other information of
% interest (for example: position (for example: 'left lateral temporal surface', 'unipolar/bipolar', etc.)).

notch = [0]; % Frequencies used for the notch filter applied to the channel,
% in Hz. If no notch filter applied, use n/a.

status = {'bad'}; % Data quality observed on the channel (good/bad). A channel is considered bad
% if its data quality is compromised by excessive noise. Description of noise type SHOULD be
% provided in [status_description].

status_description = {'n/a'}; % Freeform text description of noise or artifact affecting data
% quality on the channel. It is meant to explain why the channel was declared bad in [status].

%% write
t = table(name, type, units, low_cutoff, high_cutoff, reference, ...
          group, sampling_frequency, description, notch, status, status_description);

writetable(t, channels_tsv_name, 'FileType', 'text', 'Delimiter', '\t');


function opt=varargin2struct(varargin)
%
% opt=varargin2struct('param1',value1,'param2',value2,...)
%   or
% opt=varargin2struct(...,optstruct,...)
%
% convert a series of input parameters into a structure
%
% authors:Qianqian Fang (q.fang <at> neu.edu)
% date: 2012/12/22
%
% input:
%      'param', value: the input parameters should be pairs of a string and a value
%       optstruct: if a parameter is a struct, the fields will be merged to the output struct
%
% output:
%      opt: a struct where opt.param1=value1, opt.param2=value2 ...
%
% license:
%     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%

len=length(varargin);
opt=struct;
if(len==0) return; end
i=1;
while(i<=len)
    if(isstruct(varargin{i}))
        opt=mergestruct(opt,varargin{i});
    elseif(ischar(varargin{i}) && i<len)
        opt.(lower(varargin{i}))=varargin{i+1};
        i=i+1;
    else
        error('input must be in the form of ...,''name'',value,... pairs or structs');
    end
    i=i+1;
end


function q = subSet(q,ind)
% indexing of quaternions
%
% Syntax
%   subSet(q,ind) %
%

q.a = q.a(ind);
q.b = q.b(ind);
q.c = q.c(ind);
q.d = q.d(ind);


classdef MrUnitTest < matlab.unittest.TestCase
    % Implements unit testing for all MrClasses
    %
    % EXAMPLE
    %   MrUnitTest
    %
    %   See also

    % Author:   Saskia Bollmann
    % Created:  2017-07-07
    % Copyright (C) 2017 Institute for Biomedical Engineering
    %                    University of Zurich and ETH Zurich
    %
    % This file is part of the TAPAS UniQC Toolbox, which is released
    % under the terms of the GNU General Public License (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/>.

    properties (TestParameter)
        % MrDimInfo
        testVariantsDimInfo = {'1', '2', '3', '4', '5', '6', '7', '8', '9', ...
            '10', '11'};
        testFile = {'3DNifti', '4DNifti', 'Folder', 'ParRec'};
        testVariantsDimInfoSplit = {'singleDim', 'twoDims', 'nonExistingDim', ...
            'charSplitDim', 'differentIndex', 'cellofChars', 'emptySplitDim'};
        testVariantsDimInfoSelect = {'singleDim', 'multipleDimsWithSelection',...
            'type', 'invert', 'removeDims', 'unusedVarargin'};
        testCaseLoadMat = {'checkTempDir', 'oneVar', 'objectAsStruct', ...
            'className', 'noMatch', 'tooManyMatch', 'withVarName'};
        % MrAffineTransformation
        testVariantsAffineTrafo = {'propVal', 'matrix'};
        testFileAffineTrafo = {'3DNifti', '4DNifti', 'ParRec'};
        % MrImageGeometry
        testVariantsImageGeom = {'makeReference', ...
            'dimInfoAndaffineTransformation', 'matrix', 'dimInfo', ...
            'affineTransformation', 'timing_info'};
        % MrDataNd
        testVariantsDataNd = {'matrix', 'matrixWithDimInfo', 'matrixWithPropVal'};
        testVariantsArithmeticOperation = {'minus', 'plus', 'power', 'rdivide', 'times'};
        testVariantsDimensionOperation = {'circshift', 'flip', 'fliplr', 'flipud', ...
            'resize', 'rot90', 'select', 'split'};
        testVariantsValueOperation = {'cumsum', 'diff', 'fft', 'hist', 'ifft', ...
            'isreal', 'max', 'maxip', 'mean', 'power', 'prctile', 'real', ...
            'rms', 'rmse', 'unwrap'};
        testVariantsShiftTimeseries = {0}; % verbosity level (plots)
        testVariantsSelect = {'multipleDims', 'invert', 'removeDims', 'unusedVarargin'};
        % MrImage
        MrImageLoadConditions = {'4DNifti', 'FilePlusDimLabelsUnits', ...
            'FilePlusResolutions', 'FilePlussamplingWidths', ...
            'FilePlusSamplingPoints', 'FilePlusShearRotation', ...
            'FilePlusSelect', 'FilePlusDimInfoPropVals', ...
            'FilePlusAffineTransformation', 'FilePlusFirstSamplingPoint', ...
            'FilePlusLastSamplingPoint', 'FilePlusArrayIndex', ...
            'FilePlusOriginIndex'};
    end
    %% MrDimInfo
    methods (Test, TestTags = {'Constructor', 'MrDimInfo'})
        this = MrDimInfo_constructor(this, testVariantsDimInfo)
        this = MrDimInfo_load_from_file(this, testFile)
        this = MrDimInfo_load_from_mat(this, testCaseLoadMat)
    end

    methods (Test, TestTags = {'Methods', 'MrDimInfo'})
        this = MrDimInfo_get_add_remove(this)
        this = MrDimInfo_index2sample(this)
        this = MrDimInfo_permute(this)
        this = MrDimInfo_split(this, testVariantsDimInfoSplit)
        this = MrDimInfo_select(this, testVariantsDimInfoSelect)
        this = MrDimInfo_update_and_validate_properties_from(this)
    end

    %% MrAffineTransformation
    methods (Test, TestTags = {'Constructor', 'MrAffineTransformation'})
        this = MrAffineTransformation_constructor(this, testVariantsAffineTrafo)
        this = MrAffineTransformation_load_from_file(this, testFileAffineTrafo)
    end

    methods (Test, TestTags = {'Methods', 'MrAffineTransformation'})
        this = MrAffineTransformation_transformation(this)
        this = MrAffineTransformation_affineMatrix(this)
    end
    %% MrImageGeometry
    methods (Test, TestTags = {'Constructor', 'MrImageGeometry'})
        this = MrImageGeometry_constructor(this, testVariantsImageGeom)
        this = MrImageGeometry_load_from_file(this, testFile)
    end

    methods (Test, TestTags = {'Methods', 'MrImageGeometry'})
        this = MrImageGeometry_create_empty_image(this)
    end
    %% MrDataNd
    methods (Test, TestTags = {'Constructor', 'MrDataNd'})
        this = MrDataNd_constructor(this, testVariantsDataNd)
        % loading of nifti data will be tested in MrImage (since there,
        % also the affineTransformation is created)
    end

    methods (Test, TestTags = {'Methods', 'MrDataNd'})
        this = MrDataNd_arithmetic_operation(this, testVariantsArithmeticOperation);
        this = MrDataNd_permute(this);
        this = MrDataNd_select(this, testVariantsSelect);
        % this = MrDataNd_dimension_operation(this, testDimensionOperation);
        this = MrDataNd_value_operation(this, testVariantsValueOperation);
        this = MrDataNd_shift_timeseries(this, testVariantsShiftTimeseries);
        % these take too long, need to be shortened
        % this = MrDataNd_split_epoch(this);
    end

    %% MrImage
    methods (Test, TestTags = {'Constructor', 'MrImage'})
        this = MrImage_load_from_file(this, MrImageLoadConditions)
    end

end


function mergedFG = dtiMergeFiberGroups(fg1,fg2,name)
% Merge two fiber groups
%
%   mergedFG = dtiMergeFiberGroups(fg1,fg2,[name])
%
% The parameters are all added into a long list in the params structure.
%
%
% Author: Dougherty, Wandell

if notDefined('fg1'), error('fg1 not defined'); end
if notDefined('fg2'), error('fg2 not defined'); end

% Merge just the fiber data
mergedFG = fg1;
mergedFG.fibers = vertcat(fg1.fibers, fg2.fibers);
if ~(~isfield(fg1, 'subgroup')||~isfield(fg2, 'subgroup'))
mergedFG.subgroup = horzcat(fg1.subgroup, fg2.subgroup);
end
mergedFG.visible = 1;
mergedFG.seeds = [];

% Do the merge of the parameters the parameters
n1 = length(fg1.params);
n2 = length(fg2.params);
for ii=1:n1, mergedFG.params{ii}=fg1.params{ii}; end
for ii=(n1+1):(n1+n2), mergedFG.params{ii} = fg2.params{ii - n1}; end

if ~exist('name','var'),  mergedFG.name = [fg1.name,'_',fg2.name '_MERGED'];
else
    mergedFG.name = name;
end

return;


% Copyright 2011 Zdenek Kalal
%
% This file is part of TLD.
%
% TLD 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.
%
% TLD 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 TLD.  If not, see <http://www.gnu.org/licenses/>.

path = 'X:\PhD\Publications\2009-06_OLCV2009\Web\MultiFace\';
clf;
files = img_dir(path);
load([path 'gt.mat']);
for i = 1:length(files)
    img =  imread([path files(i).name]);
    for ii = 1:length(gt)
        img = bb_burn(img,gt{ii}.bb(:,1763+i),255);
    end
    imshow(img);
    drawnow;
end


%
report_this_filefun(mfilename('fullpath'));
%
%  This file display the original menu
%
%  Stefan Wiemer 12/94

%  Create new figure
% Find out of figure already exists
%
[existFlag,figNumber]=figure_exists('ZMAP 5.0 - Menu');
newmenuFlag=~existFlag;
my_dir = ' ';

% Set up the Seismicity Map window Enviroment
%
if newmenuFlag
    menu  = figure_w_normalized_uicontrolunits( ...
        'Name','ZMAP 5.0 - Menu',...
        'NumberTitle','off', ...
        'MenuBar','none', ...
        'NextPlot','new', ...
        'Color',color_fbg,...
        'Visible','off', ...
        'Position',[ wex wey-300 (ZmapGlobal.Data.map_len - [300 150]) ]);
    orient tall
    axis off

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','showweb(''new'');',...
        'String','Introduction',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.90 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','think;load_zmapfile()',...
        'String','Load *.mat  Datafile and go',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.80 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','think;setup',...
        'String','Create or modify *.mat Datafile',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.70 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','think;datinf',...
        'String','Current Dataset Info ',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.60 0.80 0.09]);

    % uicontrol(gcf,...
    %'Units','normalized',...
    %'Callback','think;loadcal;',...
    %'String','Load new NCEC catalog ',...
    %'BackgroundColor' ,[0.8 0.8 0.8]',...
    %'Position',[0.10 0.50 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','think;newccat=[];clusmenu',...
        'String','Load Cluster datafile ',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.50 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','web(''http://www.seismo.ethz.ch/staff/stefan/zmapnews/papers.html'');',...
        'String',' Papers written using ZMAP',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.40 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','think;dosl = ''newf'';slshow ',...
        'String','Sample Slide Show',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.30 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','think;startwebd',...
        'String','Start WEB Doumentation ',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.20 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','think;working_dir_in',...
        'String','Set working directory ',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.10 0.10 0.80 0.09]);

    uicontrol(gcf,...
        'Units','normalized',...
        'Callback','close(menu);zmap_message_center.set_info('' '','' '');done',...
        'String','Close this window ',...
        'BackgroundColor' ,[0.8 0.8 0.8]',...
        'Position',[0.15 0.00 0.70 0.09]);

end   % if fig exist

figure_w_normalized_uicontrolunits(menu)
set(gcf,'visible','on')


function [errorCode] = pco_sdk_example_swtrig(exposure_time)
% set variables grab and display a single image
%
%   [errorCode] = pco_sdk_example_swtrig(exposure_time)
%
% * Input parameters :
%    exposure_time          camera exposure time (default=10ms)
%
% * Output parameters :
%    errorCode               ErrorCode returned from pco.camera SDK-functions
%
%grab single image from a recording pco.camera
%using functions PCO_AddBufferEx and PCO_WaitforBuffer
%display the grabbed image
%
%function workflow
%open camera
%set variables
%start camera
%grab image
%show image
%stop camera
%close camera
%

glvar=struct('do_libunload',1,'do_close',0,'camera_open',0,'out_ptr',[]);

if(~exist('exposure_time','var'))
 exposure_time = 10;
end

%reduce_display_size=1: display only top-left corner 800x600Pixel
reduce_display_size=0;

pco_camera_load_defines();
subfunc=pco_camera_subfunction();
subfunc.fh_lasterr(0);

[errorCode,glvar]=pco_camera_open_close(glvar);
pco_errdisp('pco_camera_setup',errorCode);
disp(['camera_open should be 1 is ',int2str(glvar.camera_open)]);
if(errorCode~=PCO_NOERROR)
 commandwindow;
 return;
end

out_ptr=glvar.out_ptr;

try

subfunc.fh_stop_camera(out_ptr);

cam_desc=libstruct('PCO_Description');
set(cam_desc,'wSize',cam_desc.structsize);
[errorCode,out_ptr,cam_desc] = calllib('PCO_CAM_SDK', 'PCO_GetCameraDescription', out_ptr,cam_desc);
if(errorCode)
 pco_errdisp('PCO_GetCameraDescription',errorCode);
end

bitpix=uint16(cam_desc.wDynResDESC);

cam_type=libstruct('PCO_CameraType');
set(cam_type,'wSize',cam_type.structsize);
[errorCode,out_ptr,cam_type] = calllib('PCO_CAM_SDK', 'PCO_GetCameraType', out_ptr,cam_type);
if(errorCode)
 pco_errdisp('PCO_GetCameraType',errorCode);
end

interface=uint16(cam_type.wInterfaceType);
subfunc.fh_set_exposure_times(out_ptr,exposure_time,2,0,2)
subfunc.fh_set_triggermode(out_ptr,TRIGGER_MODE_SOFTWARETRIGGER);

if(bitand(cam_desc.dwGeneralCapsDESC1,GENERALCAPS1_NO_TIMESTAMP)==0)
 subfunc.fh_enable_timestamp(out_ptr,TIMESTAMP_MODE_BINARYANDASCII);
end

%set bitalignment LSB
bitalign=uint16(BIT_ALIGNMENT_LSB);
[errorCode,out_ptr] = calllib('PCO_CAM_SDK', 'PCO_SetBitAlignment', out_ptr,bitalign);
 pco_errdisp('PCO_SetBitAlignment',errorCode);

%save actual RecoderSubmode
prev_rec_submode=uint16(10);
[errorCode,out_ptr,prev_rec_submode] = calllib('PCO_CAM_SDK', 'PCO_GetRecorderSubmode', out_ptr,prev_rec_submode);
pco_errdisp('PCO_GetRecorderSubmode',errorCode);

%set RECORDER_SUBMODE_RING_BUFFER
[errorCode,out_ptr] = calllib('PCO_CAM_SDK', 'PCO_SetRecorderSubmode', out_ptr,RECORDER_SUBMODE_RINGBUFFER);
pco_errdisp('PCO_SetRecorderSubmode',errorCode);

%set highest Pixelrate
index=1;
for n=2:4
 if(cam_desc.dwPixelRateDESC(n)>cam_desc.dwPixelRateDESC(index))
  index=n;
 end
end

[errorCode,out_ptr] = calllib('PCO_CAM_SDK', 'PCO_SetPixelRate', out_ptr,cam_desc.dwPixelRateDESC(index));
if(errorCode)
 pco_errdisp('PCO_SetPixelRate',errorCode);
else
 disp(['PixelRate set to ',int2str(cam_desc.dwPixelRateDESC(index))]);
end

%if PCO_ArmCamera does fail no images can be grabbed
errorCode = calllib('PCO_CAM_SDK', 'PCO_ArmCamera', out_ptr);
if(errorCode~=PCO_NOERROR)
 pco_errdisp('PCO_ArmCamera',errorCode);
 ME = MException('PCO_ERROR:ArmCamera','Cannot continue script with not armed camera');
 subfunc.fh_lasterr(errorCode);
 throw(ME);
end

%adjust transfer parameter if necessary
subfunc.fh_set_transferparameter(out_ptr);

subfunc.fh_get_triggermode(out_ptr);
subfunc.fh_show_frametime(out_ptr);

metadatasize=0;
if(bitand(cam_desc.dwGeneralCapsDESC1,GENERALCAPS1_METADATA))
 wMetaDataMode=uint16(0);
 wMetaDataSize=uint16(0);
 wMetaDataVersion=uint16(0);

 [errorCode,~,wMetaDataMode,wMetaDataSize,wMetaDataVersion] = calllib('PCO_CAM_SDK', 'PCO_GetMetaDataMode',out_ptr,wMetaDataMode,wMetaDataSize,wMetaDataVersion);
 pco_errdisp('PCO_GetMetaDataMode',errorCode);
 if(errorCode)
  pco_errdisp('PCO_GetMetaDataMode',errorCode);
  return;
 end

 disp(['Camera supports Metadata Version: ',num2str(wMetaDataVersion)]);

 if(wMetaDataMode~=0)
  metadatasize=wMetaDataSize;
  disp(['Metadata is enabled. Number of Bytes: ',num2str(metadatasize)]);
 end
end

act_xsize=uint16(0);
act_ysize=uint16(0);
ccd_xsize=uint16(0);
ccd_ysize=uint16(0);

%use PCO_GetSizes because this always returns accurate image size for next recording
[errorCode,out_ptr,act_xsize,act_ysize]  = calllib('PCO_CAM_SDK', 'PCO_GetSizes', out_ptr,act_xsize,act_ysize,ccd_xsize,ccd_ysize);
if(errorCode)
 pco_errdisp('PCO_GetSizes',errorCode);
end

disp(['sizes: horizontal ',int2str(act_xsize),' vertical ',int2str(act_ysize)]);

lineadd=0;
if(metadatasize>0)
 xs=uint32(fix((double(bitpix)+7)/8));
 xs=xs*uint32(act_xsize);
 i=uint16(floor(metadatasize/double(xs)));
 lineadd=i+1;
end

imasize= uint32(fix((double(bitpix)+7)/8)) * uint32(act_ysize+lineadd)* uint32(act_xsize);

%only for firewire add always some lines
%to ensure enough memory is allocated for the transfer
if(interface==INTERFACE_FIREWIRE)
  imas=uint32(fix((double(bitpix)+7)/8));
  imas= imas*uint32(act_ysize+lineadd)* uint32(act_xsize);
  i=floor(double(imas)/4096);
  i=i+1;
  i=i*4096;
  imasize=i;
  i=i-double(imas);
  xs=uint32(fix((double(bitpix)+7)/8));
  xs=xs*uint32(act_xsize);
  i=floor(i/double(xs));
  i=i+1;
  lineadd=lineadd+i;
 disp(['imasize is: ',int2str(imas),' aligned: ',int2str(imasize)]);
end
disp([int2str(lineadd),' additional lines must be allocated ']);

%Allocate data array for images
image_stack=ones(act_xsize,(act_ysize+lineadd),'uint16');

sBufNr=int16(-1);
im_ptr = libpointer('uint16Ptr',image_stack(:,:));
ev_ptr = libpointer('voidPtr');

%Allocate a SDK buffer and set address of buffer from data array image_stack
[errorCode,out_ptr,sBufNr]  = calllib('PCO_CAM_SDK','PCO_AllocateBuffer', out_ptr,sBufNr,imasize,im_ptr,ev_ptr);
if(errorCode)
 pco_errdisp('PCO_AllocateBuffer',errorCode);
 clear image_stack;
 commandwindow;
 return;
end

disp(['bufnr: ',int2str(sBufNr)]);

subfunc.fh_start_camera(out_ptr);

disp('get image');
tic;
%add the allocated buffer
[errorCode]  = calllib('PCO_CAM_SDK','PCO_AddBufferEx', out_ptr,0,0,sBufNr,act_xsize,act_ysize,bitpix);
if(errorCode)
 pco_errdisp('PCO_AddBufferEx',errorCode);
end

trigdone=int16(1);
[errorCode,out_ptr,trigdone]  = calllib('PCO_CAM_SDK','PCO_ForceTrigger',out_ptr,trigdone);
if(errorCode)
 pco_errdisp('PCO_ForceTrigger',errorCode);
else
 disp(['trigger done return: ',int2str(trigdone)]);
end

buflist=libstruct('PCO_Buflist');
buflist.sBufnr_1=uint16(sBufNr);
[errorCode,out_ptr,buflist]  = calllib('PCO_CAM_SDK','PCO_WaitforBuffer', out_ptr,1,buflist,1000);
if(errorCode)
 pco_errdisp('PCO_WaitforBuffer',errorCode);
else
 disp('PCO_WaitforBuffer done');
end

if(errorCode==PCO_NOERROR)
%disp(['statusdll: ',num2str(buflist_1.dwStatusDll,'%08X'),' statusdrv: ',num2str(buflist_1.dwStatusDrv,'%08X')]);
%test and display buffer
 if((bitand(buflist.dwStatusDll_1,hex2dec('00008000')))&&(buflist.dwStatusDrv_1==0))
  disp(['Event for buffer done, StatusDrv ',num2str(buflist.dwStatusDrv_1,'%08X')]);
%show image
  ima=im_ptr.Value;
  if(reduce_display_size~=0)
   [xs,ys]=size(ima);
   xmax=800;
   ymax=600;
   if((xs>xmax)&&(ys>ymax))
    ima=ima(1:xmax,1:ymax);
   elseif(xs>xmax)
    ima=ima(1:xmax,:);
   elseif(ys>ymax)
    ima=ima(:,1:ymax);
   end
  end
  ima=ima';
  m=max(max(ima(10:end-10,10:end-10)));
  imshow(ima,[0,m+100]);
  disp(['found max ',int2str(m)]);
 end
end

subfunc.fh_stop_camera(out_ptr);

%this will remove all pending buffers in the queue
[errorCode] = calllib('PCO_CAM_SDK', 'PCO_CancelImages', out_ptr);
if(errorCode)
 pco_errdisp('PCO_CancelImages',errorCode);
end

disp('Press "Enter" to close window and proceed')
pause();
close();

%set changed values back
subfunc.fh_set_triggermode(out_ptr,TRIGGER_MODE_AUTOTRIGGER);
%set saved RecoderSubmode
[errorCode] = calllib('PCO_CAM_SDK', 'PCO_SetRecorderSubmode', out_ptr,prev_rec_submode);
if(errorCode)
 pco_errdisp('PCO_SetRecorderSubmode',errorCode);
end

[errorCode] = calllib('PCO_CAM_SDK', 'PCO_ArmCamera', out_ptr);
if(errorCode)
 pco_errdisp('PCO_ArmCamera',errorCode);
end

[errorCode]  = calllib('PCO_CAM_SDK','PCO_FreeBuffer',out_ptr,sBufNr);
if(errorCode)
 pco_errdisp('PCO_FreeBuffer',errorCode);
else
 disp('PCO_FreeBuffer done ');
end

subfunc.fh_stop_camera(out_ptr);

catch ME
 errorCode=subfunc.fh_lasterr();
 txt=blanks(101);
 txt=calllib('PCO_CAM_SDK','PCO_GetErrorTextSDK',pco_uint32err(errorCode),txt,100);

 clearvars -except ME glvar;

 if(glvar.camera_open==1)
  glvar.do_close=1;
  glvar.do_libunload=1;
  pco_camera_open_close(glvar);
 end

 if strfind(ME.identifier,'PCO_ERROR:')
  msg=[ME.identifier,' ',ME.message];
  disp(txt);
  warning('off','backtrace')
  warning(msg)
  for k=1:length(ME.stack)
    disp(['from file ',ME.stack(k).file,' at line ',num2str(ME.stack(k).line)]);
 end
  clearvars;
  commandwindow;
  return;
 else
  clearvars -except ME;
  rethrow(ME)
 end
end

clearvars -except glvar;

if(glvar.camera_open==1)
 glvar.do_close=1;
 glvar.do_libunload=1;
 pco_camera_open_close(glvar);
end

clearvars glvar;
commandwindow;
end


% EEG_EVENTTABLE - returns all events contained in the EEG structure (and
%                    optionally exports them to a CSV file)
%
% Usage:
%   >> events = eeg_eventtable(EEG);
%
% Inputs:
%   EEG          - EEG structure
%
% Optional inputs:
%   'unit'       - Unit of events containing time samples, can be either
%                  'samples' (default) or 'seconds'
%   'dispTable'  - Display an overview of all events if set to true (default);
%                  do not display if set to false
%   'exportFile' - Exports events as a CSV file (using tabs as delimiters); set
%                  this parameter to the file name you wish to export the events
%                  to (string); default: no file is exported
%   'indexCol'   - Adds a column with the event indices as the first row; note
%                  that this is not an event field; default: true
%
% Outputs:
%   events       - event structure (cell array)
%
% Examples:
%   Get all events contained in the EEG structure and display an overview:
%     >> events = eeg_eventtable(EEG);
%
%   In addition to displaying an overview, export into a CSV file:
%     >> events = eeg_eventtable(EEG, 'exportFile', 'test.csv');

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

% Revision: 0.15
% Date: 10/13/2011

% Revision history:
%   0.15: Added option to add/remove index column
%   0.11: Changed function name and updated documentation
%   0.10: Initial version

function events = eeg_eventtable(EEG, varargin)

% Default parameters, can be overwritten by varargin
unit = 'samples';  % Unit of latencies is 'samples'
dispTable = true;  % Display the event table
exportFile = [];  % Export events to text file
indexCol = true;  % Add an index column as first column

if ~isempty(varargin)  % Are there optional parameters available?
    k = 1;
    while k <= length(varargin)
        if strcmp(varargin{k}, 'dispTable')
            dispTable = varargin{k + 1};
            k = k + 2;
        elseif strcmp(varargin{k}, 'unit')
            unit = varargin{k + 1};
            k = k + 2;
        elseif strcmp(varargin{k}, 'exportFile')
            exportFile = varargin{k + 1};
            k = k + 2;
        elseif strcmp(varargin{k}, 'indexCol')
            indexCol = varargin{k + 1};
            k = k + 2;
        else  % Ignore unknown parameters
            k = k + 2;
        end
    end
end

fields = fieldnames(EEG.event);  % Get all event fields
nFields = length(fields);  % Number of event fields
nEvents = length(EEG.event);  % Number of events

events = cell(nFields, 1);
for k = 1:nFields
    events{k}.name = fields{k};  % Event name
    events{k}.values = cell(nEvents, 1);  % Will contain values for this event

    for l = 1:nEvents  % Write values
        if strcmp(events{k}.name, 'latency') && strcmp(unit, 'seconds')
            events{k}.values{l} = getfield(EEG.event(l), fields{k})/EEG.srate;
        elseif strcmp(events{k}.name, 'duration') && strcmp(unit, 'seconds')
            events{k}.values{l} = getfield(EEG.event(l), fields{k})/EEG.srate;
        else
            events{k}.values{l} = getfield(EEG.event(l), fields{k});
        end
    end

end

if dispTable || ~isempty(exportFile)  % Display overview or export to CSV file?

    nr = cell(nEvents, 1);  % Consecutive event numbers
    for l = 1:nEvents
        nr{l} = l;  end

    eventsTable = [];
    if indexCol  % Add index column
        titleTable{1} = 'number';
        titleOffset = 1;
    else  % Do not add index column
        titleOffset = 0;
    end
    for k = 1:nFields
        eventsTable = [eventsTable, events{k}.values];
        titleTable{k + titleOffset} = events{k}.name;
    end
    if indexCol
        eventsTable = [nr, eventsTable];  % Add event numbers in first column
    end
    finalTable = [titleTable; eventsTable];  % Add title in first row

    if dispTable
        format('shortG');
        disp(finalTable);
        format;
    end

    if ~isempty(exportFile)
        fid = fopen(exportFile, 'w');
        for rows = 1:size(finalTable, 1)
            for cols = 1:size(finalTable, 2)
                dataValue = finalTable(rows, cols);
                if cols < size(finalTable, 2)  % If we're not in the last column, print the delimiter
                    if iscellstr(dataValue)
                        fprintf(fid, '%s\t', dataValue{:});
                    elseif iscellnumeric(dataValue)
                        fprintf(fid, '%f\t', dataValue{:});
                    end
                else  % If we're in the last column, do not print the delimiter
                    if iscellstr(dataValue)
                        fprintf(fid, '%s', dataValue{:});
                    elseif iscellnumeric(dataValue)
                        fprintf(fid, '%f', dataValue{:});
                    end
                end
            end
            fprintf(fid, '\n');
        end
        fclose(fid);
    end
end

function b = iscellnumeric(C)
% Return 1 if all elements of cell array are numeric

b = all(cellfun(@(x) isnumeric(x),C));


function [NUM,file,fileExt] = calculateNumber(imgPath)
    imgExt = {'*.bmp', '*.jpg', '*.png'};
    k=1;
    d1 = dir([imgPath char(imgExt(k))]);
    file = {d1(~[d1.isdir]).name};
    if isempty(file)
        k = k + 1;
        d1 = dir([imgPath char(imgExt(k))]);
        file = {d1(~[d1.isdir]).name};
        if isempty(file)
            k = k + 1;
            d1 = dir([imgPath char(imgExt(k))]);
            file = {d1(~[d1.isdir]).name};
            NUM = length(file);
        else
            NUM = length(file);
        end
    else
        NUM = length(file);
    end
    fileExt = char(imgExt(k));
end


function F = remap(F,old,new)

F = flatten(F);
for i = 1:length(F.clauses)
    X = F.clauses{i}.data;
    X = sdpvarremap(X,old,new);
    F.clauses{i}.data = X;
end


function [C]=structComplete(A,B,emptyFixOpt)

% function [C]=structComplete(A,B,emptyFixOpt)
% ------------------------------------------------------------------------
% This function fills in the missing data in the structure A with the
% content from B. The structure B can be seen as a default input structure
% for instance and A might be an incomplete set of inputs. The optional
% parameter emptyFixOpt (0=no, 1=yes) determines whether empty entries in A
% are overwritten by the corresponding default values in B.
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% 2017/11/20
%------------------------------------------------------------------------

%%

fieldNameSet=fieldnames(B);

C=A; %Initialize C as the same as A
for q=1:1:numel(fieldNameSet) %Loop over field names
    fieldNameNow=fieldNameSet{q}; %Current field name
    if isfield(A,fieldNameNow) %If A contains the field in B

        if isempty(A.(fieldNameNow)) %if the field in A is empty
            if emptyFixOpt==1 %if empty field fixing is on
                C.(fieldNameNow)=B.(fieldNameNow); %Replace empty in C by default
            end
        end

        if isstruct(A.(fieldNameNow)) && isstruct(B.(fieldNameNow)) %If the field in A is a structure, check structure recursively
            [C.(fieldNameNow)]=structComplete(A.(fieldNameNow),B.(fieldNameNow),emptyFixOpt);
        end

    else %If the field is missing, add it
        C.(fieldNameNow)=B.(fieldNameNow);
    end
end

%%
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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/>.


function [isLFP] = bz_isLFP(lfp)
% USAGE
% [] = bz_isLFP(lfp)
%
% INPUT
%       lfp   - struct with the following fields
%                   .lfp
%                   .timestamps
%                   .samplingRate
%                   .channels
%
%
% OUTPUT
%      logical true if struct meets lfp criteria, false if otherwise
%
% written by david tingley, 2017

if isfield(lfp,'data') && isfield(lfp,'timestamps') && isfield(lfp,'samplingRate') && isfield(lfp,'channels') % check that fields exist
     if ismatrix(lfp.data) && isvector(lfp.timestamps) && isnumeric(lfp.samplingRate) && isvector(lfp.channels)
         isLFP = true;
     else
         warning('one of the required fields for a lfp type is not formatted correctly')
         isLFP = false;
     end
else
    warning('one of the required fields for a lfp type does not exist')
    isLFP = false;
end


function checkopt(inopt, dfopt)

% checkopt -- Check options structure for unrecognized fields
%
% Usage:
%       checkopt(inopt, dfopt)
%
% Input:
%       inopt         Input options structure
%       dfopt         Default options structure
%
%
% Author: Brendt Wohlberg <brendt@lanl.gov>  Modified: 2015-06-17
%
% This file is part of the SPORCO library. Details of the copyright
% and user license can be found in the 'License' file distributed with
% the library.

if ~isempty(inopt) && (~isfield(inopt,'NoOptionCheck') || ~inopt.NoOptionCheck),
  ifnc = fieldnames(inopt);
  for k = 1:length(ifnc),
    ifn = ifnc{k};
    if ~strcmp(ifn, 'NoOptionCheck') && ~isfield(dfopt, ifn),
      warning('SPORCO:UnknownOption', 'Unknown option field %s', ifn);
    end
  end
end

return


function x = utl_check_fingerprint(x,opts,ctx,exp)
% Check whether the given argument is an inconsistent impure expression.
% Data = utl_check_fingerprint(Data,Options,Context,Expressions)
%
% The remaining arguments are used only when the function is used as an argstep in exp_beginfun.
% There, it serves as an argstep for 'filter'/'editing' functions, to check, fix up and warn about the value of
% inconsistent impure expressions (expressions referring to signals, in particular) and data set values
% (without any notion of expressions).
%
% See also:
%   hlp_fingerprint, exp_beginfun, exp_endfun
%
%                                        Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                        2010-04-15

if nargin < 2
    opts.fingerprint_check = true;
    exp = [];
    ctx = [];
end

if isfield(x,'tracking') && all(isfield(x.tracking,{'expression','fingerprint'}))
    % get the fingerprint checking expression (either from the options or from the dynamic context)
    if isempty(opts.fingerprint_check)
        opts.fingerprint_check = hlp_resolve('fingerprint_check',true,ctx); end
    % this check can be selectively overridden with a block-scoped symbol 'fingerprint_check', which may be an expression that involves @expression
    % (the expression for which we are about to execute the check)
    if hlp_microcache('fprint_lookup',@is_enabled,opts.fingerprint_check,exp)
        if ~isequal(hlp_fingerprint(rmfield(x,'tracking')),x.tracking.fingerprint)
            error('The fingerprint of the given data structure does not match that of its expression.'); end
    end
end

% find out whether a given reference expression yields true if @expression is substituted with some substitution expression
function res = is_enabled(ref_exp,subs_exp)
if exp_eval(utl_releasehold(utl_replacerepeated(ref_exp,{exp_rule(@expression,subs_exp)})),inf)
    res = true;
else
    res = false;
end


function options = pnopt_optimset( varargin )
% pnopt_optimset : Set options for PNOPT
%
% options = pnopt_optimset( 'param1', val1, 'param2', val2,... ) creates an options
%   structure in which the named parameters have the specified values. Default
%   values are used for parameters that are not specified.
%
% pnopt_optimset with no input arguments and no output arguments displays all
%   parameter names and their default values.
%
%   $Revision: 0.8.0 $  $Date: 2012/12/01 $
%
  % Print out possible values of options.
  if nargin == 0 && nargout == 0
    fprintf('Default parameters for PNOPT:\n');
    fprintf('     curv_param : [  positive scalar |     0.9 ] \n');
    fprintf('          debug : [          logical |       0 ] \n');
    fprintf('     desc_param : [  positive scalar |  0.0001 ] \n');
    fprintf('        display : [ positive integer |      10 ] \n');
    fprintf('      Lbfgs_mem : [ positive integer |      50 ] \n');
    fprintf('  backtrack_mem : [ positive integer |      10 ] \n');
    fprintf('       maxfunEv : [ positive integer |    5000 ] \n');
    fprintf('        maxIter : [ positive integer |     500 ] \n');
    fprintf('         method : [           string |   Lbfgs ] \n');
    fprintf(' subprob_solver : [           string |  sparsa ] \n');
    fprintf('           ftol : [  positive scalar |    1e-9 ] \n');
    fprintf('      optim_tol : [  positive scalar |    1e-6 ] \n');
    fprintf('           xtol : [  positive scalar |    1e-9 ] \n');
    fprintf('\n');
    return;
  end

  Names = [
    'curv_param     '
    'debug          '
    'desc_param     '
    'display        '
    'Lbfgs_mem      '
    'backtrack_mem  '
    'maxfunEv       '
    'maxIter        '
    'method         '
    'sparsa_options '
    'subprob_solver '
    'Tfocs_opts     '
    'ftol           '
    'optim_tol      '
    'xtol           '
    'useMex         '
    ];

  [m,n] = size(Names); %#ok<NASGU>
  names = lower(Names);

  % Combine all leading options structures o1, o2, ... in l1Set(o1,o2,...).
  options = [];
  for j = 1:m
    eval(['options.' Names(j,:) '= [];']);
  end
  i = 1;
  while i <= nargin
    arg = varargin{i};
    if ischar(arg), break; end
    if ~isempty(arg)                      % [] is a valid options argument
      if ~isa(arg,'struct')
        error(sprintf(['Expected argument %d to be a string parameter name ' ...
          'or an options structure\ncreated with SetPNoptOptions.'], i)); %#ok<SPERR>
      end
      for j = 1:m
        if any(strcmp(fieldnames(arg),deblank(Names(j,:))))
          eval(['val = arg.' Names(j,:) ';']);
        else
          val = [];
        end
        if ~isempty(val)
          eval(['options.' Names(j,:) '= val;']);
        end
      end
    end
    i = i + 1;
  end

  % A finite state machine to parse name-value pairs.
  if rem(nargin-i+1,2) ~= 0
    error('Arguments must occur in name-value pairs.');
  end
  expectval = 0;                          % start expecting a name, not a value
  while i <= nargin
    arg = varargin{i};

    if ~expectval
      if ~ischar(arg)
         error('Expected argument %d to be a string parameter name.', i);
      end

      lowArg = lower(arg);
      j = strmatch(lowArg,names);
      if isempty(j)                       % if no matches
        error('Unrecognized parameter name ''%s''.', arg);
      elseif length(j) > 1                % if more than one match
        % Check for any exact matches (in case any names are subsets of others)
        k = strmatch(lowArg,names,'exact');
        if length(k) == 1
          j = k;
        else
          msg = sprintf('Ambiguous parameter name ''%s'' ', arg);
          msg = [msg '(' deblank(Names(j(1),:))]; %#ok<AGROW>
          for k = j(2:length(j))'
            msg = [msg ', ' deblank(Names(k,:))]; %#ok<AGROW>
          end
          error('%s).', msg);
        end
      end
      expectval = 1;                      % we expect a value next

    else
      eval(['options.' Names(j,:) '= arg;']);
      expectval = 0;

    end
    i = i + 1;
  end

  if expectval
    error('Expected value for parameter ''%s''.', arg);
  end


function varargout=lin2pcma(varargin)
%
% For calling details please see v_lin2pcma.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_lin2pcma.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: lin2pcma.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_lin2pcma(varargin{:});
else
    v_lin2pcma(varargin{:});
end


function varargout=sumann(varargin)
%
% report=sumann(recName,annName,stopTime,qrsAnnotationsOnly)
%
%    Wrapper to WFDB SUMANN:
%         http://www.physionet.org/physiotools/wag/sumann-1.htm
%
% Reads a WFDB annotation file and summarize its contents.
%
% Ouput Parameters:
%
% report
%       String with the contaning summary of the contents, including the
%       number of annotations of each type as well the duration and number of
%      episodes of each rhythm and signal quality.
%
%Input Parameters:
% recName
%       String specifying the WFDB record file.
%
% annName
%       String specifying the reference WFDB annotation file.
%
% stopTime (Optional)
%       String specifying the stop time in WFDB format (default is end of
%       record).
%
% qrsAnnotationsOnly (Optional)
%       1x1 Boolean. If true, summarize QRS annotation only (default = 0).
%
%
% Written by Ikaro Silva, 2013
% Last Modified: -
% Version 1.0
% Since 0.9.0
%
% %Example (this will generate a /mitdb/100.qrs file at your directory):
%
% report=sumann('mitdb/100','atr');
%
%
%
% See also RDANN, MXM, WFDBTIME, BXB

%endOfHelp

javaWfdbExec=getWfdbClass('sumann');

%Set default pararamter values
inputs={'recName','annName','stopTime','qrsAnnotationsOnly'};
recName=[];
annName=[];
stopTime=[];
qrsAnnotationsOnly=0;
for n=1:nargin
    if(~isempty(varargin{n}))
        eval([inputs{n} '=varargin{n};']);
    end
end

wfdb_argument={'-r',recName,'-a',annName};

if(~isempty(stopTime))
     wfdb_argument{end+1}='-t';
    wfdb_argument{end+1}=stopTime;
end
if(qrsAnnotationsOnly)
     wfdb_argument{end+1}='-q';
end

report=javaWfdbExec.execToStringList(wfdb_argument);
if(nargout>0)
   varargout{1}=report;
end