function [out,T] = histeq(a,cm,hgram)
%HISTEQ	Contrast enhancement via histogram modification (equalization).
%	HISTEQ enhances the contrast of images by transforming
%	values in the image so the histogram approximately matches
%	a given histogram.
%
%	J = HISTEQ(I,HGRAM) transforms the intensity image I so that
%	the histogram of J with LENGTH(HGRAM) bins approximately 
%	matches HGRAM.  The result is returned in the intensity
%	image J. The values in I and J range from 0 (black) 
%	to 1 (white).
%
%	J = HISTEQ(I,N) transforms the intensity image I so that
%	the histogram of J with N bins is approximately flat. N 
%	defaults to 64 when not specified.
%
%	NEWMAP = HISTEQ(X,MAP,HGRAM) transforms the colormap MAP
%	associated with the indexed image X so that histogram of
%	the gray component of (X,NEWMAP) approximately matches HGRAM.
%	The transformed colormap is returned in NEWMAP.  LENGTH(HGRAM)
%	must be the same as SIZE(MAP,1).
%
%	NEWMAP = HISTEQ(X,MAP) transforms the colormap MAP so that
%	the histogram of the gray component of (X,NEWMAP) is
%	approximately flat.
%
%	[J,T] = HISTEQ(...) or [NEWMAP,T] = HISTEQ(...) also returns the
%	gray level transformation.
%
%	See also IMHIST.

%	Clay M. Thompson 1-20-93
%	Copyright (c) 1993 by The MathWorks, Inc.
%	$Revision: 1.12 $  $Date: 1993/09/09 17:54:56 $

error(nargchk(1,3,nargin));
NPTS = 256;

if nargin==1, % Histogram equalization of intensity image
  if max(max(a))<=1, % Histogram equalization of intensity image
    n = 64; % Default n
    hgram = ones(1,n)*(prod(size(a))/n);
    n = NPTS;
    kind = 1;
  else
    error('Indexed image requires colormap for HISTEQ.'); 
  end
elseif nargin==2,
  if max(size(cm))==1,	% Histogram equalization of intensity image
    m = cm;
    hgram = ones(1,m)*(prod(size(a))/m);
    n = NPTS;
    kind = 1;
  elseif size(cm,2)==3 & size(cm,1)>1,% Histogram equalization of indexed image
    n = size(cm,1);
    hgram = ones(1,n)*(prod(size(a))/n);
    kind = 2;
  else,	% Histogram modification of intensity image
    hgram = cm;
    n = NPTS;
    kind = 1;
  end
else,	% Histogram modification of indexed image
  n = size(cm,1);
  if length(hgram)~=n, error('HGRAM must be the same size as MAP.'); end
  kind = 2;
end

if min(size(hgram))>1, error('HGRAM must be a vector.'); end

% Normalize hgram
hgram = hgram*(prod(size(a))/sum(hgram));
m = length(hgram);

% Compute cumulative histograms
if kind==1,
  nn = imhist(a,n)';
  cum = cumsum(nn);
else
  % Convert image to equivalent gray image
  I = ind2gray(a,cm);
  nn = imhist(I,n)';
  cum = cumsum(nn);
end
cumd = cumsum(hgram*prod(size(a))/sum(hgram));

% Create transformation to an intensity image by minimizing the error
% between desired and actual cumulative histogram.
tol = ones(m,1)*min([nn(1:n-1),0;0,nn(2:n)])/2;
err = (cumd(:)*ones(1,n)-ones(m,1)*cum(:)')+tol;
d = find(err < -prod(size(a))*sqrt(eps));
if ~isempty(d), err(d) = prod(size(a))*ones(size(d)); end
[dum,T] = min(err);
T = (T-1)/(m-1); 

if kind == 1, % Modify intensity image
  [b,map] = gray2ind(a,n);
  b(:) = T(b);
else % Modify colormap by extending the (r,g,b) vectors.

  % Compute equivalent colormap luminance
  ntsc = rgb2ntsc(cm);

  % Map to new luminance using T, store in 2nd column of ntsc.
  ntsc(:,2) = T(floor(ntsc(:,1)*(n-1))+1)';

  % Scale (r,g,b) vectors by relative luminance change
  map = cm.*((ntsc(:,2)./max(ntsc(:,1),eps))*ones(1,3));

  % Clip the (r,g,b) vectors to the unit color cube
  map = map ./ (max(max(map')',1)*ones(1,3));
end

if nargout==0,
  if kind==1, imshow(b,n), else, imshow(a,map), end
  return
end
if kind==1, out = b; else out = map; end
