UI/guiCD.m
%% A very simple Graphic User Interface for basic usage
function guiCD
addpath('../');


%% Constants
global METRICS CONFIG_METRICS ALGS THRE_ALGS
METRICS = {'OA', 'UA', 'Recall', 'FMeasure', 'Kappa'};
CONFIG_METRICS = {{}, {}, {}, {}, {}, {}};
ALGS = {'CVA', 'DPCA', 'ImageDiff', 'ImageRatio', 'ImageRegr', 'IRMAD', 'MAD', 'PCAkMeans', 'PCDA'};
THRE_ALGS = {'KMeans', 'OTSU'};


%% Place controls
fig = figure('Name', 'guiCD', 'Visible', 'off');

% Layout parameters
xMargin = 0.02;
yMargin = 0.08;

xSpaceAxes = 0.1;
ySpaceAxes = 0.1;
xSizeAxes = 0.3;
ySizeAxes = 0.3;

xSpaceButton = 0.05;
ySpaceButton = 0.05;
xSizeButton = 0.1;
ySizeButton = 0.1;

xSpacePopup = 0.1;
ySpacePopup = 0.2;
xSizePopup = 0.15;
ySizePopup = 0.1;

xSizeText = 0.15;
ySizeText = 0.05;

xAxesOffset = xMargin;
yAxesOffset = yMargin + ySpaceButton/2 + ySizeButton;

% Axes
t1Axes = axes(...
    'Position', [xAxesOffset, yAxesOffset+ySizeAxes+ySpaceAxes, xSizeAxes, ySizeAxes], ...
    'Visible', 'off', ...
    'Nextplot', 'replacechildren');
t1Text = uicontrol( ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'Position', [xAxesOffset+0.5*xSizeAxes-0.5*xSizeText,yAxesOffset+2*ySizeAxes+ySpaceAxes, xSizeText, ySizeText], ...
    'String', 'T1');

t2Axes = axes(...
    'Position', [xAxesOffset+xSizeAxes+xSpaceAxes, yAxesOffset+ySizeAxes+ySpaceAxes, xSizeAxes, ySizeAxes], ...
    'Visible', 'off', ...
    'Nextplot', 'replacechildren');
t2Text = uicontrol( ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'Position', [xAxesOffset+1.5*xSizeAxes+xSpaceAxes-0.5*xSizeText, yAxesOffset+2*ySizeAxes+ySpaceAxes, xSizeText, ySizeText], ...
    'String', 'T2');

refAxes = axes(...
    'Position', [xAxesOffset, yAxesOffset, xSizeAxes, ySizeAxes], ...
    'Visible', 'off', ...
    'Nextplot', 'replacechildren');
refText = uicontrol( ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'Position', [xAxesOffset+0.5*xSizeAxes-0.5*xSizeText, yAxesOffset+ySizeAxes, xSizeText, ySizeText], ...
    'String', 'Ref');

cmAxes = axes(...
    'Position', [xAxesOffset+xSizeAxes+xSpaceAxes, yAxesOffset, xSizeAxes, ySizeAxes], ...
    'Visible', 'off', ...
    'Nextplot', 'replacechildren');
cmText = uicontrol( ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'Position', [xAxesOffset+1.5*xSizeAxes+xSpaceAxes-0.5*xSizeText, yAxesOffset+ySizeAxes, xSizeText, ySizeText], ...
    'String', 'CM');

% Buttons
t1LoadButton = uicontrol( ...
    'Style', 'pushbutton', ...
    'Units', 'normalized', ...
    'Position', [xMargin+xSpaceButton, yMargin, xSizeButton, ySizeButton], ...
    'String', 'Load T1', ...
    'Callback', {@loadButtonPushed, t1Axes}, ...
    'Userdata', '');

t2LoadButton = uicontrol( ...
    'Style', 'pushbutton', ...
    'Units', 'normalized', ...
    'Position', [xMargin+xSizeButton+2*xSpaceButton, yMargin, xSizeButton, ySizeButton], ...
    'String', 'Load T2', ...
    'Callback', {@loadButtonPushed, t2Axes}, ...
    'Userdata', '');

