classdef MimOrientationSagittal < MimGuiPlugin
    % MimOrientationSagittal. Gui Plugin for using a preset bone window/level
    %
    %     You should not use this class within your own code. It is intended to
    %     be used by the gui of the TD MIM Toolkit.
    %
    %     MimOrientationSagittal is a Gui Plugin for the MIM Toolkit.
    %     The gui will create a button for the user to run this plugin.
    %     Running this plugin will change the window and level of the viewing
    %     panel to standard soft tissue values.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties
        ButtonText = 'Sagittal'
        SelectedText = 'Sagittal'
        ToolTip = 'Changes the image orientation to a sagittal view'
        Category = 'View'
        Visibility = 'Dataset'
        Mode = 'Toolbar'

        HidePluginInDisplay = false
        PTKVersion = '1'
        ButtonWidth = 6
        ButtonHeight = 1
        Icon = 'sagittal_thumb.png'
        Location = 4
    end

    methods (Static)
        function RunGuiPlugin(gui_app)
            gui_app.ImagePanel.Orientation = GemImageOrientation.YZ;
        end

        function enabled = IsEnabled(gui_app)
            enabled = gui_app.IsDatasetLoaded;
        end

        function is_selected = IsSelected(gui_app)
            is_selected = gui_app.ImagePanel.Orientation == GemImageOrientation.YZ && ~strcmp(gui_app.ImagePanel.Mode, char(MimModes.View3DMode));
        end
    end
end


function getMetaboliteMsDistr(mets, molfiledir, msdistrdir, phs)
% Calculate microspecies distributions at all pH values in phs using
% ChemAxon's cxcalc. Metabolite mol files in molfiledir are input to cxcalc. Mol file names
% should correspond to the metabolite ID in mets (it is assumed that
% compartment assignments are appended to the end of metabolite ID in the
% format `metID[c]`). Microspecies distributions are returned as .sdf files
% in `msdistrdir`
%
% USAGE:
%
%    getMetaboliteMsDistr(mets, molfiledir, msdistrdir, phs)
%
% INPUTS:
%    mets:          metabolites
%    molfiledir:    directory with mol files
%    msdistrdir:    directory with microspecies distributions
%    phs:           pH values

d = dir(molfiledir);
molfilelist = cat(2,d.name);
molfilelist = regexp(molfilelist,'.mol','split');
molfilelist = regexprep(molfilelist,'\.','');
molfilelist = molfilelist(~cellfun('isempty',molfilelist))';

nMet = length(mets);
done = {};

model.mets = mets;

for n = 1:nMet
    disp(n)

    if ~any(strcmp(model.mets{n}(1:(end-3)),done))
        done = [done; {model.mets{n}(1:(end-3))}];

        if any(strcmp(molfilelist,mets{n}(1:(end-3))))

            for m = 1:length(phs)
                ph = phs(m);

                if ispc
                    system(['cxcalc -o ', msdistrdir, filesep, model.mets{n}(1:(end-3)), '_msdistr_ph', num2str(ph), '.sdf msdistr -H ', num2str(ph), ' -M true ', molfiledir, filesep, model.mets{n}(1:(end-3)), '.mol']);
                end

            end

        end

    end

end


function exportTsvFile(data, filename, withQuotes)
% exportTsvFile
%
%   Export structure or table to a tsv (or txt) file. String (char) entries
%   will be enclosed in double quotes ("") by default, whereas numeric
%   (double) entries will not.
%
% Input:
%
%   data       A structure or table containing the annotation information
%              associated with the GEM reactions, metabolites, or genes.
%
%   filename   Name of the file to which the data will be written,
%              delimited by tabs.
%              If filename does not end in ".tsv" or ".txt", the extension
%              will automatically be appended as ".tsv".
%
%   withQuotes Enclose string elements with double quotes (opt, default is
%              TRUE)
%
%
% Usage:
%
%   exportTsvFile(data, filename, withQuotes);
%

if nargin < 3
    withQuotes = true;
end

if isstruct(data)
    data = struct2table(data);
end
if ~istable(data)
    error('Invalid DATA format. Must be a STRUCT or a TABLE.');
end
if ~endsWith(lower(filename), '.tsv') && ~endsWith(lower(filename), '.txt')
    filename = strcat(filename, '.tsv');
end

writetable(data, filename, 'Delimiter', '\t', 'QuoteStrings', withQuotes, 'FileType', 'text');


function c = mtexdegchar
% returns the degree character

c = getMTEXpref('degreeChar');


function out = not( in )
%NOT for nested cells
%
% (c) Thomas Kuestner
% ---------------------------------------------------------------------

[out, idx] = flattenCellMatrix(in.data);
out = cellfun(@(x) ~x, out, 'UniformOutput', false);
out = reconFlatCellMatrix(out,idx);
out = TRAFO(out,in.meta);

end


% --- Update waitbar
function DoUpdateBar(axes_handle,value,total_value)

% prevent matlab from stealing focus when updating bar
set(0,'CurrentFigure',get(axes_handle,'Parent'));
set(gcf,'CurrentAxes',axes_handle);

