function [y,w] = dctn(y,DIM,w)
%DCTN N-D discrete cosine transform.
% Y = DCTN(X) returns the discrete cosine transform of X. The array Y is
% the same size as X and contains the discrete cosine transform
% coefficients. This transform can be inverted using IDCTN.
%
% DCTN(X,DIM) applies the DCTN operation across the dimension DIM.
%
% Class Support
% -------------
% Input array can be numeric or logical. The returned array is of class
% double.
%
% Reference
% ---------
% Narasimha M. et al, On the computation of the discrete cosine
% transform, IEEE Trans Comm, 26, 6, 1978, pp 934-936.
%
% Example
% -------
% RGB = imread('autumn.tif');
% I = rgb2gray(RGB);
% J = dctn(I);
% imshow(log(abs(J)),[]), colormap(jet), colorbar
%
% The commands below set values less than magnitude 10 in the DCT matrix
% to zero, then reconstruct the image using the inverse DCT.
%
% J(abs(J)<10) = 0;
% K = idctn(J);
% figure, imshow(I)
% figure, imshow(K,[0 255])
%
% See also IDCTN, DCT, DCT2.
%
% -- Damien Garcia -- 2008/06, revised 2009/11
% website: <a
% href="matlab:web('http://www.biomecardio.com')">www.BiomeCardio.com</a>
% ----------
% [Y,W] = DCTN(X,DIM,W) uses and returns the weights which are used by the
% program. If DCTN is required for several large arrays of same size, the
% weights can be reused to make the algorithm faster. A typical syntax is
% the following:
% w = [];
% for k = 1:10
% [y{k},w] = dctn(x{k},[],w);
% end
% The weights (w) are calculated during the first call of DCTN then
% reused in the next calls.
% ----------
error(nargchk(1,3,nargin))
y = double(y);
sizy = size(y);
% Test DIM argument
if ~exist('DIM','var'), DIM = []; end
assert(~isempty(DIM) || ~isscalar(DIM),...
'DIM must be a scalar or an empty array')
assert(isempty(DIM) || DIM==round(DIM) && DIM>0,...
'Dimension argument must be a positive integer scalar within indexing range.')
% If DIM is empty, a DCT is performed across each dimension
if isempty(DIM), y = squeeze(y); end % Working across singleton dimensions is useless
dimy = ndims(y);
% Some modifications are required if Y is a vector
if isvector(y)
dimy = 1;
if size(y,1)==1
if DIM==1, w = []; return
elseif DIM==2, DIM=1;
end
y = y.';
elseif DIM==2, w = []; return
end
end
% Weighing vectors
if ~exist('w','var') || isempty(w)
w = cell(1,dimy);
for dim = 1:dimy
if ~isempty(DIM) && dim~=DIM, continue, end
n = (dimy==1)*numel(y) + (dimy>1)*sizy(dim);
w{dim} = exp(1i*(0:n-1)'*pi/2/n);
end
end
% --- DCT algorithm ---
if ~isreal(y)
y = complex(dctn(real(y),DIM,w),dctn(imag(y),DIM,w));
else
for dim = 1:dimy
if ~isempty(DIM) && dim~=DIM
y = shiftdim(y,1);
continue
end
siz = size(y);
n = siz(1);
y = y([1:2:n 2*floor(n/2):-2:2],:);
y = reshape(y,n,[]);
y = y*sqrt(2*n);
y = ifft(y,[],1);
y = bsxfun(@times,y,w{dim});
y = real(y);
y(1,:) = y(1,:)/sqrt(2);
y = reshape(y,siz);
y = shiftdim(y,1);
end
end
y = reshape(y,sizy);