├── Durand.m ├── LICENSE ├── README.md ├── Reinhard.m └── tonemapping.m /Durand.m: -------------------------------------------------------------------------------- 1 | % Getting the HDR input file 2 | Img = hdrread('memorial.hdr'); 3 | [r,c,h] = size(Img); 4 | 5 | % Luminance matrix 6 | Lum = zeros(r,c); 7 | for i=1:r 8 | for j=1:c 9 | Lum(i,j) = Img(i,j,1)*0.299 + Img(i,j,2)*0.587 + Img(i,j,3)*0.114; 10 | end 11 | end 12 | 13 | % Computing the Gradient matrix as directed in the paper 14 | H = zeros(r,c); 15 | for i=1:r 16 | for j = 1:c 17 | H(i,j) = log10(Lum(i,j)); 18 | end 19 | end 20 | 21 | gradH = zeros(r,c,2); 22 | for i=1:r 23 | for j=1:c 24 | if i==1 25 | A = H(i+1,j); 26 | B=0; 27 | elseif i==r 28 | A = 0; 29 | B= H(i-1,j); 30 | else 31 | A= H(i+1,j); 32 | B = H(i-1,j); 33 | end 34 | 35 | if j==1 36 | C = H(i,j+1); 37 | D = 0; 38 | elseif j==c 39 | C = 0; 40 | D = H(i,j-1); 41 | else 42 | C = H(i,j+1); 43 | D = H(i,j-1); 44 | end 45 | 46 | x = (A-B)/2; 47 | y = (C-D)/2; 48 | gradH(i,j,:) = [x,y]; 49 | 50 | end 51 | end 52 | 53 | sum = 0; 54 | for i=i:r 55 | for j=1:c 56 | sum = sum + sqrt(gradH(i,j,1)^2 + gradH(i,j,2)^2); 57 | end 58 | end 59 | 60 | % Getting the constants as directed in the paper 61 | average = sum/r*c; 62 | alpha = 0.1*average; 63 | beta = 0.85; 64 | 65 | % Performing the transformations as directed in the paper 66 | phi = zeros(r,c); 67 | for i=1:r 68 | for j=1:c 69 | phi(i,j) = (alpha/sqrt(gradH(i,j,1)^2 + gradH(i,j,2)^2)) * (sqrt(gradH(i,j,1)^2 + gradH(i,j,2)^2)/alpha)^(beta); 70 | end 71 | end 72 | 73 | G = gradH .* phi; 74 | divG = zeros(r,c); 75 | for i=1:r 76 | for j=1:c 77 | 78 | if ((i==1) && (j==1)) 79 | 80 | divG(i,j) = G(i,j,1) + G(i,j,2); 81 | elseif i==1 82 | 83 | divG(i,j) = G(i,j,1) + G(i,j,2) - G(i,j-1,2); 84 | elseif j==1 85 | 86 | divG(i,j) = G(i,j,1) - G(i-1,j,1) + G(i,j,2); 87 | else 88 | 89 | divG(i,j) = G(i,j,1) - G(i-1,j,1) + G(i,j,2) - G(i,j-1,2); 90 | end 91 | end 92 | end 93 | divG = fillmissing(divG,'previous'); 94 | f = fft(divG); 95 | 96 | fi = zeros(r,c); 97 | Lx = r; 98 | Ly = c; 99 | for i=1:r 100 | for j = 1:c 101 | fi(i,j) = (f(i,j))/(((2*pi*(i/Lx)*(1j))^2)+((2*pi*(j/Ly)*(1j))^2)); 102 | end 103 | end 104 | I = real(ifft(fi)); 105 | 106 | for i=1:r 107 | for j=1:c 108 | I(i,j) = 10^(I(i,j)); 109 | if j==1 110 | I(i,j) = 0; 111 | end 112 | end 113 | end 114 | 115 | % Getting the output image after all the transformations done earlier 116 | ImgOutLum = zeros(r,c,h); 117 | for i = 1:r 118 | for j = 1:c 119 | for k =1:h 120 | ImgOutLum(i,j,1) = (((Img(i,j,1))/(Lum(i,j))))^(0.5)*(I(i,j)); 121 | ImgOutLum(i,j,2) = (((Img(i,j,2))/(Lum(i,j))))^(0.5)*(I(i,j)); 122 | ImgOutLum(i,j,3) = (((Img(i,j,3))/(Lum(i,j))))^(0.5)*(I(i,j)); 123 | end 124 | end 125 | end 126 | 127 | imshow(ImgOutLum); 128 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Vedant Raval 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tone-Mapping-Library 2 | 3 | Real-world scenes often have a very large dynamic range (the ratio of brightest to darkest intensities) which can span several orders of magnitude. Such high dynamic range (HDR) images cannot be reproduced directly on conventional displays. For a more naturalistic appearance, the range of intensities has to be compressed to the low dynamic range of the display, while approximately maintaining the appearance of the image. This process is known as tone mapping or dynamic range compression. A number of algorthms which help in Tone mapping have been considered and implemented here in MATLAB. The user is free to choose any of these depending on the requirements of speed, details etc 4 | 5 | ## Linear and Logarithmic rescaling 6 | 7 | Loaded an HDR image into the program and visualized it by linearly rescaling the pixel values. Different ranges for linearly rescaling can be done and not just **0-255** 8 | 9 | Note that the HDR image contains linear intensity values, while low dynamic range images are quantized nonlinearly, so applied a gamma correction to get a reasonable image. Created two kinds of Gamma functions: 10 | 11 | 1. Unscaled: Applied the function without scaling the input image to 0-1 12 | 2. Scaled: Applied the function after the scaling, and then applying linear rescaling to **0-255** or **max(0,minOrig) - min(255,maxOrig)** 13 | 14 | As a baseline tone mapping algorithm, performed rescaling in the log-luminance domain. That is, compute the luminance **L=0.299R+0.587G+0.114B** and take its log, rescale it to decrease the dynamic range, then undo the log to recover luminances, and use the original colour ratios R/L,G/L,B/L to reconstruct a colour image. Chose a scaling in the log domain to get an output dynamic range of about 100. (Found 0.1 - 10 to be showing the best results in general) 15 | 16 | ## Detail Enhancement 17 | 18 | You should find that details in the image become weaker, because logarithmic rescaling indiscriminately compresses both large-scale intensity variations and local contrast. To counteract this effect, the following techniques are implemented for tone-maping. You can find them in the code **tonemapping.m**: 19 | 20 | 1. Sharpening 21 | 2. Laplacian 22 | 3. Sobel filter 23 | 4. Highboosting 24 | 5. Contrast stretching 25 | 6. Histogram equalization 26 | 27 | ## More involved Tone mapping algorithms 28 | 29 | 1. Reinhard et al. (http://www.cs.utah.edu/~reinhard/cdrom/tonemap.pdf) 30 | 2. Durand et al. (https://people.csail.mit.edu/fredo/PUBLI/Siggraph2002/DurandBilateral.pdf) 31 | -------------------------------------------------------------------------------- /Reinhard.m: -------------------------------------------------------------------------------- 1 | % Getting the Input image 2 | Img = hdrread('memorial.hdr'); 3 | [r,c,h] = size(Img); 4 | 5 | % Luminance matrix 6 | Lum = zeros(r,c); 7 | for i=1:r 8 | for j=1:c 9 | Lum(i,j) = Img(i,j,1)*0.299 + Img(i,j,2)*0.587 + Img(i,j,3)*0.114; 10 | end 11 | end 12 | 13 | % Performing the required operations on the Luminance values 14 | delta = 0.00001; 15 | sum = 0; 16 | for i=1:r 17 | for j=1:c 18 | sum = sum + log(delta + Lum(i,j)); 19 | end 20 | end 21 | 22 | Lw = exp(sum/(r*c)); 23 | L = zeros(r,c); 24 | a = 0.045; 25 | 26 | for i=1:r 27 | for j=1:c 28 | L(i,j) = (a/Lw)*Lum(i,j); 29 | end 30 | end 31 | 32 | % Defining the constants as directed in the paper 33 | alpha1 = 1/(2*(sqrt(2))); 34 | alpha2 = 1.6*alpha1; 35 | epsilon = 0.05; 36 | phi = 15.0; 37 | 38 | R1 = zeros(r,c,9); 39 | R2 = zeros(r,c,9); 40 | 41 | for x=1:r 42 | for y=1:c 43 | for s=1:9 44 | sS = 1.6^(s-1); 45 | R1(x,y,s) = (1/(pi*(alpha1*sS)^2))*(exp(-(x^2 + y^2)/(alpha1 * sS)^2)); 46 | R2(x,y,s) = (1/(pi*(alpha2*sS)^2))*(exp(-(x^2 + y^2)/(alpha2 * sS)^2)); 47 | end 48 | end 49 | end 50 | 51 | % Performing the required Fourier Transforms 52 | for s=1:9 53 | V1(:,:,s) = ifft(fft(L).*fft(R1(:,:,s))); 54 | V2(:,:,s) = ifft(fft(L).*fft(R1(:,:,s))); 55 | end 56 | 57 | V = zeros(r,c,9); 58 | for x=1:r 59 | for y=1:c 60 | for s=1:9 61 | sS = 1.6^(s-1); 62 | V(x,y,s) = (V1(x,y,s)-V2(x,y,s))/(((2^phi)*((a)/(sS*sS)))+V1(x,y,s)); 63 | end 64 | end 65 | end 66 | 67 | Ld = zeros(r,c); 68 | 69 | for i=1:r 70 | for j=1:c 71 | 72 | sS = 1; 73 | for s=1:9 74 | 75 | if (abs(V(i,j,s))) 1 => Luminance is scaled as 0.1 -> 10 62 | for i=1:r 63 | for j = 1: c 64 | Lumlog(i,j) = ((Lumlog(i,j)-minVal)/(maxVal-minVal))*2-1; 65 | Lumlog(i,j) = 10^(Lumlog(i,j)); 66 | end 67 | end 68 | 69 | % Using the constancy of R/L, B/L, G/L to recover the colored image from 70 | % the scaled Luminance matrix 71 | for i = 1:r 72 | for j = 1:c 73 | for k =1:h 74 | ImgOutLum(i,j,1) = (((Img(i,j,1))/(Lum(i,j))))*(Lumlog(i,j)); 75 | ImgOutLum(i,j,2) = (((Img(i,j,2))/(Lum(i,j))))*(Lumlog(i,j)); 76 | ImgOutLum(i,j,3) = (((Img(i,j,3))/(Lum(i,j))))*(Lumlog(i,j)); 77 | end 78 | end 79 | end 80 | 81 | % Writing the corrected image 82 | imshow(ImgOutLum); 83 | 84 | %Convolution matrices for the Different filters 85 | A = 1.5; 86 | Sharpen = [0,-1,0;-1,5,-1;0,-1,0]; 87 | Laplace = [0,1,0; 1 , -4,1; 0,1,0]; 88 | Highboost = [-1,-1,-1;-1,A+8,-1;-1,-1,-1]; 89 | Sobel = [-1,-2,-1;0,0,0;1,2,1]; 90 | 91 | % Using the Unsharp Masking technique 92 | ImgSharpen = convol(ImgOutLum,r,c,Sharpen); 93 | %imshow(unscaledGamma(ImgSharpen,r-2,c-2,h)); 94 | 95 | % Using the Laplace Technique 96 | ImgLap = convol(ImgOutLum, r,c,Laplace); 97 | %imshow(unscaledGamma(ImgLap,r-2,c-2,h)); 98 | 99 | % Using the Highboost filtering 100 | ImgBoost = convol(ImgOutSimple,r,c,Highboost); 101 | %imshow(ImgBoost); 102 | 103 | % Using the Gradient filter 104 | ImgGrad = convol(ImgOutLum,r,c,Sobel); 105 | %imshow(unscaledGamma(ImgGrad,r-2,c-2,h)); 106 | 107 | % Using contrast stretching 108 | imshow(contrast(ImgOutLum,r,c,h,255/3,2*255/3,255/6,5*255/6)); 109 | %imshow(unscaledGamma(contrast(ImgOutSimple,r,c,h,255/3,2*255/3,255/6,5*255/6),r,c,h)); 110 | 111 | %Using Histogram equalization 112 | imshow(unscaledGamma(histo(ImgOutLum,r,c,h),r,c,h)); 113 | 114 | % Convoluting Image Bmat by the filter Cmat 115 | function A = convol(Bmat,r,c,Cmat) 116 | 117 | Res = zeros(r-2,c-2,3); 118 | 119 | for i=1:(r-2) 120 | for j = 1:(c-2) 121 | 122 | for k=1:3 123 | sum = 0; 124 | 125 | for u=0:2 126 | for v=0:2 127 | sum = sum + Bmat(i+u,j+v,k)*Cmat(3-u,3-v); 128 | end 129 | end 130 | 131 | Res(i,j,k) = sum; 132 | 133 | end 134 | end 135 | end 136 | 137 | A = Res; 138 | 139 | end 140 | 141 | % The scaled gamma function 142 | function A = gamma(ImgOutSimple,r,c,h) 143 | 144 | ImgOutGamma = zeros(r,c,h); 145 | 146 | for i=1:r 147 | for j = 1:c 148 | for k = 1:h 149 | if (ImgOutSimple(i,j,k)/255)<=0.0031308 150 | ImgOutGamma(i,j,k) = 12.92*(ImgOutSimple(i,j,k)/255); 151 | else 152 | ImgOutGamma(i,j,k) = (((ImgOutSimple(i,j,k)/255)^(1/2.4))*1.055 + (-0.055))*1; 153 | end 154 | 155 | ImgOutGamma(i,j,k) = ImgOutGamma(i,j,k)*255; 156 | 157 | end 158 | end 159 | end 160 | 161 | A = ImgOutGamma; 162 | 163 | end 164 | 165 | % The function performing Contrast stretching. The scale is divided by four points 166 | % They are: (0,0), (r1,s1), (r2,s2), and (255,255). Linear division takes place 167 | function A = contrast(Img,r,c,h,r1,r2,s1,s2) 168 | 169 | A = zeros(r,c,h); 170 | 171 | for i=1:r 172 | for j=1:c 173 | for k=1:h 174 | 175 | if Img(i,j,k)