
%% Modified 18 Jan to fix lighting in 3rd image...

%% Combining images of different exposure
%% Richard Mann, Jan. 2001

%% Reference:
%% Debevec, P.E. and Malik, J.  Siggraph 1997.
%%
%% See also:
%% Mann, S. and Picard R.W.  Proceedings of IS&T 46th annual conference,
%% May 1995.

%% Paste the following into Matlab window.

%% g(.) is ln.f^-1 log inverse imaging function defined on 0..255
%% lE is log Brightness for each pixel 1..N
%% lT is log Exposure time for each frame 1..P
%% Z(n,p) is Image brightness, n=1..N, p=1..P
%% w is weighting function for pixels 0..255

%% Read in P images of the same scene, with different exposure
P=3; % number of frames to use
rows=300; cols=448; % image sizes
images=cell(P,1); % cell array of images
for i=1:P
  fn=sprintf('wyck-%1d.tif', i);
  images{i}=imread(fn,'tiff');
end
for i=1:P,
  figure;
  imshow(images{i});
  str=sprintf('Image %d',i);
  title(str);
end

%% Exposure times.  Reference time is 1 unit.
%T=[2 1 0.5];
T=[2 1 0.5/sqrt(2)];   %%%%% New value for dark image %%%%%
lT=log(T);

%% Select N random points from each of P images
N=200; % number of pixels to use
Z=zeros(N,P);
indices=floor(rand(N,1)*rows*cols+1);
for i=1:P
  Im=reshape(images{i},rows*cols,1); % make column vector
  Z(:,i)=double(Im(indices));
end

%% Triangular weighting function accentuates pixels in center of domain
n=256; % number of grey levels
w=[1:n/2,n/2:-1:1]/(n/2); % weighting function
figure; plot(1:n,w);

%% Show scattergram of two image's pixels.
%% This is for interest only.  Note how each image saturates.
figure;
i=3; j=1;
scatter(Z(1:N,i)+randn(N,1),Z(1:N,j)+randn(N,1),'.');
axis('square');
xlabel('Im_i (dark)');
ylabel('Im_j (light)');
title('Comparagram (pixel values): Im_i vs Im_j');

%% Data fitting equations
A=zeros(N*P+n+1,n+N);
b=zeros(N*P+n+1,1);
k=1;
for i=1:N
  for j=1:P
    wij=w(Z(i,j)+1);  % pixels 0..255
    A(k,Z(i,j)+1)=wij; A(k,n+i)=-wij;
    b(k)=wij*lT(j);
    k=k+1;
  end
end

%% Fix the curve by setting middle value to zero
A(k,129)=1;
k=k+1;

%% Smoothness terms
lambda=100;
for i=1:n-2
  A(k,i)=lambda*w(i+1);  A(k,i+1)=-2*lambda*w(i+1);  A(k,i+2)=lambda*w(i+1);
  k=k+1;
end

%% Solve using SVD
x=A\b;
g=x(1:n);
lE=x(n+1:size(x,1));
figure;
plot(g,1:n);
title('Response function');
xlabel('log exposure');
ylabel('pixel value');
hold on;
plot(lE,Z(:,floor(P/2)+1),'o'); % data

%% Combine images (using linear brighness)
Esum=zeros(rows,cols);
Wsum=zeros(rows,cols);
for i=1:P,
  Im=double(images{i}); % convert uint8->double
  E=exp(g(Im+1))/exp(lT(i)); % convert pixels->log(E*T)->E*T->E
  W=w(Im+1); % current weight
  Wsum=Wsum+W; % sum of each pixel weight
  Esum=Esum+E.*W;
end
E=Esum./Wsum; % normalize

%% Plot final image as LogE.
figure;
imshow(log(E),[]);
title('Composite image');

%% Show "ownership" maps.
for i=1:P,
  figure;
  imshow(w(double(images{i})+1),[]);
  str=sprintf('Ownership map for image %d',i);
  title(str);
end