set(axes_handle,'Visible','on');
% axes(axes_handle);
cla(axes_handle);
axis(axes_handle,[0,total_value,0,1]);
patch([0,value,value,0],[0,0,1,1],'b','FaceAlpha',0.5);
text(0.5,0.5,[num2str((value/total_value)*100, '%02.0f') '%']);
% axis off;

end


if(exist('D:\Datasets\UNBC/', 'file'))
    UNBC_dir = 'E:\Datasets\UNBC/';
elseif(exist('E:\Datasets\UNBC/', 'file'))
    UNBC_dir = 'E:\Datasets\UNBC/';
else
    fprintf('UNBC location not found (or not defined)\n');
end

all_recs = {'042-ll042', '043-jh043', '047-jl047', '048-aa048', '049-bm049',...
            '052-dr052', '059-fn059', '064-ak064', '066-mg066', '080-bn080',...
            '092-ch092', '095-tv095', '096-bg096', '097-gf097', '101-mg101',...
            '103-jk103', '106-nm106', '107-hs107', '108-th108', '109-ib109',...
            '115-jy115', '120-kz120', '121-vw121', '123-jh123', '124-dn124'};

devel_recs = all_recs(1:5:25);
train_recs = setdiff(all_recs, devel_recs);

all_aus = [4, 6, 7, 9, 10, 12, 20, 25, 26, 43];


function mex_files_to_compile_map = PTKGetMexFilesToCompile(reporting)
    % PTKGetMexFilesToCompile. Returns a list of mex files used by PTK
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    root_dir = PTKDirectories.GetSourceDirectory;
    mex_dir = PTKDirectories.GetMexSourceDirectory;

    % Populate list with known mex files
    mex_files_to_compile = CoreCompiledFileInfo.empty(0);
    mex_files_to_compile(end + 1) = CoreCompiledFileInfo(2, 'PTKFastEigenvalues', 'cpp', mex_dir, [], []);
    mex_files_to_compile(end + 1) = CoreCompiledFileInfo(1, 'PTKFastIsSimplePoint', 'cpp', mex_dir, [], []);
    mex_files_to_compile(end + 1) = CoreCompiledFileInfo(2, 'PTKWatershedFromStartingPoints', 'cpp', mex_dir, [], []);
    mex_files_to_compile(end + 1) = CoreCompiledFileInfo(3, 'PTKWatershedMeyerFromStartingPoints', 'cpp', mex_dir, [], []);
    mex_files_to_compile(end + 1) = CoreCompiledFileInfo(2, 'PTKSmoothedRegionGrowingFromBorderedImage', 'cpp', mex_dir, [], []);

    mex_files_to_compile(end + 1) = CoreCompiledFileInfo(3, 'mba_surface_interpolation', 'cpp', fullfile(root_dir, 'External', 'gerardus', 'matlab', 'PointsToolbox'), ...
        {['-I' fullfile(root_dir, 'External')], ['-I' fullfile(root_dir, 'External', 'mba', 'include')]}, ...
        {fullfile(root_dir, 'External', 'mba', 'src', 'MBA.cpp'), fullfile(root_dir, 'External', 'mba', 'src', 'UCBsplines.cpp'), ...
        fullfile(root_dir, 'External', 'mba', 'src', 'UCBsplineSurface.cpp'), fullfile(root_dir, 'External', 'mba', 'src', 'MBAdata.cpp')});

    % Transfer to a map
    mex_files_to_compile_map = containers.Map;
    for mex_file = mex_files_to_compile
        mex_files_to_compile_map(mex_file.Name) = mex_file;
    end

    % Now add unknown .cpp files
    file_list = dir(fullfile(mex_dir, '*.cpp'));
    for index = 1 : numel(file_list)
        filename = file_list(index).name;
        [~, name_part, ~] = fileparts(filename);
        if ~mex_files_to_compile_map.isKey(name_part)
            mex_files_to_compile_map(name_part) = CoreCompiledFileInfo(0, name_part, 'cpp', mex_dir, [], []);
            reporting.ShowWarning('PTKGetMexFilesToCompile:MexFileNotInList', ['The file ' filename ' was found in the mex folder but has not been added to PTKGetMexFilesToCompile.m. Mex files should be added to PTKGetMexFilesToCompile.m so they are correctly versioned.'], []);
        else
        end
    end

end


function db_reload_studies( iStudies, isUpdate )
% DB_RELOAD_STUDIES: Reload a set of studies of the current protocol.
% Parse the study's directory again and replace Study structure in Brainstorm database.
%
% USAGE:  db_reload_studies( iStudies );
%
% INPUT:  iStudies: array of study indices to reload in protocol studies array

% @=============================================================================
% 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: Francois Tadel, 2008-2010

% Parse inputs
if isempty(iStudies)
    return
end
if (nargin < 2) || isempty(isUpdate)
    isUpdate = 1;
end
% Get protocol information
ProtocolInfo = bst_get('ProtocolInfo');

% If no progressbar is visible: create one
isProgressBar = ~bst_progress('isVisible');
if isProgressBar
    bst_progress('start', 'Reload datasets', 'Reloading datasets...', 0, 100 * length(iStudies));
