Code covered by the BSD License  

Highlights from
Toolbox signal

image thumbnail
from Toolbox signal by Gabriel Peyre
Signal processing related functions.

perform_histogram_matching(x, y, options)
function x = perform_histogram_matching(x, y, options)

% perform_histogram_matching - match the histogram of two image.
%
%   x = perform_histogram_matching(x, y, nb_bins);
% or
%   x = perform_histogram_matching(x, y, options);
%
%   Perform an equalization of x so that it histogram 
%   matches the histogram of y.
%
%   Works also for vector valued (ie 3D matrix) images.
%   For color images, ie (n,p,3) sized image, the matching is performed
%       *  in RVB space if options.match_ycbcr=0
%       *  in YcBCr space if options.match_ycbcr=1 (default, works better)
%
%   Copyright (c) 2005 Gabriel Peyre

if nargin>2 && not(isstruct(options))
    opt = options;
    clear options;
    options.nb_bins = opt;
end

options.null = 0;
nb_bins = getoptions(options, 'nb_bins', 100);
match_ycbcr = getoptions(options, 'match_ycbcr', 1);
absval = getoptions(options, 'absval', 0);
cols = getoptions(options, 'cols', 0);
rows = getoptions(options, 'rows', 0);

if cols && rows
    error('You cannote specify both cols and rows');
end

if cols && size(x,2)>1
    if not(size(x,2)==size(y,2))
        error('x and y must have same number of columns');
    end
    if size(x,3)>1 || size(y,3)>1
        error('options.cols does not works for color images');
    end
    for i=1:size(x,2)
        x(:,i) = perform_histogram_matching(x(:,i),y(:,i),options);
    end
    return;
end
if cols && size(x,1)>1
    if not(size(x,1)==size(y,1))
        error('x and y must have same number of rows');
    end
    if size(x,3)>1 || size(y,3)>1
        error('options.rows does not works for color images');
    end
    for i=1:size(x,1)
        x(i,:) = perform_histogram_matching(x(i,:),y(i,:),options);
    end
    return;
end


if iscell(x)
   if ~(length(x)==length(y))
       error('For cell arrays, src and tgt must have the same length.');
   end
   for i=1:length(x)
       if length(find(isinf(x{i})))==0
            x{i} = perform_histogram_matching(x{i}, y{i}, options);
       else
			x{i} = x{i};
       end
   end
   return;
end


if size(x,3)>1
    if size(x,3)~=size(y,3)
        error('Src and tgt images must have the same number of components.');
    end
    
    if size(x,3)==3 && match_ycbcr
        x = rgb2ycbcr(x);
        y = rgb2ycbcr(y);
    end
    % match each color
    for i=1:size(y,3)
        x(:,:,i) = perform_histogram_matching(x(:,:,i), y(:,:,i), options);
    end
    if size(x,3)==3 && match_ycbcr
        x = ycbcr2rgb(x);
    end
    return;
end


if sum(abs(y(:) - mean(y(:))))<1e-8
    % histo is crashing for constant signals
    x = x*0 + mean(y(:));
    return;
end

sx = size(x);
x = x(:);
y = y(:);

if absval
    s = sign(x);
    x = abs(x);
    y = abs(y);
end


% compute transformed histograms
% [N,X] = histo(y, nb_bins);
[N,X] = histo_slow(y, nb_bins);

x = histoMatch(x, N, X);

I = find(isnan(x(:)));
x(I) = max(y(:));

if absval
    x = x .* s;
end


x = reshape(x,sx);


% [N,X] = histo_slow(MTX, nbinsOrBinsize, binCenter);
%
% Compute a histogram of (all) elements of MTX.  N contains the histogram
% counts, X is a vector containg the centers of the histogram bins.
%
% nbinsOrBinsize (optional, default = 101) specifies either
% the number of histogram bins, or the negative of the binsize.
%
% binCenter (optional, default = mean2(MTX)) specifies a center position
% for (any one of) the histogram bins.
%
% How does this differ from MatLab's HIST function?  This function:
%   - allows uniformly spaced bins only.
%   +/- operates on all elements of MTX, instead of columnwise.
%   + is much faster (approximately a factor of 80 on my machine).
%   + allows specification of number of bins OR binsize.  Default=101 bins.
%   + allows (optional) specification of binCenter.

% Eero Simoncelli, 3/97.

function [N, X] = histo_slow(mtx, nbins, binCtr)

%% NOTE: THIS CODE IS NOT ACTUALLY USED! (MEX FILE IS CALLED INSTEAD)

% fprintf(1,'WARNING: You should compile the MEX version of "histo.c",\n         found in the MEX subdirectory of matlabPyrTools, and put it in your matlab path.  It is MUCH faster.\n');

mtx = mtx(:);

%------------------------------------------------------------
%% OPTIONAL ARGS:

[mn,mx] = range2(mtx);

if (exist('binCtr') ~= 1) 
  binCtr =  mean(mtx);
end

if (exist('nbins') == 1) 
  if (nbins < 0)
    binSize = -nbins;
  else
    binSize = ((mx-mn)/nbins);
    tmpNbins = round((mx-binCtr)/binSize) - round((mn-binCtr)/binSize);
    if (tmpNbins ~= nbins)
      warning('Using %d bins instead of requested number (%d)',tmpNbins,nbins);
    end
  end
else
  binSize = ((mx-mn)/101);
end

firstBin = binCtr + binSize*round( (mn-binCtr)/binSize );

tmpNbins = round((mx-binCtr)/binSize) - round((mn-binCtr)/binSize);

bins = firstBin + binSize*[0:tmpNbins];

[N, X] = hist(mtx, bins);





% RES = histoMatch(MTX, N, X)
%
% Modify elements of MTX so that normalized histogram matches that
% specified by vectors X and N, where N contains the histogram counts
% and X the histogram bin positions (see histo).

% Eero Simoncelli, 7/96.

function res = histoMatch(mtx, N, X)

if ( exist('histo') == 3 )
  [oN, oX] = histo(mtx(:), size(X(:),1));
else
  [oN, oX] = hist(mtx(:), size(X(:),1));
end

oStep = oX(2) - oX(1);
oC = [0, cumsum(oN)]/sum(oN);
oX = [oX(1)-oStep/2, oX+oStep/2];

N = N(:)';
X = X(:)';
N = N + mean(N)/(1e8);   %% HACK: no empty bins ensures nC strictly monotonic

nStep = X(2) - X(1);
nC = [0, cumsum(N)]/sum(N);
nX = [X(1)-nStep/2, X+nStep/2];

nnX = interp1(nC, nX, oC, 'linear');

if ( exist('pointOp') == 3 )
  res = pointOp(mtx, nnX, oX(1), oStep);
else
  res = reshape(interp1(oX, nnX, mtx(:)),size(mtx,1),size(mtx,2));
end


% [MIN, MAX] = range2(MTX)
%
% Compute minimum and maximum values of MTX, returning them as a 2-vector.

% Eero Simoncelli, 3/97.

function [mn, mx] = range2(mtx)

%% NOTE: THIS CODE IS NOT ACTUALLY USED! (MEX FILE IS CALLED INSTEAD)

% fprintf(1,'WARNING: You should compile the MEX version of "range2.c",\n         found in the MEX subdirectory of matlabPyrTools, and put it in your matlab path.  It is MUCH faster.\n');

if (~isreal(mtx))
  error('MTX must be real-valued');  
end

mn = min(min(mtx));
mx = max(max(mtx));

Contact us at files@mathworks.com