├── DE_exposure_fusion_short.m ├── FGS.m ├── README.md ├── WGIF.m ├── boxfilter2.m ├── compile.m ├── contrast.m ├── downsample.m ├── f.m ├── gaussian_pyramid.m ├── guidedfilter.m ├── imgsaturation.m ├── laplacian_pyramid.m ├── load_images.m ├── luminance.m ├── mexFGS.cpp ├── mexFGS.mexw64 ├── mexFGS_simple.cpp ├── mexFGS_simple.mexw64 ├── multiscale_exposure_fusion.m ├── phi.m ├── pyramid_filter.m ├── reconstruct_laplacian_pyramid.m ├── sigma1.m ├── sigma2.m ├── upsample.m └── well_exposedness.m /DE_exposure_fusion_short.m: -------------------------------------------------------------------------------- 1 | tic 2 | clc; 3 | clear all; 4 | I = load_images('7_11'); 5 | 6 | [R,Lu] = multiscale_exposure_fusion(I); 7 | RLu = luminance(R); 8 | [h,w,t] = size(Lu); 9 | log_lu = zeros(size(Lu(:,:,:))); 10 | log_R_lu = zeros(size(RLu(:,:))); 11 | for i = 1:h 12 | for j = 1:w 13 | for k = 1:t 14 | log_lu(i,j,k) = log(Lu(i,j,k)+1); 15 | log_R_lu(i,j) = log(RLu(i,j)+1); 16 | end 17 | end 18 | end 19 | 20 | % construct weight 21 | % find the max 22 | maxX = [0,0,0]; 23 | maxY = [0,0,0]; 24 | for i = 1:h-1 25 | for j = 1:w-1 26 | for k = 1:t 27 | x = f(Lu(i,j,k))*f(Lu(i+1,j,k)); 28 | y = f(Lu(i,j,k))*f(Lu(i,j+1,k)); 29 | if x > maxX(1,k) 30 | maxX(1,k) = x; 31 | end 32 | if y >maxY(1,k) 33 | maxY(1,k) = y; 34 | end 35 | end 36 | end 37 | end 38 | 39 | weightX = zeros(size(log_lu)); 40 | weightY = zeros(size(log_lu)); 41 | for i = 1:h-1 42 | for j = 1:w-1 43 | for k = 1:t 44 | weightX(i,j,k) = f(Lu(i,j,k))*f(Lu(i+1,j,k)) / maxX(1,k); 45 | weightY(i,j,k) = f(Lu(i,j,k))*f(Lu(i,j+1,k)) / maxY(1,k); 46 | end 47 | end 48 | end 49 | 50 | % note: in each weight, the value of last column and row are still zero!!! 51 | 52 | % weighted gradient and singular value decomposition 53 | gx = zeros(size(log_lu)); 54 | gy = zeros(size(log_lu)); 55 | [Rgx,Rgy] = gradient(log_R_lu); 56 | for i = 1:3 57 | [gx(:,:,i),gy(:,:,i)]=gradient(log_lu(:,:,i)); 58 | end 59 | 60 | %weight_grad = zeros(h,w); 61 | vector_field1 = zeros(h,w); 62 | vector_field2 = zeros(h,w); 63 | for i = 1:h 64 | for j = 1:w 65 | weight_grad = [weightX(i,j,1)*gx(i,j,1),weightY(i,j,1)*gy(i,j,1);weightX(i,j,2)*gx(i,j,2),weightY(i,j,2)*gy(i,j,2);weightX(i,j,3)*gx(i,j,3),weightY(i,j,3)*gy(i,j,3)]; 66 | [U,S,V] = svd(weight_grad); 67 | s1 = sigma1(Rgx(i,j),Rgy(i,j)); 68 | s2 = sigma2(Rgx(i,j),Rgy(i,j)); 69 | denom = sqrt(Rgx(i,j)^2 + Rgy(i,j)^2); 70 | % construct vector field 71 | vf = (s1*S(1,1).*V(1,:).' + s2*S(2,2).*V(2,:).') ./ (denom); 72 | vector_field1(i,j) = vf(1,1); 73 | vector_field2(i,j) = vf(2,1); 74 | end 75 | end 76 | 77 | %lambda = 0.03125; 78 | F1 = FGS(vector_field1,0.1,0.03125); 79 | F2 = FGS(vector_field2,0.1,0.03125); 80 | F = F1 + F2; 81 | 82 | Final = R; 83 | [h,w,t] = size(R); 84 | for i = 1:h 85 | for j = 1:w 86 | Final(i,j) = Final(i,j)* exp(F(i,j)); 87 | end 88 | end 89 | toc 90 | 91 | -------------------------------------------------------------------------------- /FGS.m: -------------------------------------------------------------------------------- 1 | % FGS Fast global image smoother. 2 | % 3 | % F = FGS(img, sigma, lambda, joint_image, num_iterations, attenuation) 4 | % 5 | % Parameters: 6 | % img Input image to be filtered [0,255]. 7 | % sigma Filter range standard deviation. 8 | % lambda Filter lambda. 9 | % joint_image (optional) Guidance image for joint filtering [0,255]. 10 | % num_iterations (optional) Number of iterations to perform (default: 3). 11 | % attenuation (optional) attenuation factor for iteration (default: 4). 12 | % 13 | % This is the reference implementation of the fast global image smoother 14 | % described in the paper: 15 | % 16 | % Fast Global Image Smoothing based on Weighted Least Squares 17 | % D. Min, S. Choi, J. Lu, B. Ham, K. Sohn, and M. N. Do, 18 | % IEEE Trans. Image Processing, vol. no. pp., 2014. 19 | % 20 | % Please refer to the publication above if you use this software. For an 21 | % up-to-date version go to: 22 | % 23 | % https://sites.google.com/site/globalsmoothing/ 24 | % 25 | % THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES 26 | % OF ANY KIND, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | % OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 | % THIS SOFTWARE. 32 | % 33 | % Version 1.0 - December 2014. 34 | 35 | function F = FGS(img, sigma, lambda, joint_image, num_iterations, attenuation) 36 | 37 | I = double(img); 38 | 39 | if ~exist('num_iterations', 'var') 40 | num_iterations = 3; 41 | end 42 | 43 | if ~exist('attenuation', 'var') 44 | attenuation = 4; 45 | end 46 | 47 | 48 | if exist('joint_image', 'var') && ~isempty(joint_image) 49 | J = double(joint_image); 50 | 51 | if (size(I,1) ~= size(J,1)) || (size(I,2) ~= size(J,2)) 52 | error('Input and joint images must have equal width and height.'); 53 | end 54 | else 55 | J = []; 56 | end 57 | 58 | %% The code-optimized mex version only supports 1- or 3-channels input images 59 | if (size(I,3) ~= 1 && size(I,3) ~= 3) || (size(J,3) ~= 1 && size(J,3) ~= 3) 60 | error('FGS only supports 1- or 3-channel images.'); 61 | end 62 | F = mexFGS(I, J, sigma, lambda, num_iterations, attenuation); 63 | 64 | %% The intuitive mex version 65 | % F = mexFGS_simple(I, J, sigma, lambda, num_iterations, attenuation); 66 | 67 | %% Return the result 68 | F = cast(F, class(img)); 69 | 70 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multi-scale-exposure-fusion 2 | matlab code for 2017 Detail-Enhanced Multi-Scale Exposure Fusion 3 | This paper is separated into A and B parts. 4 | Code for A part: 5 | mainly to fuse different exposed images, and code here is based on the reference [12] and [13] with a little modification. 6 | Code for B part: 7 | mainly to enhance the fusion image's detail, and code of opimization part is based on the reference [31]. 8 | -------------------------------------------------------------------------------- /WGIF.m: -------------------------------------------------------------------------------- 1 | function q = WGIF(I, p, r, eps) 2 | % GUIDEDFILTER O(1) time implementation of guided filter. 3 | % 4 | % - guidance image: I (should be a gray-scale/single channel image) 5 | % - filtering input image: p (should be a gray-scale/single channel image) 6 | % - local window radius: r 7 | % - regularization parameter: eps 8 | 9 | [hei, wid] = size(I); 10 | %N=(2*r+1)^2 11 | N = boxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels. 12 | 13 | mean_I = boxfilter(I, r) ./ N; 14 | mean_p = boxfilter(p, r) ./ N; 15 | mean_Ip = boxfilter(I.*p, r) ./ N; 16 | cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch. 17 | 18 | mean_II = boxfilter(I.*I, r) ./ N; 19 | var_I = mean_II - mean_I .* mean_I; 20 | 21 | 22 | % weight coefficient 23 | sigma = zeros(hei,wid); 24 | denomin = 0; 25 | eps2 = 0.001*256*256; 26 | for i = 1:hei 27 | for j = 1:wid 28 | denomin = denomin + (1/(var_I(i,j)+eps2)); 29 | end 30 | end 31 | for i = 1:hei 32 | for j = 1:wid 33 | sigma(i,j) = (var_I(i,j)+eps2) * (denomin) / (hei*wid); 34 | end 35 | end 36 | 37 | a = cov_Ip ./ (var_I + (eps./sigma)); % Eqn. (5) in the paper; 38 | b = mean_p - a .* mean_I; % Eqn. (6) in the paper; 39 | 40 | mean_a = boxfilter(a, r) ./ N; 41 | mean_b = boxfilter(b, r) ./ N; 42 | 43 | q = mean_a .* I + mean_b; % Eqn. (8) in the paper; 44 | end -------------------------------------------------------------------------------- /boxfilter2.m: -------------------------------------------------------------------------------- 1 | function C = boxfilter2(I,r) 2 | w=(1/r^2)*ones(r,r); % Defining the box filter mask 3 | 4 | % get array sizes 5 | [ma, na] = size(I); 6 | [mb, nb] = size(w); 7 | 8 | % To do convolution 9 | c = zeros( ma+mb-1, na+nb-1 ); 10 | for i = 1:mb 11 | for j = 1:nb 12 | r1 = i; 13 | r2 = r1 + ma - 1; 14 | c1 = j; 15 | c2 = c1 + na - 1; 16 | c(r1:r2,c1:c2) = c(r1:r2,c1:c2) + w(i,j) * double(I); 17 | end 18 | end 19 | % extract region of size(a) from c 20 | r1 = floor(mb/2) + 1; 21 | r2 = r1 + ma - 1; 22 | c1 = floor(nb/2) + 1; 23 | c2 = c1 + na - 1; 24 | C = c(r1:r2, c1:c2); 25 | end -------------------------------------------------------------------------------- /compile.m: -------------------------------------------------------------------------------- 1 | % tested under Windows7 64bit, MSVC v10.0 compiler 2 | mex OPTIMFLAGS="/Ox /Oi /Oy /DNDEBUG /fp:fast /arch:SSE2 /DMEX_MODE" mexFGS.cpp 3 | mex OPTIMFLAGS="/Ox /Oi /Oy /DNDEBUG /fp:fast /arch:SSE2 /DMEX_MODE" mexFGS_simple.cpp -------------------------------------------------------------------------------- /contrast.m: -------------------------------------------------------------------------------- 1 | % contrast measure 2 | function C = contrast(I) 3 | h = [0 1 0; 1 -4 1; 0 1 0]; % laplacian filter 4 | N = size(I,4); % we have 3 different exposure images 5 | C = zeros(size(I,1),size(I,2),N); 6 | for i = 1:N 7 | mono = rgb2gray(I(:,:,:,i)); 8 | C(:,:,i) = abs(imfilter(mono,h,'replicate')); 9 | end -------------------------------------------------------------------------------- /downsample.m: -------------------------------------------------------------------------------- 1 | %{ 2 | Copyright (c) 2015, Tom Mertens 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | %} 26 | 27 | % Downsampling procedure. 28 | % 29 | % Arguments: 30 | % grayscale I image 31 | % downsampling filter 'filter', should be a 1D separable filter. 32 | % 'border_mode' should be 'circular', 'symmetric', or 'replicate'. See 'imfilter'. 33 | % 34 | % If image width W is odd, then the resulting image will have width (W-1)/2+1, 35 | % Same for height. 36 | % 37 | % tom.mertens@gmail.com, August 2007 38 | % 39 | 40 | function R = downsample(I, filter) 41 | 42 | border_mode = 'symmetric'; 43 | 44 | % low pass, convolve with separable filter 45 | R = imfilter(I,filter,border_mode); %horizontal 46 | R = imfilter(R,filter',border_mode); %vertical 47 | 48 | % decimate 49 | r = size(I,1); 50 | c = size(I,2); 51 | R = R(1:2:r, 1:2:c, :); -------------------------------------------------------------------------------- /f.m: -------------------------------------------------------------------------------- 1 | function z = f(Y) 2 | if Y <= 128 3 | z = Y+1; 4 | else 5 | z = 257-Y; 6 | end 7 | end -------------------------------------------------------------------------------- /gaussian_pyramid.m: -------------------------------------------------------------------------------- 1 | %{ 2 | Copyright (c) 2015, Tom Mertens 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | %} 26 | 27 | % Contruction of Gaussian pyramid 28 | % 29 | % Arguments: 30 | % image 'I' 31 | % 'nlev', number of levels in the pyramid (optional) 32 | % 33 | % tom.mertens@gmail.com, August 2007 34 | % 35 | 36 | function pyr = gaussian_pyramid(I,nlev) 37 | 38 | r = size(I,1); 39 | c = size(I,2); 40 | 41 | if ~exist('nlev') 42 | %compute the highest possible pyramid 43 | nlev = floor(log(min(r,c)) / log(2)); 44 | end 45 | 46 | % start by copying the image to the finest level 47 | pyr = cell(nlev,1); 48 | pyr{1} = I; 49 | 50 | % recursively downsample the image 51 | filter = pyramid_filter; 52 | for l = 2:nlev 53 | I = downsample(I,filter); 54 | pyr{l} = I; 55 | end -------------------------------------------------------------------------------- /guidedfilter.m: -------------------------------------------------------------------------------- 1 | function q = guidedfilter(I, p, r, eps) 2 | % GUIDEDFILTER O(1) time implementation of guided filter. 3 | % 4 | % - guidance image: I (should be a gray-scale/single channel image) 5 | % - filtering input image: p (should be a gray-scale/single channel image) 6 | % - local window radius: r 7 | % - regularization parameter: eps 8 | 9 | [hei, wid] = size(I); 10 | %N=(2*r+1)^2 11 | N = boxfilter2(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels. 12 | 13 | mean_I = boxfilter2(I, r) ./ N; 14 | mean_p = boxfilter2(p, r) ./ N; 15 | mean_Ip = boxfilter2(I.*p, r) ./ N; 16 | cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch. 17 | 18 | mean_II = boxfilter2(I.*I, r) ./ N; 19 | var_I = mean_II - mean_I .* mean_I; 20 | 21 | a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper; 22 | b = mean_p - a .* mean_I; % Eqn. (6) in the paper; 23 | 24 | mean_a = boxfilter2(a, r) ./ N; 25 | mean_b = boxfilter2(b, r) ./ N; 26 | 27 | q = mean_a .* I + mean_b; % Eqn. (8) in the paper; 28 | end -------------------------------------------------------------------------------- /imgsaturation.m: -------------------------------------------------------------------------------- 1 | % saturation measure 2 | function C = imgsaturation(I) 3 | N = size(I,4); 4 | C = zeros(size(I,1),size(I,2),N); 5 | for i = 1:N 6 | % saturation is computed as the standard deviation of the color channels 7 | R = I(:,:,1,i); 8 | G = I(:,:,2,i); 9 | B = I(:,:,3,i); 10 | mu = (R + G + B)/3; 11 | C(:,:,i) = sqrt(((R - mu).^2 + (G - mu).^2 + (B - mu).^2)/3); 12 | end -------------------------------------------------------------------------------- /laplacian_pyramid.m: -------------------------------------------------------------------------------- 1 | %{ 2 | Copyright (c) 2015, Tom Mertens 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | %} 26 | 27 | % Contruction of Laplacian pyramid 28 | % 29 | % Arguments: 30 | % image 'I' 31 | % 'nlev', number of levels in the pyramid (optional) 32 | % 33 | % tom.mertens@gmail.com, August 2007 34 | % 35 | % 36 | % More information: 37 | % 'The Laplacian Pyramid as a Compact Image Code' 38 | % Burt, P., and Adelson, E. H., 39 | % IEEE Transactions on Communication, COM-31:532-540 (1983). 40 | % 41 | 42 | function pyr = laplacian_pyramid(I,nlev) 43 | 44 | r = size(I,1); 45 | c = size(I,2); 46 | 47 | if ~exist('nlev') 48 | % compute the highest possible pyramid 49 | nlev = floor(log(min(r,c)) / log(2)); 50 | end 51 | 52 | % recursively build pyramid 53 | pyr = cell(nlev,1); 54 | filter = pyramid_filter; 55 | J = I; 56 | for l = 1:nlev - 1 57 | % apply low pass filter, and downsample 58 | I = downsample(J,filter); 59 | odd = 2*size(I) - size(J); % for each dimension, check if the upsampled version has to be odd 60 | % in each level, store difference between image and upsampled low pass version 61 | pyr{l} = J - upsample(I,odd,filter); 62 | J = I; % continue with low pass image 63 | end 64 | pyr{nlev} = J; % the coarest level contains the residual low pass image 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /load_images.m: -------------------------------------------------------------------------------- 1 | %{ 2 | Copyright (c) 2015, Tom Mertens 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | %} 26 | 27 | % This procedure loads a sequence of images 28 | % 29 | % Arguments: 30 | % 'path', refers to a directory which contains a sequence of JPEG or PPM 31 | % images 32 | % 'reduce' is an optional parameter that controls downsampling, e.g., reduce = .5 33 | % downsamples all images by a factor of 2. 34 | % 35 | % tom.mertens@gmail.com, August 2007 36 | % 37 | 38 | function I = load_images(path, reduce) 39 | 40 | if ~exist('reduce') 41 | reduce = 1; 42 | end 43 | 44 | if (reduce > 1 || reduce <= 0) 45 | error('reduce must fulfill: 0 < reduce <= 1'); 46 | end 47 | 48 | % find all JPEG or PPM files in directory 49 | files = dir([path '/*.png']); 50 | N = length(files); 51 | if (N == 0) 52 | files = dir([path '/*.ppm']); 53 | N = length(files); 54 | if (N == 0) 55 | error('no files found'); 56 | end 57 | end 58 | 59 | % allocate memory 60 | sz = size(imread([path '/' files(1).name])); 61 | r = floor(sz(1)*reduce); 62 | c = floor(sz(2)*reduce); 63 | I = zeros(r,c,3,N); 64 | 65 | % read all files 66 | for i = 1:N 67 | 68 | % load image 69 | filename = [path '/' files(i).name]; 70 | im = double(imread(filename)) / 255; 71 | if (size(im,1) ~= sz(1) || size(im,2) ~= sz(2)) 72 | error('images must all have the same size'); 73 | end 74 | 75 | % optional downsampling step 76 | if (reduce < 1) 77 | im = imresize(im,[r c],'bicubic'); 78 | end 79 | 80 | I(:,:,:,i) = im; 81 | end 82 | -------------------------------------------------------------------------------- /luminance.m: -------------------------------------------------------------------------------- 1 | % luminance measure 2 | function Y = luminance(I) 3 | N = size(I,4); 4 | Y = zeros(size(I,1),size(I,2),N); 5 | for i = 1:N 6 | Ycbcr = rgb2ycbcr(I(:,:,:,i)); 7 | Y(:,:,i) = Ycbcr(:,:,1); 8 | end -------------------------------------------------------------------------------- /mexFGS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "mex.h" 6 | 7 | #define SQ(x) ((x)*(x)) 8 | 9 | int W, H; // image width, height 10 | int nChannels, nChannels_guide; 11 | double *BLFKernelI; // Kernel LUT 12 | 13 | // Main functions 14 | void prepareBLFKernel(double sigma); 15 | void FGS(double*** image, double*** joint_image, double sigma, double lambda, int solver_iteration, double solver_attenuation); 16 | void FGS_single(double*** image, double*** joint_image, double sigma, double lambda, int solver_iteration, double solver_attenuation); 17 | void FGS_13(double*** image, double*** joint_image, double sigma, double lambda, int solver_iteration, double solver_attenuation); 18 | void FGS_31(double*** image, double*** joint_image, double sigma, double lambda, int solver_iteration, double solver_attenuation); 19 | 20 | // Memory management 21 | double *** memAllocDouble3(int n,int r,int c); 22 | double** memAllocDouble2(int r,int c); 23 | void memFreeDouble3(double ***p); 24 | void memFreeDouble2(double **p); 25 | 26 | 27 | // Build LUT for bilateral kernel weight 28 | void prepareBLFKernel(double sigma) 29 | { 30 | const int MaxSizeOfFilterI = 195075; 31 | BLFKernelI = (double *)malloc(sizeof(double)*MaxSizeOfFilterI); 32 | 33 | for(int m=0;m 2) 50 | nChannels = mxGetDimensions(img)[2]; 51 | else 52 | nChannels = 1; 53 | 54 | // FGS parameters 55 | double sigma = mxGetScalar(prhs[2]); 56 | double lambda = mxGetScalar(prhs[3]); 57 | int solver_iteration = (int)mxGetScalar(prhs[4]); 58 | double solver_attenuation = mxGetScalar(prhs[5]); 59 | 60 | mexPrintf("Image resolution: %d x %d x %d\n", W, H, nChannels); 61 | mexPrintf("Parameters:\n"); 62 | mexPrintf(" Sigma = %f\n", sigma); 63 | mexPrintf(" Lambda = %f\n", lambda); 64 | mexPrintf(" Iteration = %d\n", solver_iteration); 65 | mexPrintf(" Attenuation = %f\n", solver_attenuation); 66 | 67 | // Image buffer preperation 68 | double*** image_filtered = memAllocDouble3(H, W, nChannels); 69 | double* ptr_image = (double*)mxGetPr(img); 70 | double* ptr_image_array = image_filtered[0][0]; 71 | for(int y=0;y 2) 83 | nChannels_guide = mxGetDimensions(imgGuide)[2]; 84 | else 85 | nChannels_guide = 1; 86 | 87 | mexPrintf("Joint filtering mode: %d x %d x %d\n", W, H, nChannels_guide); 88 | image_guidance = memAllocDouble3(H, W, nChannels_guide); 89 | 90 | double* ptr_guidance = (double*)mxGetPr(imgGuide); 91 | double* ptr_guidance_array = image_guidance[0][0]; 92 | for(int y=0;y 0; ) { 221 | double tcr = *--pc; 222 | double tcg = *--pc; 223 | double tcb = *--pc; 224 | 225 | double ncr = tcr - *pc_vec * tpr; 226 | double ncg = tcg - *pc_vec * tpg; 227 | double ncb = tcb - *pc_vec * tpb; 228 | 229 | pc_vec--; 230 | tpr = ncr; tpg = ncg; tpb = ncb; 231 | *--po = ncr; 232 | *--po = ncg; 233 | *--po = ncb; 234 | } 235 | } 236 | 237 | // column 238 | for(int j=0;j 0; ) { 318 | pc-=(width-1)*3; 319 | double tcr = *--pc; 320 | double tcg = *--pc; 321 | double tcb = *--pc; 322 | 323 | double ncr = tcr - *pc_vec * tpr; 324 | double ncg = tcg - *pc_vec * tpg; 325 | double ncb = tcb - *pc_vec * tpb; 326 | pc_vec--; 327 | tpr = ncr; tpg = ncg; tpb = ncb; 328 | *--po = ncr; 329 | *--po = ncg; 330 | *--po = ncb; 331 | po-=(width-1)*3; 332 | } 333 | } 334 | 335 | lambda_in /= solver_attenuation; //solver_attenuation = 4 (default parameter) 336 | } 337 | 338 | free(a_vec); free(b_vec); free(c_vec); 339 | free(a2_vec); free(b2_vec); free(c2_vec); 340 | } 341 | 342 | void FGS_single(double*** image, double*** joint_image, double sigma, double lambda, int solver_iteration, double solver_attenuation) 343 | { 344 | if(joint_image == NULL) joint_image = image; 345 | 346 | int width = W; 347 | int height = H; 348 | 349 | double *a_vec = (double *)malloc(sizeof(double)*width); 350 | double *b_vec = (double *)malloc(sizeof(double)*width); 351 | double *c_vec = (double *)malloc(sizeof(double)*width); 352 | double *a2_vec = (double *)malloc(sizeof(double)*height); 353 | double *b2_vec = (double *)malloc(sizeof(double)*height); 354 | double *c2_vec = (double *)malloc(sizeof(double)*height); 355 | 356 | double lambda_in = 1.5*lambda*pow(4.0,solver_iteration-1)/(pow(4.0,solver_iteration)-1.0); 357 | prepareBLFKernel(sigma); // prepare kernel LUT 358 | 359 | for(int iter=0;iter 0; ) { 437 | double tcr = *--pc; 438 | //double tcg = *--pc; 439 | //double tcb = *--pc; 440 | 441 | double ncr = tcr - *pc_vec * tpr; 442 | //double ncg = tcg - *pc_vec * tpg; 443 | //double ncb = tcb - *pc_vec * tpb; 444 | 445 | pc_vec--; 446 | tpr = ncr; //tpg = ncg; tpb = ncb; 447 | *--po = ncr; 448 | //*--po = ncg; 449 | //*--po = ncb; 450 | } 451 | } 452 | 453 | // column 454 | for(int j=0;j 0; ) { 534 | pc-=(width-1); //pc-=(width-1)*3; 535 | double tcr = *--pc; 536 | //double tcg = *--pc; 537 | //double tcb = *--pc; 538 | 539 | double ncr = tcr - *pc_vec * tpr; 540 | //double ncg = tcg - *pc_vec * tpg; 541 | //double ncb = tcb - *pc_vec * tpb; 542 | pc_vec--; 543 | tpr = ncr; //tpg = ncg; tpb = ncb; 544 | *--po = ncr; 545 | //*--po = ncg; 546 | //*--po = ncb; 547 | po-=(width-1); //po-=(width-1)*3; 548 | } 549 | } 550 | 551 | lambda_in /= solver_attenuation; //solver_attenuation = 4 (default parameter) 552 | } 553 | 554 | free(a_vec); free(b_vec); free(c_vec); 555 | free(a2_vec); free(b2_vec); free(c2_vec); 556 | } 557 | 558 | void FGS_13(double*** image, double*** joint_image, double sigma, double lambda, int solver_iteration, double solver_attenuation) 559 | { 560 | int width = W; 561 | int height = H; 562 | 563 | double *a_vec = (double *)malloc(sizeof(double)*width); 564 | double *b_vec = (double *)malloc(sizeof(double)*width); 565 | double *c_vec = (double *)malloc(sizeof(double)*width); 566 | double *a2_vec = (double *)malloc(sizeof(double)*height); 567 | double *b2_vec = (double *)malloc(sizeof(double)*height); 568 | double *c2_vec = (double *)malloc(sizeof(double)*height); 569 | 570 | double lambda_in = 1.5*lambda*pow(4.0,solver_iteration-1)/(pow(4.0,solver_iteration)-1.0); 571 | prepareBLFKernel(sigma); // prepare kernel LUT 572 | 573 | for(int iter=0;iter 0; ) { 651 | double tcr = *--pc; 652 | //double tcg = *--pc; 653 | //double tcb = *--pc; 654 | 655 | double ncr = tcr - *pc_vec * tpr; 656 | //double ncg = tcg - *pc_vec * tpg; 657 | //double ncb = tcb - *pc_vec * tpb; 658 | 659 | pc_vec--; 660 | tpr = ncr; //tpg = ncg; tpb = ncb; 661 | *--po = ncr; 662 | //*--po = ncg; 663 | //*--po = ncb; 664 | } 665 | } 666 | 667 | // column 668 | for(int j=0;j 0; ) { 748 | pc-=(width-1); //pc-=(width-1)*3; 749 | double tcr = *--pc; 750 | //double tcg = *--pc; 751 | //double tcb = *--pc; 752 | 753 | double ncr = tcr - *pc_vec * tpr; 754 | //double ncg = tcg - *pc_vec * tpg; 755 | //double ncb = tcb - *pc_vec * tpb; 756 | pc_vec--; 757 | tpr = ncr; //tpg = ncg; tpb = ncb; 758 | *--po = ncr; 759 | //*--po = ncg; 760 | //*--po = ncb; 761 | po-=(width-1); //po-=(width-1)*3; 762 | } 763 | } 764 | 765 | lambda_in /= solver_attenuation; //solver_attenuation = 4 (default parameter) 766 | } 767 | 768 | free(a_vec); free(b_vec); free(c_vec); 769 | free(a2_vec); free(b2_vec); free(c2_vec); 770 | } 771 | 772 | 773 | void FGS_31(double*** image, double*** joint_image, double sigma, double lambda, int solver_iteration, double solver_attenuation) 774 | { 775 | int width = W; 776 | int height = H; 777 | 778 | double *a_vec = (double *)malloc(sizeof(double)*width); 779 | double *b_vec = (double *)malloc(sizeof(double)*width); 780 | double *c_vec = (double *)malloc(sizeof(double)*width); 781 | double *a2_vec = (double *)malloc(sizeof(double)*height); 782 | double *b2_vec = (double *)malloc(sizeof(double)*height); 783 | double *c2_vec = (double *)malloc(sizeof(double)*height); 784 | 785 | double lambda_in = 1.5*lambda*pow(4.0,solver_iteration-1)/(pow(4.0,solver_iteration)-1.0); 786 | prepareBLFKernel(sigma); // prepare kernel LUT 787 | 788 | for(int iter=0;iter 0; ) { 866 | double tcr = *--pc; 867 | double tcg = *--pc; 868 | double tcb = *--pc; 869 | 870 | double ncr = tcr - *pc_vec * tpr; 871 | double ncg = tcg - *pc_vec * tpg; 872 | double ncb = tcb - *pc_vec * tpb; 873 | 874 | pc_vec--; 875 | tpr = ncr; tpg = ncg; tpb = ncb; 876 | *--po = ncr; 877 | *--po = ncg; 878 | *--po = ncb; 879 | } 880 | } 881 | 882 | // column 883 | for(int j=0;j 0; ) { 963 | pc-=(width-1)*3; 964 | double tcr = *--pc; 965 | double tcg = *--pc; 966 | double tcb = *--pc; 967 | 968 | double ncr = tcr - *pc_vec * tpr; 969 | double ncg = tcg - *pc_vec * tpg; 970 | double ncb = tcb - *pc_vec * tpb; 971 | pc_vec--; 972 | tpr = ncr; tpg = ncg; tpb = ncb; 973 | *--po = ncr; 974 | *--po = ncg; 975 | *--po = ncb; 976 | po-=(width-1)*3; 977 | } 978 | } 979 | 980 | lambda_in /= solver_attenuation; //solver_attenuation = 4 (default parameter) 981 | } 982 | 983 | free(a_vec); free(b_vec); free(c_vec); 984 | free(a2_vec); free(b2_vec); free(c2_vec); 985 | } 986 | 987 | 988 | double *** memAllocDouble3(int n,int r,int c) 989 | { 990 | int padding=10; 991 | double *a,**p,***pp; 992 | int rc=r*c; 993 | int i,j; 994 | a=(double*) malloc(sizeof(double)*(n*rc+padding)); 995 | if(a==NULL) {mexErrMsgTxt("memAllocDouble: Memory is too huge.\n"); } 996 | p=(double**) malloc(sizeof(double*)*n*r); 997 | pp=(double***) malloc(sizeof(double**)*n); 998 | for(i=0;i 2 | #include 3 | #include 4 | #include 5 | #include "mex.h" 6 | 7 | #define SQ(x) ((x)*(x)) 8 | 9 | int W, H; // image width, height 10 | int nChannels, nChannels_guide; 11 | double *BLFKernelI; // Kernel LUT 12 | 13 | // Main functions 14 | void prepareBLFKernel(double sigma); 15 | void FGS_simple(double ***image, double ***joint_image, double sigma, double lambda, int solver_iteration, double solver_attenuation); 16 | void solve_tridiagonal_in_place_destructive(double x[], const size_t N, const double a[], const double b[], double c[]); 17 | 18 | // Memory management 19 | double *** memAllocDouble3(int n,int r,int c); 20 | double** memAllocDouble2(int r,int c); 21 | void memFreeDouble3(double ***p); 22 | void memFreeDouble2(double **p); 23 | 24 | 25 | // Build LUT for bilateral kernel weight 26 | void prepareBLFKernel(double sigma) 27 | { 28 | const int MaxSizeOfFilterI = 195075; 29 | BLFKernelI = (double *)malloc(sizeof(double)*MaxSizeOfFilterI); 30 | 31 | for(int m=0;m 2) 48 | nChannels = mxGetDimensions(img)[2]; 49 | else 50 | nChannels = 1; 51 | 52 | // FGS parameters 53 | double sigma = mxGetScalar(prhs[2]); 54 | double lambda = mxGetScalar(prhs[3]); 55 | int solver_iteration = (int)mxGetScalar(prhs[4]); 56 | double solver_attenuation = mxGetScalar(prhs[5]); 57 | 58 | mexPrintf("Image resolution: %d x %d x %d\n", W, H, nChannels); 59 | mexPrintf("Parameters:\n"); 60 | mexPrintf(" Sigma = %f\n", sigma); 61 | mexPrintf(" Lambda = %f\n", lambda); 62 | mexPrintf(" Iteration = %d\n", solver_iteration); 63 | mexPrintf(" Attenuation = %f\n", solver_attenuation); 64 | 65 | // Image buffer preperation 66 | double*** image_filtered = memAllocDouble3(H, W, nChannels); 67 | double* ptr_image = (double*)mxGetPr(img); 68 | double* ptr_image_array = image_filtered[0][0]; 69 | for(int y=0;y 2) 81 | nChannels_guide = mxGetDimensions(imgGuide)[2]; 82 | else 83 | nChannels_guide = 1; 84 | 85 | mexPrintf("Joint filtering mode: %d x %d x %d\n", W, H, nChannels_guide); 86 | image_guidance = memAllocDouble3(H, W, nChannels_guide); 87 | 88 | double* ptr_guidance = (double*)mxGetPr(imgGuide); 89 | double* ptr_guidance_array = image_guidance[0][0]; 90 | for(int y=0;y= 0; n--) 233 | x[n] = x[n] - c[n] * x[n + 1]; 234 | } 235 | 236 | double *** memAllocDouble3(int n,int r,int c) 237 | { 238 | int padding=10; 239 | double *a,**p,***pp; 240 | int rc=r*c; 241 | int i,j; 242 | a=(double*) malloc(sizeof(double)*(n*rc+padding)); 243 | if(a==NULL) {mexErrMsgTxt("memAllocDouble: Memory is too huge.\n"); } 244 | p=(double**) malloc(sizeof(double*)*n*r); 245 | pp=(double***) malloc(sizeof(double**)*n); 246 | for(i=0;i 0) 29 | W = W.*contrast(I).^contrast_parm; 30 | end 31 | if (sat_parm > 0) 32 | W = W.*imgsaturation(I).^sat_parm; 33 | end 34 | if (wexp_parm > 0) 35 | W = W.*well_exposedness(I).^wexp_parm; 36 | end 37 | 38 | %normalize weights: make sure that weights sum to one for each pixel 39 | W = W + 1e-12; %avoids division by zero 40 | W = W./repmat(sum(W,3),[1 1 N]); 41 | 42 | % create empty pyramid 43 | nlev = floor(log(min(r,c)) / log(2)); % numbers of layers 44 | pyr_1R = gaussian_pyramid(zeros(r,c),nlev); 45 | pyr_2R = gaussian_pyramid(zeros(r,c),nlev); 46 | pyr_3R = gaussian_pyramid(zeros(r,c),nlev); 47 | pyr_1G = gaussian_pyramid(zeros(r,c),nlev); 48 | pyr_2G = gaussian_pyramid(zeros(r,c),nlev); 49 | pyr_3G = gaussian_pyramid(zeros(r,c),nlev); 50 | pyr_1B = gaussian_pyramid(zeros(r,c),nlev); 51 | pyr_2B = gaussian_pyramid(zeros(r,c),nlev); 52 | pyr_3B = gaussian_pyramid(zeros(r,c),nlev); 53 | wgifW_1 = gaussian_pyramid(zeros(r,c),nlev); % WGIF weight map pyramid 54 | wgifW_2 = gaussian_pyramid(zeros(r,c),nlev); 55 | wgifW_3 = gaussian_pyramid(zeros(r,c),nlev); 56 | 57 | %construct laplacian pyramid of input image 58 | pyrI_1R = laplacian_pyramid(I_1R,nlev); 59 | pyrI_2R = laplacian_pyramid(I_2R,nlev); 60 | pyrI_3R = laplacian_pyramid(I_3R,nlev); 61 | pyrI_1G = laplacian_pyramid(I_1G,nlev); 62 | pyrI_2G = laplacian_pyramid(I_2G,nlev); 63 | pyrI_3G = laplacian_pyramid(I_3G,nlev); 64 | pyrI_1B = laplacian_pyramid(I_1B,nlev); 65 | pyrI_2B = laplacian_pyramid(I_2B,nlev); 66 | pyrI_3B = laplacian_pyramid(I_3B,nlev); 67 | 68 | pyrW_1 = gaussian_pyramid(W(:,:,1),nlev); 69 | pyrW_2 = gaussian_pyramid(W(:,:,2),nlev); 70 | pyrW_3 = gaussian_pyramid(W(:,:,3),nlev); 71 | pyrY_1 = gaussian_pyramid(Lu(:,:,1),nlev); 72 | pyrY_2 = gaussian_pyramid(Lu(:,:,2),nlev); 73 | pyrY_3 = gaussian_pyramid(Lu(:,:,3),nlev); 74 | 75 | for k = 1:nlev 76 | wgifW_1{k} = WGIF(pyrY_1{k},pyrW_1{k},4,1/1024); 77 | wgifW_2{k} = WGIF(pyrY_2{k},pyrW_2{k},4,1/1024); 78 | wgifW_3{k} = WGIF(pyrY_3{k},pyrW_3{k},4,1/1024); 79 | 80 | pyr_1R{k} = pyr_1R{k} + wgifW_1{k}.*pyrI_1R{k}; 81 | pyr_1G{k} = pyr_1G{k} + wgifW_1{k}.*pyrI_1G{k}; 82 | pyr_1B{k} = pyr_1B{k} + wgifW_1{k}.*pyrI_1B{k}; 83 | pyr_2R{k} = pyr_2R{k} + wgifW_2{k}.*pyrI_2R{k}; 84 | pyr_2G{k} = pyr_2G{k} + wgifW_2{k}.*pyrI_2G{k}; 85 | pyr_2B{k} = pyr_2B{k} + wgifW_2{k}.*pyrI_2B{k}; 86 | pyr_3R{k} = pyr_3R{k} + wgifW_3{k}.*pyrI_3R{k}; 87 | pyr_3G{k} = pyr_3G{k} + wgifW_3{k}.*pyrI_3G{k}; 88 | pyr_3B{k} = pyr_3B{k} + wgifW_3{k}.*pyrI_3B{k}; 89 | 90 | end 91 | 92 | % reconstruct 93 | R = zeros(r,c,3); 94 | pyr_R = cellfun(@plus,pyr_1R,pyr_2R,'Un',0); 95 | pyr_R = cellfun(@plus,pyr_R,pyr_3R,'Un',0); 96 | pyr_G = cellfun(@plus,pyr_1G,pyr_2G,'Un',0); 97 | pyr_G = cellfun(@plus,pyr_G,pyr_3G,'Un',0); 98 | pyr_B = cellfun(@plus,pyr_1B,pyr_2B,'Un',0); 99 | pyr_B = cellfun(@plus,pyr_B,pyr_3B,'Un',0); 100 | 101 | R(:,:,1) = reconstruct_laplacian_pyramid(pyr_R); 102 | R(:,:,2) = reconstruct_laplacian_pyramid(pyr_G); 103 | R(:,:,3) = reconstruct_laplacian_pyramid(pyr_B); 104 | end 105 | -------------------------------------------------------------------------------- /phi.m: -------------------------------------------------------------------------------- 1 | function denom = phi(z) 2 | % formula (15) 3 | denom = sqrt((abs(z))^0.75 + 0.0001); 4 | end -------------------------------------------------------------------------------- /pyramid_filter.m: -------------------------------------------------------------------------------- 1 | %{ 2 | Copyright (c) 2015, Tom Mertens 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | %} 26 | 27 | % This is a 1-dimensional 5-tap low pass filter. It is used as a 2D separable low 28 | % pass filter for constructing Gaussian and Laplacian pyramids. 29 | % 30 | % tom.mertens@gmail.com, August 2007 31 | % 32 | 33 | function f = pyramid_filter; 34 | f = [.0625, .25, .375, .25, .0625]; -------------------------------------------------------------------------------- /reconstruct_laplacian_pyramid.m: -------------------------------------------------------------------------------- 1 | %{ 2 | Copyright (c) 2015, Tom Mertens 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | %} 26 | 27 | % Reconstruction of image from Laplacian pyramid 28 | % 29 | % Arguments: 30 | % pyramid 'pyr', as generated by function 'laplacian_pyramid' 31 | % 32 | % tom.mertens@gmail.com, August 2007 33 | % 34 | % 35 | % More information: 36 | % 'The Laplacian Pyramid as a Compact Image Code' 37 | % Burt, P., and Adelson, E. H., 38 | % IEEE Transactions on Communication, COM-31:532-540 (1983). 39 | % 40 | 41 | function R = reconstruct_laplacian_pyramid(pyr) 42 | 43 | r = size(pyr{1},1); 44 | c = size(pyr{1},2); 45 | nlev = length(pyr); 46 | 47 | % start with low pass residual 48 | R = pyr{nlev}; 49 | filter = pyramid_filter; 50 | for l = nlev - 1 : -1 : 1 51 | % upsample, and add to current level 52 | odd = 2*size(R) - size(pyr{l}); 53 | R = pyr{l} + upsample(R,odd,filter); 54 | end 55 | -------------------------------------------------------------------------------- /sigma1.m: -------------------------------------------------------------------------------- 1 | function S1 = sigma1(gradientX,gradientY) 2 | % formula (12) 3 | % note !! we use intermediate image's gradient here 4 | if abs(gradientX) > abs(gradientY) 5 | S1 = gradientX; 6 | else 7 | S1 = gradientY; 8 | end 9 | end -------------------------------------------------------------------------------- /sigma2.m: -------------------------------------------------------------------------------- 1 | function S2 = sigma2(gradientX,gradientY) 2 | % formula (13) 3 | % note !! we use intermediate image's gradient here 4 | if abs(gradientX) > abs(gradientY) 5 | S2 = gradientY; 6 | else 7 | S2 = gradientX; 8 | end 9 | end -------------------------------------------------------------------------------- /upsample.m: -------------------------------------------------------------------------------- 1 | %{ 2 | Copyright (c) 2015, Tom Mertens 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | %} 26 | 27 | % Upsampling procedure. 28 | % 29 | % Argments: 30 | % 'I': greyscale image 31 | % 'odd': 2-vector of binary values, indicates whether the upsampled image 32 | % should have odd size for the respective dimensions 33 | % 'filter': upsampling filter 34 | % 35 | % If image width W is odd, then the resulting image will have width (W-1)/2+1, 36 | % Same for height. 37 | % 38 | % tom.mertens@gmail.com, August 2007 39 | % 40 | 41 | function R = upsample(I,odd,filter) 42 | 43 | % increase resolution 44 | I = padarray(I,[1 1 0],'replicate'); % pad the image with a 1-pixel border 45 | r = 2*size(I,1); 46 | c = 2*size(I,2); 47 | k = size(I,3); 48 | R = zeros(r,c,k); 49 | R(1:2:r, 1:2:c, :) = 4*I; % increase size 2 times; the padding is now 2 pixels wide 50 | 51 | % interpolate, convolve with separable filter 52 | R = imfilter(R,filter); %horizontal 53 | R = imfilter(R,filter'); %vertical 54 | 55 | % remove the border 56 | R = R(3:r - 2 - odd(1), 3:c - 2 - odd(2), :); 57 | 58 | -------------------------------------------------------------------------------- /well_exposedness.m: -------------------------------------------------------------------------------- 1 | % well-exposedness measure 2 | function C = well_exposedness(I) 3 | sig = .2; 4 | N = size(I,4); % we have 3 different exposure images 5 | C = zeros(size(I,1),size(I,2),N); 6 | for i = 1:N 7 | R = exp(-.5*(I(:,:,1,i) - .5).^2/sig.^2); 8 | G = exp(-.5*(I(:,:,2,i) - .5).^2/sig.^2); 9 | B = exp(-.5*(I(:,:,3,i) - .5).^2/sig.^2); 10 | C(:,:,i) = R.*G.*B; 11 | end --------------------------------------------------------------------------------