end
% Process
for iStudy = iStudies
    % Get study
    sStudy = bst_get('Study', iStudy);
    if isempty(sStudy)
        continue;
    end
    % Get study directory
    studySubDir = bst_fileparts(sStudy.FileName);
    % Check the existance of the study's directory
    if ~file_exist(bst_fullfile(ProtocolInfo.STUDIES, studySubDir))
        db_fix_protocol();
        bst_progress('stop');
        return
    end
    % Parse study directory
    sStudyNew = db_parse_study(ProtocolInfo.STUDIES, studySubDir, 100);
    % If study could not be loaded
    if isempty(sStudyNew)
        db_fix_protocol();
        bst_progress('stop');
        return
    end
    % Try to reuse the existing selection of headmodel (which is not saved on the hard drive)
    if ~isempty(sStudy.HeadModel) && ~isempty(sStudy.iHeadModel) && ~isempty(sStudyNew.HeadModel)
        sStudyNew.iHeadModel = find(strcmp(sStudy.HeadModel(sStudy.iHeadModel).FileName, {sStudyNew.HeadModel.FileName}));
    end
    if ~isempty(sStudy.iHeadModel) && (sStudy.iHeadModel <= length(sStudyNew.HeadModel)) && isempty(sStudyNew.iHeadModel)
        sStudyNew.iHeadModel = sStudy.iHeadModel;
    end
    % Else study was reloaded
    bst_set('Study', iStudy, sStudyNew);
end

% Update display
if isUpdate
    % Update links
    db_links('Study', iStudies);
    % Update tree
    panel_protocols('UpdateNode', 'Study', iStudies);
end
% Save database
db_save();
% Close progress bar
if isProgressBar
    bst_progress('stop');
end


function os_seg_test(varargin)
% note: this function runs multiple setups (feature combinations) at the
% same time

% load stuff
[opts, imdb] = os_setup(varargin{:}) ;
classes = find(imdb.meta.inUse) ;

figure(200) ; clf ;
cmap = plot_legend(imdb) ;
for s = 1:numel(opts.suffix)
  vl_xmkdir(opts.segPublishDir{s});
  print(fullfile(opts.segPublishDir{s}, [opts.dataset '-legend.pdf']), '-dpdf') ;
end

info = struct() ;
encoders = struct() ;
models = struct() ;
for s = 1:numel(opts.suffix)
  vl_xmkdir(fileparts(opts.segResultPath{s})) ;
  setupName = opts.suffix{s} ;
  fprintf('preparing setup %s\n', setupName) ;

  % make a directory to contain the segment scores for each image
  [setupLoc,setupBaseName,~] = fileparts(opts.segResultPath{s}) ;
  vl_xmkdir(fullfile(setupLoc, setupBaseName)) ;

  % source all encoders for this setup (could be the same encoder of
  % another setup)
  for j = 1:numel(opts.encoders{s})
    name = opts.encoders{s}{j}.name ;
    if ~isfield(encoders, 'name')
      fprintf('loading encoder %s\n', name) ;
      encoders.(name) = load(opts.encoders{s}{j}.path) ;
      if isfield(encoders.(name), 'net')
        if opts.useGpu
          encoders.(name).net = vl_simplenn_move(encoders.(name).net, 'gpu') ;
          encoders.(name).net.useGpu = true ;
        else
          encoders.(name).net = vl_simplenn_move(encoders.(name).net, 'cpu') ;
          encoders.(name).net.useGpu = false ;
        end
      end
    end
  end

  % load the SVM classifiers for this setup
  tmp = load(opts.resultPath{s}) ;
  models(s).w = tmp.w ;
  models(s).b = tmp.b ;

  info.(setupName) = init_info(classes) ;
end

% -------------------------------------------------------------------------
%                                                            Process images
% -------------------------------------------------------------------------

rng(0) ;
printThisImage = false(1, numel(imdb.images.id)) ;
test = find(imdb.images.set <= 3) ;
printThisImage(vl_colsubset(test, 60)) = true ;
confusion = cell(1, numel(imdb.images.id)) ;

%fprintf('num labs: %d\n', matlabpool('size')) ;
parfor i = 1:numel(imdb.images.id)
  confusion{i} = do_one_image(opts, encoders, models, imdb, classes, cmap, printThisImage, i) ;
end

for s = 1:numel(opts.suffix)
  setupName = opts.suffix{s} ;
  for i = 1:numel(imdb.images.id)
    if ismember(imdb.images.set(i), [1 2]), setName = 'train' ; else setName = 'test' ; end
    info.(setupName).(setName).confusion_ = info.(setupName).(setName).confusion_ + confusion{i}{s} ;
  end
  for setName = {'train', 'test'}
    setName = char(setName) ;
    [info.(setupName).(setName).confusion, ...
      info.(setupName).(setName).acc, ...
      info.(setupName).(setName).msrcAcc] = ...
      nconfusion(info.(setupName).(setName).confusion_) ;
  end

  % save
  [setupLoc,setupBaseName,~] = fileparts(opts.segResultPath{s}) ;
  info_ = info.(setupName) ;
  save(opts.segResultPath{s}, '-struct', 'info_') ;

  % print the confusion
  figure(1) ; clf ; t = 0 ;
  for setName = {'train', 'test'}
    t = t + 1 ;
    setName = char(setName) ;
    subplot(1,2,t) ; imagesc(info.(setupName).(setName).confusion) ; axis equal ;
    title(sprintf('%s %s acc:%.2f%% (msrc acc: %.2f%%)', ...
      setupName, setName, ...
      info.(setupName).(setName).acc*100, ...
      info.(setupName).(setName).msrcAcc*100)) ;
  end
  vl_printsize(1) ;
  print(fullfile(setupLoc, [setupBaseName '.pdf']), '-dpdf') ;
