function [X]=MinMaxdenoise(X,m,n)
% pre-processing function that takes out the outliers.
% see paper for more information.
Xmin = ordfilt2(X,n,ones(m,m));
Xmax = ordfilt2(X,m*m-n+1,ones(m,m));
X = max(min(X,Xmax),Xmin);
function [Y] = TLSdenoise(X,k0,k1)
% *********************************************
% * Total Least Squares Denoising Algorithm *
% *********************************************
% Designed by: Keigo Hirakawa
%
% Y = TLSdenoise(X,k0,k1)
% X grascale image
% k0,k1 noise parameters corresponding to
% X = S + (k0 + k1*S).*randn(size(S))
% Y denoised image
%
% This algorithm was developed according to Hirakawa's PhD
% thesis. The matlab code is prepared strictly for research
% use only. Do not distribute the matlab code without a
% written permission from either Prof. Thomas W. Parks or from
% Keigo Hirakawa. The details of algorithm are published in
% ICASSP 2005.
%
% [1] K. Hirakawa, T. W. Parks, "Image Denoising For Signal-
% Dependent Noise," IEEE ICASSP 2005
%
% We would appreciate if you let us know whenever you cite our
% work in your paper. We would also appreciate if acknowledgments
% were made for the use of our codes.
% parameters
m = 23; % image patch size
n = [2,2]; % patch search area
e = 4; % parameter for pre-processing
p = 5; % size of the redundant estimation
% convenient notations
M = (m-1)/2;
N = max(n+M*[1:length(n)]);
P = (p-1)/2;
% search area
I = reshape(1:(N*2+1)^2,N*2+1,N*2+1);
J = reshape(1:m^2,m,m);
% center patch index
%t = I(1+N+[-M:M],1+N+[-M:M]);
%indexA = t(:);
% training patch index
indexB = []; % for noisy image patches
centerN = []; % indeces in S corresponding to the center patches (redundant estimation)
for i=1:length(n)
for b=-n(i):n(i)
for a=-n(i):n(i)
t = I(1+a+N+[-M:M]*i,1+b+N+[-M:M]*i);
indexB = [indexB t(:)];
if (abs(a)<=P & abs(b)<=P & i==1)
centerN = [centerN size(indexB,2)];
end
end
end
end
numN = size(indexB,2);
numM = m*m;
centerM = (numM+1)/2; % index for center pixel
indexI = -N:N; % indexing local search window
indexJ = -P:P; % indexing redundant image patches
indexP = J(1+M+[-P:P],1+M+[-P:P]);
numP = p*p;
% gaussian window for weighting (see paper)
hB = exp(-(-M:M).^2/10);
hB = hB'*hB;
hB = hB(:);
hB = hB/max(hB);
% padding/pre-processing
X = TLSpadarray(X,N+P); % pad the image boarders
x = MinMaxdenoise(X,5,e); % pre-processing (see paper)
% parameters for adaptive weighting
kA =5000;
kB = 500;
% initialize output
Y = zeros(size(X));
% main loop
tic;
for b = 1+N:size(X,2)-N
for a = 1+N:size(X,1)-N
% local search window
windowx = x(a+indexI,b+indexI); % preprocessed local search window
windowX = X(a+indexI,b+indexI); % not-preprocessed local search window
% center/training patchs
% s0 = windowx(indexA); % center patch
S = windowx(indexB); % noisy image patches
T = windowX(indexB); % noisy image patches
% adaptive weights
dA = mean((S-repmat(S(centerM,:),numM,1)).^2,2); % distance
A = exp(-dA/kA);
A = (A/sum(A)).^.5;
% adaptive weights
dB = mean((repmat(hB,1,numN+numP).*([S S(:,centerN)]-repmat(mean(S(:,centerN),2),1,numN+numP))).^2,1)'; % distance
B = [exp(-dB/kB)];
B(end-numP+1:end) = 1/20;
B = (B/sum(B)).^.5;
% affine approximation (see paper)
s_ave = A'.^2*S;
S = S-repmat(s_ave,numM,1);
T = T-repmat(s_ave,numM,1);
% P matrix
P0 = S'*(S.*repmat(A.^2,1,numN)); % Pxx matrix
P1 = P0 - diag((k0+k1*s_ave).^2) - 2*k1*diag((k0+k1*s_ave).*(A'.^2*S));
P1 = P1-diag(diag(P1))+diag(diag(P1)/(1+k1^2));
P1 = P1 + (P1'-P1)/2; % make sure it's symmetric
[Vp,Dp] = eig(P1);
P1 = Vp*diag(max(diag(Dp),0))*Vp'; % make sure it's positive definite
R = [P0 P1(:,centerN); P1(centerN,:) P1(centerN,centerN)]; % P matrix in paper
R = (B*B').*R;
R = R + (R'-R)/2; % make sure it's symmetric
[Vr,Dr] = eig(R);
[v_eig,v_index] = sort(real(diag(Dr)));
V = Vr(:,v_index(1:numP)); % right singular vector that we're interested in
% estimate
f = -(B(1:end-numP)*(B(end-numP+1:end)'.^-1)).*(V(1:end-numP,:)/V(end-numP+1:end,:));
f = real(f); % TLS solution
y = T*f+repmat(s_ave(centerN),numM,1); % our best estimate
% average the multiple estimates of the same pixel
y0 = zeros(p,p);
for i=1:numP
H = zeros(p,p); H(i)=1;
y1 = conv2(reshape(y(:,i),m,m),H,'same');
y0 = y0 + y1(1+M+indexJ,1+M+indexJ)/p^2;
end
% store the estimate
Y(a+indexJ,b+indexJ) = Y(a+indexJ,b+indexJ)+y0;
end
fprintf(1,'%3.0f minutes: processing column %3.0f\n', round(toc/60), b-N-P);
imwrite(Y/256/p^2,'tempY.bmp');
end
Y=Y/p^2;
% 8-bit data
Y = max(Y,0);
Y = min(Y,256);
% un-pad boarder
Y = TLSpadarray(Y,-(N+P));
function [Y] = TLSpadarray(X,s)
% this function is used to expand the boarders of the image
% to handle the image boarders.
Y = zeros(size(X)+s*2);
if s>0 % make image bigger
Y(1+s:end-s,1+s:end-s)=X;
Y(1+s:end-s,1:s)=X(:,s:-1:1);
Y(1+s:end-s,end-s+1:end)=X(:,end:-1:end-s+1);
Y(1:s,1+s:end-s)=X(s:-1:1,:);
Y(end-s+1:end,1+s:end-s)=X(end:-1:end-s+1,:);
Y(1:s,1:s) = X(1,1);
Y(end-s+1:end,1:s) = X(end,1);
Y(1:s,end-s+1:end) = X(1,end);
Y(end-s+1:end,end-s+1:end) = X(end,end);
else % make image smaller
s = -s;
Y = X(1+s:end-s,1+s:end-s);
end