├── Data ├── hazed1.jpg ├── hazed2.jpg ├── hazed3.jpg ├── hazed4.jpg └── hazed5.jpg ├── Code ├── luminanceWeightmap.m ├── fusedPyramid.m ├── pyrReconstruct.m ├── saliencyWeightmap.m ├── chromaticWeightmap.m ├── enhanceContrast.m ├── genPyr.m ├── pyr_reduce.m ├── whiteBalance.m ├── pyrBlend.m ├── pyr_expand.m └── main.m └── README.md /Data/hazed1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utpal0401/Wavelength-Compensation-and-Dehazing/HEAD/Data/hazed1.jpg -------------------------------------------------------------------------------- /Data/hazed2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utpal0401/Wavelength-Compensation-and-Dehazing/HEAD/Data/hazed2.jpg -------------------------------------------------------------------------------- /Data/hazed3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utpal0401/Wavelength-Compensation-and-Dehazing/HEAD/Data/hazed3.jpg -------------------------------------------------------------------------------- /Data/hazed4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utpal0401/Wavelength-Compensation-and-Dehazing/HEAD/Data/hazed4.jpg -------------------------------------------------------------------------------- /Data/hazed5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utpal0401/Wavelength-Compensation-and-Dehazing/HEAD/Data/hazed5.jpg -------------------------------------------------------------------------------- /Code/luminanceWeightmap.m: -------------------------------------------------------------------------------- 1 | function [ lumWeightmap ] = luminanceWeightmap( im ) 2 | L = mean(im,3); 3 | 4 | lumWeightmap = sqrt((1/3) * (im(:, :, 1) - L).^2 + (im(:, :, 2) - L).^2 + (im(:, :, 3) - L).^2); 5 | end 6 | -------------------------------------------------------------------------------- /Code/fusedPyramid.m: -------------------------------------------------------------------------------- 1 | function [ fusedPyramid ] = fusedPyramid( input_args ) 2 | 3 | for i = 1 : 5 4 | fusedPyramid{i} = (gaussianPyramid1{i} .* laplacianPyramid1{i}) + (gaussianPyramid2{i} .* laplacianPyramid2{i}); 5 | end 6 | 7 | end 8 | 9 | -------------------------------------------------------------------------------- /Code/pyrReconstruct.m: -------------------------------------------------------------------------------- 1 | function [ img ] = pyrReconstruct( pyr ) 2 | %PYRRECONSTRUCT Uses a Laplacian pyramid to reconstruct a image 3 | % IMG = PYRRECONSTRUCT(PYR) PYR should be a 1*level cell array containing 4 | % the pyramid, SIZE(PYR{i}) = SIZE(PYR{i-1})*2-1 5 | 6 | for p = length(pyr)-1:-1:1 7 | pyr{p} = pyr{p}+pyr_expand(pyr{p+1}); 8 | end 9 | img = pyr{1}; 10 | 11 | end 12 | 13 | -------------------------------------------------------------------------------- /Code/saliencyWeightmap.m: -------------------------------------------------------------------------------- 1 | function [ saliencyWeightmap ] = saliencyWeightmap( im ) 2 | 3 | im = im2double(im); 4 | 5 | if(size(im,3) > 1) 6 | imGray = rgb2gray(im); 7 | else 8 | imGray = im; 9 | end 10 | 11 | kernel_1D = (1/16) * [1, 4, 6, 4, 1]; 12 | kernel_2D = kron(kernel_1D, kernel_1D'); 13 | 14 | I_mean = mean(imGray(:)); 15 | 16 | I_Whc = conv2(imGray, kernel_2D, 'same'); 17 | 18 | saliencyWeightmap = abs(I_Whc - I_mean); 19 | 20 | end -------------------------------------------------------------------------------- /Code/chromaticWeightmap.m: -------------------------------------------------------------------------------- 1 | function [ chromaticWeightmap ] = chromaticWeightmap( im ) 2 | 3 | hsvImage = rgb2hsv(im); % Convert the image to HSV space 4 | saturationValue = hsvImage(:,:,2); % find saturation 5 | 6 | % Chromatic weight map = Distnc b/w saturation value and max sat range.. 7 | saturationMax = 1 ; 8 | sigma = .3 ; 9 | chromaticWeightmap = exp( -1 * (((saturationValue - saturationMax).^2) / (2*(sigma^2))) ); 10 | 11 | end 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Code/enhanceContrast.m: -------------------------------------------------------------------------------- 1 | function [ enhancedIm ] = enhanceContrast( im ) 2 | 3 | luminance= im(:,:,1)*0.299+im(:,:,2)*0.587+im(:,:,3)*0.114; 4 | avgLuminance =mean(luminance(:)); 5 | gamma = 2 * (0.5 + avgLuminance); 6 | % Second input= g * (original image components - avg of the image components) 7 | enhancedIm(:,:,1) = gamma * (im(:,:,1) - avgLuminance); 8 | enhancedIm(:,:,2) = gamma * (im(:,:,2) - avgLuminance); 9 | enhancedIm(:,:,3) = gamma * (im(:,:,3) - avgLuminance); 10 | end -------------------------------------------------------------------------------- /Code/genPyr.m: -------------------------------------------------------------------------------- 1 | function [ pyr ] = genPyr( img, type, level ) 2 | %GENPYR generate Gaussian or Laplacian pyramid 3 | % PYR = GENPYR(A,TYPE,LEVEL) A is the input image, 4 | % can be gray or rgb, will be forced to double. 5 | % TYPE can be 'gauss' or 'laplace'. 6 | 7 | pyr = cell(1,level); 8 | pyr{1} = im2double(img); 9 | for p = 2:level 10 | pyr{p} = pyr_reduce(pyr{p-1}); 11 | end 12 | if strcmp(type,'gauss'), return; end 13 | 14 | for p = level-1:-1:1 % adjust the image size 15 | osz = size(pyr{p+1})*2-1; 16 | pyr{p} = pyr{p}(1:osz(1),1:osz(2),:); 17 | end 18 | 19 | for p = 1:level-1 20 | pyr{p} = pyr{p}-pyr_expand(pyr{p+1}); 21 | end 22 | 23 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Underwater-Image-Enhancement-using-Wavelength-Compensation-and-Dehazing 2 | Acquiring clear images in underwater environments is an important issue in ocean engineering. The quality of underwater images plays a pivotal role in scientific missions such as monitoring sea life, taking census of populations, and assessing geological or biological environments. Capturing images underwater is challenging, mostly due to haze caused by light that is reflected from a surface and is deflected and scattered by water particles, and colour change due to varying degrees of light attenuation for different wavelengths. Light scattering and colour change result in contrast loss and colour deviation in images acquired underwater. 3 | -------------------------------------------------------------------------------- /Code/pyr_reduce.m: -------------------------------------------------------------------------------- 1 | function [ imgout ] = pyr_reduce( img ) 2 | %PYR_REDUCE Image pyramid reduction 3 | % B = PYR_REDUCE( A ) If A is M-by-N, then the size of B 4 | % is ceil(M/2)-by-ceil(N/2). Support gray or rgb image. 5 | % B will be transformed to double class. 6 | 7 | kernelWidth = 5; % default 8 | cw = .375; % kernel centre weight, same as MATLAB func impyramid. 0.6 in the Paper 9 | ker1d = [.25-cw/2 .25 cw .25 .25-cw/2]; 10 | kernel = kron(ker1d,ker1d'); 11 | 12 | img = im2double(img); 13 | sz = size(img); 14 | imgout = []; 15 | 16 | for p = 1:size(img,3) 17 | img1 = img(:,:,p); 18 | imgFiltered = imfilter(img1,kernel,'replicate','same'); 19 | imgout(:,:,p) = imgFiltered(1:2:sz(1),1:2:sz(2)); 20 | end 21 | 22 | end -------------------------------------------------------------------------------- /Code/whiteBalance.m: -------------------------------------------------------------------------------- 1 | function [ whiteBalanced ] = whiteBalance( im ) 2 | % Using Grayworld assumtion color balancing..... 3 | 4 | R_avg = mean(mean(im(:,:,1))); % Getting the average Of R ,G, B components 5 | G_avg = mean(mean(im(:,:,2))); 6 | B_avg = mean(mean(im(:,:,3))); 7 | RGB_avg = [R_avg G_avg B_avg]; 8 | 9 | gray_value = (R_avg + G_avg + B_avg)/3 % By Grey world, avg color of the whole image is gray 10 | scaleValue = gray_value./RGB_avg; % By Grey world, scale value=gray / avg of each color component 11 | 12 | whiteBalanced(:,:,1) = scaleValue(1) * im(:,:,1); % R,G,B components of the new white balanced new image 13 | whiteBalanced(:,:,2) = scaleValue(2) * im(:,:,2); 14 | whiteBalanced(:,:,3) = scaleValue(3) * im(:,:,3); 15 | 16 | end -------------------------------------------------------------------------------- /Code/pyrBlend.m: -------------------------------------------------------------------------------- 1 | close all 2 | clear 3 | imga = im2double(imread('apple1.jpg')); 4 | imgb = im2double(imread('orange1.jpg')); % size(imga) = size(imgb) 5 | imga = imresize(imga,[size(imgb,1) size(imgb,2)]); 6 | [M N ~] = size(imga); 7 | 8 | v = 230; 9 | level = 5; 10 | limga = genPyr(imga,'lap',level); % the Laplacian pyramid 11 | limgb = genPyr(imgb,'lap',level); 12 | 13 | maska = zeros(size(imga)); 14 | maska(:,1:v,:) = 1; 15 | maskb = 1-maska; 16 | blurh = fspecial('gauss',30,15); % feather the border 17 | maska = imfilter(maska,blurh,'replicate'); 18 | maskb = imfilter(maskb,blurh,'replicate'); 19 | 20 | limgo = cell(1,level); % the blended pyramid 21 | for p = 1:level 22 | [Mp Np ~] = size(limga{p}); 23 | maskap = imresize(maska,[Mp Np]); 24 | maskbp = imresize(maskb,[Mp Np]); 25 | limgo{p} = limga{p}.*maskap + limgb{p}.*maskbp; 26 | end 27 | imgo = pyrReconstruct(limgo); 28 | figure,imshow(imgo) % blend by pyramid 29 | imgo1 = maska.*imga+maskb.*imgb; 30 | figure,imshow(imgo1) % blend by feathering -------------------------------------------------------------------------------- /Code/pyr_expand.m: -------------------------------------------------------------------------------- 1 | function [ imgout ] = pyr_expand( img ) 2 | %PYR_EXPAND Image pyramid expansion 3 | % B = PYR_EXPAND( A ) If A is M-by-N, then the size of B 4 | % is (2*M-1)-by-(2*N-1). Support gray or rgb image. 5 | % B will be transformed to double class. 6 | kw = 5; % default kernel width 7 | cw = .375; % kernel centre weight, same as MATLAB func impyramid. 0.6 in the Paper 8 | ker1d = [.25-cw/2 .25 cw .25 .25-cw/2]; 9 | kernel = kron(ker1d,ker1d')*4; 10 | 11 | % expand [a] to [A00 A01;A10 A11] with 4 kernels 12 | ker00 = kernel(1:2:kw,1:2:kw); % 3*3 13 | ker01 = kernel(1:2:kw,2:2:kw); % 3*2 14 | ker10 = kernel(2:2:kw,1:2:kw); % 2*3 15 | ker11 = kernel(2:2:kw,2:2:kw); % 2*2 16 | 17 | img = im2double(img); 18 | sz = size(img(:,:,1)); 19 | osz = sz*2-1; 20 | imgout = zeros(osz(1),osz(2),size(img,3)); 21 | 22 | for p = 1:size(img,3) 23 | img1 = img(:,:,p); 24 | img1ph = padarray(img1,[0 1],'replicate','both'); % horizontally padded 25 | img1pv = padarray(img1,[1 0],'replicate','both'); % horizontally padded 26 | 27 | img00 = imfilter(img1,ker00,'replicate','same'); 28 | img01 = conv2(img1pv,ker01,'valid'); % imfilter doesn't support 'valid' 29 | img10 = conv2(img1ph,ker10,'valid'); 30 | img11 = conv2(img1,ker11,'valid'); 31 | 32 | imgout(1:2:osz(1),1:2:osz(2),p) = img00; 33 | imgout(2:2:osz(1),1:2:osz(2),p) = img10; 34 | imgout(1:2:osz(1),2:2:osz(2),p) = img01; 35 | imgout(2:2:osz(1),2:2:osz(2),p) = img11; 36 | end 37 | 38 | end -------------------------------------------------------------------------------- /Code/main.m: -------------------------------------------------------------------------------- 1 | clc 2 | close all 3 | clear all 4 | im = im2double(imread('C:\Users\utpal\Desktop\Image Processing\data\hazed5.jpg')); 5 | imshow(im); 6 | title('Original Hazy Image'); 7 | 8 | % Inputs that are derrived from the Hazy image 9 | firstInput = whiteBalance( im ); 10 | figure;subplot(1,2,1);imshow(firstInput);title('First Input'); 11 | secondInput = enhanceContrast( im ); 12 | subplot(1,2,2);imshow(secondInput);title('Second Input'); 13 | 14 | %Weight maps of the First Input 15 | luminanceWeightmap1 = luminanceWeightmap(firstInput); 16 | figure;subplot(1,3,1);imshow(luminanceWeightmap1);title('luminanceWeightmap of First input'); 17 | chromaticWeightmap1 = chromaticWeightmap(firstInput); 18 | subplot(1,3,2);imshow(chromaticWeightmap1);title('chromaticWeightmap of First input'); 19 | saliencyWeightmap1 = saliencyWeightmap(firstInput); 20 | subplot(1,3,3);imshow(saliencyWeightmap1);title('saliencyWeightmap of First input'); 21 | 22 | %Resultant Weight map of the first input 23 | resultedWeightmap1 = luminanceWeightmap1 .* chromaticWeightmap1 .* saliencyWeightmap1 ; 24 | 25 | %Weightmaps of the Second Input 26 | luminanceWeightmap2 = luminanceWeightmap(secondInput); 27 | figure;subplot(1,3,1);imshow(luminanceWeightmap2);title('luminanceWeightmap of Second input'); 28 | chromaticWeightmap2 = chromaticWeightmap(secondInput); 29 | subplot(1,3,2);imshow(chromaticWeightmap2);title('chromaticWeightmap of Second input'); 30 | saliencyWeightmap2 = saliencyWeightmap(secondInput); 31 | subplot(1,3,3);imshow(saliencyWeightmap2);title('saliencyWeightmap of Second input'); 32 | 33 | %Resultant Weight map of the second input 34 | resultedWeightmap2 = luminanceWeightmap2 .* chromaticWeightmap2 .* saliencyWeightmap2 ; 35 | 36 | %Normalized Weight maps of the Inputs 37 | normaizedWeightmap1 = resultedWeightmap1 ./ (resultedWeightmap1 + resultedWeightmap2); 38 | normaizedWeightmap2 = resultedWeightmap2 ./ (resultedWeightmap1 + resultedWeightmap2); 39 | 40 | 41 | %Generating Gaussian Pyramid for normalized weight maps 42 | gaussianPyramid1 = genPyr(normaizedWeightmap1,'gauss',5); 43 | gaussianPyramid2 = genPyr(normaizedWeightmap2,'gauss',5); 44 | 45 | for i = 1 : 5 46 | tempImg = []; 47 | for j = 1 : size(im,3) 48 | laplacianPyramid1 = genPyr(firstInput(:,:,j),'laplace',5); %Generating Laplacian Pyramid for derrived inputs 49 | laplacianPyramid2 = genPyr(secondInput(:,:,j),'laplace',5); 50 | rowSize = min([size(laplacianPyramid1{i},1),size(laplacianPyramid2{i},1),size(gaussianPyramid1{i},1),size(gaussianPyramid2{i},1)]); 51 | columnSize = min([size(laplacianPyramid1{i},2),size(laplacianPyramid2{i},2),size(gaussianPyramid1{i},2),size(gaussianPyramid2{i},2)]); 52 | tempImg(:,:,j) = laplacianPyramid1{i}(1:rowSize , 1:columnSize) .* gaussianPyramid1{i}(1:rowSize, 1:columnSize) + laplacianPyramid2{i}(1:rowSize, 1:columnSize) .* gaussianPyramid2{i}(1:rowSize, 1:columnSize); 53 | end 54 | fusedPyramid1{i} = tempImg; 55 | end 56 | 57 | enhancedImage = pyrReconstruct(fusedPyramid1); 58 | figure 59 | imshow(enhancedImage); 60 | title('Dehazed Image'); 61 | 62 | --------------------------------------------------------------------------------