end

function saveIntermediate(scoresPath, scores, confusion_)
save(scoresPath, 'scores', 'confusion_') ;

function confusion_ = loadIntermediate(scoresPath)
load(scoresPath, 'confusion_') ;

% -------------------------------------------------------------------------
function confusion = do_one_image(opts, encoders, models, imdb, classes, cmap, printThisImage, i)
% -------------------------------------------------------------------------
if ismember(imdb.images.set(i), [1 2]), setName = 'train' ; else setName = 'test' ; end
task = getCurrentTask() ;
if ~isempty(task), tid = task.ID ; else tid = 1 ; end
fprintf('Task %5d: segmenting image %d of %d (%s)\n', tid, i, numel(imdb.images.id), setName) ;
[~,baseName,~] = fileparts(imdb.images.name{i}) ;
features = struct() ;
for s = 1:numel(opts.suffix)
  setupName = opts.suffix{s} ;
  [setupLoc,setupBaseName,~] = fileparts(opts.segResultPath{s}) ;
  scoresPath = fullfile(setupLoc, setupBaseName, [baseName '-scores.mat']) ;
  nClasses = numel(classes);

  seg_labels = imdb.segments.label(:, imdb.segments.imageId == imdb.images.id(i));
  if (max(max(seg_labels)) == 0)
    confusion_ = zeros(nClasses, nClasses + 1);
  elseif exist(scoresPath)
    % load previous results
    confusion_ = loadIntermediate(scoresPath) ;
  else
    % get the region proposals
    im = imread(fullfile(imdb.imageDir, imdb.images.name{i})) ;
    switch opts.segProposalType
      case 'crisp'
        regions = read_crisp_regions(...
          fullfile(imdb.segmDir, 'crisp', sprintf('%s.png', baseName)), ...
          [size(im,1) size(im,2)]) ;
      case 'scg'
        regions = read_scg_regions(...
          fullfile(imdb.segmDir, 'scg_proposals', sprintf('%s.mat', baseName))) ;
      case 'scg200'
        regions = read_scg_regions(...
          fullfile(imdb.segmDir, 'scg_proposals', sprintf('%s.mat', baseName)), ...
          'maxNumRegions', 200) ;
    end

    % get the region features
    psi = {} ;
    for j = 1:numel(opts.encoders{s})
      n = opts.encoders{s}{j}.name ;
      if ~isfield(features, n)
        features.(n) = encoder_extract_for_regions(encoders.(n), im, regions) ;
      end
      psi{j} = features.(n) ;
    end
    psi = cat(1, psi{:}) ;

    % evaluate classifiers
    scores = bsxfun(@plus, models(s).w' * psi, models(s).b') ;

    % compute confusion and save results
    [~,~,gt] = os_get_gt_regions(imdb, imdb.images.id(i)) ;
    [confusion_, gt_, pred_] = evaluate_seg(classes, gt, regions, scores) ;
    saveIntermediate(scoresPath, scores, confusion_) ;

    % optionally print the image
    if printThisImage(i)
      err = (gt_ ~= pred_) & (gt_ > 0) ;
      good = (gt_ == pred_) & (gt_ > 0) ;
      name = sprintf('%s-%s', baseName, setupName) ;
      pdir = opts.segPublishDir{s} ;
      imwrite(im, fullfile(pdir, [baseName '.jpg'])) ;
      imwrite(gt_+1, colormap(cmap), fullfile(pdir, [name '-gt.png'])) ;
      imwrite(pred_+1, colormap(cmap), fullfile(pdir, [name '-pred.png'])) ;
      imwrite(1 + err + 2*good, [[1 1 1];[1 0 0];[0 1 0]], fullfile(pdir, [name '-err.png'])) ;
    end
  end
  confusion{s} = confusion_ ;
end

% -------------------------------------------------------------------------
function [c, gt_, pred_] = evaluate_seg(classes, gt, regions, scores)
% -------------------------------------------------------------------------
numClasses = numel(classes) ;
if (numel(size(gt)) == 2)
    pred = zeros(size(gt)) ;
else
    pred = zeros(size(gt, 2), size(gt, 3));
end
%scores = scores(1:23,:) ;
[~, labels] = max(scores,[],1) ;
for r=1:numel(labels)
  mask = ismember(regions.basis, regions.labels{r}) ;
  pred(mask) = classes(labels(r)) ;
end

