Skip to content
Snippets Groups Projects
GtGuiThresholdGrain.m 8.59 KiB
classdef GtGuiThresholdGrain < GtVolView
    properties
        threshold = 0;
        min_threshold = 0;
        max_threshold = 1;
        range = 1;
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Public object API - Interaction with outside
    methods
        function obj = GtGuiThresholdGrain(vol, varargin)
            viewer_args = varargin;
            if ~ismember('f_title', varargin(1:2:end))
                viewer_args(end+1:end+2) = {'f_title', 'Volume Segmentation'};
            end
            if ~ismember('overlay', varargin(1:2:end))
                viewer_args(end+1:end+2) = {'overlay', vol};
            end

            obj = obj@GtVolView(vol, viewer_args{:});
        end

        function changeThreshold(obj, new_threshold)
            obj.setThreshold(new_threshold);
            set(obj.conf.h_thr_slider, 'Value', obj.threshold);
            set(obj.conf.h_thr_edit, 'String', num2str(obj.threshold));
            obj.updateDisplay();
        end

        function setSavingFunction(obj, func_handle)
            obj.conf.save_func = func_handle;
        end

        function setSegmentFunction(obj, func_handle)
            obj.conf.segment_func = func_handle;
        end
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Internal methods - Addressable from derived classes
    methods (Access = protected)
        function setConfigInvariants(obj)
            setConfigInvariants@GtVolView(obj);
            obj.conf.transparency = 0.4;
        end

        function initParams(obj, arguments)
            initParams@GtVolView(obj, arguments)

            obj.min_threshold = min(obj.conf.vol(:));
            obj.max_threshold = max(obj.conf.vol(:));
            obj.range = obj.max_threshold - obj.min_threshold;

            obj.threshold = obj.min_threshold;
        end

        function initGui(obj)
            initGui@GtVolView(obj)
            % Let's disable zoom, while configuring
            zoomOp = zoom(obj.conf.h_figure);
            zoomState = get(zoomOp, 'Enable');
            zoom(obj.conf.h_figure, 'off');

            obj.conf.main_t_boxes = uiextras.VBox('Parent', obj.conf.currentParent);
            obj.conf.upper_t_boxes = uiextras.HBox('Parent', obj.conf.main_t_boxes);
            obj.conf.center_t_boxes = uiextras.HBox('Parent', obj.conf.main_t_boxes);

            set(obj.conf.main_t_boxes, 'Sizes', [20, -1]);
            obj.conf.h_thr_label = uicontrol('Style', 'text', ...
                                             'Parent', obj.conf.upper_t_boxes, ...
                                             'HorizontalAlignment', 'left');
            obj.conf.h_thr_edit = uicontrol('Style', 'edit', ...
                                            'Parent', obj.conf.upper_t_boxes);
            obj.conf.radio_boxes = uiextras.HBox('Parent', obj.conf.upper_t_boxes);
            obj.conf.h_thr_apply = uicontrol('Parent', obj.conf.upper_t_boxes, ...
                                            'Style', 'pushbutton', ...
                                            'String', 'Segment');
            obj.conf.h_thr_seed = uicontrol('Parent', obj.conf.upper_t_boxes, ...
                                            'Style', 'text', ...
                                            'String', '');

            set(obj.conf.upper_t_boxes, 'Sizes', [250, 100, -1, 70, 140]);

            obj.conf.slider_main_t_boxes = uiextras.VBox( ...
                'Parent', obj.conf.center_t_boxes);

            obj.conf.slider_contr_t_boxes = uiextras.HBox( ...
                'Parent', obj.conf.slider_main_t_boxes);

            obj.conf.sliders_t_boxes = uiextras.HBox( ...
                'Parent', obj.conf.slider_main_t_boxes);

            obj.conf.h_thr_slider = uicontrol('Style', 'slider', ...
                'Parent', obj.conf.sliders_t_boxes);

            obj.conf.h_viewer_panel = uipanel('BorderWidth', 4, ...
                                              'BorderType', 'line', ...
                                              'Parent', obj.conf.center_t_boxes);
            set(obj.conf.main_boxes, 'Parent', obj.conf.h_viewer_panel);

            set(obj.conf.slider_main_t_boxes, 'Sizes', [0, -1]);
            set(obj.conf.center_t_boxes, 'Sizes', [20, -1]);

            % Reset back the zoom to the previous state (before the inclusion)
            set(zoomOp, 'Enable', zoomState);
        end

        function resetUiComponents(obj)
            resetUiComponents@GtVolView(obj);

            set(obj.conf.h_thr_slider, 'Min',  obj.min_threshold, ...
                'Max', obj.max_threshold, 'Value', obj.threshold, ...
                'SliderStep', [0.005 0.05]);
            label_str = ['Threshold [' num2str(obj.min_threshold) ', ' ...
                         num2str(obj.max_threshold) ']:'];
            set(obj.conf.h_thr_label, 'String', label_str);
            set(obj.conf.h_thr_edit, 'String', num2str(obj.threshold));
        end

        function addUICallbacks(obj)
            addUICallbacks@GtVolView(obj)

            obj.addUICallback(obj.conf.h_thr_slider, ...
                              'AdjustmentValueChangedCallback', ...
                              @(src, evt)movedSlider(obj), true);

            obj.addUICallback(obj.conf.h_thr_apply, ...
                              'Callback', ...
                              @(src, evt)segment(obj), false);
            obj.addUICallback(obj.conf.h_thr_edit, ...
                              'Callback', ...
                              @(src, evt)changeThreshold(obj, str2double(get(obj.conf.h_thr_edit, 'String'))), false);
        end

        function setVisualisedData(obj, image, vol, is_overlay)
            slice = obj.loadSlice(vol);

            if (is_overlay)
                slice = slice > obj.threshold;
                zero_slice = zeros(size(slice));
                slice(:, :, 2) = zero_slice;
                slice(:, :, 3) = zero_slice;
            else
                slice_max = get(obj.conf.h_max, 'Value');
                slice_min = get(obj.conf.h_min, 'Value');
                slice = (slice - slice_min)/(slice_max - slice_min);
                slice(slice > 1) = 1;
                slice(slice < 0) = 0;
                slice = repmat(slice, [1,1,3]);
            end
            set(image, 'cdata', slice);
        end

        function createAxesMenu(obj)
            createAxesMenu@GtVolView(obj);

            obj.conf.h_menu_items{end+1} = uimenu(obj.conf.h_context_menu, ...
                                           'Label', 'Set as seed (Morpho)', ...
                                           'Callback', @(src,evt)setSeed(obj));
        end

        function guiQuit(obj)
            if (isfield(obj.conf, 'save_func'))
                obj.conf.save_func(obj.threshold);
            end

            guiQuit@GtVolView(obj);
        end
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Public Callbacks - Interaction with GUI elements
    methods (Access = public)
        function updateBC(obj)
            updateBC@GtVolView(obj);
            obj.setVisualisedData(obj.conf.h_im, obj.conf.vol, false);
        end

        function movedSlider(obj)
            new_thresh = get(obj.conf.h_thr_slider, 'Value');
            set(obj.conf.h_thr_edit, 'String', num2str(obj.threshold));
            obj.setThreshold(new_thresh);
            obj.updateDisplay();
        end

        function segment(obj)
            if (isfield(obj.conf, 'segment_func'))
                if (isfield(obj.conf, 'morpho') && ~isempty(obj.conf.morpho))
                    obj.conf.segment_func(obj.threshold, obj.conf.morpho);
                else
                    obj.conf.segment_func(obj.threshold, 0);
                end
            else
                errordlg('No segmentation function assigned', 'Segment');
            end
        end

        function setSeed(obj, point)
            if (~exist('point', 'var'))
                point = obj.conf.clicked_point;
            end
            voxel = round(point);
            obj.conf.morpho = voxel;
            set(obj.conf.h_thr_seed, 'String', sprintf('Seed: (%d, %d, %d)', voxel));
        end
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Very internal methods - Private for this class
    methods (Access = protected)
        function setThreshold(obj, new_threshold)
            obj.threshold = new_threshold;
            if (obj.threshold > obj.max_threshold)
                obj.threshold = obj.max_threshold;
            elseif (obj.threshold < obj.min_threshold)
                obj.threshold = obj.min_threshold;
            end
        end
    end
end