refLoadButton = uicontrol( ...
    'Style', 'pushbutton', ...
    'Units', 'normalized', ...
    'Position', [xMargin+2*xSizeButton+3*xSpaceButton, yMargin, xSizeButton, ySizeButton], ...
    'String', 'Load GT', ...
    'Callback', {@loadButtonPushed, refAxes}, ...
    'Userdata', '');

cdButton = uicontrol( ...
    'Style', 'pushbutton', ...
    'Units', 'normalized', ...
    'Position', [xMargin+3*xSizeButton+4*xSpaceButton, yMargin, xSizeButton, ySizeButton], ...
    'String', 'detect', ...
    'Callback', @cdButtonPushed, ...
    'Userdata', []);

indexButton = uicontrol( ...
    'Style', 'pushbutton', ...
    'Units', 'normalized', ...
    'Position', [xMargin+4*xSizeButton+5*xSpaceButton, yMargin, xSizeButton, ySizeButton], ...
    'String', 'indexes', ...
    'Callback', @indexButtonPushed, ...
    'Userdata', []);

resetButton = uicontrol( ...
    'Style', 'pushbutton', ...
    'Units', 'normalized', ...
    'Position', [xMargin+5*xSizeButton+6*xSpaceButton, yMargin, xSizeButton, ySizeButton], ...
    'String', 'reset', ...
    'Callback', @resetButtonPushed, ...
    'Userdata', []);

algPopup = uicontrol( ...
    'Style', 'popupmenu', ...
    'Units', 'normalized', ...
    'Position', [xAxesOffset+2*xSizeAxes+xSpaceAxes+xSpacePopup, yAxesOffset+2*ySpacePopup+ySizePopup, xSizePopup, ySizePopup], ...
    'String', ALGS, ...
    'Callback', @cdButtonPushed, ...
    'Value', 1);
algText = uicontrol( ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'Position', [xAxesOffset+2*xSizeAxes+xSpaceAxes+xSpacePopup, yAxesOffset+2*ySpacePopup+2*ySizePopup, xSizeText, ySizeText], ...
    'String', 'CD Alg.', ...
    'HorizontalAlignment', 'left');

threPopup = uicontrol( ...
    'Style', 'popupmenu', ...
    'Units', 'normalized', ...
    'Position', [xAxesOffset+2*xSizeAxes+xSpaceAxes+xSpacePopup, yAxesOffset+ySpacePopup, xSizePopup, ySizePopup], ...
    'String', THRE_ALGS, ...
    'Callback', @cdButtonPushed, ...
    'Value', 1);
algThre = uicontrol( ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'Position', [xAxesOffset+2*xSizeAxes+xSpaceAxes+xSpacePopup, yAxesOffset+ySpacePopup+ySizePopup, xSizeText, ySizeText], ...
    'String', 'Thre. Alg.', ...
    'HorizontalAlignment', 'left');

% Store the handles in a struct
handles = struct;
handles.t1Axes = t1Axes;
handles.t2Axes = t2Axes;
handles.refAxes = refAxes;
handles.cmAxes = cmAxes;
handles.t1LoadButton = t1LoadButton;
handles.t2LoadButton = t2LoadButton;
handles.refLoadButton = refLoadButton;
handles.cdButton = cdButton;
handles.indexButton = indexButton;
handles.resetButton = resetButton;
handles.algPopup = algPopup;
handles.threPopup = threPopup;
setappdata(fig, 'handles', handles);

% Show the image
set(fig, 'Visible', 'on');
end

%% Callback functions
function loadButtonPushed(src, event, axes_)
persistent last_path
if isempty(last_path)
    last_path = '.';
end
[file_,path_] = uigetfile(fullfile(last_path, '*.*'), 'Select a file');
last_path = path_;
imgPath = fullfile(path_, file_);
if ~exist(imgPath, 'file')
    return
