function rgb3d=label2rgb3d(varargin)
[label,map,zerocolor,order,fcnflag] = parse_inputs(varargin{:});
%label= 3d image with labels
% map= specified color map
%==================================
numregion = double(max(label(:)));

% If MAP is a function, evaluate it.  Make sure that the evaluated function
% returns a valid colormap.
if  fcnflag == 1
    cmap = feval(map, numregion);
    if ~isreal(cmap) || any(cmap(:) > 1) || any(cmap(:) < 0) || ...
            ~isequal(size(cmap,2),3) || size(cmap,1) < 1
        eid = sprintf('Images:%s:functionReturnsInvalidColormap',mfilename);
        msg = 'function handle MAP must return a n x 3 colormap array';
        error(eid,'%s',msg);
    end
else
    cmap = map;
end

% If ORDER is set to 'shuffle', save original state.  The SHUFFLE keyword
% uses the same state every time it is called. After shuffling is completed,
% go back to original state.
if isequal(order,'shuffle')
    S = rand('state');
    rand('state', 0);
    index = randperm(numregion);
    cmap = cmap(index,:,:);
    rand('state', S);
end

% Issue a warning if the zerocolor (boundary color) matches the color of one
% of the regions. 
for i=1:numregion
  if isequal(zerocolor,cmap(i,:))
    wid= sprintf('Images:%s:zerocolorSameAsRegionColor',mfilename);
    msg= sprintf('Region number %d has the same color as the ZEROCOLOR.',i);
    warning(wid,'%s',msg);
  end
end
cmap = [zerocolor;cmap];

% if label is of type double, need to pass 'label + 1' into IND2RGB.
% IND2RGB does not like double arrays containing zero values.
if isa(label, 'double')
    rgb3d = ind2rgb3d(label + 1, cmap);
else
    rgb3d = ind2rgb3d(label, cmap);
end

%======================================================================
%======================================================================
function [L, Map, Zerocolor, Order, Fcnflag] = parse_inputs(varargin) 
% L         label 3d matrix: matrix containing non-negative values.  
% Map       colormap: name of standard colormap, user-defined map, function
%           handle.
% Zerocolor RGB triple or Colorspec
% Order     keyword if specified: 'shuffle' or 'noshuffle'
% Fcnflag   flag to indicating that Map is a function

valid_order = {'shuffle', 'noshuffle'};
iptchecknargin(1,4,nargin,mfilename);

% set defaults
L = varargin{1};
Map = 'jet';    
Zerocolor = [1 1 1]; 
Order = 'noshuffle';
Fcnflag = 0;

% parse inputs
if nargin > 1
    Map = varargin{2};
end
if nargin > 2
    Zerocolor = varargin{3};
end
if nargin > 3
    Order = varargin{4};
end

% error checking for L
iptcheckinput(L,{'numeric' 'logical'}, ...
              {'real' 'nonsparse' 'finite' 'nonnegative' 'integer'}, ...
              mfilename,'L',1);

% error checking for Map
[fcn, fcnchk_msg] = fcnchk(Map);
if isempty(fcnchk_msg)
    Map = fcn;
    Fcnflag = 1;
else
    if isnumeric(Map)
        if ~isreal(Map) || any(Map(:) > 1) || any(Map(:) < 0) || ...
                    ~isequal(size(Map,2), 3) || size(Map,1) < 1
          eid = sprintf('Images:%s:invalidColormap',mfilename);
          msg = 'Invalid entry for MAP.';
          error(eid,'%s',msg);
        end
    else
        eid = sprintf('Images:%s:invalidFunctionforMAP',mfilename);
        error(eid,'%s',fcnchk_msg);
    end
end    
    
% error checking for Zerocolor
if ~ischar(Zerocolor)
    % check if Zerocolor is a RGB triple
    if ~isreal(Zerocolor) || ~isequal(size(Zerocolor),[1 3]) || ...
                any(Zerocolor> 1) || any(Zerocolor < 0)
      eid = sprintf('Images:%s:invalidZerocolor',mfilename);
      msg = 'Invalid RGB triple entry for ZEROCOLOR.';
      error(eid,'%s',msg);
    end
else    
    [cspec, msg] = cspecchk(Zerocolor);
    if ~isempty(msg)
        eid = sprintf('Images:%s:notInColorspec',mfilename); 
        error(eid,'%s',msg);
    else
        Zerocolor = cspec;
    end
end

% error checking for Order
idx = strmatch(lower(Order), valid_order);
eid = sprintf('Images:%s:invalidEntryForOrder',mfilename);
if isempty(idx)
    msg = 'Valid entries for ORDER are ''shuffle'' or ''noshuffle''.';
    error(eid,'%s',msg);
elseif length(idx) > 1
    msg = sprintf('Ambiguous string for ORDER: %s.', Order);
    error(eid,'%s',msg);
else
    Order = valid_order{idx};
end


%================================================================
%=================================================================
function [rout,g,b] = ind2rgb3d(a,cm)
%IND2RGB Convert indexed image to RGB image.
%   RGB = IND2RGB(X,MAP) converts the 3d matrix X and corresponding
%   colormap MAP to RGB (truecolor) format.
%
%   Class Support
%   -------------
%   X can be of class uint8, uint16, or double. RGB is an 
%   M-by-N-by-3 array of class double.
%
%   See also IND2GRAY, RGB2IND (in the Image Processing Toolbox).


if ~isa(a, 'double')
    a = double(a)+1;    % Switch to one based indexing
end

error(nargchk(2,2,nargin));

% Make sure A is in the range from 1 to size(cm,1)
a = max(1,min(a,size(cm,1)));

% Extract r,g,b components
r = zeros(size(a)); r(:) = cm(a,1);
g = zeros(size(a)); g(:) = cm(a,2);
b = zeros(size(a)); b(:) = cm(a,3);

if nargout==3,
  rout = r;
else
  rout = zeros([size(r),3]);
  rout(:,:,:,1) = r;
  rout(:,:,:,2) = g;
  rout(:,:,:,3) = b;
end
  



 