📄 ice_stand_alone.m
字号:
function varargout = ice(varargin)
%ICE Interactive Color Editor.
%
% OUT = ICE('Property Name', 'Property Value', ...) transforms
% an image's color components based on interactively specified
% mapping functions. Inputs are Property Name/Property Value pairs:
%
% Name Value
% ------------ -------------------------------------------------
% 'image' An RGB or monochrome input image to be transformed
% by interactively specified mappings.
% 'space' The color space of the components to be modified.
% Possible values are 'rgb', 'cmy', 'hsi',
% 'hsv', 'ntsc' (or 'yiq'), 'ycbcr'. When omitted,
% the RGB color space is assumed.
% 'wait' If 'on' (the default), OUT is the mapped input image
% and ICE returns to the calling function or workspace
% when closed. If 'off', OUT is the handle of the mapped
% input image and ICE returns immediately.
%
% EXAMPLES:
% ice % Demo curves mode
% ice('image', f) % Map RGB or mono image
% ice('image', f, 'space', 'hsv') % Map HSV of RGB image
% g = ice('image', f, 'wait', 'off'); % Return with handles of g
%
% ICE displays one popup menu selectable mapping function at a time.
% Each image component is mapped by a dedicated curve (e.g., R, G,
% or B) and then bt an all-component curve (e.g., RGB). Each curve's
% control points are depicted as circles that can be moved, added,
% or deleted with a three-button mouse:
%
% Mouse Button Editing Operation
% ------------ -------------------------------------------------
% Left Move control point by pressing and dragging.
% Middle Add and position a control point by pressing
% and dragging. (Optionally Shift-Left)
% Right Deleted a control point. (Optionally Control-Left)
%
% Checkboxes determine how mapping function are computed, whether
% the input image and reference pseudo- and full-color bars are
% mapped, and the displayed reference curve information (e.g., PDF):
%
% Checkbox Function
% ------------ -------------------------------------------------
% Smooth Checked for cubic spline (smooth curve) interpo-
% lation. If unchecked, piecewise linear.
% Clamp Ends Checked to force the starting and ending curve
% slopes in cubic spline interpolation to 0. No
% effect on piecewise linear.
% Show PDF Display probablity density function(s) [i.e.,
% histogram(s)] of the image components effected by
% the mapping function.
% Show CDF Display cumulative distributions function(s)
% instead of PDFs.
% <Note: Show PDF/CDF are mutually exclusive.>
% Map Image If checked, image mapping is enabled; else not.
% Map Bars If checked, pseudo- and full-color bar mapping is
% enabled; else display th eunmapped bars (a gray
% wedge and hue wedge, respectively).
%
% Mapping functions can be initialized via pushbuttons:
%
% Button Function
% ------------ -------------------------------------------------
% Reset Init the currently displayed mapping function
% and uncheck all curve parameters.
% Reset All Initalize all mapping functions.
% Copyright 2002-2004 R. C. Gonzalez, R. E. Woods, & S. L. Eddins
% Digital Image Processing Using MATLAB, Prentice-Hall, 2004
% $Revision: 1.2 $ $Date: 2003/02/19 22:10:00 $
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @ice_OpeningFcn, ...
'gui_OutputFcn', @ice_OutputFcn, ...
'gui_LayoutFcn', @ice_LayoutFcn, ...
'gui_Callback', []);
if nargin & isstr(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
%-------------------------------------------------------------------%
function ice_OpeningFcn(hObject, eventdata, handles, varargin)
% When ICE is opened, perform basic initialization (e.g., setup
% globals, ...) before it is made visible.
% Set ICE globals to defaults.
handles.updown = 'none'; % Mouse updown state
handles.plotbox = [0 0 1 1]; % Plot area parameters in pixels
handles.set1 = [0 0; 1 1]; % Curve 1 control points
handles.set2 = [0 0; 1 1]; % Curve 2 control points
handles.set3 = [0 0; 1 1]; % Curve 3 control points
handles.set4 = [0 0; 1 1]; % Curve 4 control points
handles.curve = 'set1'; % Structure name of selected curve
handles.cindex = 1; % Index of selected curve
handles.node = 0; % Index of selected control point
handles.below = 1; % Index of node below control point
handles.above = 2; % Index of node above control point
handles.smooth = [0; 0; 0; 0]; % Curve smoothing states
handles.slope = [0; 0; 0; 0]; % Curve end slope control states
handles.cdf = [0; 0; 0; 0]; % Curve CDF states
handles.pdf = [0; 0; 0; 0]; % Curve PDF states
handles.output = []; % Output image handle
handles.df = []; % Input PDFs and CDFs
handles.colortype = 'rgb'; % Input image color space
handles.input = []; % Input image data
handles.imagemap = 1; % Image map enable
handles.barmap = 1; % Bar map enable
handles.graybar = []; % Pseudo (gray) bar image
handles.colorbar = []; % Color (hue) bar image
% Process Property Name/Property Value input argument pairs.
wait = 'on';
if(nargin > 3)
for i = 1: 2: (nargin - 3),
if nargin - 3 == i break; end
switch lower(varargin{i})
case 'image'
if ndims(varargin{i + 1}) == 3
handles.input = varargin{i + 1};
elseif ndims(varargin{i + 1}) == 2
handles.input = cat(3, varargin{i + 1}, ...
varargin{i + 1}, varargin{i + 1}); end;
handles.input = double(handles.input);
inputmax = max(handles.input(:));
if inputmax > 255 handles.input = handles.input / 65535;
elseif inputmax > 1
handles.input = handles.input / 255; end
case 'space'
handles.colortype = lower(varargin{i + 1});
switch handles.colortype
case 'cmy', list = {'CMY' 'Cyan' 'Magenta' 'Yellow'};
case {'ntsc', 'yiq'}
list = {'YIQ' 'Luminance' 'Hue' 'Saturation'};
handles.colortype = 'ntsc';
case 'ycbcr', list = {'YCbCr' 'Luminance' 'Blue' ...
'Difference' 'Red Difference'};
case 'hsv', list = {'HSV' 'Hue' 'Saturation' 'Value'};
case 'hsi', list = {'HSI' 'Hue' 'Saturation' 'Intensity'};
otherwise
list = {'RGB' 'Red' 'Green' 'Blue'};
handles.colortype = 'rgb';
end
set(handles.component_popup, 'String', list);
case 'wait', wait = lower(varargin{i + 1});
end
end
end
% Create pseudo- and full-color mapping bars (grays and hues). Store a
% color space converted 1x128x3 line of each bar for mapping.
xi = 0: 1/127: 1; x = 0: 1 / 6: 1; x = x';
y = [1 1 0 0 0 1 1; 0 1 1 1 0 0 0; 0 0 0 1 1 1 0]';
gb = repmat(xi, [1 1 3]); cb = interp1q(x, y, xi');
cb = reshape(cb, [1 128 3]);
if ~strcmp(handles.colortype, 'rgb')
gb = eval(['rgb2' handles.colortype '(gb)']);
cb = eval(['rgb2' handles.colortype '(cb)']); end
gb = round(255 * gb); gb = max(0, gb); gb = min(255, gb);
cb = round(255 * cb); cb = max(0, cb); cb = min(255, cb);
handles.graybar = gb; handles.colorbar = cb;
% Do color space transforms, clamp to [0, 255], compute histograms
% and cumulative distribution functions, and create output figure.
if size(handles.input, 1)
if ~strcmp(handles.colortype, 'rgb')
handles.input = eval(['rgb2' handles.colortype ...
'(handles.input)']); end
handles.input = round(255 * handles.input);
handles.input = max(0, handles.input);
handles.input = min(255, handles.input);
for i = 1: 3
color = handles.input(:, :, i);
df = hist(color(:), 0: 255);
handles.df = [handles.df; df / max(df(:))];
df = df / sum(df(:)); df = cumsum(df);
handles.df = [handles.df; df];
end
figure; handles.output = gcf;
end
% Compute ICE's screen position and display image/graph.
set(0, 'Units', 'pixels'); ssz = get(0, 'Screensize');
set(handles.ice, 'Units', 'pixels');
uisz = get(handles.ice, 'Position');
if size(handles.input, 1)
fsz = get(handles.output, 'Position');
bc = (fsz(4) - uisz(4)) / 3;
if bc > 0 bc = bc + fsz(2);
else bc = fsz(2) + fsz(4) - uisz(4) - 10; end
lc = fsz(1) + (size(handles.input, 2) / 4) + (3 * fsz(3) / 4);
lc = min(lc, ssz(3) - uisz(3) - 10);
set(handles.ice, 'Position', [lc bc 463 391]);
else
bc = round((ssz(4) - uisz(4)) / 2) - 10;
lc = round((ssz(3) - uisz(3)) / 2) - 10;
set(handles.ice, 'Position', [lc bc uisz(3) uisz(4)]);
end
set(handles.ice, 'Units', 'normalized');
graph(handles); render(handles);
% Update handles and Make ICE wait before exit if required.
guidata(hObject, handles);
if strcmpi(wait, 'on') uiwait(handles.ice); end
%-------------------------------------------------------------------%
function varargout = ice_OutputFcn(hObject, eventdata, handles)
% After ICE is closed, get the image data of the current figure
% for the output. If 'handles' exists, ICE isn抰 closed (there was
% no 'uiwait') so output figure handle.
if max(size(handles)) == 0
figh = get(gcf);
imageh = get(figh.Children);
if max(size(imageh)) > 0
image = get(imageh.Children);
varargout{1} = image.CData;
end
else varargout{1} = hObject; end
%-------------------------------------------------------------------%
function ice_WindowButtonDownFcn(hObject, eventdata, handles)
% Start mapping function control point editing. Do move, add, or
% delete for left, middle, and right button mouse clicks ('normal',
% 'extend', and 'alt' cases) over plot area.
set(handles.curve_axes, 'Units', 'pixels');
handles.plotbox = get(handles.curve_axes, 'Position');
set(handles.curve_axes, 'Units', 'normalized');
[inplot, x, y] = cursor(hObject, handles);
if inplot
nodes = getfield(handles, handles.curve);
i = find(x >= nodes(:, 1)); below = max(i);
above = min(below + 1, size(nodes, 1));
if (x - nodes(below, 1)) > (nodes(above, 1) - x) node = above;
else node = below; end
deletednode = 0;
switch get(hObject, 'SelectionType')
case 'normal'
if node == above above = min(above + 1, size(nodes, 1));
elseif node == below below = max(below - 1, 1); end
if node == size(nodes, 1) below = above;
elseif node == 1 above = below; end
if x > nodes(above, 1) x = nodes(above, 1);
elseif x < nodes(below, 1) x = nodes(below, 1); end
handles.node = node; handles.updown = 'down';
handles.below = below; handles.above = above;
nodes(node, :) = [x y];
case 'extend'
if ~length(find(nodes(:, 1) == x))
nodes = [nodes(1: below, :); [x y]; nodes(above: end, :)];
handles.node = above; handles.updown = 'down';
handles.below = below; handles.above = above + 1;
end
case 'alt'
if (node ~= 1) & (node ~= size(nodes, 1))
nodes(node, :) = []; deletednode = 1; end
handles.node = 0;
set(handles.input_text, 'String', '');
set(handles.output_text, 'String', '');
end
handles = setfield(handles, handles.curve, nodes);
guidata(hObject, handles);
graph(handles);
if deletednode render(handles); end
end
%-------------------------------------------------------------------%
function ice_WindowButtonMotionFcn(hObject, eventdata, handles)
% Do nothing unless a mouse 'down' event has occurred. If it has,
% modify control point and make new mapping function.
if ~strcmpi(handles.updown, 'down') return; end
[inplot, x, y] = cursor(hObject, handles);
if inplot
nodes = getfield(handles, handles.curve);
nudge = handles.smooth(handles.cindex) / 256;
if (handles.node ~= 1) & (handles.node ~= size(nodes, 1))
if x >= nodes(handles.above, 1)
x = nodes(handles.above, 1) - nudge;
elseif x <= nodes(handles.below, 1)
x = nodes(handles.below, 1) + nudge; end
else
if x > nodes(handles.above, 1)
x = nodes(handles.above, 1);
elseif x < nodes(handles.below, 1)
x = nodes(handles.below, 1); end
end
nodes(handles.node, :) = [x y];
handles = setfield(handles, handles.curve, nodes);
guidata(hObject, handles);
graph(handles);
end
%-------------------------------------------------------------------%
function ice_WindowButtonUpFcn(hObject, eventdata, handles)
% Terminate ongoing control point move or add operation. Clear
% coordinate text below plot and update display.
update = strcmpi(handles.updown, 'down');
handles.updown = 'up'; handles.node = 0;
guidata(hObject, handles);
if update
set(handles.input_text, 'String', '');
set(handles.output_text, 'String', '');
render(handles);
end
%-------------------------------------------------------------------%
function component_popup_Callback(hObject, eventdata, handles)
% Accept color component selection, update component specific
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -