├── 1.bmp ├── CCF.m ├── CCFcontrast.m ├── CE.m ├── FADE.m ├── README.md ├── border_in.m ├── border_out.m ├── example.m ├── model.mat ├── natural_fogfree_image_features_ps8.mat ├── natural_foggy_image_features_ps8.mat └── templateModel.mat /1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenglab/CCF/89cb93187d68dcb82ed65b8f8ad50b8184bfb9e0/1.bmp -------------------------------------------------------------------------------- /CCF.m: -------------------------------------------------------------------------------- 1 | function [quality] = CCF(im) 2 | 3 | %-------------CCF_colorfulness ----------------- 4 | imColor = double(im); 5 | 6 | R = imColor(:,:,1); 7 | G = imColor(:,:,2); 8 | B = imColor(:,:,3); 9 | 10 | RR = log(R+0.00001) - mean2(log(R+0.00001)); 11 | GG = log(G+0.00001) - mean2(log(G+0.00001)); 12 | BB = log(B+0.00001) - mean2(log(B+0.00001)); 13 | 14 | alpha = RR-GG; 15 | beta = 0.5*(RR+GG)-BB; 16 | 17 | mu_alpha=mean(mean(alpha)); 18 | mu_beta=mean(mean(beta)); 19 | var_alpha=var(var(alpha)); 20 | var_beta=var(var(beta)); 21 | 22 | CCF_colorfulness=1000*((sqrt(var_alpha+var_beta)+0.3*sqrt(mu_alpha*mu_alpha+mu_beta*mu_beta))/85.59); 23 | 24 | %-------------CCF_contrast---------------------- 25 | 26 | im1=rgb2gray(im); 27 | CCF_contrast = CCFcontrast(im1); 28 | 29 | %-------------CCF_FADE-------------------------- 30 | 31 | CCF_FADE = FADE(im); 32 | 33 | %------------ normalization ------------------ 34 | 35 | CCF_colorfulness=mapminmax(CCF_colorfulness,1,10); 36 | CCF_contrast=mapminmax(CCF_contrast,1,10); 37 | CCF_FADE=10-mapminmax(CCF_FADE,1,10); 38 | 39 | % ------------calculate image quality with coefficients--------------------- 40 | 41 | c=[0.17593 0.61759 0.33988 ]; 42 | quality = c(1)*(CCF_colorfulness) + c(2)*(CCF_contrast) + c(3)*(CCF_FADE) 43 | 44 | end 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /CCFcontrast.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenglab/CCF/89cb93187d68dcb82ed65b8f8ad50b8184bfb9e0/CCFcontrast.m -------------------------------------------------------------------------------- /CE.m: -------------------------------------------------------------------------------- 1 | function [CE_gray CE_by CE_rg] = CE(I) 2 | 3 | % Input 4 | % I: input image 5 | % Output 6 | % Perceived Contrast Energy for gray, blue-yellow, red-green color channels 7 | 8 | % parameters 9 | % In this code, I followed Groen's experiment [28]: fixed sigma, weight, t1, t2,and t3 10 | % sigma: 0.16 degree =~ 3.25pixel, filter windows =~ 20 x 20 = (-3.25*3:1:3.25*3) 11 | % semisaturation: 0.1 12 | % t1, t2, t3 follows the EmpiricalNoiseThreshold used in [28] 13 | 14 | 15 | % Basic parameters 16 | sigma = 3.25; 17 | semisaturation = 0.1; 18 | t1 = 9.225496406318721e-004 *255; %0.2353; % 19 | t2 = 8.969246659629488e-004 *255; %0.2287; % 20 | t3 = 2.069284034165411e-004 *255; %0.0528; % 21 | border_s = 20; 22 | 23 | % Gaussian & LoG & Retification, Normalization(?) 24 | break_off_sigma = 3; 25 | filtersize = break_off_sigma*sigma; 26 | x = -filtersize:1:filtersize; 27 | Gauss = 1/(sqrt(2 * pi) * sigma)* exp((x.^2)/(-2 * sigma * sigma) ); 28 | Gauss = Gauss./(sum(Gauss)); 29 | Gx = (x.^2/sigma^4-1/sigma^2).*Gauss; %LoG 30 | Gx = Gx-sum(Gx)/size(x,2); 31 | Gx = Gx/sum(0.5*x.*x.*Gx); 32 | 33 | % Color conversion 34 | I = double(I); 35 | R = I(:,:,1); 36 | G = I(:,:,2); 37 | B = I(:,:,3); 38 | gray = 0.299*R + 0.587*G + 0.114*B; 39 | by = 0.5*R + 0.5*G - B ; 40 | rg = R - G; 41 | [row col dim] = size(I); 42 | CE_gray = double(zeros(row, col)); 43 | CE_by = double(zeros(row, col)); 44 | CE_rg = double(zeros(row, col)); 45 | 46 | % CE_Gray 47 | gray_temp1 = border_in(gray,border_s); 48 | Cx_gray = conv2(gray_temp1, Gx, 'same'); 49 | Cy_gray = conv2(gray_temp1, Gx','same'); 50 | C_gray_temp2 = sqrt(Cx_gray.^2+Cy_gray.^2); 51 | C_gray = border_out(C_gray_temp2,border_s); 52 | R_gray = (C_gray.*max(C_gray(:)))./(C_gray+(max(C_gray(:))*semisaturation)); 53 | R_gray_temp1 = R_gray - t1; 54 | index1 = find(R_gray_temp1 > 0.0000001); 55 | CE_gray(index1) = R_gray_temp1(index1); 56 | 57 | % CE_by 58 | by_temp1 = border_in(by,border_s); 59 | Cx_by = conv2(by_temp1, Gx, 'same'); 60 | Cy_by = conv2(by_temp1, Gx','same'); 61 | C_by_temp2 = sqrt(Cx_by.^2+Cy_by.^2); 62 | C_by = border_out(C_by_temp2,border_s); 63 | R_by = (C_by.*max(C_by(:)))./(C_by+(max(C_by(:))*semisaturation)); 64 | R_by_temp1 = R_by - t2; 65 | index2 = find(R_by_temp1 > 0.0000001); 66 | CE_by(index2) = R_by_temp1(index2); 67 | 68 | % CE_rg 69 | rg_temp1 = border_in(rg,border_s); 70 | Cx_rg = conv2(rg_temp1, Gx, 'same'); 71 | Cy_rg = conv2(rg_temp1, Gx','same'); 72 | C_rg_temp2 = sqrt(Cx_rg.^2+Cy_rg.^2); 73 | C_rg = border_out(C_rg_temp2,border_s); 74 | R_rg = (C_rg.*max(C_rg(:)))./(C_rg+(max(C_rg(:))*semisaturation)); 75 | R_rg_temp1 = R_rg - t3; 76 | index3 = find(R_rg_temp1 > 0.0000001); 77 | CE_rg(index3) = R_rg_temp1(index3); -------------------------------------------------------------------------------- /FADE.m: -------------------------------------------------------------------------------- 1 | function [D D_map] = FADE(I) 2 | % Input: a test image, I 3 | % Output: perceptual fog density D and fog density map D_map 4 | % Detail explanation: 5 | % L. K. Choi, J. You, and A. C. Bovik, "Referenceless Prediction of Perceptual Fog Density and Perceptual Image Defogging", 6 | % IEEE Transactions on Image Processing, to appear (2015). 7 | 8 | %% Basic setup 9 | ps = 8; % patch size 8 x 8 pixels 10 | % Size of a test image for checking possilbe distinct patches 11 | [row col dim] = size(I); 12 | patch_row_num = floor(row/ps); 13 | patch_col_num = floor(col/ps); 14 | I = I(1:patch_row_num*ps,1:patch_col_num*ps,1:3); 15 | [row col dim] = size(I); 16 | patch_row_num = floor(row/ps); 17 | patch_col_num = floor(col/ps); 18 | I = I(1:patch_row_num*ps,1:patch_col_num*ps,1:3); 19 | % RGB and gray channel 20 | R = double(I(:,:,1)); % Red 21 | G = double(I(:,:,2)); % Green 22 | B = double(I(:,:,3)); % Blue 23 | Ig = double(rgb2gray(I)); % Gray 24 | % Dark channel prior image: Id, pixel-wise, scaled to [0 1] 25 | Irn = R./255; 26 | Ign = G./255; 27 | Ibn = B./255; 28 | Id = min(min(Irn,Ign),Ibn); 29 | % HSV color space: saturation image: Is 30 | I_hsv = rgb2hsv(I); 31 | Is = I_hsv(:,:,2); 32 | % MSCN 33 | MSCN_window = fspecial('gaussian',7,7/6); 34 | MSCN_window = MSCN_window/sum(sum(MSCN_window)); 35 | warning('off'); 36 | mu = imfilter(Ig,MSCN_window,'replicate'); 37 | mu_sq = mu.*mu; 38 | sigma = sqrt(abs(imfilter(Ig.*Ig,MSCN_window,'replicate') - mu_sq)); 39 | MSCN = (Ig-mu)./(sigma+1); 40 | cv = sigma./mu; 41 | % rg and by channel 42 | rg = R-G; 43 | by = 0.5*(R+G)-B; 44 | 45 | %% Fog aware statistical feature extraction 46 | % f1 47 | MSCN_var = reshape(nanvar(im2col(MSCN, [ps ps], 'distinct')),[row col]/ps); 48 | % f2,f3 49 | MSCN_V_pair_col = im2col((MSCN.*circshift(MSCN,[1 0])),[ps ps], 'distinct'); %vertical 50 | MSCN_V_pair_col_temp1 = MSCN_V_pair_col; MSCN_V_pair_col_temp1(MSCN_V_pair_col_temp1>0)=NaN; 51 | MSCN_V_pair_col_temp2 = MSCN_V_pair_col; MSCN_V_pair_col_temp2(MSCN_V_pair_col_temp2<0)=NaN; 52 | MSCN_V_pair_L_var = reshape(nanvar(MSCN_V_pair_col_temp1),[row col]/ps); 53 | MSCN_V_pair_R_var = reshape(nanvar(MSCN_V_pair_col_temp2),[row col]/ps); 54 | % f4 55 | Mean_sigma = reshape(mean(im2col(sigma, [ps ps], 'distinct')),[row col]/ps); 56 | % f5 57 | Mean_cv = reshape(mean(im2col(cv, [ps ps], 'distinct')),[row col]/ps); 58 | % f6, f7, f8 59 | [CE_gray CE_by CE_rg] = CE(I); 60 | Mean_CE_gray = reshape(mean(im2col(CE_gray, [ps ps], 'distinct')),[row col]/ps); 61 | Mean_CE_by = reshape(mean(im2col(CE_by, [ps ps], 'distinct')),[row col]/ps); 62 | Mean_CE_rg = reshape(mean(im2col(CE_rg, [ps ps], 'distinct')),[row col]/ps); 63 | % f9 64 | IE_temp = num2cell(im2col(uint8(Ig), [ps ps], 'distinct'),1); 65 | IE = reshape(cellfun(@entropy,IE_temp),[row col]/ps); 66 | % f10 67 | Mean_Id = reshape(mean(im2col(Id, [ps ps], 'distinct')),[row col]/ps); 68 | % f11 69 | Mean_Is = reshape(mean(im2col(Is, [ps ps], 'distinct')),[row col]/ps); 70 | % f12 71 | CF = reshape(sqrt(std(im2col(rg, [ps ps], 'distinct')).^2 + std(im2col(by, [ps ps], 'distinct')).^2) + 0.3* sqrt(mean(im2col(rg, [ps ps], 'distinct')).^2 + mean(im2col(by, [ps ps], 'distinct')).^2),[row col]/ps); 72 | feat = [MSCN_var(:) MSCN_V_pair_R_var(:) MSCN_V_pair_L_var(:) Mean_sigma(:) Mean_cv(:) Mean_CE_gray(:) Mean_CE_by(:) Mean_CE_rg(:) IE(:) Mean_Id(:) Mean_Is(:) CF(:)]; 73 | feat = log(1 + feat); 74 | 75 | %% MVG model distance 76 | %Df (foggy level distance) for each patch 77 | % load natural fogfree image features (mu, cov) 78 | load('natural_fogfree_image_features_ps8.mat'); 79 | % test param for each patch 80 | mu_fog_param_patch = feat; 81 | cov_fog_param_patch = nanvar(feat')'; 82 | % Distance calculation - includes intermediate steps 83 | feature_size = size(feat,2); 84 | mu_matrix = repmat(mu_fogfreeparam, [size(feat,1),1]) - mu_fog_param_patch; 85 | cov_temp1 = []; 86 | cov_temp1(cumsum(feature_size.*ones(1,length(cov_fog_param_patch))))=1; 87 | cov_temp2 = cov_fog_param_patch(cumsum(cov_temp1)-cov_temp1+1,:); 88 | cov_temp3 = repmat(cov_temp2, [1,feature_size]); 89 | cov_temp4 = repmat(cov_fogfreeparam,[length(cov_fog_param_patch),1]); 90 | cov_matrix = (cov_temp3 + cov_temp4)/2; 91 | % cell computation 92 | mu_cell = num2cell(mu_matrix,2); 93 | cov_cell = mat2cell(cov_matrix, feature_size*ones(1, size(mu_matrix,1)),feature_size); 94 | mu_transpose_cell = num2cell(mu_matrix',1); 95 | % foggy level computation 96 | distance_patch = sqrt(cell2mat(cellfun(@mtimes,cellfun(@mrdivide,mu_cell,cov_cell, 'UniformOutput',0),mu_transpose_cell', 'UniformOutput',0))); 97 | Df = nanmean(distance_patch); % Mean_distance_patch 98 | Df_map = reshape(distance_patch,[row,col]/ps); 99 | clear mu_matrix cov_matrix mu_cell cov_cell mu_transpose_cell distance_patch 100 | 101 | %Dff 102 | % load natural foggy image features (mu, cov) 103 | load('natural_foggy_image_features_ps8.mat'); 104 | % calculation of distance - includes intermediate steps 105 | mu_matrix = repmat(mu_foggyparam, [size(feat,1),1]) - mu_fog_param_patch; 106 | cov_temp5 = repmat(cov_foggyparam,[length(cov_fog_param_patch),1]); 107 | cov_matrix = (cov_temp3 + cov_temp5)/2; 108 | % cell computation 109 | mu_cell = num2cell(mu_matrix,2); 110 | cov_cell = mat2cell(cov_matrix, feature_size*ones(1, size(mu_matrix,1)),feature_size); 111 | mu_transpose_cell = num2cell(mu_matrix',1); 112 | % fog-free level computation 113 | distance_patch = sqrt(cell2mat(cellfun(@mtimes,cellfun(@mrdivide,mu_cell,cov_cell, 'UniformOutput',0),mu_transpose_cell', 'UniformOutput',0))); 114 | Dff = nanmean(distance_patch); % Mean_distance_patch 115 | Dff_map = reshape(distance_patch,[row,col]/ps); 116 | clear mu_matrix cov_matrix mu_cell cov_cell mu_transpose_cell 117 | %% Perceptual fog density and density map 118 | D = Df/(Dff+1); 119 | D_map = Df_map./(Dff_map+1); 120 | end 121 | 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CCF 2 | An imaging-inspired no-reference underwater color image quality assessment metric. 3 | 4 | # Usage: 5 | 6 | 1. Load the image, for example: 7 | `im = imread('1.bmp');` 8 | 9 | 2. Call this function to calculate the quality score: 10 | `quality = CCF_main(im)` 11 | 12 | 13 | # Cite 14 | ~~~~ 15 | @article{wang2018imaging, 16 | title={An imaging-inspired no-reference underwater color image quality assessment metric}, 17 | author={Wang, Yan and Li, Na and Li, Zongying and Gu, Zhaorui and Zheng, Haiyong and Zheng, Bing and Sun, Mengnan}, 18 | journal={Computers \& Electrical Engineering}, 19 | volume={70}, 20 | pages={904--913}, 21 | year={2018}, 22 | publisher={Elsevier} 23 | } 24 | ~~~~ 25 | -------------------------------------------------------------------------------- /border_in.m: -------------------------------------------------------------------------------- 1 | function [nI]=border_in(I,ps) 2 | 3 | % Input - input image I, patch size ps 4 | % Output - border added image 5 | 6 | if mod(ps,2)==0 7 | uc = ps/2; % upperside copy 8 | dc = ps/2-1; % downside copy 9 | elseif mod(ps,2)==1 10 | uc = floor(ps/2); 11 | dc = uc; 12 | end 13 | 14 | ucb = I(1:uc,:); 15 | dcb = I(end-dc:end,:); 16 | Igtemp1 = [ucb;I;dcb]; 17 | 18 | lcb = Igtemp1(:,1:uc); 19 | rcb = Igtemp1(:,end-dc:end); 20 | nI = [lcb Igtemp1 rcb]; 21 | 22 | end 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /border_out.m: -------------------------------------------------------------------------------- 1 | function [nI]=border_out(I,ps) 2 | 3 | % Input - input image I, patch size ps 4 | % Output - border trimmed image 5 | 6 | if mod(ps,2)==0 7 | uc = ps/2; % upperside copy 8 | dc = ps/2-1; % downside copy 9 | 10 | elseif mod(ps,2)==1 11 | uc = floor(ps/2); 12 | dc = uc; 13 | end 14 | 15 | I(:,1:uc) = []; 16 | I(:,end-dc:end) = []; 17 | I(1:uc,:) = []; 18 | I(end-dc:end,:) = []; 19 | 20 | nI=I; 21 | end 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /example.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc 3 | 4 | im = imread('1.bmp'); 5 | 6 | quality = CCF(im) -------------------------------------------------------------------------------- /model.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenglab/CCF/89cb93187d68dcb82ed65b8f8ad50b8184bfb9e0/model.mat -------------------------------------------------------------------------------- /natural_fogfree_image_features_ps8.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenglab/CCF/89cb93187d68dcb82ed65b8f8ad50b8184bfb9e0/natural_fogfree_image_features_ps8.mat -------------------------------------------------------------------------------- /natural_foggy_image_features_ps8.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenglab/CCF/89cb93187d68dcb82ed65b8f8ad50b8184bfb9e0/natural_foggy_image_features_ps8.mat -------------------------------------------------------------------------------- /templateModel.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhenglab/CCF/89cb93187d68dcb82ed65b8f8ad50b8184bfb9e0/templateModel.mat --------------------------------------------------------------------------------