function mrAnatAverageAcpcAnalyze(fileNameList, outFileBaseName, alignLandmarks, newMmPerVox, weights, bb, clipVals, showFigs);
%
% mrAnatAverageAcpcAnalyze(fileNameList, outFileBaseName, [alignLandmarks=[]], ...
%                          [newMmPerVox=[1 1 1]], [weights=ones(size(fileNameList))], ...
%                          [bb], [clipVals], [showFigs=1])
%
% Reslices the first analyze file to ac-pc space at
% 1x1x1mm resolution and then aligns all the rest of the analyze
% files to that one and averages them all together.
%
% You can specify the ac-pc landmarks as a 3x3 matrix of the form:
%  [ acX, acY, acZ; pcX, pcY, pcZ; midSagX, midSagY, midSagZ ]
% Where:
%  X is the (left -> right) location of a point,
%  Y is the (posterior -> anterior) location of a point,
%  Z is the (inferior -> superior) location of a point,
% ac is the anterior commissure, pc is the posterior commissure, and midSag
% is another poit in the mid-sagittal plane that is somewhat distant from
% the ac-pc line. These 3 points define the rotation/translation into ac-pc
% space. If the ac is properly set in the image header, then you can just
% pass in the pc and midSag coords, specified as the offset from the ac.
%
% If these landmarks aren't provided, then the xform from the image header
% is used. Note that if the image origin isn't close to the AC, then the
% default bounding box ([-90,90; -126,90; -72,108]') won't be appropriate.
%
% weights specifies the weighting factor to be applied to each of the input
% images (fileNameList).
%
% REQUIRES:
%  * Stanford anatomy tools (eg. /usr/local/matlab/toolbox/mri/Anatomy)
%  * spm2 tools (eg. /usr/local/matlab/toolbox/mri/spm2)
%
% HISTORY:
% 2004.11.10 RFD (bob@white.stanford.edu) wrote it, based on averageAnalyze
if ~exist('showFigs','var') | isempty(showFigs), showFigs = 1; end

if (~exist('fileNameList','var') | isempty(fileNameList) | ...
        ~exist('outFileBaseName','var') | isempty(outFileBaseName))
    help(mfilename);
    return;
end
if (~exist('newMmPerVox','var') | isempty(newMmPerVox))
    newMmPerVox = [1 1 1];
end
if ~exist('saveIntermediate','var') | isempty(saveIntermediate)
  saveIntermediate = 0;
end

if (~exist('alignLandmarks','var')) alignLandmarks = []; end

if ~exist('weights','var') | isempty(weights)
  weights = ones(size(fileNameList));
end

if(~exist('bb','var') | isempty(bb))
    % Bounding box, in physical space (ie. mm from the origin, which should be
    % at or near the AC).
    bb = [-90,90; -126,90; -72,108]';
end

if (~exist('clipVals','var')) clipVals = []; end

% from spm_bsplins:
% d(1:3) - degree of B-spline (from 0 to 7) along different dimensions
% d(4:6) - 1/0 to indicate wrapping along the dimensions
% not sure what wrapping is, but '7' is the highest quality (but slowest).
bSplineParams = [7 7 7 0 0 0];

% We explicitly initialize the spm_defaults global here, and ensure that
% the analyze_flip option is turned off. (Our analyze files are never
% right-left reversed!)
spm_defaults;
defaults.analyze.flip = 0;

numImages = length(fileNameList);

% Load the first image (the reference)
[refImg,mmPerVox,refImgHdr] = loadAnalyze(fileNameList{1});

if(isempty(clipVals))
  clipVals = repmat([0.4 0.98],numImages,1);
end

refImg = mrAnatHistogramClip(refImg, clipVals(1,1), clipVals(1,2));
%[refImg, lc, uc] = mrAnatHistogramClipOptimal(refImg, 99);
%fprintf('\nClipped reference image at [%0.1f, %0.1f].\n', lc, uc);

if(isempty(alignLandmarks))
    % *** TO DO: allow user to select the landmarks!
    tal2ref = inv(refImgHdr.mat);

else
    if(size(alignLandmarks,1)==2)
        origin = inv(refImgHdr.mat)*[0 0 0 1]'-0.5;
        %origin(3) = size(refImg,3)-origin(3);
        %alignLandmarks(:,3) = -alignLandmarks(:,3);
        origin = origin(1:3)';
        imY = alignLandmarks(1,:); imY = imY./norm(imY);
        imZ = alignLandmarks(2,:); imZ = imZ./norm(imZ);
    else
        %% flip 3rd axis
        %alignLandmarks(:,3) = size(refImg,3)-alignLandmarks(:,3);
        % The first landmark should be the anterior commissure (AC)- our origin
        origin = alignLandmarks(1,:);
        % Define the current image axes by re-centering on the origin (the AC)
        imY = alignLandmarks(2,:)-origin; imY = imY./norm(imY);
        imZ = alignLandmarks(3,:)-origin; imZ = imZ./norm(imZ);
    end
    % x-axis (left-right) is the normal to [ac, pc, mid-sag] plane
    imX = cross(imZ,imY);
    % Make sure the vectors point right, superior, anterior
    if(imX(1)<0) imX = -imX; end
    if(imY(2)<0) imY = -imY; end
    if(imZ(3)<0) imZ = -imZ; end
    % Project the current image axes to the cannonical AC-PC axes. These
    % are defined as X=[1,0,0], Y=[0,1,0], Z=[0,0,1], with the origin
    % (0,0,0) at the AC. Note that the following are the projections
    x = [0 1 imY(3)]; x = x./norm(x);
    y = [1  0 imX(3)]; y = y./norm(y);
    %z = [0  imX(2) 1]; z = z./norm(z);
    z = [0  -imY(1) 1]; z = z./norm(z);
    % Define the 3 rotations using the projections. We have to set the sign
    % of the rotation, depending on which side of the plane we came from.
    rot(1) = sign(x(3))*acos(dot(x,[0 1 0])); % rot about x-axis (pitch)
    rot(2) = sign(y(3))*acos(dot(y,[1 0 0])); % rot about y-axis (roll)
    rot(3) = sign(z(2))*acos(dot(z,[0 0 1])); % rot about z-axis (yaw)

    scale = mmPerVox;

    % Affine build assume that we need to translate before rotating. But,
    % our rotations have been computed about the origin, so we'll pass a
    % zero translation and set it ourselves (below).
    ref2tal = affineBuild([0 0 0], rot, scale, [0 0 0]);
    tal2ref = inv(ref2tal);

    % Insert the translation.
    tal2ref(1:3,4) = [origin+newMmPerVox/2]';
end

% Resample it to 1x1x1
disp('Resampling reference image to ac-pc space, isotropic voxels...');
[newRefImg,xform] = mrAnatResliceSpm(refImg, tal2ref, bb, newMmPerVox, bSplineParams, showFigs);
newOrigin = inv(xform)*[0 0 0 1]'; newOrigin = newOrigin(1:3)'-newMmPerVox/2;
% Reclip in case the interpolation introduced out-of-range values
newRefImg(newRefImg<0) = 0; newRefImg(newRefImg>1) = 1;
if(showFigs)
    o = round(newOrigin);
    figure; set(gcf,'Name',[fileNameList{1} ' (ref)']);
    subplot(1,3,1); imagesc(flipud(squeeze(newRefImg(:,:,o(3)))')); axis image; colormap gray;
    subplot(1,3,2); imagesc(flipud(squeeze(newRefImg(:,o(2),:))')); axis image; colormap gray;
    subplot(1,3,3); imagesc(flipud(squeeze(newRefImg(o(1),:,:))')); axis image; colormap gray;
    %imagesc(makeMontage(refImg,[20:4:size(newRefImg,3)-18]));axis image;colormap gray;
    %title([fileNameList{1} ' (reference image) aligned.']);
    pause(0.1);
end
Vref.uint8 = uint8(round(newRefImg.*255));
Vref.mat = xform;

outImg = newRefImg.*weights(1);
numSamples = zeros(size(outImg));
nans = isnan(outImg);
numSamples(~nans) = weights(1);
outImg(nans) = 0;
for(ii=2:numImages)
    if(saveIntermediate)
        % We do this first since the final result will be saved after this loop.
        fname = sprintf('%s_%d',outFileBaseName,ii-1);
        disp(['writing intermediate result ',fname,'...']);
        img = outImg;
        nz = numSamples>0;
        img(nz) = img(nz)./numSamples(nz);
        img = img-min(img(:));
        img = int16(img.*(32767/max(img(:))));
        saveAnalyze(img, fname, newMmPerVox, ['AVERAGE:' refImgHdr.descrip], newOrigin);
    end
    fprintf('Aligning %s to reference image...\n',fileNameList{ii});
    [img,mmPerVox,hdr] = loadAnalyze(fileNameList{ii});
    img = mrAnatHistogramClip(img, clipVals(ii,1), clipVals(ii,2));
    %[img, lc, uc] = mrAnatHistogramClipOptimal(img, 99);
    %fprintf('Clipped image %d at [%0.1f, %0.1f].\n', ii, lc, uc);
    Vin.uint8 = uint8(round(img.*255));
    Vin.mat = hdr.mat;
    %transRot = spm_coreg(Vin, Vref);
    %xform = spm_matrix(transRot(:)')*Vin.mat\Vref.mat*inv(Vref.mat);
    transRot = spm_coreg(Vref, Vin);
    xform = inv(Vin.mat)*spm_matrix(transRot(:)');
    fprintf('Resampling %s to reference image...\n',fileNameList{ii});
    [img,xform] = mrAnatResliceSpm(img, xform, bb, newMmPerVox, bSplineParams, showFigs);
    % Reclip in case the interpolation introduced out-of-range values
    img(img<0) = 0; img(img>1) = 1;
    if(showFigs)
        o = round(newOrigin);
    	figure; set(gcf,'Name',[fileNameList{ii}]);
        subplot(1,3,1); imagesc(flipud(squeeze(img(:,:,o(3)))')); axis image; colormap gray;
        subplot(1,3,2); imagesc(flipud(squeeze(img(:,o(2),:))')); axis image; colormap gray;
        subplot(1,3,3); imagesc(flipud(squeeze(img(o(1),:,:))')); axis image; colormap gray;
        %figure; imagesc(makeMontage(img,[20:4:size(img,3)-18])); axis image; colormap gray;
        %title([fileNameList{ii} ' aligned.']);
        pause(0.1);
    end
    nans = isnan(img);
    numSamples(~nans) = numSamples(~nans)+weights(ii);
    img(nans) = 0;
    outImg = outImg+img.*weights(ii);
end
% Rescale based on the number of samples at each voxel
nz = numSamples>0;
outImg(nz) = outImg(nz)./numSamples(nz);

if(showFigs)
    o = round(newOrigin);
    figure; set(gcf,'Name',['Average']);
    subplot(1,3,1); imagesc(flipud(squeeze(outImg(:,:,o(3)))')); axis image; colormap gray;
    subplot(1,3,2); imagesc(flipud(squeeze(outImg(:,o(2),:))')); axis image; colormap gray;
    subplot(1,3,3); imagesc(flipud(squeeze(outImg(o(1),:,:))')); axis image; colormap gray;
    figure; imagesc(makeMontage(outImg,[20:4:size(outImg,3)-18])); axis image; colormap gray;
    title(['Average aligned.']);
    pause(0.1);
end

% rescale to 15 bits (0-32767)
outImg = outImg-min(outImg(:));
outImg = int16(outImg.*(32767/max(outImg(:))));

disp(['writing ',outFileBaseName,'...']);
hdr = saveAnalyze(outImg, outFileBaseName, newMmPerVox, ['AVERAGE:' refImgHdr.descrip], newOrigin);

return;


function [net_conv, net_fc, opts] = mdnet_init(image, net)
% MDNET_INIT
% Initialize MDNet tracker.
%
% Hyeonseob Nam, 2015
%

%% set opts
% use gpu
opts.useGpu = true;

% model def
opts.net_file = net;

% test policy
opts.batchSize_test = 256; % <- reduce it in case of out of gpu memory

% bounding box regression
opts.bbreg = true;
opts.bbreg_nSamples = 1000;

% learning policy
opts.batchSize = 128;
opts.batch_pos = 32;
opts.batch_neg = 96;

% initial training policy
opts.learningRate_init = 0.0001; % x10 for fc6
opts.maxiter_init = 30;

opts.nPos_init = 500;
opts.nNeg_init = 5000;
opts.posThr_init = 0.7;
opts.negThr_init = 0.5;

% update policy
opts.learningRate_update = 0.0003; % x10 for fc6
opts.maxiter_update = 10;

opts.nPos_update = 50;
opts.nNeg_update = 200;
opts.posThr_update = 0.7;
opts.negThr_update = 0.3;

opts.update_interval = 10; % interval for long-term update

% data gathering policy
opts.nFrames_long = 100; % long-term period
opts.nFrames_short = 20; % short-term period

% cropping policy
opts.input_size = 107;
opts.crop_mode = 'wrap';
opts.crop_padding = 16;

% scaling policy
opts.scale_factor = 1.05;

% sampling policy
opts.nSamples = 256;
opts.trans_f = 0.6; % translation std: mean(width,height)*trans_f/2
opts.scale_f = 1; % scaling std: scale_factor^(scale_f/2)

% set image size
opts.imgSize = size(image);

%% load net
net = load(opts.net_file);
if isfield(net,'net'), net = net.net; end
net_conv.layers = net.layers(1:10);
net_fc.layers = net.layers(11:end);
clear net;

for i=1:numel(net_fc.layers)
    switch (net_fc.layers{i}.name)
        case {'fc4','fc5'}
            net_fc.layers{i}.filtersLearningRate = 1;
            net_fc.layers{i}.biasesLearningRate = 2;
        case {'fc6'}
            net_fc.layers{i}.filtersLearningRate = 10;
            net_fc.layers{i}.biasesLearningRate = 20;
    end
end

if opts.useGpu
    net_conv = vl_simplenn_move(net_conv, 'gpu') ;
    net_fc = vl_simplenn_move(net_fc, 'gpu') ;
else
    net_conv = vl_simplenn_move(net_conv, 'cpu') ;
    net_fc = vl_simplenn_move(net_fc, 'cpu') ;
end

end


% nbins = 8;
% psize = 10;
% npatches = 8;
% optflowwinsig = 3;
% optflowsig = 2;
% optreliability = 1e-4;
% patchsz = psize*npatches;

params = getParams;
npatches = params.npatches;
psize = params.psize;
nbins = params.nbins;
patchsz = params.patchsz;
scale = params.scale;

optflowwinsig = params.optflowwinsig ;
optflowsig = params.optflowsig ;
optreliability = params.optreliability ;

maxflow = 5;
fly_thres = 90;
flow_thres = params.flow_thres;

makeVideo = false;

% Antennal grooming for andy
expdir = '/home/mayank/Dropbox/ForMayankFromAlice/grooming_GMR_30B01_AE_01_CsChr_RigB_20150903T161828/';
fly = 1;
frames = 5961:5980;

% expdir = '../mated10_20140714T131113';
% % frames = 10900 +(1:200);
% % fly = 1;
% fly = 1;
% % frames = 11043; % large middle leg movement
% frames = 10925; % large middle leg movement

% expdir = '/home/mayank/Work/FlySpaceTime/walkMovies/SS03500';
% fly = 1;
% frames = 10200 + (1:100);
% frames = 735:780;
% fly = 3;
% frames = 1886:1888;
% frames = 1477:1477;

% fly = 2; % This one shows the failure of HS-brightness on rear leg.
% frames = 5503;

[~,expname] = fileparts(expdir);
moviefilestr = 'movie.ufmf';
moviefile = fullfile(expdir,moviefilestr);
trxfilestr = 'trx.mat';
trxfile = fullfile(expdir,trxfilestr);

[readframe,nframes] = get_readframe_fcn(moviefile);
td = load(trxfile);
tracks = td.trx;
dx = []; dy = [];
theta = [];
rdx = [];rdy = [];
im1 = []; im2 = []; im3 = [];
for i = 1:numel(frames),
  curf = readframe(frames(i));
  nextf = readframe(frames(i)+1);

  trackndx = frames(i) - tracks(fly).firstframe + 1;
  locy = round(tracks(fly).y(trackndx));
  locx = round(tracks(fly).x(trackndx));
  curpatch = extractPatch(curf,...
    locy,locx,tracks(fly).theta(trackndx),patchsz);
  locy = round(tracks(fly).y(trackndx+1));
  locx = round(tracks(fly).x(trackndx+1));
  curpatch2 = extractPatch(nextf,...
    locy,locx,tracks(fly).theta(trackndx+1),patchsz);

  curpatch3 = extractPatch(nextf,...
    locy,locx,tracks(fly).theta(trackndx),patchsz);

  im1(:,:,i) = curpatch;
  im2(:,:,i) = curpatch2;
  im3(:,:,i) = curpatch3;
  dx(i) = round(tracks(fly).x(trackndx+1))-round(tracks(fly).x(trackndx));
  dy(i) = round(tracks(fly).y(trackndx+1))-round(tracks(fly).y(trackndx));
  rdx(i) = tracks(fly).x(trackndx+1)-tracks(fly).x(trackndx)-dx(i);
  rdy(i) = tracks(fly).y(trackndx+1)-tracks(fly).y(trackndx)-dy(i);
  dtheta(i) = tracks(fly).theta(trackndx+1)-tracks(fly).theta(trackndx);
  theta(i) = tracks(fly).theta(trackndx);
end

[nr,nc,~] = size(im1);
%
% figure out the histogram bins
tmptheta = (0:179)*pi/180;
res = nan(nbins,numel(tmptheta));
m = single(ones(10,10));
o = single(zeros(10,10));
for i = 1:numel(tmptheta),
%   fprintf('i = %d, theta = %f\n',i,tmptheta(i));
  o(:) = single(tmptheta(i));
  rescurr = gradientHist(m,o,1,nbins,1);
  res(:,i) = rescurr(1,1,:);
end

bincenters = nan(1,nbins);
for i = 1:nbins,
  bincenters(i) = tmptheta(argmax(res(i,:)));
end

% this seems to be what the centers correspond to
bincenters = linspace(0,pi,nbins+1);
bincenters = bincenters(1:nbins);

% mayank divides by 2
bincenters2 = bincenters*2;
dt = mean(diff(bincenters2));
binedges2 = [bincenters2(1)-dt/2,(bincenters2(1:end-1)+bincenters2(2:end))/2,bincenters2(end)+dt/2];

%% make a video

tr = 191;
hfig = 100;
t0 = frames(1);
t1 = frames(end);
colorpos = [1,0,0];
colorneg = [0,.3,1];

maxv2 = 0;
colors = hsv(nbins);
sz = size(im1);
bwimg = zeros(sz(1),sz(2));
ctr = [ceil( (sz(1)+1)/2),ceil( (sz(2)+1)/2)];
bwimg(ctr(1),ctr(2))=1;
dimg = bwdist(bwimg,'euclidean');
[xx,yy]= meshgrid(1:sz(2),1:sz(1));
aimg = atan2(-(yy-ctr(1)),-(xx-ctr(2)));

for t = t0:20:t1,

  im1curr = im1(:,:,t-t0+1);
  im2curr = im2(:,:,t-t0+1);
%   [Vx,Vy,~] = optFlowLk(im1(:,:,i),im2(:,:,i),[],optflowwinsig,optflowsig,optreliability);
%  [Vx,Vy,] = optFlowHorn(im1curr,im2curr,optflowsig);
  uv = estimate_flow_interface(im1curr,im2curr,'hs-brightness',{'max_warping_iters',10});
%   uv = estimate_flow_interface(im1curr,im2curr,'ba-brightness');
  Vx = uv(:,:,1); Vy = uv(:,:,2);

%   Vx = Vx-dx(t-t0+1);
%   Vy = Vy-dy(t-t0+1);

  M = sqrt(Vx.^2 + Vy.^2);
  O = mod(atan2(Vy,Vx)/2,pi);
  O = min(O,pi-1e-6);
  H = gradientHist(single(M),single(O),psize,nbins,1);
  maxv2 = max(maxv2,max(H(:)));
end

%%
if makeVideo
  vid = VideoWriter(sprintf('%s_Fly%d_From%d_To%d_HOF_%s.avi',expname,fly,t0,t1,datestr(now,'yyyymmdd')));
  open(vid);
end

dd_err = dimg/patchsz;
% There is some flow towards the center in certain cases.
% d_err is for that.

for t = t0:t1,

  im1curr = im1(:,:,t-t0+1);
  im2curr = im2(:,:,t-t0+1);

  imsz = size(im1curr);
  pairimg = zeros(2*imsz(1),3*imsz(2),3);
  ttimg = [];
  tt(:,:,1) = im2curr;
  tt(:,:,2) = im1curr;
  tt(:,:,3) = im2curr;
  pairimg(1:imsz(1),:,:) = repmat(tt,[1 3 1]);

%   [Vx,Vy,~] = optFlowLk(im1curr,im2curr,[],3);
%   [Vx,Vy,~] = optFlowLk(im1curr,im2curr,[],optflowwinsig,optflowsig,optreliability);
%   [Vx,Vy,] = optFlowHorn(im1curr,im2curr,optflowsig);
  uv = estimate_flow_interface(im1curr,im2curr,'hs-brightness',...
    {'max_warping_iters',2 });
%   uv = estimate_flow_interface(im1curr,im2curr,'ba-brightness',{'max_warping_iters',2 });
%   uv = estimate_flow_interface(im1curr,im2curr,'classic++');
  uvorig = uv;
  pairimg(imsz(1)+(1:imsz(1)),1:imsz(2),:) = flowToColor(uv,maxflow);

  cdx = dx(t-t0+1);
  cdy = dy(t-t0+1);
  curt = theta(t-t0+1);
  rotd = [cos(curt) sin(curt); -sin(curt) cos(curt)]*[cdx;cdy];
  cdx = -rotd(1); cdy = -rotd(2);

  ctheta = dtheta(t-t0+1);
  rotflowu = dimg.*(cos(aimg+ctheta)-cos(aimg));
  rotflowv = dimg.*(sin(aimg+ctheta)-sin(aimg));

  uv = uvorig;
  dd1 = sqrt( (uv(:,:,1)-cdx-rotflowu).^2 + (uv(:,:,2)-cdy-rotflowv).^2);
  for ndx = 1:2
    tt = uv(:,:,ndx);
    tt(dd1< (dd_err+flow_thres)) = 0;
    uv(:,:,ndx) = tt;
  end
  uvmotion = uv;
  pairimg(imsz(1)+(1:imsz(1)),imsz(2)+(1:imsz(2)),:) = flowToColor(uvmotion,maxflow);

  % Using bkg/fkg.
%   fly_bod = im1curr<fly_thres;
%   fly_flow = zeros(1,2);
%   for ndx = 1:2
%     tt = uv(:,:,ndx);
%     fly_flow(ndx) = median(tt(fly_bod));
%   end

  %using computation.
  crdx = rdx(t-t0+1);  crdy = rdy(t-t0+1);
  rotd = [cos(curt) sin(curt); -sin(curt) cos(curt)]*[crdx;crdy];
  fly_flow = rotd;

  uv = uvorig;
  dd2 = sqrt( (uv(:,:,1)-fly_flow(1)).^2 + (uv(:,:,2)-fly_flow(2)).^2);
  dd = min(dd1,dd2);
  for ndx = 1:2
    tt = uv(:,:,ndx);
    tt( dd<(dd_err+flow_thres)) = 0;
    uv(:,:,ndx) = tt;
  end
  uvall = uv;

  pairimg(imsz(1)+(1:imsz(1)),2*imsz(2)+(1:imsz(2)),:) = flowToColor(uvall,maxflow);

  pairimg = uint8(pairimg);
  pairimg = imresize(pairimg,scale);
  Vx = uvorig(:,:,1); Vy = uvorig(:,:,2);
  M = sqrt(Vx.^2 + Vy.^2);
  O = mod(atan2(Vy,Vx)/2,pi);
  O = min(O,pi-1e-6);
  Horig = gradientHist(single(M),single(O),psize,nbins,1);

  Vx = uvmotion(:,:,1); Vy = uvmotion(:,:,2);
  M = sqrt(Vx.^2 + Vy.^2);
  O = mod(atan2(Vy,Vx)/2,pi);
  O = min(O,pi-1e-6);
  Hmotion = gradientHist(single(M),single(O),psize,nbins,1);

  Vx = uvall(:,:,1); Vy = uvall(:,:,2);
  M = sqrt(Vx.^2 + Vy.^2);
  O = mod(atan2(Vy,Vx)/2,pi);
  O = min(O,pi-1e-6);
  Hall = gradientHist(single(M),single(O),psize,nbins,1);

  if t == t0,
    figure(hfig);
    clf;
    hax = axes('Position',[0,0,1,1]);
    set(hfig,'Units','pixels','Position',get(0,'ScreenSize'));

    him = imshow(pairimg);
    axis image;
    truesize;
    colormap gray;
    hold on;
    axis off;
    htext = text(1,nr-1,sprintf('%.2f s',(t-1)/200),'Color','k','HorizontalAlignment','left','VerticalAlignment','bottom','FontSize',18);

  else
    delete(horig(ishandle(horig)));
    delete(hmotion(ishandle(hmotion)));
    delete(hall(ishandle(hall)));
    set(him,'CData',pairimg);
    set(htext,'String',sprintf('%.2f s',(t-1)/200));
  end

  horig = plotHofFeatures(Horig,hax,maxv2,colors,binedges2,psize*scale,[0 0]);
  hmotion = plotHofFeatures(Hmotion,hax,maxv2,colors,binedges2,psize*scale,[imsz(2) 0]*scale);
  hall = plotHofFeatures(Hall,hax,maxv2,colors,binedges2,psize*scale,[2*imsz(2) 0]*scale);

  drawnow;
  if makeVideo
    fr = getframe(hax);
    writeVideo(vid,fr);
  elseif t0<t1
    pause;
  end
end

if makeVideo,  close(vid); end


% STD_PLOTTF - plot ERSP/ITC images a component
%              or channel cluster in a STUDY. Also allows plotting scalp
%              maps.
% Usage:
%          >> std_plottf( times, freqs, data, 'key', 'val', ...)
% Inputs:
%  times - [vector] latencies in ms of the data points.
%  freqs - [vector] frequencies in Hz of the data points.
%  data  -  [cell array] mean data for each subject group and/or data
%           condition. For example, to plot mean ERPs from a STUDY
%           for epochs of 800 frames in two conditions from three groups
%           of 12 subjects:
%
%           >> data = { [800x12] [800x12] [800x12];... % 3 groups, cond 1
%                       [800x12] [800x12] [800x12] };  % 3 groups, cond 2
%           >> std_plottf(erp_ms,data);
%
%           By default, parametric statistics are computed across subjects
%           in the three groups. (group,condition) ERP averages are plotted.
%           See below and >> help statcond
%           for more information about the statistical computations.
%
% Optional display parameters:
%  'datatype'    - ['ersp'|'itc'] data type {default: 'ersp'}
%  'titles'      - [cell array of string] titles for each of the subplots.
%                  { default: none}
%
% Statistics options:
%  'groupstats'  - ['on'|'off'] Compute (or not) statistics across groups.
%                  {default: 'off'}
%  'condstats'   - ['on'|'off'] Compute (or not) statistics across groups.
%                  {default: 'off'}

%  'threshold'   - [NaN|real<<1] Significance threshold. NaN -> plot the
%                  p-values themselves on a different figure. When possible,
%                  significance regions are indicated below the data.
%                  {default: NaN}
%  'maskdata'    - ['on'|'off'] when threshold is non-NaN and not both
%                  condition and group statistics are computed, the user
%                  has the option to mask the data for significance.
%                  {default: 'off'}
%
% Other plotting options:
%  'plotmode'    - ['normal'|'condensed'] statistics plotting mode:
%                  'condensed' -> plot statistics under the curves
%                  (when possible); 'normal' -> plot them in separate
%                  axes {default: 'normal'}
%  'freqscale'   - ['log'|'linear'|'auto'] frequency plotting scale. This
%                  will only change the ordinate not interpolate the data.
%                  If you change this option blindly, your frequency scale
%                  might be inaccurate {default: 'auto'}
%
% ITC/ERSP image plotting options:
%  'tftopoopt'   - [cell array] TFTOPO plotting options (ERSP and ITC)
%  'caxis'       - [min max] color axis (ERSP, ITC, scalp maps)
%
% Scalp map plotting options:
%  'chanlocs'    - [struct] channel location structure
%
% Author: Arnaud Delorme, CERCO, CNRS, 2006-
%
% See also: POP_ERSPPARAMS, POP_ERPPARAMS, POP_SPECPARAMS, STATCOND

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

function [pgroup, pcond, pinter] = std_plottf(timevals, freqs, data, varargin)

pgroup = [];
pcond  = [];
pinter = [];
if nargin < 2
    help std_plottf;
    return;
end

opt = finputcheck( varargin, { 'titles'         'cell'   []              cellfun(@num2str, cell(20,20), 'uniformoutput', false);
                               'caxis'          'real'   []              [];
                               'ersplim'        'real'   []              []; % same as above
                               'itclim'         'real'   []              []; % same as above
                               'ylim'           'real'   []              [];
                               'tftopoopt'      'cell'   []              {};
                               'threshold'      'real'   []              NaN;
                               'unitx'          'string' []              'ms'; % just for titles
                               'unitcolor'      'string' {}              'dB';
                               'chanlocs'       'struct' []              struct('labels', {});
                               'freqscale'      'string' { 'log','linear','auto' }  'auto'; % note that paramsersp in std_erspplot contains the information as well
                               'effect'         'string' { 'main','marginal' }   'marginal';
                               'averagemode'    'string' { 'rms','ave' }   'rms';
                               'events'         'cell'   []              {};
                               'groupstats'     'cell'   []              {};
                               'condstats'      'cell'   []              {};
                               'interstats'     'cell'   []              {};
                               'maskdata'       'string' { 'on','off' }   'off';
                               'plottopo'       'string' { 'on','off' }   'off';
                               'datatype'       'string' { 'ersp','itc' 'erpim' }    'ersp';
                               'plotmode'       'string' { 'normal','condensed' }  'normal' }, 'std_plottf');
if ischar(opt), error(opt); end
if all(all(cellfun('size', data, 3)==1))               opt.singlesubject = 'on'; end

% remove empty entries
datapresent = ~cellfun(@isempty, data);
for c = size(data,1):-1:1, if sum(datapresent(c,:)) == 0, data(c,:) = []; opt.titles(c,:) = []; if ~isempty(opt.groupstats), opt.groupstats(c) = []; end; end; end
for g = size(data,2):-1:1, if sum(datapresent(:,g)) == 0, data(:,g) = []; opt.titles(:,g) = []; if ~isempty(opt.condstats ), opt.condstats( g) = []; end; end; end

if ~isempty(opt.groupstats) && ~isempty(opt.condstats) && strcmpi(opt.maskdata, 'on')
    disp('Cannot use ''maskdata'' option with both condition stat. and group stat. on');
    disp('Disabling statistics');
    opt.groupstats = {}; opt.condstats = {}; opt.maskdata = 'off';
end
if ~isempty(opt.ersplim), opt.caxis = opt.ersplim; end
if ~isempty(opt.itclim), opt.caxis = opt.itclim; end
onecol  = { 'b' 'b' 'b' 'b' 'b' 'b' 'b' 'b' 'b' 'b' };
manycol = { 'b' 'r' 'g' 'k' 'c' 'y' };

nc = size(data,1);
ng = size(data,2);
if nc >= ng, opt.transpose = 'on';
else         opt.transpose = 'off';
end

% test log frequencies
% --------------------
if length(freqs) > 2 && strcmpi(opt.freqscale, 'auto')
    midind  = floor(length(freqs)/2);
    if abs(freqs(midind)/freqs(end) - 1/2) < 0.1, opt.freqscale = 'linear';
    else                                          opt.freqscale = 'log';
    end
end

% condensed plot
% --------------
if strcmpi(opt.plotmode, 'condensed')
    meanplot = zeros(size(data{1},1), size(data{1},2));
    count = 0;
    for c = 1:nc
        for g = 1:ng
            if ~isempty(data{c,g})
                meanplot = meanplot + mean(data{c,g},3);
                count = count+1;
            end
        end
    end
    meanplot = meanplot/count;
    options = { 'chanlocs', opt.chanlocs, 'electrodes', 'off', 'cbar', 'on', ...
            'cmode', 'separate', opt.tftopoopt{:} };
    if strcmpi(opt.datatype, 'erpim'), options = { options{:} 'ylabel' 'Trials' }; end
    if strcmpi(opt.freqscale, 'log'), options = { options{:} 'logfreq', 'native' }; end
    tftopo( meanplot', timevals, freqs, 'title', opt.titles{1}, options{:});
    currentHangle = gca;
    if ~isempty( opt.caxis )
        caxis( currentHangle, opt.caxis )
    end
    cbar_standard(opt.datatype, ng, opt.unitcolor);
    axes(currentHangle);
    return;
end

% plotting parameters
% ------------------
if ng > 1 && ~isempty(opt.groupstats), addc = 1; else addc = 0; end
if nc > 1 && ~isempty(opt.condstats  ), addr = 1; else addr = 0; end

% compute significance mask
% --------------------------
pinterplot = {};
if strcmpi(opt.effect, 'marginal') || ng == 1 || nc == 1
    if ~isnan(opt.threshold) && ( ~isempty(opt.groupstats) || ~isempty(opt.condstats) )
        pcondplot  = opt.condstats;
        pgroupplot = opt.groupstats;
        maxplot = 1;
    else
        for ind = 1:length(opt.condstats),  pcondplot{ind}  = -log10(opt.condstats{ind}); end
        for ind = 1:length(opt.groupstats), pgroupplot{ind} = -log10(opt.groupstats{ind}); end
        maxplot = 3;
    end
elseif strcmpi(opt.effect, 'main') && ~isempty(opt.interstats)
    if ~isnan(opt.threshold) && ( ~isempty(opt.groupstats) || ~isempty(opt.condstats) )
        pcondplot  = { opt.interstats{2} };
        pgroupplot = { opt.interstats{1} };
        pinterplot = opt.interstats{3};
        maxplot = 1;
    else
        if ~isempty(opt.interstats{2}), pcondplot  = { -log10(opt.interstats{2}) }; end
        if ~isempty(opt.interstats{1}), pgroupplot = { -log10(opt.interstats{1}) }; end
        if ~isempty(opt.interstats{3}), pinterplot = -log10(opt.interstats{3}); end
        maxplot = 3;
    end
end

% -------------------------------
% masking for significance of not
% -------------------------------
statmask = 0;
if strcmpi(opt.maskdata, 'on') && ~isnan(opt.threshold) && ...
        (~isempty(opt.condstats) || ~isempty(opt.condstats))
    addc = 0; addr = 0; statmask = 1;
end

% -------------------------
% plot time/frequency image
% -------------------------
options = { 'chanlocs', opt.chanlocs, 'electrodes', 'off', 'cbar', 'off', ...
            'cmode', 'separate', opt.tftopoopt{:} };
if strcmpi(opt.freqscale, 'log'), options = { options{:} 'logfreq', 'native' }; end
if strcmpi(opt.datatype, 'erpim'), options = { options{:} 'ylabel' 'Trials' }; end

% adjust figure size
% ------------------
fig = figure('color', 'w');
pos = get(fig, 'position');
set(fig, 'position', [ pos(1)+15 pos(2)+15 pos(3)/2.5*(nc+addr), pos(4)/2*(ng+addc) ]);
pos = get(fig, 'position');
if strcmpi(opt.transpose, 'off'), set(gcf, 'position', [ pos(1) pos(2) pos(4) pos(3)]);
else                              set(gcf, 'position', pos);
end

% options
% -------
options = { 'limits' [NaN NaN NaN NaN opt.caxis] 'verbose' 'off' 'mode' opt.averagemode options{:} };

for c = 1:nc
    for g = 1:ng
        %hdl(c,g) = mysubplot(nc+addr, ng+addc, g + (c-1)*(ng+addc), opt.transpose);
        hdl(c,g) = mysubplot(nc+addr, ng+addc, c, g, opt.transpose);
        if ~isempty(data{c,g})
            if strcmpi(opt.plottopo, 'off')
                tmpplot = mean(data{c,g},3);
            else
                tmpplot = data{c,g};
                tmpplot = permute(tmpplot, [3 1 2 4]);
            end
            if ~isreal(tmpplot(1)), tmpplot = abs(tmpplot); end % comes second for processing single trials
            if statmask,
                if ~isempty(opt.condstats), tmpplot(find(pcondplot{g}(:) == 0)) = 0;
                else                        tmpplot(find(pgroupplot{c}(:) == 0)) = 0;
                end
            end
            if ~isempty(opt.events) && ~isempty(opt.events{c,g})
                 tmpevents = mean(opt.events{c,g},2);
            else tmpevents = [];
            end
            if strcmpi(opt.plottopo, 'on') && length(opt.chanlocs) > 1
                metaplottopo(tmpplot, 'chanlocs', opt.chanlocs, 'plotfunc', 'tftopo', 'squeeze', 'on', ...
                    'plotargs', { timevals, freqs, 'events', tmpevents, options{:} }, 'title', opt.titles{c,g});
            else
                tftopo( tmpplot, timevals, freqs, 'events', tmpevents, 'title', opt.titles{c,g}, options{:});
            end

            if c > 1
                ylabel('');
            end
        end

        % statistics across groups
        % -------------------------
        if strcmpi(opt.effect, 'marginal') || (strcmpi(opt.effect, 'main') && c == 1)
            if g == ng && ng > 1 && ~isempty(opt.groupstats) && ~isinf(pgroupplot{c}(1)) && ~statmask
                if strcmpi(opt.effect, 'main') && nc>1, centerc = nc/2-0.5; else centerc = 0; end
                hdl(c,g+1) = mysubplot(nc+addr, ng+addc, c+centerc, ng + 1, opt.transpose);
                pgroupplot{c}(pgroupplot{c}<0) = 0;
                tmpOptions = { 'limits' [nan nan nan nan -maxplot maxplot] options{3:end} };
                if strcmpi(opt.plottopo, 'on') && length(opt.chanlocs) > 1
                    metaplottopo(permute(pgroupplot{c}, [3 1 2]), 'chanlocs', opt.chanlocs, 'plotfunc', 'tftopo', 'squeeze', 'on', ...
                        'plotargs', { timevals, freqs, tmpOptions{:} }, 'title', opt.titles{c,g+1});
                else
                    tftopo( pgroupplot{c}, timevals, freqs, 'title', opt.titles{c,g+1}, tmpOptions{:});
                end
            end
        end
    end
end

for g = 1:ng
    % statistics across conditions
    % -----------------------------
    if strcmpi(opt.effect, 'marginal') || (strcmpi(opt.effect, 'main') && g == 1)
        if ~isempty(opt.condstats) && ~isinf(pcondplot{g}(1)) && ~statmask && nc > 1
            if strcmpi(opt.effect, 'main') && ng>1, centerg = ng/2-0.5; else centerg = 0; end
            hdl(nc+1,g) = mysubplot(nc+addr, ng+addc, nc+addr, g+centerg, opt.transpose);
            pcondplot{g}(pcondplot{g}<0) = 0;
            tmpOptions = { 'limits' [nan nan nan nan -maxplot maxplot] options{3:end} };
            if strcmpi(opt.plottopo, 'on') && length(opt.chanlocs) > 1
                metaplottopo(permute(pcondplot{g}, [3 1 2]), 'chanlocs', opt.chanlocs, 'plotfunc', 'tftopo', 'squeeze', 'on', ...
                    'plotargs', { timevals, freqs, tmpOptions{:} }, 'title', opt.titles{nc+1,g});
            else
                tftopo( pcondplot{g}, timevals, freqs, 'title', opt.titles{nc+1,g}, options{:});
            end
        end
    end
end

% statistics across group and conditions
% ---------------------------------------
if ~isempty(opt.groupstats) && ~isempty(opt.condstats) && ng > 1 && nc > 1 && ~isempty(pinterplot)
    hdl(nc+1,ng+1) = mysubplot(nc+addr, ng+addc, nc+addr, ng+1, opt.transpose);
    pinterplot(pinterplot<0) = 0;
    tftopo( pinterplot,  timevals, freqs, 'title', opt.titles{nc+1,ng+1}, options{:});
    caxis([-maxplot maxplot]);
    ylabel('');
end

% color bars
% ----------
axes(hdl(nc,ng));
cbar_standard(opt.datatype, ng, opt.unitcolor);
if isnan(opt.threshold) && (nc ~= size(hdl,1) || ng ~= size(hdl,2))
    ind = find(ishandle(hdl(end:-1:1)));
    axes(hdl(end-ind(1)+1));
    cbar_signif(ng, maxplot);
end

% mysubplot2 (allow to transpose if necessary)
% -------------------------------------------
function hdl = mysubplot(nr,nc,r,c,subplottype)

    cmargin = 0.2/nc;
    rmargin = 0.2/nr;
    if strcmpi(subplottype, 'transpose') || strcmpi(subplottype, 'on'),   hdl = subplot('position',[(r-1)/nr+rmargin (nc-c)/nc+cmargin 1/nr-2*rmargin 1/nc-2*cmargin]);
    elseif strcmpi(subplottype, 'normal') || strcmpi(subplottype, 'off'), hdl = subplot('position',[(c-1)/nc+cmargin (nr-r)/nr+rmargin 1/nc-2*cmargin 1/nr-2*rmargin]);
    elseif strcmpi(subplottype, 'noplot'), hdl = gca;
    else error('Unknown subplot type');
    end

% % mysubplot (allow to transpose if necessary)
% % -------------------------------------------
% function hdl = mysubplot(nr,nc,ind,transp);
%
%     r = ceil(ind/nc);
%     c = ind -(r-1)*nc;
%     if strcmpi(transp, 'on'), hdl = subplot(nc,nr,(c-1)*nr+r);
%     else                      hdl = subplot(nr,nc,(r-1)*nc+c);
%     end

% colorbar for ERSP and scalp plot
% --------------------------------
function cbar_standard(datatype, ng, unitcolor);
    pos = get(gca, 'position');
    tmpc = caxis;
    fact = fastif(ng == 1, 40, 20);
    tmp = axes('position', [ pos(1)+pos(3)+max(pos(3)/fact,0.006) pos(2) max(pos(3)/fact,0.01) pos(4) ]);
    set(gca, 'unit', 'normalized');
    if strcmpi(datatype, 'itc')
         cbar(tmp, 0, tmpc, 10); ylim([0.5 1]);
         title('ITC','fontsize',10,'fontweight','normal','interpreter','none');
    elseif strcmpi(datatype, 'erpim')
        cbar(tmp, 0, tmpc, 5);
    else
        cbar(tmp, 0, tmpc, 5);
        title(unitcolor);
    end

% colorbar for significance
% -------------------------
function cbar_signif(ng, maxplot);
    % Retrieving Defaults
    icadefs;

    pos = get(gca, 'position');
    tmpc = caxis;
    fact = fastif(ng == 1, 40, 20);
    tmp = axes('position', [ pos(1)+pos(3)+max(pos(3)/fact,0.006) pos(2) max(pos(3)/fact,0.01) pos(4) ]);
    map = colormap(DEFAULT_COLORMAP);
    n = size(map,1);
    cols = [ceil(n/2):n]';
    image([0 1],linspace(0,maxplot,length(cols)),[cols cols]);
    %cbar(tmp, 0, tmpc, 5);
    tick = linspace(0, maxplot, maxplot+1);
    set(gca, 'ytickmode', 'manual', 'YAxisLocation', 'right', 'xtick', [], ...
        'ytick', tick, 'yticklabel', round(10.^-tick*1000)/1000);
    xlabel('');
    colormap(DEFAULT_COLORMAP);

% rapid filtering for ERP
% -----------------------
function tmpdata2 = myfilt(tmpdata, lowpass, highpass, factor, filtertype)

    tmpdata2 = reshape(tmpdata, size(tmpdata,1), size(tmpdata,2)*size(tmpdata,3)*size(tmpdata,4));
    tmpdata2 = eegfiltfft(tmpdata2',lowpass, highpass, factor, filtertype)';
    tmpdata2 = reshape(tmpdata2, size(tmpdata,1), size(tmpdata,2), size(tmpdata,3), size(tmpdata,4));


function events = in_events_xltek(sFile, EventFile)
% IN_EVENTS_XLTEK: Open an XLTEK exported events file (.txt)

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Olivier David, Francois Tadel, 2017

% Open and read file
fid = fopen(EventFile,'r');
% Skip 6 header lines
tmp = fgetl(fid);
tmp = fgetl(fid);
tmp = fgetl(fid);
tmp = fgetl(fid);
tmp = fgetl(fid);
tmp = fgetl(fid);

% Read start time
strLine = fgetl(fid);
[tmp,tmp2] = strtok(strLine);
starttime = strtok(tmp2);
starttime = sum(sscanf(starttime, '%d:%d:%d') .* [3600;60;1]);

% Loop to read all the events
evtLabel = {};
evtTime  = [];
while 1
    % Get line
    strLine = fgetl(fid);
    if (strLine == -1)
        break;
    end
    % Get label and timing
    [tmp1,tmp2] = strtok(strLine);
    [tmp1,tmp2] = strtok(tmp2);
    evtTime(end+1) = sum(sscanf(tmp1, '%d:%d:%d') .* [3600;60;1]) - starttime;
    evtLabel{end+1} = strtrim(tmp2);
end
% Close file
fclose(fid);

% ===== CONVERT TO BRAINSTORM FORMAT =====
% List of events (keep original order)
[uniqueEvt, I] = unique(evtLabel);
uniqueEvt = evtLabel(sort(I));
% Initialize returned structure
events = repmat(db_template('event'), [1, length(uniqueEvt)]);
% Create events list
for iEvt = 1:length(uniqueEvt)
    % Find all the occurrences of event #iEvt
    iMrk = find(strcmpi(evtLabel, uniqueEvt{iEvt}));
    % Add event structure
    events(iEvt).label      = uniqueEvt{iEvt};
    events(iEvt).times      = unique(round(evtTime(iMrk) .* sFile.prop.sfreq)) ./ sFile.prop.sfreq;
    events(iEvt).epochs     = ones(1, length(events(iEvt).times));
    events(iEvt).reactTimes = [];
    events(iEvt).select     = 1;
    events(iEvt).channels   = [];
    events(iEvt).notes      = [];
end


% pop_timtopo() - call the timtopo() function for epoched EEG datasets.
%                 Plots the epoch mean for each channel on a single axis,
%                 plus scalp maps of the data at specified latencies.
% Usage:
%   >> pop_timtopo( EEG, timerange, topotimes, title, 'key', 'val', ...);
%
% Inputs:
%   EEG         - input dataset
%   timerange   - [min max] epoch time range (in ms) to plot
%   topotimes   - array of times to plot scalp maps {Default: NaN
%                 = display scalp map at frame of max var()}
%
% Optional inputs:
%   title       - optional plot title
%   'key','val' - optional topoplot() arguments (see >> help topoplot)
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: timtopo()

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

% 01-25-02 reformated help & license -ad
% 02-16-02 text interface editing -sm & ad
% 03-15-02 add all topoplot options -ad
% 03-18-02 added title -ad & sm

function com = pop_timtopo( EEG, timerange, topotime, plottitle, varargin);

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

if nargin < 3
	promptstr    = { 'Plotting time range (ms):', ...
			         ['Scalp map latencies (ms, NaN -> max-RMS)'], ...
					 'Plot title:' ...
			         'Scalp map options (see >> help topoplot):' };
	inistr       = { [num2str( EEG.xmin*1000) ' ' num2str(EEG.xmax*1000)], ...
			         'NaN', ...
	                 ['ERP data and scalp maps' fastif(~isempty(EEG.setname), [' of ' EEG.setname ], '') ], ...
			         ''  };
	result       = inputdlg2( promptstr, 'ERP data and scalp maps -- pop_timtopo()', 1, inistr, 'pop_timtopo');
	if size(result,1) == 0 return; end;
	timerange    = eval( [ '[' result{1} ']' ] );
	topotime     = eval( [ '[' result{2} ']' ] );
	plottitle    = result{3};
	options      = [ ',' result{4} ];
	figure;
else
	options = [];
	for i=1:length( varargin )
		if isstr( varargin{ i } )
			options = [ options ', ''' varargin{i} '''' ];
		else
			options = [ options ', [' num2str(varargin{i}) ']' ];
		end;
	end;
end;
try, icadefs; set(gcf, 'color', BACKCOLOR, 'Name', ' timtopo()'); catch, end;

if exist('plottitle') ~= 1
    plottitle = ['ERP data and scalp maps' fastif(~isempty(EEG.setname), [' of ' EEG.setname ], '') ];
end;

if ~isempty(EEG.chanlocs)
    if ~isfield(EEG, 'chaninfo'), EEG.chaninfo = []; end;
	SIGTMP = reshape(EEG.data, size(EEG.data,1), EEG.pnts, EEG.trials);
	posi = round( (timerange(1)/1000-EEG.xmin)/(EEG.xmax-EEG.xmin) * (EEG.pnts-1))+1;
	posf = round( (timerange(2)/1000-EEG.xmin)/(EEG.xmax-EEG.xmin) * (EEG.pnts-1))+1;
	if length( options ) < 2
    	timtopo( mean(SIGTMP(:,posi:posf,:),3), EEG.chanlocs, [timerange(1) timerange(2) 0 0], topotime, '', 0, 0, 'chaninfo', EEG.chaninfo);
        com = sprintf('figure; pop_timtopo(%s, [%s], [%s], ''%s'');', inputname(1), num2str(timerange), num2str(topotime), plottitle);
	else
		com = sprintf('timtopo( mean(SIGTMP(:,posi:posf,:),3), EEG.chanlocs, [timerange(1) timerange(2) 0 0], topotime, '''', 0, 0, ''chaninfo'', EEG.chaninfo %s);', options);
		eval(com)
	    com = sprintf('figure; pop_timtopo(%s, [%s], [%s], ''%s'' %s);', inputname(1), num2str(timerange), num2str(topotime), plottitle, options);
	end;
else
	fprintf('Cannot make plot without channel locations\n');
	return;
end;
return;


function Reinforce(~, ~, game, player)

%% REPLACE BUTTONS
button1 = findobj('style', 'pushbutton', 'String', 'Reinforce');
button2 = findobj('style', 'pushbutton', 'String', 'Attack');
delete([button1, button2])

ConfirmBtn = ...
uicontrol('style', 'pushbutton', ...
          'Parent', game.figH, ...
          'Units', 'normalized', ...
          'Position', [0.46 0.87, 0.08, 0.03], ...
          'String', 'Confirm', ...
          'Callback', {@ConfirmReinforcements, game, player}); %5

N = numel(game.board);

%% CALCULATE NUMBER OF EXTRA TROOPS
list = zeros(1, N);
for i = 1:N
    occupant = get(game.board(i).Patch, 'UserData');
    list(i) = (occupant(1) == player);
end
n = floor(sum(list)/3);
if n < 3
    n = 3;
end

%% SET BUTTONDWNFCNS
for i = find(list)
    set(game.board(i).Patch, 'ButtonDownFcn', {@ClickToReinforce, game, player})
end

%% SHOW TEXT
str = sprintf('%s, you may add %d troops.', game.names{player}, n);
set(game.txtH, 'String', str, 'UserData', n);

uiwait(game.figH);  %5

%% CONFIRMED!
delete(ConfirmBtn)
uiresume(game.figH) %2


function [trl] = ft_trialfun_twoclass_classification(cfg)

% FT_TRIALFUN_TWOCLASS_CLASSIFICATION can be used to train and test a real-time
% classifier in offline and online mode. It selects pieces of data in the two classes
% based on two trigger values. The first N occurences in each class are marked as
% training items. All subsequent occurrences are marked as test items.
%
% This function can be used in conjunction with FT_REALTIME_CLASSIFICATION. The
% configuration structure should contain
%   cfg.dataset              = string with the filename
%   cfg.trialfun             = 'ft_trialfun_twoclass_classification'
%   cfg.trialdef.numtrain    = number of training items, e.g. 20
%   cfg.trialdef.eventvalue1 = trigger value for the 1st class
%   cfg.trialdef.eventvalue2 = trigger value for the 2nd class
%   cfg.trialdef.eventtype   = string, e.g. 'trigger'
%   cfg.trialdef.prestim     = latency in seconds, e.g. 0.3
%   cfg.trialdef.poststim    = latency in seconds, e.g. 0.7
%
% See also FT_DEFINETRIAL, FT_TRIALFUN_GENERAL

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

% these are used to count the number of training items in each class
persistent numtrain1
persistent numtrain2

if isempty(numtrain1)
  numtrain1 = 0;
end
if isempty(numtrain2)
  numtrain2 = 0;
end

if isfield(cfg, 'hdr')
  hdr = cfg.hdr;
else
  hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat);
end

if isfield(cfg, 'event')
  event = cfg.event;
else
  event = ft_read_event(cfg.headerfile, 'headerformat', cfg.headerformat);
end

baseline = round(cfg.trialdef.prestim*hdr.Fs);
duration = round(cfg.trialdef.prestim*hdr.Fs + cfg.trialdef.poststim*hdr.Fs);

% make a subset of the interesting events
sel   = strcmp(cfg.trialdef.eventtype, {event.type});
event = event(sel);
num   = length(event);
trl   = zeros(num,5);

for i=1:num
  % determine the location of this trial in the data stream
  begsample = event(i).sample - baseline;
  endsample = begsample + duration - 1;
  offset    = baseline;
  % determine the class and wether this trial is eligeable for training
  if event(i).value==cfg.trialdef.eventvalue1
    class = 1;
    train = (numtrain1 < cfg.trialdef.numtrain); % boolean
    numtrain1 = numtrain1 + train;  % increment the counter
  elseif event(i).value==cfg.trialdef.eventvalue2
    class = 2;
    train = (numtrain2 < cfg.trialdef.numtrain); % boolean
    numtrain2 = numtrain2 + train;  % increment the counter
  else
    % the class is unknown and therefore irrelevant
    class = nan;
    train = false;
  end
  % remember this trial, the class and whether it should be used for training
  trl(i,:) = [begsample endsample offset class train];
end


function makeDatFromCTF(filesearch,datfilename,typego,typebutton)

% makeDatFromCTF
% filesearch is a string that if used with dir, can identify all files
% necssary to include. Make sure you're in the right directory. It should
% lead to files with columns of continuous STIM channel output
% typego lists the types of stim that one should expect button responses
% to.
% typebutton is the button response one should get. 0 if not buttonpress

if (nargin < 3)
    typego = [6 7 8 9];
    typebutton = [2 0 0 0];
end

respvals = [33554432 65536 262144 327680 393216 458752 524288 589824];
resptype = [2 1 4 5 6 7 8 9];
maxtypeval = 589824; % above this should be button presses only.
RESPLENGTH = 50;

fs = 1200;
buttonwait = fs*1.5;
numHeaderLines = 19;
files = dir(filesearch);

allStim = [];
for i = 1:length(files)
    fprintf('Getting Data from %s ... \n',files(i).name);
    [time,stim] = textread(files(i).name,'%f %f','delimiter','\t','headerlines',2);
    allStim = [allStim;stim];
    clear time stim;
end

fid = fopen(datfilename,'W');

for i = 1:numHeaderLines
    fprintf(fid,'\n');
end

fprintf(fid,'Trial\tResp\tType\tCorrect\tLatency\tStim/Resp\n');
fprintf(fid,'-----\t----\t----\t-------\t-------\t---------\n');
fprintf(fid,'1\t0\t1\t1\t1000\tStim\n');

i = 1;
trialnum = 2;
while i <= length(allStim)
    nextJump = 1;
    tmp = allStim(i:min(i+RESPLENGTH,length(allStim)));
    if (tmp(1) > 10 && ~isempty(find(respvals == max(tmp))) && max(tmp) <= maxtypeval)
        type = resptype(find(respvals == max(allStim(i:i+RESPLENGTH))));

        correct = 1;
        latency = 0;
        buttonPressed = 0;

        if (~isempty(find(typego == type))) % s2 occured, look for button press
            validButton = typebutton(find(typego == type));
            j = i + RESPLENGTH;
            correct = 0;

            while j < i + buttonwait % see if a button was pressed during the wait period
                tmp = allStim(j:min(j+RESPLENGTH,length(allStim)));
                if (~isempty(tmp) && tmp(1) > 10 && ~isempty(find(respvals == max(tmp))))
                    latency = round((j - i) * 1000 / fs);
                    buttonPressed = resptype(find(respvals == max(tmp)));
                    j = i + buttonwait;

                end
                j = j + 1;
            end

            if (buttonPressed == validButton)
                correct = 1;
            end

        end

        if (~buttonPressed) % get Latency if not button pressed
            j = i + RESPLENGTH;
            cont = 1;
            while (cont && j < length(allStim))
                j = j + 1;
                tmp = allStim(j:min(j+RESPLENGTH,length(allStim)));
                if (isempty(tmp))
                    cont = 0;
                elseif (tmp(1) > 10 && ~isempty(find(respvals == max(tmp))) && max(tmp) <= maxtypeval)
                    cont = 0;
                end
            end
            latency = round((j - i) * 1000 / fs);
            nextJump = (j - i) - 1;
        else
            nextJump = round(latency * fs / 1000) + RESPLENGTH;
        end
        fprintf(fid,'%d\t%d\t%d\t%d\t%d\tStim\n',trialnum,buttonPressed,type,correct,latency);
        trialnum = trialnum+1;
    end
    i = i + nextJump;
end

fclose(fid);

fprintf('***********************************************\n');
fprintf('%s created successfully: %d events found\n\n',datfilename,trialnum);


function c = minus(c,I)

   % C = MINUS(C,I)
   % The function subtracts the waveform specified by trace index I from all
   % other traces. The resulting correlation object has the same number of
   % traces as the original though trace I is essentially zero amplitude.
   %
   % C = MINUS(C)
   % Short hand version of MINUS where I is assumed to be the last trace in
   % the list. That is, MINUS(C, C.ntraces ). This use is common
   % following the STACK routine.
   %
   % Before using MINUS, time windows need to be cropped to the same interval
   % relative to the triggers. This is most easily accomplished using the CROP
   % function prior to MINUS. If the traces have not been cropped, MINUS will
   % attempt to figure out which time window of data should be differenced.
   % This can result in unanticipated signals at the ends of each trace.
   % Caveat Emptor!
   %
   % MINUS will erase the CORR, LAG, STAT, LINK and CLUST fields from the
   % objects. After differencing, these fields are no longer valid.
   %
   % The traces are not normalized prior to subtracting. For most
   % applications the user will first want to normalize the trace amplitudes
   % using the NORM function. Typically, plots of the residual data will use
   % the 'raw' plotting option.
   %
   % In order to be differenced, the "phase shift" of the samples within the
   % trace must be the same. If it is not, MINUS will make a call to ALIGN to
   % resample all traces such that one sample falls directly on the trigger
   % time.
   %
   % Example - subtract the stacked waveform from each trace
   %   c = xcorr(c)
   %   c = adjusttrig(c)
   %   c = crop(c,-3,5)
   %   c = stack(c)
   %   c = norm(c)      % stacked waveform is the last trace
   %   c_residual = minus(c)
   %   plot(c_residual,'raw');

   % Author: Michael West, Geophysical Institute, Univ. of Alaska Fairbanks
   % $Date$
   % $Revision$

   % READ & CHECK ARGUMENTS
   if ~exist('I','var')
      I = c.ntraces;
   end;
   assert(numel(I)==1, 'Only one trace can be subtracted from the others');

   if check(c,'SCALE')
      disp('Warning: Traces appear to have very different overall amplitudes');
   end

   % CREATE CORREATION OBJECT FOR INTERNAL MANIPULATIONS
   c1 = NewCorrelation;
   c1.traces = c.traces;
   c1.trig = c.trig;
   if exist('index','var')               % Is this necessary?
      c1 = subset(c1,index);
   end

   % CHECK IF TRACES ARE DESCRITIZED ON THE SAME INVERVALS
   t = 86400 * (c1.trig - c1.traces.firstsampletime());
   Fs = c1.samplerate;
   sampleshift = mod(t,1/Fs);
   if (mean(sampleshift) ~= sampleshift)   % if all sampleshifts are the same
      c1 = align(c1);
   end

   % CHECK IF TRACES ARE EQUALLY CROPPED
   pretrig  = c1.traces.firstsampletime() - c1.trig; %ALL? just one?
   posttrig = c1.traces.lastsampletime()  - c1.trig;
   if (mean(pretrig)~=pretrig(1)) || (mean(posttrig)~=posttrig(1))
      center = mean([pretrig ; posttrig])*86400;
      pretrig = center - (0.5 * c1.nsamples * get(c1,'Period'));
      posttrig = pretrig + (c1.nsamples + 1) * get(c1,'Period');
      % is it the right length?
      c1 = crop(c1,pretrig(1),posttrig(1)); %should all have same pre & post
   end

   toSubtract = c1.traces(I).data; %this trace will be subtracted from all
   for i = 1:length(c.trig)
      d = c1.traces(i).data - toSubtract;
      c.traces(i).data = d;
      c.trig(i) = c1.trig(i);
   end
   c.corrmatrix = [];
   c.lags = [];
   c.stat = [];
   c.link = [];
   c.clust = [];
end


function V=mrLoadRet3StatsToAnalyze(outFileName,scanNum,mapName)
%
% V=mrLoadRet3StatsToAnalyze(outFileName,scanNum,mapName)
%
% AUTHOR:  Wade
% DATE: 06.10.03
% PURPOSE:
% Converts a statistical map in a mrLoadRet 3 Gray view into a 8 bit
% analyze file. Data are scaled from 0 to 2^8-1
% Uses the current scan if no scanNum is passed
% mapName can be 'co', 'amp', 'ph' or any other similar statistical map in
% the VOLUME structure.
% If no mapName is passed, it defaults to writing out 'co'.
% If embedDimensions are passed, the data are embedded into an even larger
% volume. This is useful when
% dealing with BV volume anatomies that have been embedded into 256x256x256
%
% RETURNS:
% Number of bytes written in main data block.
%
% EXAMPLE:
% 1) V=mrLoadRet3StatsToAnalyze('temp');
% 2) V=mrLoadRet3StatsToAnalyze('temp_ph','ph');
%
% NOTES
% Originall coded to transfer mrLoadRet gray stats into SSI's EMSE / mrViewer
% $Author: wade $
% $Date: 2003/09/09 21:18:59 $
mrGlobals;
if (isempty(selectedVOLUME))
    error('You must select (click within) a volume window before proceeding');
end

if ((~exist('scanNum','var')) | (isempty(scanNum)))
    scanNum=getCurScan(VOLUME{selectedVOLUME});
end
% Get a coherence threshold
coThresh=getCothresh(VOLUME{selectedVOLUME});

if ((~exist('outFileName','var')) | (isempty(outFileName)))
    a=dataTYPES(VOLUME{selectedVOLUME}.curDataType).name;
    outFileName=[a,'_',int2str(scanNum),'_co_',int2str(coThresh*100)];
end

if ((~exist('mapName','var')) | (isempty(mapName)))
    mapName='co';
end
volAnatSize=size(VOLUME{selectedVOLUME}.anat);
% We need to permute this into the correct format.
volAnatSize=volAnatSize([2 1 3]);
if ((~exist('embedDimensions','var')) | (isempty(embedDimensions)))
    embedDimensions=volAnatSize;
end
if ((~exist('VOLUME','var')) | (isempty(VOLUME{selectedVOLUME}.co)))
    error('mrLoadRet must be running and the GRAY corAnal must be loaded');
end
if (isempty(VOLUME{selectedVOLUME}.anat))
    error('The anatomy must be loaded');
end

% % Find the size of the full anatomy
coords=VOLUME{selectedVOLUME}.coords;
coords=coords';
%
% minVals=min(coords);
% maxVals=max(coords);
% bbSize=maxVals-minVals+1
%
% if(find(bbSize<=0))
%     error('The GRAY data are in an invalid VOI');
% end

dataVolume=uint8(ones(size(VOLUME{selectedVOLUME}.anat)));
[ySiz xSiz zSiz]=size(VOLUME{selectedVOLUME}.anat);

% Do the mother of all sub2inds to get a linear index into dataVolume
coords=sub2ind([ySiz xSiz zSiz],coords(:,1),coords(:,2),coords(:,3));
if (~strcmp(mapName,'co'))
    error('Only co maps allowed for now');
end

co=(VOLUME{selectedVOLUME}.co(scanNum));
co=co{1};

% Now threshold according to the current cothresh
co(co<coThresh)=0;

blurKern=ones(3,3,3);
blurKern=blurKern./sum(blurKern(:));
blurKern=blurKern*20;

co=convn(co,blurKern,'same');
co(co>=1)=0.9999; % Just to make sure
co(co<=0)=0;

% Scale co from 0 to 2^8-1
max(co);
min(co);
% co=log10(co*10);
co(co<=0)=0;
co=co*((2^8)-1);

max(co)
min(co)

% Send it into the large data volume
dataVolume(coords)=(co);

dataVolume=permute(dataVolume,[3 2 1]);
dataVolume=flipdim(dataVolume,3);
%dataVolume=flipdim(dataVolume,2);
dataVolume=flipdim(dataVolume,1);
% Call SPM writevol routine to write out the data.

    s=spm_hwrite(outFileName,[ySiz xSiz zSiz],[1 1 1],1,spm_type('uint8'),0);
    V=spm_vol(outFileName);

    V.descrip=['Converted from tSeries file in session',mrSESSION.sessionCode,' : ',mrSESSION.subject,':  on ',datestr(now)];

    s=spm_write_vol(V,double(dataVolume));

return;


function patcht(FF,VV,TF,VT,I,Options)
% This function PATCHT, will show a triangulated mesh like Matlab function
% Patch but then with a texture.
%
% Alec: Essentially this calls "surface" for each triangle of the triangle mesh
% with the appropriate texture coordinates
%
% patcht(FF,VV,TF,VT,I,Options);
%
% inputs,
%   FF : Face list #F x 3 with vertex indices
%   VV : Vertices #V x 3
%   TF : Texture list #F x 3 with texture vertex indices
%   VT : Texture Coordinates s 2 x #VT, range must be [0..1] or real pixel postions
%   I : The texture-image RGB [O x P x 3] or Grayscale [O x P]
%   Options : Structure with options for the textured patch such as
%           EdgeColor, EdgeAlpha see help "Surface Properties :: Functions"
%
%   Options.PSize : Special option, defines the image texturesize for each
%           individual  polygon, a low number gives a more block
%           like texture, defaults to 64;
%
% note:
%   On a normal PC displaying 10,000 faces will take about 6 sec.
%
% Example,
%
%  % Load Data;
%   load testdata;
%  % Show the textured patch
%   figure, patcht(FF,VV,TF,VT,I);
%  % Allow Camera Control (with left, right and center mouse button)
%   mouse3d
%
%  % file containing image
%  image_source = 'woody.png';
%  % load image with alpha mask
%  [im,map,alpha] = imread(image_source);
%  % mesh based on alpha values with approximately 100 boundary vertices
%  [V,F] = png2mesh(image_source,0,100);
%  % treat alpha as white in display
%  im = over(im,alpha,ones(size(im)),1);
%  % dummy display white image the same size as input image
%  imshow(ones([max(V(:,2))-min(V(:,2)) max(V(:,1))-min(V(:,1))]));
%  % display original mesh
%  % reverse y-direction so mesh display is upright (we're displaying the mesh
%  % ontop of the imshow() display to get pixel perfect images)
%  patcht(F,[V(:,1) size(im,1)-V(:,2)],F,V,permute(flipdim(im,1),[2 1 3]));
%  % create some trivial deformation
%  new_V = [V(:,1) 2*V(:,2)];
%  figure;
%  % dummy display white image the same size as input image
%  imshow(ones([max(new_V(:,2))-min(new_V(:,2)) max(new_V(:,1))-min(new_V(:,1))]));
%  % display deformed mesh
%  patcht(F,[new_V(:,1) max(new_V(:,2)+0.5)-new_V(:,2)],F,V,permute(flipdim(im,1),[2 1 3]));
%
% Function is written by D.Kroon University of Twente (July 2010)

% FaceColor is a texture
Options.FaceColor='texturemap';
% noe edges
Options.EdgeColor='none';

% Size of texture image used for every triangle
if(isfield(Options,'PSize'))
    sizep=round(Options.PSize(1));
    Options=rmfield(Options,'PSize');
else
    sizep=64;
end

% Check input sizes
if(size(FF,2)~=size(TF,2))
    error('patcht:inputs','Face list must be equal in size to texture-index list');
end

if((ndims(I)~=2)&&(ndims(I)~=3))
    error('patcht:inputs','No valid Input texture image');
end

% Detect if grayscale or color image
switch(size(I,3))
    case 1
        iscolor=false;
    case 3
        iscolor=true;
    otherwise
        error('patcht:inputs','No valid Input texture image');
end

if(max(VT(:))<2)
    % Remap texture coordinates to image coordinates
    VT2(:,1)=(size(I,1)-1)*(VT(:,1))+1;
    VT2(:,2)=(size(I,2)-1)*(VT(:,2))+1;
else
    VT2=VT;
end

% Calculate the texture interpolation values
[lambda1 lambda2 lambda3 jind]=calculateBarycentricInterpolationValues(sizep);

% Split texture-image in r,g,b to allow fast 1D index
Ir=I(:,:,1); if(iscolor), Ig=I(:,:,2); Ib=I(:,:,3); end

% The Patch used for every triangle (rgb)
Jr=zeros([(sizep+1) (sizep+1) 1],class(I));
if(iscolor)
    Jg=zeros([(sizep+1) (sizep+1) 1],class(I));
    Jb=zeros([(sizep+1) (sizep+1) 1],class(I));
end

% if no z coordinates are given then use 0s
if size(VV,2) < 3
  VV = [VV zeros(size(VV,1),1)];
end

hold on;
% Loop through all triangles of the mesh
for i=1:size(FF,1)
    % Get current triangle vertices and current texture-vertices
    V=VV(FF(i,:),:);
    Vt=VT2(TF(i,:),:);

    % Define the triangle as a surface
    x=[V(1,1) V(2,1); V(3,1) V(3,1)];
    y=[V(1,2) V(2,2); V(3,2) V(3,2)];
    z=[V(1,3) V(2,3); V(3,3) V(3,3)];

    % Define the texture coordinates of the surface
    tx=[Vt(1,1) Vt(2,1) Vt(3,1) Vt(3,1)];
    ty=[Vt(1,2) Vt(2,2) Vt(3,2) Vt(3,2)] ;
    xy=[tx(1) ty(1); tx(2) ty(2); tx(3) ty(3); tx(3) ty(3)];

    % Calculate texture interpolation coordinates
    pos(:,1)=xy(1,1)*lambda1+xy(2,1)*lambda2+xy(3,1)*lambda3;
    pos(:,2)=xy(1,2)*lambda1+xy(2,2)*lambda2+xy(3,2)*lambda3;
    pos=round(pos); pos=max(pos,1); pos(:,1)=min(pos(:,1),size(I,1)); pos(:,2)=min(pos(:,2),size(I,2));
    posind=(pos(:,1)-1)+(pos(:,2)-1)*size(I,1)+1;

    % Map texture to surface image
    Jr(jind)=Ir(posind);
    J(:,:,1)=Jr;
    if(iscolor)
        Jg(jind)=Ig(posind);
        Jb(jind)=Ib(posind);
        J(:,:,2)=Jg;
        J(:,:,3)=Jb;
    end

    % Show the surface
    surface(x,y,z,J,Options)
end
hold off;

function [lambda1 lambda2 lambda3 jind]=calculateBarycentricInterpolationValues(sizep)
% Define a triangle in the upperpart of an square, because only that
% part is used by the surface function
x1=sizep; y1=sizep; x2=sizep; y2=0; x3=0 ;y3=0;
% Calculate the bary centric coordinates (instead of creating a 2D image
% with the interpolation values, we map them directly to an 1D vector)
detT = (x1-x3)*(y2-y3) - (x2-x3)*(y1-y3);
[x,y]=ndgrid(0:sizep,0:sizep); x=x(:); y=y(:);
lambda1=((y2-y3).*(x-x3)+(x3-x2).*(y-y3))/detT;
lambda2=((y3-y1).*(x-x3)+(x1-x3).*(y-y3))/detT;
lambda3=1-lambda1-lambda2;
% Make from 2D (surface)image indices 1D image indices
[jx jy]=ndgrid(sizep-(0:sizep)+1,sizep-(0:sizep)+1);
jind=(jx(:)-1)+(jy(:)-1)*(sizep+1)+1;


function ps_parms_default()
%PS_PARMS_DEFAULT set parms to default value if not already set
%
%   Andy Hooper, June 2006
%
%   ======================================================================
%   04/2008 AH: SB default processing corrected
%   06/2009 AH: scla_deramp added
%   08/2009 AH: unwrap_gold_alpha added
%   09/2009 AH: merge_resample_size added
%   09/2009 AH: select_method added
%   09/2009 AH: density_rand added
%   11/2009 AH: pixel_aspect_ratio removed
%   01/2010 AH: add check for write permission before saving
%   02/2010 AH: weed_alpha replaced by weed_time_win
%   02/2010 AH: weed_max_noise added
%   02/2010 AH: plot_pixel_size replaced by plot_scatterer_size (in m)
%   02/2010 AH: plot_dem_posting added
%   02/2010 AH: ref_centre_lonlat and ref_radius added
%   02/2010 AH: unwrap_ifg_index replaced by drop_ifg_index
%   02/2010 AH: weed_time_win and unwrap_time_win default changed to 730
%   03/2010 AH: add logging
%   09/2010 MA: oversampling factor
%   09/2010 AH: plot_pixels_scatterer added
%   11/2010 AH: (sb_)recalc_index replaced by (sb_)scla_drop_index
%   06/2011 AH: add weed_neighbours
%   12/2012 AH: add insar_processor
%   06/2013 DB: add parameters to include tropopshere in scla estimation
%   01/2014 DB: Add wavelength and heading to parameters list. This in case
%               not all stamps steps are ran.
%   01/2014 DB: Add a multi-core option for step 1-5
%   02/2014 AH: add unwrap_hold_good_values
%   08/2014 DB: explicit search if there is not a processor.txt file
%   05/2015 AH: add gamma_max_iterations
%   09/2015 AH: change default weed_neighbours = 'n'
%   09/2015 AH: change default max_topo_err = 20
%   10/2016 DB: Change other processor type to a warning not an error.
%   ======================================================================

parmfile='parms.mat';
parent_flag=0;

if exist('./parms.mat','file')
    parms=load(parmfile);
elseif exist('../parms.mat','file')
    parmfile='../parms.mat';
    parms=load(parmfile);
    parent_flag=1;
else
    parms=struct('Created',date);
    parms.small_baseline_flag='n';
end

parmfields_before=fieldnames(parms);
num_fields=size(parmfields_before,1);

if ~isfield(parms,'max_topo_err')
    parms.max_topo_err=20;
end

if ~isfield(parms,'quick_est_gamma_flag')
    parms.quick_est_gamma_flag='y';
end

if ~isfield(parms,'select_reest_gamma_flag')
    parms.select_reest_gamma_flag='y';
end

if ~isfield(parms,'filter_grid_size')
    parms.filter_grid_size=50;
end

if ~isfield(parms,'filter_weighting')
    parms.filter_weighting='P-square'; % filter weighting strategy
end

if ~isfield(parms,'gamma_change_convergence')
    parms.gamma_change_convergence=0.005; % change in change in gamma that signals convergence
end

if ~isfield(parms,'gamma_max_iterations')
    parms.gamma_max_iterations=3; % maximum number of iterations for gamma estimation
end

if ~isfield(parms,'slc_osf')
    parms.slc_osf=1;  % [MA] SLC oversampling factor
end

if ~isfield(parms,'clap_win')
    parms.clap_win=32;
end

if ~isfield(parms,'clap_low_pass_wavelength')
    parms.clap_low_pass_wavelength=800;
end

if ~isfield(parms,'clap_alpha')
    parms.clap_alpha=1;
end

if ~isfield(parms,'clap_beta')
    parms.clap_beta=0.3;
end

if ~isfield(parms,'select_method')
    parms.select_method='DENSITY'; %'DENSITY' or 'PERCENT'
end

if ~isfield(parms,'density_rand')
    if strcmpi(parms.small_baseline_flag,'y')
        parms.density_rand=2;  % Random-phase pixels per km2 (before weeding)
    else
        parms.density_rand=20; % Random-phase pixels per km2 (before weeding)
    end
end

if ~isfield(parms,'percent_rand')
    if strcmpi(parms.small_baseline_flag,'y')
        parms.percent_rand=1; % Percent random-phase pixels (before weeding)
    else
        parms.percent_rand=20;% Percent random-phase pixels (before weeding)
    end
end

if ~isfield(parms,'gamma_stdev_reject')
    parms.gamma_stdev_reject=0;
end

if isfield(parms,'weed_alpha')
    parms=rmfield(parms,'weed_alpha');
end

if ~isfield(parms,'weed_time_win')
    parms.weed_time_win=730;    % weeding smoothing window alpha (days)
end

if ~isfield(parms,'weed_max_noise')
    parms.weed_max_noise=inf;   % maximum arc noise in any ifg (rad)
end

if ~isfield(parms,'weed_standard_dev')
    if strcmpi(parms.small_baseline_flag,'y')
        parms.weed_standard_dev=inf;
    else
        parms.weed_standard_dev=1.0;
    end
end

if ~isfield(parms,'weed_zero_elevation')
    parms.weed_zero_elevation='n';
end

if ~isfield(parms,'weed_neighbours')
    parms.weed_neighbours='n';
end

if ~isfield(parms,'unwrap_method')
    if strcmpi(parms.small_baseline_flag,'y')
        parms.unwrap_method='3D_QUICK';
    else
        parms.unwrap_method='3D';
    end
end

if ~isfield(parms,'unwrap_patch_phase')
    parms.unwrap_patch_phase='n';
end

if isfield(parms,'unwrap_ifg_index')
    try
       ps=load('ps2.mat');
    catch
       try
          ps=load('ps1.mat');
       catch
       end
    end
    if exist('ps','var') & ~strcmpi(parms.unwrap_ifg_index,'all')
       parms.drop_ifg_index=setdiff([1:ps.n_ifg],parms.unwrap_ifg_index);
    end
    parms=rmfield(parms,'unwrap_ifg_index');
    num_fields=0;
end

if ~isfield(parms,'drop_ifg_index')
    parms.drop_ifg_index=[];
end

if ~isfield(parms,'unwrap_la_error_flag')
    parms.unwrap_la_error_flag='y';
end

if ~isfield(parms,'unwrap_spatial_cost_func_flag')
    parms.unwrap_spatial_cost_func_flag='n';
end

if ~isfield(parms,'unwrap_prefilter_flag')
    parms.unwrap_prefilter_flag='y';
end

if ~isfield(parms,'unwrap_grid_size')
    parms.unwrap_grid_size=200; % prefilter grid size
end

if ~isfield(parms,'unwrap_gold_n_win')
    parms.unwrap_gold_n_win=32; % prefilter goldstein filtering window size
end

if ~isfield(parms,'unwrap_alpha')
    parms.unwrap_alpha=8;    % unwrapping smoothing window alpha
end

if ~isfield(parms,'unwrap_time_win')
    parms.unwrap_time_win=730;    % unwrapping smoothing window alpha
end

if ~isfield(parms,'unwrap_gold_alpha')
    parms.unwrap_gold_alpha=0.8;  % unwrapping goldstein filter alpha
end

if ~isfield(parms,'unwrap_hold_good_values')
    parms.unwrap_hold_good_values='n';       % fix unwrapped values judged to be good
end

if isfield(parms,'recalc_index')
    try
       ps=load('ps2.mat');
    catch
       try
          ps=load('ps1.mat');
       catch
       end
    end
    if exist('ps','var') & ~strcmpi(parms.recalc_index,'all')
        if strcmpi(parms.small_baseline_flag,'y')
           parms.scla_drop_index=setdiff([1:ps.n_image],parms.recalc_index);
        else
           parms.scla_drop_index=setdiff([1:ps.n_ifg],parms.recalc_index);
        end
    end
    parms=rmfield(parms,'recalc_index');
    if isfield(parms,'sb_recalc_index')
        if exist('ps','var') & ~strcmpi(parms.sb_recalc_index,'all')
            parms.sb_scla_drop_index=setdiff([1:ps.n_ifg],parms.sb_recalc_index);
        end
        parms=rmfield(parms,'sb_recalc_index');
    end
    num_fields=0;
end

if ~isfield(parms,'scla_drop_index')
    parms.scla_drop_index=[];
end

if ~isfield(parms,'scn_wavelength')
    parms.scn_wavelength=100; % spatially correlated noise wavelength
end

if ~isfield(parms,'scn_time_win')
    parms.scn_time_win=365; % 1 year time window
end

if ~isfield(parms,'scn_deramp_ifg')
    parms.scn_deramp_ifg=[];  % deramp these ifgs and add to estimate of scn
end

if ~isfield(parms,'scn_kriging_flag')
    parms.scn_kriging_flag='n';  % use kriging, 'y' or 'n'
end

if ~isfield(parms,'ref_lon')
    parms.ref_lon=[-inf,inf];  % low and high longitude for ref ps
end

if ~isfield(parms,'ref_lat')
    parms.ref_lat=[-inf,inf];  % low and high latitude for ref ps
end

if ~isfield(parms,'ref_centre_lonlat')
    parms.ref_centre_lonlat=[0,0];  % centre lon/lat for ref ps
end

if ~isfield(parms,'ref_radius')
    parms.ref_radius=inf;  % radius from centre for ref ps
end

if ~isfield(parms,'ref_velocity')
    parms.ref_velocity=0;  % velocity of reference point if known
end

if ~isfield(parms,'n_cores')
    parms.n_cores=1;  % n_cores for the muti-core option (step 1-5)
end

if ~isfield(parms,'plot_dem_posting')
    parms.plot_dem_posting=90;
end

if isfield(parms,'plot_pixel_size')
    parms.plot_scatterer_size=parms.plot_pixel_size*25;
    num_fields=0;
    parms=rmfield(parms,'plot_pixel_size');
end

if ~isfield(parms,'plot_scatterer_size')
    parms.plot_scatterer_size=120;
end

if ~isfield(parms,'plot_pixels_scatterer')
    parms.plot_pixels_scatterer=3;
end

if ~isfield(parms,'plot_color_scheme')
    parms.plot_color_scheme='inflation';
end

if isfield(parms,'pixel_aspect_ratio')
    parms=rmfield(parms,'pixel_aspect_ratio');
end

if ~isfield(parms,'shade_rel_angle')
    parms.shade_rel_angle=[90,45]; % look angle for dem shaded relief
end

if ~isfield(parms,'lonlat_offset')
    parms.lonlat_offset=[0,0]; % offset of PS in degrees from dem
end

if ~isfield(parms,'merge_resample_size')
    if strcmpi(parms.small_baseline_flag,'y')
        parms.merge_resample_size=100; % grid size (in m) to resample to during merge of patches
    else
        parms.merge_resample_size=0;   % (0=no resampling)
    end
end

if ~isfield(parms,'merge_standard_dev')
    parms.merge_standard_dev=inf;
end

if ~isfield(parms,'scla_method')
    parms.scla_method='L2'; % method for estmating SCLA, L1- or L2-norm
end

if ~isfield(parms,'scla_deramp')
    parms.scla_deramp='n'; % estimate an orbital ramp before SCLA
end

lambdaname=['lambda.1.in'];         % wavelength
if ~isfield(parms,'lambda')
    if ~exist(lambdaname,'file')
        lambdaname= ['../',lambdaname];
    end
    if ~exist(lambdaname,'file')
        lambdaname= ['../',lambdaname];
    end
    if ~exist(lambdaname,'file')
        parms.lambda=NaN; % Add wavelength
    else
        lambda=load(lambdaname);
        parms.lambda=lambda; % Add wavelength
    end
end

headingname=['heading.1.in'];       % satellite heading
if ~isfield(parms,'heading')
    if ~exist(headingname,'file')
        headingname= ['../',headingname];
    end
    if ~exist(headingname,'file')
        headingname= ['../',headingname];
    end
    if ~exist(headingname,'file')
        parms.heading=NaN; % Add heading
    else
        heading=load(headingname);
        parms.heading=heading; % Add heading
    end
end

if ~isfield(parms,'scla_deramp')
    parms.scla_deramp='n'; % estimate an orbital ramp before SCLA
end

if ~isfield(parms,'sb_scla_drop_index')
    if strcmpi(parms.small_baseline_flag,'y')
        parms.sb_scla_drop_index=[];
    end
end

if ~isfield(parms,'insar_processor')
    processor_file = 'processor.txt';
    if exist(processor_file,'file')~=2
       if exist(['..' filesep processor_file],'file')==2
           processor_file = ['..' filesep processor_file];
           if exist(['..' filesep processor_file],'file')==2
               processor_file = ['..' filesep processor_file];
           end
       end
    end

   if exist(processor_file,'file')~=2
       parms.insar_processor='doris'; %
   else
       processor = fileread(processor_file);
       processor = strtrim(processor);
       parms.insar_processor=processor; %

       if ~strcmpi(processor,'gamma') & ~strcmpi(processor,'doris')
           fprintf('WARNING: This processor is not supported (doris and gamma)')
       end
   end
end

if ~isfield(parms,'subtr_tropo')
    parms.subtr_tropo='n';         % remove tropospheric estimate
end

if ~isfield(parms,'tropo_method')
    parms.tropo_method='a_l';       % method for tropopsheric estimate
end

parmfields=fieldnames(parms);
if size(parmfields,1)~=num_fields
    try
        save(parmfile,'-struct','parms')
        for i=1:size(parmfields,1)
            if isempty(strmatch(parmfields{i},parmfields_before))
               parmname=parmfields{i};
               value=getfield(parms,parmname);
               if isempty(value)
                   value='[]';
               end
               if isnumeric(value)
                   logit([parmname,' = ',num2str(value)],0,parent_flag);
               else
                   logit([parmname,' = ',value],0,parent_flag);
               end
            end
        end

    catch
        fprintf('Warning: missing parameters could not be updated (no write access)\n')
    end
end


function [removingList] = plotTracks(ax, tracks, currentFrame, params, removingList)
%% Plot bounding boxes
% Remove old lines
if nargin > 4
    if size(removingList, 1) > 0
       for i = 1:size(removingList, 1)
          delete(removingList(i));
       end
    end
end
% Important parameters for plotting the bounding boxes
removingList = [];
boundingBoxColor = params.boundingBoxColor;
% We need to draw the bounding boxes from 0 to negative because the image
% coordinate origin is in the upper left corner. Therefore the bounding box
% coordinates are mirrored.
ySign = -1;
% Now plot the bounding boxes together with annotations
for iTrack = 1:size(tracks, 2)
    track = tracks(iTrack);
    initialFrame = track.initialFrame;
    finalFrame = track.finalFrame;
    if (initialFrame <= currentFrame) && (currentFrame < finalFrame)
        % Get internal track index for the chosen frame
        currentIndex = currentFrame - initialFrame + 1;
        % Try to get the bounding box
        try
            boundingBox = track.bbox(currentIndex, :);
            velocity = track.xVelocity(currentIndex);
        catch
           continue
        end
        % Plot the bounding box
        positionBoundingBox = [boundingBox(1) ...
                               ySign*boundingBox(2)+ySign*boundingBox(4) ...
                               boundingBox(3) ...
                               boundingBox(4)];
        if params.stop == 1
            rect = rectangle(ax, 'Position', positionBoundingBox, ...
                                 'FaceColor', boundingBoxColor, ...
                                 'EdgeColor', [0 0 0], ...
                                 'PickableParts', 'visible', ...
                                 'ButtonDownFcn',{@params.onClick, track, currentFrame});
        else
            rect = rectangle(ax, 'Position', positionBoundingBox, ...
                                 'FaceColor', boundingBoxColor, ...
                                 'EdgeColor', [0 0 0], ...
                                 'PickableParts', 'visible');
        end
        removingList = [removingList; rect];

        % Plot the triangle that represents the direction of the vehicle
        if velocity < 0
            centroidSign = 1;
            front = boundingBox(1) + (boundingBox(3)*0.2);
            triangleXPosition = [front front boundingBox(1)];
        else
            centroidSign = -1;
            front = boundingBox(1) + boundingBox(3) - (boundingBox(3)*0.2);
            triangleXPosition = [front front boundingBox(1)+boundingBox(3)];
        end
        triangleYPosition = [ySign*boundingBox(2) ...
                             ySign*boundingBox(2)+ySign*boundingBox(4)...
                             ySign*boundingBox(2)+ySign*(boundingBox(4)/2)];
        triangle = fill(ax, triangleXPosition, triangleYPosition, [0 0 0]);
        removingList = [removingList; triangle];

        % Plot the text annotation
        if params.plotTextAnnotation
            velocityKmh = abs(velocity) * 3.6;
            boundingBoxAnnotationText = sprintf('%s|%.2fkm/h|ID%d', ...
                                                track.class(1), ...
                                                velocityKmh, ...
                                                track.id);
            textAnnotation = text(ax, boundingBox(1), ySign*boundingBox(2)+0.6, ...
                                  boundingBoxAnnotationText, 'FontSize',8);
            textAnnotation.BackgroundColor = [1 1 0.3];
            textAnnotation.Margin = .5;
            removingList = [removingList; textAnnotation];
        end

        % Plot the track line
        if params.plotTrackingLine
            relevantBoundingBoxes = track.bbox(1:currentIndex, :);
            centroids = [relevantBoundingBoxes(:,1) + relevantBoundingBoxes(:,3)/2, ...
                         relevantBoundingBoxes(:,2) + relevantBoundingBoxes(:,4)/2];
            plottedCentroids = line(ax, centroids(:, 1)+ centroidSign * (boundingBox(3)/2), ...
                                    ySign*centroids(:, 2));
            removingList = [removingList; plottedCentroids];
        end
    end
end
xlim(ax, [0 params.trackWidth]);
axis off;
end


function [planC,allLabelNamesC,dcmExportOptS] = ...
    processAndImportAIOutput(planC,userOptS,origScanNumV,scanNumV,...
    outputScanNum,algorithm,hashID,sessionPath,cmdFlag,hWait)
%[planC,,origScanNumV,allLabelNamesC,dcmExportOptS] = ...
%processAndImportAIOutput(planC,userOptS,origScanNumV,scanNumV,...
% outputScanNum,algorithm,hashID,sessionPath,cmdFlag,hWait)
%--------------------------------------------------------------------------
% AI 08/29/22

outputS = userOptS.output;

%Loop over model outputs

outputC = fieldnames(outputS);
for nOut = 1:length(outputC)

    outType = outputC{nOut};

    switch(lower(outType))

        case 'labelmap'
            %Segmentations

            % Import segmentations
            if ishandle(hWait)
                waitbar(0.9,hWait,'Importing segmentation results to CERR');
            end
            [planC,allLabelNamesC,dcmExportOptS] = ...
                processAndImportSeg(planC,origScanNumV,scanNumV,...
                outputScanNum,sessionPath,userOptS);

        case 'dvf'
            %Deformation vector field

            outFmt = outputS.DVF.outputFormat;
            DVFpath = fullfile(sessionPath,'outputH5','DVF');
            DVFfile = dir([DVFpath,filesep,'*.h5']);
            outFile = fullfile(DVFpath,DVFfile.name);
            switch(lower(outFmt))
                case 'h5'
                    DVF4M = h5read(outFile,'/dvf');
                otherwise
                    error('Invalid model output format %s.',outFmt)
            end

            % Convert to CERR coordinate sytem

            if ~iscell(planC)
                cerrDir = planC;
                cerrDirS = dir(cerrDir);
                cerrFile = cerrDirS(3).name;
                planC = loadPlanC(fullfile(cerrDir,cerrFile),tempdir);
            else
                cerrFile = '';
            end
            indexS = planC{end};

            % Get associated scan num
            idS = userOptS.outputAssocScan.identifier;
            assocScan = getScanNumFromIdentifiers(idS,planC);

            tempOptS = userOptS;
            outTypesC = fieldnames(userOptS.output);
            matchIdx = strcmpi(outTypesC,'DVF');
            outTypesC = outTypesC(~matchIdx);
            tempOptS.output = rmfield(tempOptS.output,outTypesC);
            niiOutDir = tempOptS.output.DVF.outputDir;
            DVFfilename = strrep(DVFfile.name,'.h5','');
            dimsC = {'dx','dy','dz'};
            niiFileNameC = cell(1,length(dimsC));
            for nDim = 1:size(DVF4M,1)
                DVF3M = squeeze(DVF4M(nDim,:,:,:));
                DVF3M = permute(DVF3M,[2,3,1]);
                [DVF3M,planC] = joinH5planC(assocScan,DVF3M,[DVFfilename,'_'...
                    dimsC{nDim}],tempOptS,planC);
                niiFileNameC{nDim} = fullfile(niiOutDir,[DVFfilename,'_'...
                    dimsC{nDim},'.nii.gz']);
                fprintf('\n Writing DVF to file %s\n',niiFileNameC{nDim});
                DVF3M_nii = make_nii(DVF3M);
                save_nii(DVF3M_nii, niiFileNameC{nDim}, 0);
            end

            %Calc. deformation magnitude
            DVFmag3M = zeros(size(DVF3M));
            assocScanUID = planC{indexS.scan}(assocScan).scanUID;
            for nDim = 1:size(DVF4M,1)
                doseNum = length(planC{indexS.dose})-nDim+1;
                doseArray3M = double(getDoseArray(doseNum,planC));
                DVFmag3M = DVFmag3M + doseArray3M.^2;
            end
            DVFmag3M = sqrt(DVFmag3M);
            description = 'Deformation magnitude';
            planC = dose2CERR(DVFmag3M,[],description,'',description,...
                'CT',[],'no',assocScanUID, planC);

            % Store to deformS
            indexS = planC{end};
            idS = userOptS.register.baseScan.identifier;
            baseScanNum = getScanNumFromIdentifiers(idS,planC,1);
            idS = userOptS.register.movingScan.identifier;
            movScanNum = getScanNumFromIdentifiers(idS,planC,1);

            planC{indexS.deform}(end+1).baseScanUID = ...
                planC{indexS.scan}(baseScanNum).scanUID;
            planC{indexS.deform}(end+1).movScanUID = ...
                planC{indexS.scan}(movScanNum).scanUID;

            planC{indexS.deform}(end+1).algorithm = algorithm;
            planC{indexS.deform}(end+1).registrationTool = 'CNN';
            planC{indexS.deform}(end+1).algorithmParamsS.singContainerHash = ...
                hashID;
            planC{indexS.deform}(end+1).DVFfileName = niiFileNameC;

            if ~isempty(cerrFile)
                save_planC(planC,[],'PASSED',cerrFile);
                planC = cerrFile;
            end

        case 'derivedimage'
            %Read output image
            outFmt = outputS.derivedImage.outputFormat;
            outputImgType = outputS.derivedImage.imageType;
            imgPath = fullfile(sessionPath,'outputH5');
            imgFile = dir([imgPath,filesep,'*.h5']);
            outFile = fullfile(imgFile,DVFfile.name);
            switch(lower(outFmt))
                case 'h5'
                    img3M = h5read(outFile,'/scan'); %Dataset name for derived images?
                otherwise
                    error('Invalid model output format %s.',outFmt)
            end

            indexS = planC{end};
            initTextureS = initializeCERR('texture');
            initTextureS(end+1).textureUID = createUID('texture');
            planC{indexS.texture} = ...
                dissimilarInsert(planC{indexS.texture},initTextureS);
            currentTexture = length(planC{indexS.texture});
            planC{indexS.texture}(currentTexture).textureUID = ...
                createUID('TEXTURE');

            %Get associated scan index
            identifierS = userOptS.outputAssocScan.identifier;
            idS = rmfield(identifierS,{'warped','filtered'});
            idC = fieldnames(idS);
            if ~isempty(idC)
                assocScanNum = getScanNumFromIdentifiers(identifierS,planC);
            else
                assocScanNum = 1; %Assoc with first scan by default
            end
            assocScanUID = planC{indexS.scan}(assocScanNum).scanUID;
            planC{indexS.texture}(currentTexture).assocScanUID = assocScanUID;

            %Get associated structure index
            sizeV = size(getScanArray(assocScanNum,planC));
            minc = 1;
            maxr = sizeV(1);
            uniqueSlicesV = 1:sizeV(3);
            if isfield(userOptS.input,'structure')
                strC = {planC{indexS.structures}.structureName};
                if isfield(userOptS.input.structure,'name')
                    strName =  userOptS.input.structure.name;
                else
                    if isfield(userOptS.input.structure,'strNameToLabelMap')
                        strName =  userOptS.input.structure.strNameToLabelMap.structureName;
                    end
                end
                strIdx = getMatchingIndex(strName,strC,'EXACT');
                if ~isempty(strIdx)
                    assocStrUID = planC{indexS.structures}(strIdx).strUID;
                    planC{indexS.texture}(currentTexture).assocStructUID = assocStrUID;
                    mask3M = getStrMask(strIdx,planC);
                    [~,maxr,minc,~,~,~] = compute_boundingbox(mask3M);
                    uniqueSlicesV = find(sum(sum(mask3M))>0);
                end
            end

            % Assign parameters based on category of texture
            planC{indexS.texture}(currentTexture).parameters = ...
                userOptS;
            planC{indexS.texture}(currentTexture).description = algorithm;

            % Create Texture Scans
            [xValsV, yValsV] = ...
                getScanXYZVals(planC{indexS.scan}(assocScanNum));
            dx = median(diff(xValsV));
            dy = median(diff(yValsV));
            zV = zVals(uniqueSlicesV);
            regParamsS.horizontalGridInterval = dx;
            regParamsS.verticalGridInterval = dy;
            regParamsS.coord1OFFirstPoint = xVals(minc);
            regParamsS.coord2OFFirstPoint   = yVals(maxr);
            regParamsS.zValues  = zV;
            regParamsS.sliceThickness = ...
            [planC{indexS.scan}(assocScanNum).scanInfo(uniqueSlicesV).sliceThickness];
            assocTextureUID = planC{indexS.texture}(currentTexture).textureUID;

            %Save to planC
            planC = scan2CERR(img3M,outputImgType,'Passed',regParamsS,...
                assocTextureUID,planC);

        otherwise
            error('Invalid output type '' %s ''.',outType)

    end
    userOptS.output.(outType) =  outputS;

end

end


function Script_CECLM_general()

addpath(genpath('../'));

% Replace this with the location of the 300W data location
if(exist([getenv('USERPROFILE') '/Dropbox/AAM/test data/'], 'file'))
    root_test_data = [getenv('USERPROFILE') '/Dropbox/AAM/test data/'];
else
    root_test_data = 'F:\Dropbox\AAM\test data/';
end
[images, detections, labels] = Collect_wild_imgs(root_test_data);

%% loading the CE-CLM model and parameters
[patches, pdm, clmParams, early_term_params] = Load_CECLM_general();
% Use the multi-hypothesis model, as bounding box tells nothing about
% orientation
views = [0,0,0; 0,-30,0; 0,30,0; 0,0,30; 0,0,-30;];
views = views * pi/180;

%% Setup recording

num_points = numel(pdm.M)/3;

shapes_all = zeros(size(labels,2),size(labels,3), size(labels,1));
labels_all = zeros(size(labels,2),size(labels,3), size(labels,1));
lhoods = zeros(numel(images),1);
all_lmark_lhoods = zeros(num_points, numel(images));
all_views_used = zeros(numel(images),1);

% Change if you want to visualize the outputs
verbose = false;
output_img = false;

if(output_img)
    output_root = './ceclm_gen_out/';
    if(~exist(output_root, 'dir'))
        mkdir(output_root);
    end
end
if(verbose)
    f = figure;
end

%% Fitting the model to the provided images

tic
for i=1:numel(images)

    image = imread(images(i).img);
    image_orig = image;

    if(size(image,3) == 3)
        image = rgb2gray(image);
    end

    bbox = detections(i,:);

    [shape,~,~,lhood,lmark_lhood,view_used] =...
        Fitting_from_bb_multi_hyp(image, [], bbox, pdm, patches, clmParams, views, early_term_params);

    all_lmark_lhoods(:,i) = lmark_lhood;
    all_views_used(i) = view_used;

    shapes_all(:,:,i) = shape;
    labels_all(:,:,i) = labels(i,:,:);

    if(mod(i, 200)==0)
        fprintf('%d done\n', i );
    end

    lhoods(i) = lhood;

    if(output_img)
        v_points = sum(squeeze(labels(i,:,:)),2) > 0;
        DrawFaceOnImg(image_orig, shape, sprintf('%s/%s%d.jpg', output_root, 'fit', i), bbox, v_points);
    end

    if(verbose)
        v_points = sum(squeeze(labels(i,:,:)),2) > 0;
        DrawFaceOnFig(image_orig, shape, bbox, v_points);
    end
end
toc

experiment.errors_normed = compute_error(labels_all, shapes_all + 1.0);
experiment.lhoods = lhoods;
experiment.shapes = shapes_all;
experiment.labels = labels_all;
experiment.all_lmark_lhoods = all_lmark_lhoods;
experiment.all_views_used = all_views_used;

fprintf('Done: mean normed error %.3f median normed error %.4f\n', ...
    mean(experiment.errors_normed), median(experiment.errors_normed));

%%
output_results = 'results/results_ceclm_general.mat';
save(output_results, 'experiment');

end


function [output, layerOut] = FeatureTree_obj(visible, para, layer)
% remove target and cost function nodes if any
for i=1:length(layer)
    if strcmpi(layer{i}.name, 'target') || strcmpi(layer{i}.name, 'cross_entropy') || strcmpi(layer{i}.name, 'mse') || strcmpi(layer{i}.name, 'logistic')
        layer{i}.name = 'ignore';
    end
    if i > max(para.out_layer_idx)  % we don't compute layers that is after the last output layer
        layer{i}.name = 'ignore';
    end
end
para.NET.sentenceMinibatch = 1;
visible = visible.ShuffleData(para);
randomOrder = 0;

output = {}; layerOut = {};
for blk_i = 1:visible.nBlock
    minibatch = visible.PrepareMinibatch(para.precision, 1, para.NET.batchSize, blk_i,randomOrder);
    nMinibatch = size(minibatch,2);

    for utt_i = 1:nMinibatch
        PrintProgress(utt_i, nMinibatch, 100);
        batch_data = GetMinibatch(minibatch, utt_i, para.useGPU);

        % Use mode=3 to generate network output only
        if nargout>1
            [~, layerOut{end+1}, output{end+1}] = DNN_Cost10(layer, batch_data, para,3);
        else
            [~, ~, output{end+1}] = DNN_Cost10(layer, batch_data, para,3);
        end
    end
end
end


function [ds_all, bs_all, targets] = bboxpred_data(name)
% Collect training data for bounding box prediction.
%   [ds, bs, targets] = bboxpred_data(name)
%
% Return values
%   ds_all    Predicted bounding boxes (clipped to the image)
%             One cell percomponent
%   bs_all    All filter bounding boxes (unclipped)
%             One cell percomponent
%   targets   Ground-truth bounding boxes (clipped)
%             One cell percomponent
%
% Argument
%   name      Object class

% AUTORIGHTS
% -------------------------------------------------------
% Copyright (C) 2011-2012 Ross Girshick
% Copyright (C) 2008, 2009, 2010 Pedro Felzenszwalb, Ross Girshick
%
% This file is part of the voc-releaseX code
% (http://people.cs.uchicago.edu/~rbg/latent/)
% and is available under the terms of an MIT-like license
% provided in COPYING. Please retain this notice and
% COPYING if you use this file (or a portion of it) in
% your project.
% -------------------------------------------------------

conf = voc_config();

try
  load([conf.paths.model_dir name '_bboxdata']);
catch
  % load final model for class
  load([conf.paths.model_dir name '_final']);
  % get training data
  pos = pascal_data(model.class, model.year);

  numpos = length(pos);
  model.interval = conf.training.interval_fg;
  pixels = model.minsize * model.sbin / 2;
  minsize = prod(pixels);
  nrules = length(model.rules{model.start});
  parb = cell(1,numpos);
  part = cell(1,numpos);

  % compute latent filter locations and record target bounding boxes
  parfor i = 1:numpos
    pard{i} = cell(1,nrules);
    parb{i} = cell(1,nrules);
    part{i} = cell(1,nrules);
    fprintf('%s %s: bboxdata: %d/%d\n', procid(), name, i, numpos);
    bbox = pos(i).boxes;
    % skip small examples
    if (bbox(3)-bbox(1)+1)*(bbox(4)-bbox(2)+1) < minsize
      continue;
    end
    % get example
    im = imreadx(pos(i));
    [im, bbox] = croppos(im, bbox);
    [pyra, model_dp] = gdetect_pos_prepare(im, model, bbox, 0.7);
    [ds, bs] = gdetect_pos(pyra, model_dp, 1, ...
                            1, 0.7, [], 0.5);
    if ~isempty(ds)
      % component index
      c = ds(1,end-1);
      bs = reduceboxes(model, bs);
      ds = clipboxes(im, ds);
      pard{i}{c} = [pard{i}{c}; ds(:,1:end-2)];
      parb{i}{c} = [parb{i}{c}; bs(:,1:end-2)];
      part{i}{c} = [part{i}{c}; bbox];
    end
  end
  ds_all = cell(1,nrules);
  bs_all = cell(1,nrules);
  targets = cell(1,nrules);
  for i = 1:numpos
    for c = 1:nrules
      ds_all{c} = [ds_all{c}; pard{i}{c}];
      bs_all{c} = [bs_all{c}; parb{i}{c}];
      targets{c} = [targets{c}; part{i}{c}];
    end
  end
  save([conf.paths.model_dir name '_bboxdata'], ...
       'ds_all', 'bs_all', 'targets');
end