if (numel(size(gt)) == 2)
sel = find(gt(:) > 0) ;
[~, gt_] = ismember(gt, classes) ;
[~, pred_] = ismember(pred, classes) ;
pred_(pred_ == 0) = numClasses + 1 ;
c = accumarray([gt_(sel), pred_(sel)], 1, [numClasses numClasses+1]) ;
else

    [~, pred_] = ismember(pred, classes) ;
    pred_(pred_ == 0) = numClasses + 1 ;
    gt_ = zeros(size(gt, 2), size(gt, 3));
    % fill all labels; we do not care of overlaps for now;
    for ll = 1 : size(gt, 1)
        gt0 = reshape(gt(ll, :, :), size(gt, 2), size(gt, 3));
        gt_(gt0 == 1) = ll;
    end

    % now make sure ground truth matches the predictions
    for ll = 1 : size(gt, 1)
        gt0 = reshape(gt(ll, :, :), size(gt, 2), size(gt, 3));
        sel_gt = gt0 == 1;
        sel_pred = pred_ == ll;
        mask_ = min(sel_pred, sel_gt);
        gt_(mask_) = ll;
    end
    sel = find(gt_(:) > 0);
    c = accumarray([gt_(sel), pred_(sel)], 1, [numClasses numClasses+1]) ;
end
if 0
  cmap = [[1 1 1] ; distinguishable_colors(numel(classes))] ;
  figure(100) ; clf ;
  subplot(1,2,1); image(gt_+1); axis equal ; title('(partial) gt') ;
  subplot(1,2,2); image(pred_+1); axis equal ; title('predicted') ;
  colormap(cmap) ;
  drawnow ;
  keyboard
end

% -------------------------------------------------------------------------
function [c,acc,msrcAcc]=nconfusion(c)
% -------------------------------------------------------------------------
msrcAcc = sum(diag(c)) / sum(c(:)) ;
c = bsxfun(@times, 1./max(sum(c,2),1e-10), c) ;
acc = mean(diag(c)) ;

% -------------------------------------------------------------------------
function info = init_info(classes)
% -------------------------------------------------------------------------
nc = numel(classes) ;
info.train.confusion_ = zeros(nc,nc+1) ;
info.train.confusion = zeros(nc,nc+1) ;
info.test.confusion_ = zeros(nc,nc+1) ;
info.test.confusion = zeros(nc,nc+1) ;
info.train.acc = 0 ;
info.train.msrcAcc = 0 ;
info.test.acc = 0 ;
info.test.msrcAcc = 0 ;
info.lastProcessedImage = 0 ;

% -------------------------------------------------------------------------
function cmap = plot_legend(imdb)
% -------------------------------------------------------------------------
numClasses = sum(imdb.meta.inUse) ;
classes = find(imdb.meta.inUse) ;
cmap = [[1 1 1] ; distinguishable_colors(numClasses) ;] ;
h = 16 ;
set(gca,'units', 'points', 'position',[0 0 100*8 h*3]) ;
set(gcf,'paperunits', 'points', 'paperposition',[0 0 150*8 h*3]) ;
set(gcf,'paperunits', 'points', 'papersize',[100*8 h*3]) ;

for i=1:3
  for j=1:8
    t = (i-1)*8 + j;
    if t > numClasses, break ; end
    x = (j-1)*100 ;
    y = (4-i-1)*h ;
    text(x+1.5*h, y+0.5*h, imdb.meta.classes{classes(t)}, ...
      'interpreter', 'none', 'verticalalign', 'middle', 'fontsize', 10) ;
    patch([0 h h 0]+x,[0 0 h h]+y,cmap(t+1,:)) ;
  end
end
axis equal off ;
xlim([0 100*8])
ylim([0 h*3]) ;

% -------------------------------------------------------------------------
function code = encoder_extract_for_regions(encoder, im, regions)
% -------------------------------------------------------------------------
switch encoder.type
  case 'rcnn'
    code = get_rcnn_features(encoder.net, ...
      im, regions, ...
      'regionBorder', encoder.regionBorder) ;
  case 'dcnn'
    code = get_dcnn_features(encoder.net, ...
      im, regions, ...
      'encoder', encoder) ;
  case 'dsift'
    code = get_dcnn_features([], im, regions, ...
      'useSIFT', true, ...
      'encoder', encoder) ;
end
code = cat(2, code{:}) ;