end
set(src, 'Userdata', imgPath);
im = readFile_(imgPath);
if size(im, 3) ~= 1 && size(im, 3) ~= 3
    im = Utilities.normMinMax(Utilities.mergeAvg(double(im)));
end
imshow(im, 'Parent', axes_);
clearResults_(getappdata(gcbf, 'handles'));
end


function cdButtonPushed(src, event)
global METRICS CONFIG_METRICS
% fig = get(src, 'Parent');
% h = getappdata(fig, 'handles');
h = getappdata(gcbf, 'handles');
if isempty(get(h.t1LoadButton, 'Userdata')) || isempty(get(h.t2LoadButton, 'Userdata'))
    return
end
algs = get(h.algPopup, 'String');
thre_algs = get(h.threPopup, 'String');
try
    if isempty(get(h.refLoadButton, 'Userdata'))
        [CM, DI] = detectChange( ...
            algs{get(h.algPopup, 'Value')}, {}, ...
            thre_algs{get(h.threPopup, 'Value')}, {}, ...
            get(h.t1LoadButton, 'Userdata'), ...
            get(h.t2LoadButton, 'Userdata'));
    else
        [CM, DI, results] = detectChange( ...
            algs{get(h.algPopup, 'Value')}, {}, ...
            thre_algs{get(h.threPopup, 'Value')}, {}, ...
            get(h.t1LoadButton, 'Userdata'), ...
            get(h.t2LoadButton, 'Userdata'), ...
            get(h.refLoadButton, 'Userdata'), ...
            METRICS, ...
            CONFIG_METRICS);
        aucer = Metrics.AUC();
        aucer.update(CM, readFile_(get(h.refLoadButton, 'Userdata')), DI);
        results.aucer = aucer;
        set(h.indexButton, 'Userdata', results);
    end
catch ME
    if eq(src, h.cdButton)
        errordlg(['An error occured: ', ME.message], 'Error');
    end
    return;
end
imshow(CM, 'Parent', h.cmAxes);
end


function indexButtonPushed(src, event)
results = get(src, 'Userdata');
if isempty(results)
    return;
end
try
    results.aucer.plotROC();
    message_ = {};
    for field = fieldnames(results)'
        name = field{1};
        if strcmp(name, 'aucer')
            continue;
        end
        message_ = [message_, {[name, ': ', num2str(results.(name))]}];
    end
    msgbox(message_, 'Indexes');
catch ME
    errordlg(['An error occured: ', ME.message], 'Error');
end
end


function resetButtonPushed(src, event)
handles = getappdata(gcbf, 'handles');
for name = fieldnames(handles)'
    obj = handles.(name{1});
    if strcmp(get(obj, 'Type'), 'axes')
        delete(get(obj, 'Children'));
    elseif strcmp(get(obj, 'Type'), 'uicontrol')
        if strcmp(get(obj, 'Style'), 'pushbutton')
            if ischar(get(obj, 'Userdata'))
                set(obj, 'Userdata', '');
            else
                set(obj, 'Userdata', []);
            end
        elseif strcmp(get(obj, 'Style'), 'popupmenu')
            set(obj, 'Value', 1);
        end
    end
end
end


% Utilities
function clearResults_(handles)
% Clear cmAxes
if ~isempty(get(handles.cmAxes,'Children'))
    delete(get(handles.cmAxes,'Children'));
end
% Clear indxes
if ~isempty(get(handles.indexButton, 'Userdata'))
    set(handles.indexButton, 'Userdata', []);
end
end


function im = readFile_(path_)
try
    % Try to read via default loader
    im = Datasets.Loaders.defaultLoader(path_);
catch ME
    % Otherwise, read as envi file
    if strcmp(ME.identifier, 'MATLAB:imagesci:imread:fileFormat')
        im = Datasets.Loaders.enviLoader(path_);
    else
        rethrow(ME);
    end
end
end