function [cout,map] = imapprox(a,cm,n,flag)
%IMAPPROX Approximate indexed image by an image with less colors.
%	[Y,NEWMAP] = IMAPPROX(X,MAP,N) approximates the indexed image X
%	with colormap MAP by another indexed image Y with colormap
%	NEWMAP.  NEWMAP will have N colors which will be chosen
%	to best approximate the colors in MAP.
%
%	[Y,NEWMAP] = IMAPPROX(X,MAP,TOL) approximates the colors in the
%	indexed image by choosing colors via uniform quantization 
%	in RGB space. NEWMAP will contain at most (FLOOR(1/TOL)+1)^3 
%	colors.  TOL must be between 0 and 1.0. 
%
%	B = IMAPPROX(X,MAP,NEWMAP) approximates the colors in MAP by
%	the closest match in NEWMAP.
%
%	[Y,NEWMAP] = IMAPPROX(X,MAP) uniformly removes colors
%	from the colormap if necessary so that NEWMAP has fewer
%	than 256 colors.  The removed colors are approximated
%	by other colors in the colormap.
%
%	[...] = IMAPPROX(...,'dither_option') allows you to enable
%	or disable dithering.  Possiblities are 'dither' or 'nodither'.
%	'dither' is the default.
%
%	See also RGB2IND, CMUNIQUE.

%	Clay M. Thompson 2-25-93
%	Copyright (c) 1993 by The MathWorks, Inc.
%	$Revision: 1.11 $  $Date: 1993/09/09 18:22:38 $

if nargin<2, error('Not enough input arguments.'); end

if nargin==2, % imapprox(a,cm) (remove colors)
  if size(cm,1)<=256,
    c = a; map = cm;
  else
    n = size(cm,1)-256; 
    ndx = floor((1:n)/(n+1)*size(cm,1)+1);
    map = cm; map(ndx,:) = [];
    [r,g,b] = ind2rgb(a,cm);
    c = dither(r,g,b,map);
  end

elseif isstr(n), % imapprox(a,cm,'dither_option')
  flag = [lower(flag) ' ']; % Protect against short string
  if size(cm,1)<=256,
    c = a; map = cm;
  elseif flag(1)=='n', % 'nodither'
    n = size(cm,1)-256; 
    ndx = floor((1:n)/(n+1)*size(cm,1)+1);
    map = cm; map(ndx,:) = [];

    % Manhattan Distance to colors in reduced colormap
    M = size(map,1); N = length(ndx);
    [v,loc] = min(abs(map(:,1)*ones(1,N)-ones(M,1)*cm(ndx,1)') + ...
                  abs(map(:,2)*ones(1,N)-ones(M,1)*cm(ndx,2)') + ...
                  abs(map(:,3)*ones(1,N)-ones(M,1)*cm(ndx,3)'));
    dpos = ones(size(cm,1),1); 
    dpos(ndx) = zeros(size(ndx));
    pos = cumsum(dpos); pos(ndx) = loc;
    c = zeros(size(a));
    c(:) = pos(a);
  else
    n = size(cm,1)-256; 
    ndx = floor((1:n)/(n+1)*size(cm,1)+1);
    map = cm; map(ndx,:) = [];
    [r,g,b] = ind2rgb(a,cm);
    c = dither(r,g,b,map);
  end

elseif max(size(n))==1, % imapprox(a,cm,tol) or imapprox(a,cm,n)
  if nargin<4, flag = 'dither'; end
  if n>size(cm,1),
    c = a; map = cm;
  else
    % Convert colormap to RGB so that rgb2ind can do all the work
    r = cm(:,1); g = cm(:,2); b = cm(:,3);

    [ndx,map] = rgb2ind(r,g,b,n,'n');
    if flag(1)=='n', % 'nodither'
      c = zeros(size(a));
      c(:) = ndx(a);
    else
      [r,g,b] = ind2rgb(a,cm);
      c = dither(r,g,b,map);
    end
  end

elseif size(n,2)==3, % imapprox(a,cm,map)
  if nargin<4, flag = 'dither'; end
  flag = [lower(flag) ' ']; % Protect against short string
  map = n;
  if flag(1)=='n', % 'nodither'
    % Manhattan Distance to colors in new colormap
    M = size(map,1); N = size(cm,1);
    [v,loc] = min(abs(map(:,1)*ones(1,N)-ones(M,1)*cm(:,1)') + ...
                  abs(map(:,2)*ones(1,N)-ones(M,1)*cm(:,2)') + ...
                  abs(map(:,3)*ones(1,N)-ones(M,1)*cm(:,3)'));
    c = zeros(size(a));
    c(:) = loc(a);
  else
    [r,g,b] = ind2rgb(a,cm);
    c = dither(r,g,b,map);
  end    
end

if nargout==0,
  imshow(c,map)
  return
end
cout = c;



