Code covered by the BSD License  

Highlights from
Toolbox Wavelets

image thumbnail
from Toolbox Wavelets by Gabriel Peyre
Wavelet transform and coding functions, including other more exotic transforms (laplacian, steerable

perform_pyramid_transform_simoncelli(x, Jmin,options)
function y = perform_pyramid_transform_simoncelli(x, Jmin,options)

% perform_pyramid_transform_simoncelli - Laplacian pyramidal transform
%
%   y = perform_pyramid_transform_simoncelli(x, Jmin);
%
%   This is just a convenient wrapper to the original steerable 
%   matlab toolbox of Simoncelli that can be downloaded from
%       http://www.cns.nyu.edu/~eero/STEERPYR/
%   If you want a fast implementation of this function, you
%   have to install Simoncelli toolbox (to use mex files).
%
%   It provide a simpler interface that directly output a cell
%   array of images. Usage :
%
%   M = load_image('lena');
%   MS = perform_pyramid_transform_simoncelli(M, 3); % synthesis
%   M1 = perform_pyramid_transform_simoncelli(MS);   % reconstruction
%   
%   Copyright (c) 2005 Gabriel Peyr

if nargin<3
    options.null = 0;
end

filts = 'binom5';

if ~iscell(x)
    if nargin<2
        Jmin = 4;
    end
    Jmax = log2(size(x,1))-1;
    nbr_bands = Jmax - Jmin + 2;
    % fwd transform
    [pyr,pind] = buildLpyr(x, nbr_bands, filts, filts, 'reflect1');
    % copy into cell array    
    y = {};
    for k=1:size(pind, 1)
        indices =  pyrBandIndices(pind,k);
        L = length(indices);    % length of this scale
        y{k} = reshape( pyr(indices), sqrt(L), sqrt(L) );
    end
else
    n = size(x{1},1);
    Jmax = log2(n)-1;
    nbr_bands = length(x);
    % copy from cell array
    pind = n ./ 2.^(0:nbr_bands-1);
    pind = [pind(:), pind(:)];
    % build the matrix
    n = sum( prod(pind,2) );
    pyr = zeros(n, 1);
    for k=1:size(pind, 1)
        indices =  pyrBandIndices(pind,k);
        L = length(indices);    % length of this scale
        pyr(indices) = x{k}(:);
    end
    % bwd transform
    y = reconLpyr(pyr, pind, 'all', filts); 
end





% [PYR, INDICES] = buildLpyr(IM, HEIGHT, FILT1, FILT2, EDGES)
%
% Construct a Laplacian pyramid on matrix (or vector) IM.
%
% HEIGHT (optional) specifies the number of pyramid levels to build. Default
% is 1+maxPyrHt(size(IM),size(FILT)).  You can also specify 'auto' to
% use this value.
%
% FILT1 (optional) can be a string naming a standard filter (see
% namedFilter), or a vector which will be used for (separable)
% convolution.  Default = 'binom5'.  FILT2 specifies the "expansion"
% filter (default = filt1).  EDGES specifies edge-handling, and
% defaults to 'reflect1' (see corrDn).
%
% PYR is a vector containing the N pyramid subbands, ordered from fine
% to coarse.  INDICES is an Nx2 matrix containing the sizes of
% each subband.  This is compatible with the MatLab Wavelet toolbox.

% Eero Simoncelli, 6/96.

function [pyr,pind] = buildLpyr(im, ht, filt1, filt2, edges)

if (nargin < 1)
  error('First argument (IM) is required');
end

im_sz = size(im);

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

if (exist('filt1') ~= 1)
  filt1 = 'binom5';
end
 
if isstr(filt1)
  filt1 = namedFilter(filt1);
end

if ( (size(filt1,1) > 1) & (size(filt1,2) > 1) )
  error('FILT1 should be a 1D filter (i.e., a vector)');
else
  filt1 = filt1(:);
end

if (exist('filt2') ~= 1)
  filt2 = filt1;
end

if isstr(filt2)
  filt2 = namedFilter(filt2);
end

if ( (size(filt2,1) > 1) & (size(filt2,2) > 1) )
  error('FILT2 should be a 1D filter (i.e., a vector)');
else
  filt2 = filt2(:);
end

max_ht = 1 + maxPyrHt(im_sz, max(size(filt1,1), size(filt2,1)));
if ( (exist('ht') ~= 1) | (ht == 'auto') )
  ht = max_ht;
else
  if (ht > max_ht)
    error(sprintf('Cannot build pyramid higher than %d levels.',max_ht));
  end
end

if (exist('edges') ~= 1)
  edges= 'reflect1';
end

%------------------------------------------------------------

if (ht <= 1)

  pyr = im(:);
  pind = im_sz;

else

  if (im_sz(2) == 1)
    lo2 = corrDn(im, filt1, edges, [2 1], [1 1]);
  elseif (im_sz(1) == 1)
    lo2 = corrDn(im, filt1', edges, [1 2], [1 1]);
  else
    lo = corrDn(im, filt1', edges, [1 2], [1 1]);
    int_sz = size(lo);
    lo2 = corrDn(lo, filt1, edges, [2 1], [1 1]);
  end

  [npyr,nind] = buildLpyr(lo2, ht-1, filt1, filt2, edges);

  if (im_sz(1) == 1)
    hi2 = upConv(lo2, filt2', edges, [1 2], [1 1], im_sz);
  elseif (im_sz(2) == 1)
    hi2 = upConv(lo2, filt2, edges, [2 1], [1 1], im_sz);
  else
    hi = upConv(lo2, filt2, edges, [2 1], [1 1], int_sz);
    hi2 = upConv(hi, filt2', edges, [1 2], [1 1], im_sz);
  end

  hi2 = im - hi2;

  pyr = [hi2(:); npyr];
  pind = [im_sz; nind];

end
  


% KERNEL = NAMED_FILTER(NAME)
%
% Some standard 1D filter kernels.  These are scaled such that
% their L2-norm is 1.0.
%
%  binomN             - binomial coefficient filter of order N-1
%  haar:              - Haar wavelet.
%  qmf8, qmf12, qmf16 - Symmetric Quadrature Mirror Filters [Johnston80]
%  daub2,daub3,daub4  - Daubechies wavelet [Daubechies88].
%  qmf5, qmf9, qmf13: - Symmetric Quadrature Mirror Filters [Simoncelli88,Simoncelli90]
%
%  See bottom of file for full citations.

% Eero Simoncelli, 6/96.

function [kernel] = namedFilter(name)

if strcmp(name(1:min(5,size(name,2))), 'binom')
  kernel = sqrt(2) * binomialFilter(str2num(name(6:size(name,2))));
elseif strcmp(name,'qmf5')
  kernel = [-0.076103 0.3535534 0.8593118 0.3535534 -0.076103]';
elseif strcmp(name,'qmf9')
  kernel = [0.02807382 -0.060944743 -0.073386624 0.41472545 0.7973934 ...
      0.41472545 -0.073386624 -0.060944743 0.02807382]';
elseif strcmp(name,'qmf13')
  kernel = [-0.014556438 0.021651438 0.039045125 -0.09800052 ...
	  -0.057827797 0.42995453 0.7737113 0.42995453 -0.057827797 ...
	  -0.09800052 0.039045125 0.021651438 -0.014556438]';
elseif strcmp(name,'qmf8')
  kernel = sqrt(2) * [0.00938715 -0.07065183 0.06942827 0.4899808 ...
    0.4899808 0.06942827 -0.07065183 0.00938715 ]';
elseif strcmp(name,'qmf12')
  kernel = sqrt(2) * [-0.003809699 0.01885659 -0.002710326 -0.08469594 ...
	0.08846992 0.4843894 0.4843894 0.08846992 -0.08469594 -0.002710326 ...
	0.01885659 -0.003809699 ]';
elseif strcmp(name,'qmf16')
  kernel = sqrt(2) * [0.001050167 -0.005054526 -0.002589756 0.0276414 -0.009666376 ...
	-0.09039223 0.09779817 0.4810284 0.4810284 0.09779817 -0.09039223 -0.009666376 ...
	0.0276414 -0.002589756 -0.005054526 0.001050167 ]';
elseif strcmp(name,'haar')
  kernel = [1 1]' / sqrt(2);
elseif strcmp(name,'daub2')
  kernel = [0.482962913145 0.836516303738 0.224143868042 -0.129409522551]';
elseif strcmp(name,'daub3')
  kernel = [0.332670552950 0.806891509311 0.459877502118 -0.135011020010 ...
	-0.085441273882  0.035226291882]';
elseif strcmp(name,'daub4')
  kernel = [0.230377813309 0.714846570553 0.630880767930 -0.027983769417 ...
	-0.187034811719 0.030841381836 0.032883011667 -0.010597401785]';
elseif strcmp(name,'gauss5')  % for backward-compatibility
  kernel = sqrt(2) * [0.0625 0.25 0.375 0.25 0.0625]';
elseif strcmp(name,'gauss3')  % for backward-compatibility
  kernel = sqrt(2) * [0.25 0.5 0.25]';
else
  error(sprintf('Bad filter name: %s\n',name));
end
  
% [Johnston80] - J D Johnston, "A filter family designed for use in quadrature 
%    mirror filter banks", Proc. ICASSP, pp 291-294, 1980.
%
% [Daubechies88] - I Daubechies, "Orthonormal bases of compactly supported wavelets",
%    Commun. Pure Appl. Math, vol. 42, pp 909-996, 1988.
%
% [Simoncelli88] - E P Simoncelli,  "Orthogonal sub-band image transforms",
%     PhD Thesis, MIT Dept. of Elec. Eng. and Comp. Sci. May 1988.
%     Also available as: MIT Media Laboratory Vision and Modeling Technical 
%     Report #100.
%
% [Simoncelli90] -  E P Simoncelli and E H Adelson, "Subband image coding",
%    Subband Transforms, chapter 4, ed. John W Woods, Kluwer Academic 
%    Publishers,  Norwell, MA, 1990, pp 143--192.


% KERNEL = binomialFilter(size)
%
% Returns a vector of binomial coefficients of order (size-1) .

% Eero Simoncelli, 2/97.

function [kernel] = binomialFilter(sz)

if (sz < 2)
  error('size argument must be larger than 1');
end

kernel = [0.5 0.5]';

for n=1:sz-2
  kernel = conv([0.5 0.5]', kernel);
end
  
% HEIGHT = maxPyrHt(IMSIZE, FILTSIZE)
%
% Compute maximum pyramid height for given image and filter sizes.
% Specifically: the number of corrDn operations that can be sequentially
% performed when subsampling by a factor of 2.

% Eero Simoncelli, 6/96.

function height = maxPyrHt(imsz, filtsz)

imsz = imsz(:);
filtsz = filtsz(:);

if any(imsz == 1) % 1D image
  imsz = prod(imsz);
  filtsz = prod(filtsz);
elseif any(filtsz == 1)              % 2D image, 1D filter
  filtsz = [filtsz(1); filtsz(1)];
end

if any(imsz < filtsz)
  height = 0;
else
  height = 1 + maxPyrHt( floor(imsz/2), filtsz ); 
end


% RES = corrDn(IM, FILT, EDGES, STEP, START, STOP)
%
% Compute correlation of matrices IM with FILT, followed by
% downsampling.  These arguments should be 1D or 2D matrices, and IM
% must be larger (in both dimensions) than FILT.  The origin of filt
% is assumed to be floor(size(filt)/2)+1.
% 
% EDGES is a string determining boundary handling:
%    'circular' - Circular convolution
%    'reflect1' - Reflect about the edge pixels
%    'reflect2' - Reflect, doubling the edge pixels
%    'repeat'   - Repeat the edge pixels
%    'zero'     - Assume values of zero outside image boundary
%    'extend'   - Reflect and invert
%    'dont-compute' - Zero output when filter overhangs input boundaries
%
% Downsampling factors are determined by STEP (optional, default=[1 1]), 
% which should be a 2-vector [y,x].
% 
% The window over which the convolution occurs is specfied by START 
% (optional, default=[1,1], and STOP (optional, default=size(IM)).
% 
% NOTE: this operation corresponds to multiplication of a signal
% vector by a matrix whose rows contain copies of the FILT shifted by
% multiples of STEP.  See upConv.m for the operation corresponding to
% the transpose of this matrix.

% Eero Simoncelli, 6/96, revised 2/97.

function res = corrDn(im, filt, edges, step, start, stop)

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

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

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

if (exist('edges') == 1) 
  if (strcmp(edges,'reflect1') ~= 1)
    warning('Using REFLECT1 edge-handling (use MEX code for other options).');
  end
end

if (exist('step') ~= 1)
	step = [1,1];
end	

if (exist('start') ~= 1)
	start = [1,1];
end	

if (exist('stop') ~= 1)
	stop = size(im);
end	

%------------------------------------------------------------

% Reverse order of taps in filt, to do correlation instead of convolution
filt = filt(size(filt,1):-1:1,size(filt,2):-1:1);

tmp = rconv2(im,filt);
res = tmp(start(1):step(1):stop(1),start(2):step(2):stop(2));


% RES = RCONV2(MTX1, MTX2, CTR)
%
% Convolution of two matrices, with boundaries handled via reflection
% about the edge pixels.  Result will be of size of LARGER matrix.
% 
% The origin of the smaller matrix is assumed to be its center.
% For even dimensions, the origin is determined by the CTR (optional) 
% argument:
%      CTR   origin
%       0     DIM/2      (default)
%       1     (DIM/2)+1  

% Eero Simoncelli, 6/96.

function c = rconv2(a,b,ctr)

if (exist('ctr') ~= 1)
  ctr = 0;
end

if (( size(a,1) >= size(b,1) ) & ( size(a,2) >= size(b,2) ))
    large = a; small = b;
elseif  (( size(a,1) <= size(b,1) ) & ( size(a,2) <= size(b,2) ))
    large = b; small = a;
else
  error('one arg must be larger than the other in both dimensions!');
end

ly = size(large,1);
lx = size(large,2);
sy = size(small,1);
sx = size(small,2);

%% These values are one less than the index of the small mtx that falls on 
%% the border pixel of the large matrix when computing the first 
%% convolution response sample:
sy2 = floor((sy+ctr-1)/2);
sx2 = floor((sx+ctr-1)/2);

% pad with reflected copies
clarge = [ 
    large(sy-sy2:-1:2,sx-sx2:-1:2), large(sy-sy2:-1:2,:), ...
	large(sy-sy2:-1:2,lx-1:-1:lx-sx2); ...
    large(:,sx-sx2:-1:2),    large,   large(:,lx-1:-1:lx-sx2); ...
    large(ly-1:-1:ly-sy2,sx-sx2:-1:2), ...
      large(ly-1:-1:ly-sy2,:), ...
      large(ly-1:-1:ly-sy2,lx-1:-1:lx-sx2) ];

c = conv2(clarge,small,'valid');

% RES = upConv(IM, FILT, EDGES, STEP, START, STOP, RES)
%
% Upsample matrix IM, followed by convolution with matrix FILT.  These
% arguments should be 1D or 2D matrices, and IM must be larger (in
% both dimensions) than FILT.  The origin of filt
% is assumed to be floor(size(filt)/2)+1.
%
% EDGES is a string determining boundary handling:
%    'circular' - Circular convolution
%    'reflect1' - Reflect about the edge pixels
%    'reflect2' - Reflect, doubling the edge pixels
%    'repeat'   - Repeat the edge pixels
%    'zero'     - Assume values of zero outside image boundary
%    'extend'   - Reflect and invert
%    'dont-compute' - Zero output when filter overhangs OUTPUT boundaries
%
% Upsampling factors are determined by STEP (optional, default=[1 1]),
% a 2-vector [y,x].
% 
% The window over which the convolution occurs is specfied by START 
% (optional, default=[1,1], and STOP (optional, default = 
% step .* (size(IM) + floor((start-1)./step))).
%
% RES is an optional result matrix.  The convolution result will be 
% destructively added into this matrix.  If this argument is passed, the 
% result matrix will not be returned. DO NOT USE THIS ARGUMENT IF 
% YOU DO NOT UNDERSTAND WHAT THIS MEANS!!
% 
% NOTE: this operation corresponds to multiplication of a signal
% vector by a matrix whose columns contain copies of the time-reversed
% (or space-reversed) FILT shifted by multiples of STEP.  See corrDn.m
% for the operation corresponding to the transpose of this matrix.

% Eero Simoncelli, 6/96.  revised 2/97.

function result = upConv(im,filt,edges,step,start,stop,res)

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

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

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

if (exist('edges') == 1) 
  if (strcmp(edges,'reflect1') ~= 1)
    warning('Using REFLECT1 edge-handling (use MEX code for other options).');
  end
end

if (exist('step') ~= 1)
  step = [1,1];
end	

if (exist('start') ~= 1)
  start = [1,1];
end	

% A multiple of step
if (exist('stop') ~= 1)
  stop = step .* (floor((start-ones(size(start)))./step)+size(im))
end	

if ( ceil((stop(1)+1-start(1)) / step(1)) ~= size(im,1) )
  error('Bad Y result dimension');
end
if ( ceil((stop(2)+1-start(2)) / step(2)) ~= size(im,2) )
  error('Bad X result dimension');
end

if (exist('res') ~= 1)
  res = zeros(stop-start+1);
end	

%------------------------------------------------------------

tmp = zeros(size(res));
tmp(start(1):step(1):stop(1),start(2):step(2):stop(2)) = im;

result = rconv2(tmp,filt) + res;


% RES = pyrBandIndices(INDICES, BAND_NUM)
%
% Return indices for accessing a subband from a pyramid 
% (gaussian, laplacian, QMF/wavelet, steerable).

% Eero Simoncelli, 6/96.

function indices =  pyrBandIndices(pind,band)

if ((band > size(pind,1)) | (band < 1))
  error(sprintf('BAND_NUM must be between 1 and number of pyramid bands (%d).', ...
      size(pind,1)));
end

if (size(pind,2) ~= 2)
  error('INDICES must be an Nx2 matrix indicating the size of the pyramid subbands');
end

ind = 1;
for l=1:band-1
  ind = ind + prod(pind(l,:));
end

indices = ind:ind+prod(pind(band,:))-1;


% RES = reconLpyr(PYR, INDICES, LEVS, FILT2, EDGES)
%
% Reconstruct image from Laplacian pyramid, as created by buildLpyr.
%
% PYR is a vector containing the N pyramid subbands, ordered from fine
% to coarse.  INDICES is an Nx2 matrix containing the sizes of
% each subband.  This is compatible with the MatLab Wavelet toolbox.
%
% LEVS (optional) should be a list of levels to include, or the string
% 'all' (default).  The finest scale is number 1.  The lowpass band
% corresponds to lpyrHt(INDICES)+1.
%
% FILT2 (optional) can be a string naming a standard filter (see
% namedFilter), or a vector which will be used for (separable)
% convolution.  Default = 'binom5'.  EDGES specifies edge-handling,
% and defaults to 'reflect1' (see corrDn).

% Eero Simoncelli, 6/96

function res = reconLpyr(pyr, ind, levs, filt2, edges)

if (nargin < 2)
  error('First two arguments (PYR, INDICES) are required');
end
  
%%------------------------------------------------------------
%% DEFAULTS:

if (exist('levs') ~= 1)
  levs = 'all';
end

if (exist('filt2') ~= 1)
  filt2 = 'binom5';
end

if (exist('edges') ~= 1)
  edges= 'reflect1';
end
%%------------------------------------------------------------

maxLev =  1+lpyrHt(ind);
if strcmp(levs,'all')
  levs = [1:maxLev]';
else
  if (any(levs > maxLev))
    error(sprintf('Level numbers must be in the range [1, %d].', maxLev));
  end
  levs = levs(:);
end

if isstr(filt2)
  filt2 = namedFilter(filt2);
end

filt2 = filt2(:);
res_sz = ind(1,:);

if any(levs > 1)

  int_sz = [ind(1,1), ind(2,2)];
  
  nres = reconLpyr( pyr(prod(res_sz)+1:size(pyr,1)), ...
      ind(2:size(ind,1),:), levs-1, filt2, edges);
  
  if (res_sz(1) == 1)
    res = upConv(nres, filt2', edges, [1 2], [1 1], res_sz);
  elseif (res_sz(2) == 1)
    res = upConv(nres, filt2, edges, [2 1], [1 1], res_sz);
  else
    hi = upConv(nres, filt2, edges, [2 1], [1 1], int_sz);
    res = upConv(hi, filt2', edges, [1 2], [1 1], res_sz);
  end

else
  
  res = zeros(res_sz);

end

if any(levs == 1)
  res = res + pyrBand(pyr,ind,1);
end


% [HEIGHT] = lpyrHt(INDICES)
%
% Compute height of Laplacian pyramid with given its INDICES matrix.
% See buildLpyr.m

% Eero Simoncelli, 6/96.

function [ht] =  lpyrHt(pind)

% Don't count lowpass residual band
ht = size(pind,1)-1;


% RES = pyrBand(PYR, INDICES, BAND_NUM)
%
% Access a subband from a pyramid (gaussian, laplacian, QMF/wavelet, 
% or steerable).  Subbands are numbered consecutively, from finest
% (highest spatial frequency) to coarsest (lowest spatial frequency).

% Eero Simoncelli, 6/96.

function res =  pyrBand(pyr, pind, band)

res = reshape( pyr(pyrBandIndices(pind,band)), pind(band,1), pind(band,2) );

Contact us at files@mathworks.com