function dt6 = dtiMakeDt6FromFsl(b0FileName, t1FileName)
%
% dt6 = dtiMakeDt6FromFsl([b0FileName], [t1FileName])
%
% Takes a set of images from FSL's DTI image files and saves them out as
% in a dt6 matlab file. You should specify the FSL S0 (usually b=0) file as
% input (a file dialog will pop-up if you don't).
%
% The t1 file is optional- if it is omitted, then the b=0 will be used as
% the anatomical reference.
%
% HISTORY:
% 2005.08.04 RFD (bob@white.stanford.edu) wrote it (based on dtiMakeDt6)
% 2006.04.27 RFD: adapted it for the Phillips data at MUSC. The old version
% (customized for data from U Washington) is now saved as
% dtiMakeDt6FromFsl_UW.

slice = [0,0,0]; % slice to display for checking coregistration
bb = [-80,80; -120,90; -60,90]';
mmDt = [1 1 1];
mmAnat = [1 1 1];
autoAlign = true;
showFigs = true;
tensorInterpSpline = false;

if ~exist('b0FileName','var') | isempty(b0FileName)
    [f, p] = uigetfile({'*.nii.gz','NIFTI gz';'*.*','All files'}, 'Select the FSL S0 file...');
    if(isnumeric(f)) error('Need an S0 file to continue...'); end
    b0FileName = fullfile(p, f);
    disp(b0FileName);
end
b0 = niftiRead(b0FileName);
% Fix ill-specified quaternion xforms so that they do something reasonable.
if(all(b0.qto_ijk(1:3,4) == [0 0 0]') | any(b0.qto_ijk(1:3,4)>1000))
    % *** HACK! [0.95 1.1 0.7] is near the ac for one data set
    if(det(b0.qto_ijk(1:3,1:3))<0)
        flipDti = 1;
        b0.data = flipdim(b0.data,1);
    end
    sz = size(b0.data);
    origin = round(sz(1:3)./2.*[0.95 1.1 0.7]);
    b0.qto_ijk = affineBuild(origin'+0.5, [0 0 0], 1./b0.pixdim, [0 0 0]);
    b0.qto_xyz = inv(b0.qto_ijk);
end
b0.data = double(b0.data);
% Clip vals <0 (these should be junk for a b=0 image)
b0.data(b0.data<0) = 0;

if ~exist('t1FileName','var')
    [f, p] = uigetfile({'*.nii.gz','NIFTI gz';'*.hdr','Analyze files (*.hdr)';'*.*','All files'},...
        'Select the T1 file...', b0FileName);
    if(isnumeric(f))
        t1FileName = [];
    else
        t1FileName = fullfile(p, f);
        disp(t1FileName);
    end
end
if(~isempty(t1FileName))
    t1 = niftiRead(t1FileName);
    % Fix ill-specified quaternion xforms so that they do something reasonable.
    if(all(t1.qto_ijk(1:3,4) == [0 0 0]'))
        sz = size(t1.data);
        origin = round(sz(1:3)./2.*[0.95 1.1 0.9]);
        t1.qto_ijk(1:3,4) = origin'+0.5;
        t1.qto_xyz = inv(t1.qto_ijk);
    end
    t1.data = double(t1.data);
    t1.data(t1.data<0) = 0;
else
    t1 = b0;
end

[datapath,basename] = fileparts(b0FileName);
us = strfind(basename,'_');
basename = basename(1:us(end));

if(~exist('outPathName','var') | isempty(outPathName))
    outPathName = fullfile(datapath, [basename 'dt6.mat']);
end
if(exist(outPathName,'file') | exist([outPathName '.mat'],'file'))
  disp('output file exists- please rename...');
  [f,p] = uiputfile('*.mat', 'Select output file...', outPathName);
  if(isnumeric(f)) error('User cancelled.'); end
  outPathName = fullfile(p,f);
end

disp(['Data will be saved in ' outPathName '...']);

% *** TO DO: fix this- here we assume that the data use a NIFTI-style
% header and this it's quaternion xform is specified correctly.
t1.acpcXform = t1.qto_xyz;
b0.acpcXform = b0.qto_xyz;

h = figure;
showFigure(h, t1, b0, bb, slice);
%set(h,'Position', [10, 50, 1000, 1000]);
set(h, 'PaperPositionMode', 'auto');
print(h, '-dpng', '-r90', [outPathName,'_headerAlign.png']);
if(~showFigs) close(h); end

if(autoAlign)
    spm_defaults;
    if(~exist('defaults','var')) global defaults; end
    disp('Coregistering (using spm tools)...');
    img = t1.data;
    img = mrAnatHistogramClip(img, 0.50, 0.995);
    VG.uint8 = uint8(round(img*255));
    VG.mat = t1.acpcXform;

    img = b0.data;
    img = mrAnatHistogramClip(img,0.40, 0.99);
    VF.uint8 = uint8(round(img*255));
    VF.mat = b0.acpcXform;
    p = defaults.coreg.estimate;
    % NOTE: there seems to be a consistent 1mm (1/2 of B0 voxel) translation
    % between the t1 and B0.
    transRot = spm_coreg(VG,VF,p);
    transRot(1:3) = transRot(1:3)+mmDt/2;
    b0.acpcXform = inv(VF.mat\spm_matrix(transRot(:)'));
    fig = figure;
    showFigure(fig, t1, b0, bb, [0,0,0], ['auto aligned']);
    set(fig, 'PaperPositionMode', 'auto');
    print(fig, '-dpng', '-r90', [outPathName,'_autoAlign.png']);
end

% Now build and save the dt6 data
eigVal = zeros([size(b0.data) 3]);
eigVec = zeros([size(b0.data) 3 3]);
for(ii=1:3)
    tmp = niftiRead(fullfile(datapath, [basename 'L' num2str(ii) '.nii.gz']));
    if(flipDti) tmp.data = flipdim(tmp.data,1); end
    eigVal(:,:,:,ii) = double(tmp.data);
end
for(ii=1:3)
    tmp = niftiRead(fullfile(datapath, [basename 'V' num2str(ii) '.nii.gz']));
    if(flipDti) tmp.data = flipdim(tmp.data,1); end
    eigVec(:,:,:,:,ii) = double(tmp.data);
    %eigVec(:,:,:,2,ii) = -eigVec(:,:,:,2,ii);
    if(flipDti) eigVec(:,:,:,1,ii) = -eigVec(:,:,:,1,ii); end
end

dt6 = dtiRebuildTensor(eigVec, eigVal);
clear eigVal eigVec;
%dt6_tmp = dtiLoadTensorElements(fullfile(fileparts(b0.baseFname), 'TensorElements.float.'));
%%dt6_tmp = permute(dt6_tmp,[2 1 3 4]);
%for(ii=1:6)
%    dt6(:,:,:,ii) = applyCannonicalXform(dt6_tmp(:,:,:,ii), b0.cannonical, b0.mmPerVox);
%end
%dt6 = permute(dt6,[2 1 3 4]);
%clear dt6_tmp;

% Reslice everything
disp('Interpolating tensors...');
%dt6A = dtiResliceTensorAffine(dt6, inv(b0.acpcXform), b0.cannonical_mmPerVox, bb, mmDt);
%dt6A = permute(dt6A,[2 1 3 4]);
if(tensorInterpSpline) tensorInterp = [7 7 7 0 0 0];
else tensorInterp = [1 1 1 0 0 0]; end
dt6 = mrAnatResliceSpm(dt6, inv(b0.acpcXform), bb, mmDt, tensorInterp, showFigs);
dt6(isnan(dt6)) = 0;
% NOTE: we want to apply b0.acpcXform to the tensors, even though we
% resliced them with inv(b0.acpcXform). inv(b0.acpcXform) maps from
% the new space to the old- the correct mapping for the interpolation,
% since we interpolate by creating a grid in the new space and fill it by
% pulling data from the old space. But the tensor reorientation should be
% done using the old-to-new space mapping (b0.acpcXform).
rigidXform = dtiFiniteStrainDecompose(b0.acpcXform);
[t,r] = affineDecompose([rigidXform,[0 0 0]';[0 0 0 1]]);
if(all(all(rigidXform==eye(3))))
    disp('No PPD correction needed- rotation is zero.');
else
    fprintf('Applying PPD rotation [%0.4f %0.4f %0.4f]...\n',r);
    dt6 = dtiXformTensors(dt6, rigidXform);
end
%figure; imagesc(makeMontage(dt6_new(:,:,:,1))); axis equal; colormap gray

disp('Interpolating B0...');
[b0_img,newXform] = mrAnatResliceSpm(b0.data, inv(b0.acpcXform), bb, mmDt, [7 7 7 0 0 0], showFigs);
b0_img(b0_img<0) = 0;
b0_img(isnan(b0_img)) = 0;

% create and apply a brain mask to the dt6 data
brainMask = mrAnatHistogramClip(b0_img, 0.4, 0.99);
brainMask = brainMask > 0.1;
% [c,v] = mrAnatHistogramSmooth(b0_img,256,0.05);
% % derivative of the thresholded derivative gives us the locations where a
% % rising or falling trend begins. In general, we can just take the first
% % rising trend (ie. just after the background noise) to find the brain.
% % We then back off from that by 25% (an empirically determined heuristic).
% peakStart = find(diff(diff(c)>0)>0);
% thresh = v(peakStart(1)+2);
% thresh = thresh.*0.75;
% brainMask = b0_img > thresh;
brainMask = dtiCleanImageMask(brainMask, 9);
figure; imagesc(makeMontage(brainMask)); axis equal tight; colormap(gray);
title('Brain Mask (based on b=0 image)');
dt6(repmat(~brainMask, [1,1,1,6])) = 0;

disp('Interpolating T1...');
anat.img = mrAnatResliceSpm(t1.data, inv(t1.acpcXform), bb, mmAnat, [], showFigs);
anat.img(anat.img<0) = 0;
anat.img(isnan(anat.img)) = 0;
anat.img = int16(round(anat.img));

mmPerVox = mmDt;
notes = 'Built from FSL data';
b0 = int16(round(b0_img));
anat.mmPerVox = mmAnat;

origin = bb(1,[1,2,3])-mmDt./2;
xformToAnat = [diag(mmDt./mmAnat) [0 0 0]'; [0 0 0 1]];
xformToAcPc = [diag(mmDt) origin'; [0 0 0 1]]; %swapXY*[diag(mm) origin'; [0 0 0 1]];
anat.xformToAcPc = [diag(mmAnat) origin'; [0 0 0 1]];
% rp = t1.talairach.refPoints;
% % Why swap coords like this? Well, the real reason has to do with the
% % history of ComputeTalairach. We could figure this out in a more general
% % way using t1.talairach.refPoints.mat, which tells us how the coords were
% % transformed in ComputeTalairach. In the end, the following reordering
% % works for our data, since the pre-processing is consistent.
% mm = t1.cannonical_mmPerVox([2 3 1]);
anat.talScale.notes = ['Scale factors to go from subject mm to Talairach mm.' ...
                       'Eg. talCoord = anat.talScale.sac * imgCoord.' ...
                       'The scales are (in order) superior, inferior, left, right ' ...
                       'and anterior of AC, ac-to-pc and posterior of pc.'];
% anat.talScale.sac = 72./sqrt(sum(((rp.acXYZ-rp.sacXYZ).*mm).^2));
% anat.talScale.iac = 42./sqrt(sum(((rp.acXYZ-rp.iacXYZ).*mm).^2));
% anat.talScale.lac = 62./sqrt(sum(((rp.acXYZ-rp.lacXYZ).*mm).^2));
% anat.talScale.rac = 62./sqrt(sum(((rp.acXYZ-rp.racXYZ).*mm).^2));
% anat.talScale.aac = 68./sqrt(sum(((rp.acXYZ-rp.aacXYZ).*mm).^2));
% anat.talScale.acpc = 24./sqrt(sum(((rp.acXYZ-rp.pcXYZ).*mm).^2));
% % The PPC is referenced to the PC. It is at Talairach (0,-102,0) and the PC
% % is at (0,-24,0), so it is 78 mm beyond the PC.
% anat.talScale.ppc = 78./sqrt(sum(((rp.pcXYZ-rp.ppcXYZ).*mm).^2));
anat.talScale.sac = 1.0;
anat.talScale.iac = 1.0;
anat.talScale.lac = 1.0;
anat.talScale.rac = 1.0;
anat.talScale.aac = 1.0;
anat.talScale.acpc = 1.0;
anat.talScale.ppc = 1.0;

disp(['Saving to ' outPathName '...']);
l = license('inuse'); h = hostid;
created = ['Created at ' datestr(now,31) ' by ' l(1).user ' on ' h{1} '.'];
save(outPathName, 'dt6', 'mmPerVox', 'notes', 'xformToAnat', 'xformToAcPc', 'b0', 'anat', 'created');
if(nargout==0)
    clear dt6;
end
return;

function showFigure(fig, t1, b0, bb, slice, figName)
if(~exist('figName','var')) figName = 'Interpolated slices'; end
% Get X,Y and Z (L-R, A-P, S-I) slices from T1 and b0 volumes
[t1Xsl] = dtiGetSlice(t1.acpcXform,t1.data,3,slice(3),bb);
[t1Ysl] = dtiGetSlice(t1.acpcXform,t1.data,2,slice(2),bb);
[t1Zsl] = dtiGetSlice(t1.acpcXform,t1.data,1,slice(1),bb);
[b0Xsl] = dtiGetSlice(b0.acpcXform,b0.data,3,slice(3),bb);
[b0Ysl] = dtiGetSlice(b0.acpcXform,b0.data,2,slice(2),bb);
[b0Zsl] = dtiGetSlice(b0.acpcXform,b0.data,1,slice(1),bb);
% Max values for image scaling
t1mv = max([t1Xsl(:); t1Ysl(:); t1Zsl(:)])+0.000001;
b0mv = max([b0Xsl(:); b0Ysl(:); b0Zsl(:)])+0.000001;
% Create XxYx3 RGB images for each of the axis slices. The green and
% blue channels are from the T1, the red channel is an average of T1
% and b=0.
Xsl(:,:,1) = t1Xsl./t1mv.*.5 + b0Xsl./b0mv.*.5;
Xsl(:,:,2) = t1Xsl./t1mv.*.5; Xsl(:,:,3) = t1Xsl./t1mv.*.5;
Ysl(:,:,1) = t1Ysl./t1mv.*.5 + b0Ysl./b0mv.*.5;
Ysl(:,:,2) = t1Ysl./t1mv.*.5; Ysl(:,:,3) = t1Ysl./t1mv.*.5;
Zsl(:,:,1) = t1Zsl./t1mv.*.5 + b0Zsl./b0mv.*.5;
Zsl(:,:,2) = t1Zsl./t1mv.*.5; Zsl(:,:,3) = t1Zsl./t1mv.*.5;

% Show T1 slices
figure(fig); set(fig, 'NumberTitle', 'off', 'Name', figName);
figure(fig); subplot(3,3,1); imagesc(bb(:,1), bb(:,2), t1Xsl);
colormap(gray); axis equal tight xy;
figure(fig); subplot(3,3,2); imagesc(bb(:,3), bb(:,1), t1Ysl);
colormap(gray); axis equal tight xy;
figure(fig); subplot(3,3,3); imagesc(bb(:,3), bb(:,2), t1Zsl);
colormap(gray); axis equal tight xy;
axis equal tight;

% Show b=0 slices
figure(fig); subplot(3,3,4); imagesc(bb(:,1), bb(:,2), b0Xsl);
colormap(gray); axis equal tight xy;
figure(fig); subplot(3,3,5); imagesc(bb(:,3), bb(:,1), b0Ysl);
colormap(gray); axis equal tight xy;
figure(fig); subplot(3,3,6); imagesc(bb(:,3), bb(:,2), b0Zsl);
colormap(gray); axis equal tight xy;
axis equal tight;

% Show combined slices
figure(fig); subplot(3,3,7); imagesc(bb(:,1), bb(:,2), Xsl);
axis equal tight xy;
figure(fig); subplot(3,3,8); imagesc(bb(:,3), bb(:,1), Ysl);
axis equal tight xy;
figure(fig); subplot(3,3,9); imagesc(bb(:,3), bb(:,2), Zsl);
axis equal tight xy;
axis equal tight;

return;