Code covered by the BSD License  

Highlights from
The Warholer

image thumbnail

The Warholer

by

 

15 Aug 2012 (Updated )

GUI that displays an 8-color version of an image, based on RGB thresholding.

warholer
classdef warholer < handle
    %WARHOLER  GUI for creating 8-color images by thresholding R, G, B values

    % GUI properties
    properties
        img      % Original image (data)
        img8     % Thresholded image
        fname    % Filename for image
        handles  % GUI control handles
    end
    
    methods
        % Constructor method (creates the GUI)
        function obj = warholer(fname)
            % Blank image (size chosen to make nice initial window arrangement)
            obj.img = zeros(100,89);
            % Make window
            obj.handles.fig = figure('Toolbar','none','Menubar','none');
            
            % Make GUI controls
            % Note: positions are left as default; everything will be
            % adjusted by the adjustsize callback (which is called
            % immediately)
            
            % Get background color
            bgc = get(obj.handles.fig,'color');
            % Make pushbutton to get file (this will become the axes where
            % image is displayed, after the file is selected)
            obj.handles.ax = uicontrol(obj.handles.fig,...
                'units','normalized','style','pushbutton',...
                'string','Click to choose image','fontweight','bold',...
                'fontsize',10,'callback',@obj.getimg);
            % Make slider controls -- currently all disabled
            % Add text below sliders (to show current slider value)
            obj.handles.rval = uicontrol(obj.handles.fig,...
                'units','normalized','style','text','string','128',...
                'fontsize',10,'fontweight','bold',...
                'backgroundcolor',bgc,'Enable','off');
            obj.handles.gval = uicontrol(obj.handles.fig,...
                'units','normalized','style','text','string','128',...
                'fontsize',10,'fontweight','bold',...
                'backgroundcolor',bgc,'Enable','off');
            obj.handles.bval = uicontrol(obj.handles.fig,...
                'units','normalized','style','text','string','128',...
                'fontsize',10,'fontweight','bold',...
                'backgroundcolor',bgc,'Enable','off');
            % Add static labels above sliders
            obj.handles.rtxt = uicontrol(obj.handles.fig,...
                'units','normalized','style','text','string','R',...
                'fontsize',10,'fontweight','bold',...
                'backgroundcolor',bgc,'Enable','off');
            obj.handles.gtxt = uicontrol(obj.handles.fig,...
                'units','normalized','style','text','string','G',...
                'fontsize',10,'fontweight','bold',...
                'backgroundcolor',bgc,'Enable','off');
            obj.handles.btxt = uicontrol(obj.handles.fig,...
                'units','normalized','style','text','string','B',...
                'fontsize',10,'fontweight','bold',...
                'backgroundcolor',bgc,'Enable','off');
            % Make sliders
            obj.handles.rs = uicontrol(obj.handles.fig,...
                'units','normalized','style','slider','min',0,'max',255,...
                'value',128,'SliderStep',[1 10]/255,...
                'callback',@obj.changer,'Enable','off');
            obj.handles.gs = uicontrol(obj.handles.fig,...
                'units','normalized','style','slider','min',0,'max',255,...
                'value',128,'SliderStep',[1 10]/255,...
                'callback',@obj.changeg,'Enable','off');
            obj.handles.bs = uicontrol(obj.handles.fig,...
                'units','normalized','style','slider','min',0,'max',255,...
                'value',128,'SliderStep',[1 10]/255,...
                'callback',@obj.changeb,'Enable','off');
            % Add "randomize" button
            obj.handles.rnd = uicontrol(obj.handles.fig,...
                'units','normalized','style','pushbutton',...
                'string','Randomize','fontweight','bold','fontsize',10,...
                'callback',@obj.rndm,'Enable','off');
            
            % Was the constructor called with an input (filename)?
            if nargin
                % If so, use that as the image
                obj.fname = fname;
                % Use the image
                getimg(obj,obj.handles.ax)
            else
                % If not, leave filename property empty
                obj.fname = '';
                % Adjust UI control locations
                adjustsize(obj)
            end
        end % constructor
        
        %%%% UTILITIES %%%%
        
        % Set positions of UI window elements
        function adjustsize(obj)
            % Get dimensions
            ar = get(0,'ScreenSize');
            is = size(obj.img);
            hpos = get(obj.handles.fig,'Position');
            sw = 30;  % Slider width
            % Do clever fiddling to arrange image and sliders nicely
            y = sw/hpos(4);
            hpos(3) = hpos(3)*ar(4)*is(2)/(ar(3)*is(1));
            x = hpos(3)/(hpos(3)+7*sw);
            hpos(3) = hpos(3) + 7*sw;
            hpos(1) = ar(1) + 0.5*(ar(3)-hpos(3));
            sw = sw/hpos(3);
            
            % Adjust window position
            set(obj.handles.fig,'Position',hpos)
            % Adjust axes position
            if isempty(obj.fname)
                % No image => "axes" are actually pushbutton
                set(obj.handles.ax,'Position',[0.05,0.4,x-0.05,0.2])
            else
                % Image exists
                set(obj.handles.ax,'Position',[0.05,0,x-0.05,1])
            end
            
            % Slider dimensions (more or less -- used to position UI
            % elements related to the sliders)
            sldht = 1-5*y;
            sldst = 3*y;
            % Set positions of text below sliders (showing current values)
            set(obj.handles.rval,'position',[x+sw,sldst,sw,y/2]);
            set(obj.handles.gval,'position',[x+3*sw,sldst,sw,y/2]);
            set(obj.handles.bval,'position',[x+5*sw,sldst,sw,y/2]);
            % Set positions of static text
            sldst = 3.5*y + sldht;
            set(obj.handles.rtxt,'position',[x+sw,sldst,sw,y/2]);
            set(obj.handles.gtxt,'position',[x+3*sw,sldst,sw,y/2]);
            set(obj.handles.btxt,'position',[x+5*sw,sldst,sw,y/2]);
            % Set positions of sliders
            sldst = 3.5*y;
            set(obj.handles.rs,'position',[x+sw,sldst,sw,sldht]);
            set(obj.handles.gs,'position',[x+3*sw,sldst,sw,sldht]);
            set(obj.handles.bs,'position',[x+5*sw,sldst,sw,sldht]);
            % Set position of randomize button
            set(obj.handles.rnd,'position',[x+2*sw,y,3*sw,y]);
        end
        
        %%%% CALLBACKS %%%%
        
        % Get and display image
        function getimg(obj,h,~)
            % Retrieve current filename (either empty or given when the
            % constructor was called)
            fname = obj.fname; %#ok<*PROP>
            % Empty filename => let user choose file
            if isempty(fname)
                [fname,pathname] = uigetfile({'*.jpg;*.tif;*.png;*.gif','All Image Files'});
            end
            % If user pressed "cancel", do nothing.
            % Otherwise, load and display image
            if ~isequal(fname,0)
                % Full path not given if user provides filename when calling the constructor
                if exist('pathname','var')
                    fname = fullfile(pathname, fname);
                end
                % Now (finally!) we have the filename of the image
                obj.fname = fname;
                % Read the image from file
                obj.img = imread(fname);
                % Get the image size
                is = size(obj.img);
                % Check if image is b/w, rather than color
                if numel(is)<3
                    % Make sure image is 3-D array
                    obj.img = repmat(obj.img,[1,1,3]);
                end
                % Do thresholding (with default value)
                obj.img8 = (obj.img>=128);
                % Delete and replace current axes (current "axes" are
                % actually the pushbutton)
                x = get(h,'position');
                delete(h)
                obj.handles.ax = axes('position',x,'Parent',obj.handles.fig);
                % Display image in new axes
                obj.handles.him = image(obj.img8,'Parent',obj.handles.ax);
                axis image
                axis off
                % Enable all the slider controls & randomize button
                set(obj.handles.rval,'Enable','on')
                set(obj.handles.gval,'Enable','on')
                set(obj.handles.bval,'Enable','on')
                set(obj.handles.rtxt,'Enable','on')
                set(obj.handles.gtxt,'Enable','on')
                set(obj.handles.btxt,'Enable','on')
                set(obj.handles.rs,'Enable','on')
                set(obj.handles.gs,'Enable','on')
                set(obj.handles.bs,'Enable','on')
                set(obj.handles.rnd,'Enable','on')
                
                % Resize everything
                adjustsize(obj)
            end
        end
        
        % Change red value slider
        function changer(obj,h,~)
            % Get the value and round off
            val = round(get(h,'value'));
            % Set the value back to the rounded value
            set(h,'value',val);
            % Update the string
            set(obj.handles.rval,'string',num2str(val));
            % Update the image (red channel)
            obj.img8(:,:,1) = (obj.img(:,:,1)>=val);
            set(obj.handles.him,'CData',obj.img8)
        end
        
        % Change green value slider
        function changeg(obj,h,~)
            val = round(get(h,'value'));
            set(h,'value',val);
            set(obj.handles.gval,'string',num2str(val));
            % Update the image (green channel)
            obj.img8(:,:,2) = (obj.img(:,:,2)>=val);
            set(obj.handles.him,'CData',obj.img8)
        end
        
        % Change blue value slider
        function changeb(obj,h,~)
            val = round(get(h,'value'));
            set(h,'value',val);
            set(obj.handles.bval,'string',num2str(val));
            % Update the image (blue channel)
            obj.img8(:,:,3) = (obj.img(:,:,3)>=val);
            set(obj.handles.him,'CData',obj.img8)
        end
        
        % Randomize button
        function rndm(obj,~,~)
            % Set the sliders to random integer values from 0 to 255
            set(obj.handles.rs,'value',randi([0,255]))
            set(obj.handles.gs,'value',randi([0,255]))
            set(obj.handles.bs,'value',randi([0,255]))
            % Call the updating callbacks
            changer(obj,obj.handles.rs,[])
            changeg(obj,obj.handles.gs,[])
            changeb(obj,obj.handles.bs,[])
        end
        
    end
    
end

Contact us