├── README.md ├── allmodel_aut ├── allmodel_syn ├── allrange_aut ├── allrange_syn ├── dct_feats ├── co_benford.m ├── co_energy_subband_ratio.m ├── co_frequency_varication.m ├── co_orientation.m └── ext_feats_DCT.m ├── main.m ├── pred_model └── pred_score.m ├── spa_feats ├── ext_feats_Spa.m ├── param_asyggd.m └── param_ggd.m ├── svm-predict.exe ├── svm-scale.exe ├── test_aut(MOS=46.47).bmp └── test_syn(DMOS=61.18).bmp /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This repository contain the source code of the following technical report: 4 | 5 | @inproceedings{NBIQA2019, 6 | author = {Fu-Zhao {Ou} and 7 | Yuan-Gen {Wang} and 8 | Guopu {Zhu}}, 9 | title = {A Novel Blind Image Quality Assessment Method Based on Refined Natural Scene Statistics}, 10 | booktitle = {2019 IEEE International Conference on Image Processing (ICIP)}, 11 | pages = {1004-1008}, 12 | year = {2019}, 13 | } 14 | 15 | Abstract: Natural scene statistics (NSS) model has received considerable attention in the image quality assessment (IQA) community 16 | due to its high sensitivity to image distortion. However, most existing NSS-based IQA methods extract features either from spatial domain or from transform domain. There is little work to simultaneously consider the features from these two domains. In this paper, a novel blind IQA method (NBIQA) based on refined NSS is proposed. The proposed NBIQA first investigates the performance of a large number 17 | of candidate features from both the spatial and transform domains. Based on the investigation, we construct a refined NSS model by selecting competitive features from existing NSS models and adding three new features. Then the refined NSS is fed into SVM tool to learn a simple regression model. Finally, the trained regression model is used to predict the scalar quality score of the image. Experimental results tested on both LIVE IQA and LIVE-C databases show that the proposed NBIQA performs better in terms of synthetic and authentic image distortion than current mainstream IQA methods. 18 | 19 | # Usage 20 | 21 | Running on Matlab 22 | 23 | Input : A test image loaded in an array, Image distortion type parameter 24 | Image distortion type parameter: If the input image is a synthetically distorted image, input 1 as the second parameter 25 | Else, The input image is a theauthentically distorted image, ipnut 2 as the second parameter 26 | 27 | Output: A predition score. The score typically is a value on the range of [0, 100]. 28 | (if evaluate the synthetic image: 0 represents the best, if evaluate the authentic image: 0 represents the worst). 29 | 30 | Running the main.m 31 | 32 | 1. Load the image, for example 33 | 34 | img = imread('test.bmp'); 35 | 36 | 2. Call this function to calculate the quality score: 37 | 38 | If The input image is the synthetically distorted image, 39 | input 1 as the second parameter, for example 40 | score = pred_score(feats,1); 41 | Else, The input image is the authentically distorted image, 42 | ipnut 2 as the second parameter, for example 43 | score = pred_score(feats,2); 44 | 45 | # Dependencies 46 | 47 | Binaries: svm-predict.exe, svm-scale.exe (from LibSVM) - provided with release 48 | 49 | Image Files: test_aut(MOS=46.47).bmp, test_syn(DMOS=61.18).bmp ( Respectively from the LIVE IQA Database and the LIVE-C Database, neither of which is included in the training model) 50 | 51 | Data files: allmodel_aut, allmodel_syn, allrange_aut, allrange_syn (provided with release) 52 | 53 | MATLAB files: main.m, co_benford.m, co_energy_subband_ratio.m, co_frequency_varication.m, co_orientation1.m, co_orientation2.m, co_orientation3.m, ext_feats_DCT.m, param_asyggd.m, param_ggd.m, ext_feats_Spa.m, pred_score.m 54 | 55 | # License 56 | 57 | This source code is made available for research purpose only. 58 | 59 | -------------------------------------------------------------------------------- /allrange_aut: -------------------------------------------------------------------------------- 1 | x 2 | -1 1 3 | 1 0.407586 6.890808 4 | 2 0.273077 0.985105 5 | 3 0.983201 2.183141 6 | 4 0.05239 0.360154 7 | 5 0.226842 1.333223 8 | 6 0.547037 7.678764 9 | 7 0.37626 0.978742 10 | 8 0.982537 1.606112 11 | 9 0.055942 0.301784 12 | 10 0.209735 1.20424 13 | 11 0.42961 0.970399 14 | 12 0.958029 2.268741 15 | 13 0.051997 0.295738 16 | 14 0.198109 0.923711 17 | 15 0.287 10 18 | 16 0.005828 0.13598 19 | 17 0.2 1.481 20 | 18 -0.02458 0.056834 21 | 19 6.9e-005 0.019945 22 | 20 0.000188 0.016086 23 | 21 0.2 1.453 24 | 22 -0.056402 0.050742 25 | 23 5.8e-005 0.022469 26 | 24 0.00018 0.019275 27 | 25 0.2 1.286 28 | 26 -0.031098 0.043215 29 | 27 7.100000000000001e-005 0.021541 30 | 28 0.000132 0.016788 31 | 29 0.2 1.295 32 | 30 -0.03377 0.016279 33 | 31 7.2e-005 0.020468 34 | 32 0.000131 0.017134 35 | 33 4.7e-005 0.456874 36 | 34 0.324 10 37 | 35 0.007026 0.140801 38 | 36 0.217 1.542 39 | 37 -0.030465 0.046715 40 | 38 9.899999999999999e-005 0.019976 41 | 39 0.000314 0.017379 42 | 40 0.213 1.573 43 | 41 -0.043555 0.036256 44 | 42 9.1e-005 0.020758 45 | 43 0.000327 0.018368 46 | 44 0.208 1.326 47 | 45 -0.024796 0.038206 48 | 46 0.0001 0.022467 49 | 47 0.00025 0.018852 50 | 48 0.209 1.35 51 | 49 -0.035462 0.034106 52 | 50 9.000000000000001e-005 0.023258 53 | 51 0.000226 0.018447 54 | -------------------------------------------------------------------------------- /allrange_syn: -------------------------------------------------------------------------------- 1 | x 2 | -1 1 3 | 1 0.471019 10.652297 4 | 2 0.215993 1.119937 5 | 3 0.990746 4.630254 6 | 4 0.050801 0.518798 7 | 5 0.266538 1.674552 8 | 6 0.450095 10.464429 9 | 7 0.337222 0.991627 10 | 8 0.9868170000000001 2.147503 11 | 9 0.058654 0.437462 12 | 10 0.257474 0.9544010000000001 13 | 11 0.433622 0.992749 14 | 12 0.976286 1.43766 15 | 13 0.072395 0.276401 16 | 14 0.266128 0.776859 17 | 15 0.269 10 18 | 16 0.00434 0.230325 19 | 17 0.235 3.859 20 | 18 -0.06856 0.038159 21 | 19 3.6e-005 0.06435 22 | 20 5.2e-005 0.029703 23 | 21 0.235 3.876 24 | 22 -0.06875100000000001 0.031722 25 | 23 3.6e-005 0.064445 26 | 24 4.7e-005 0.029692 27 | 25 0.219 2.798 28 | 26 -0.029896 0.017151 29 | 27 2.6e-005 0.050844 30 | 28 5.1e-005 0.054629 31 | 29 0.218 2.8 32 | 30 -0.027961 0.014656 33 | 31 2.5e-005 0.050864 34 | 32 5e-005 0.054792 35 | 33 0.00029 0.456874 36 | 34 0.455 10 37 | 35 0.002485 0.19006 38 | 36 0.2 2.025 39 | 37 -0.041794 0.034188 40 | 38 2e-006 0.039745 41 | 39 7.4e-005 0.021817 42 | 40 0.2 2.027 43 | 41 -0.041704 0.027357 44 | 42 2e-006 0.039581 45 | 43 6.600000000000001e-005 0.021785 46 | 44 0.2 1.645 47 | 45 -0.028355 0.014344 48 | 46 2e-006 0.038012 49 | 47 5.7e-005 0.034053 50 | 48 0.2 1.645 51 | 49 -0.026009 0.016087 52 | 50 2e-006 0.037981 53 | 51 5.5e-005 0.03426 54 | -------------------------------------------------------------------------------- /dct_feats/co_benford.m: -------------------------------------------------------------------------------- 1 | function output = co_benford(img) 2 | %% benford's law 3 | 4 | benf_stb = [31,17.6,12.5,9.7,7.9,6.7,5.8,5.1,4.6]'; 5 | 6 | I = dct2(img); 7 | 8 | leading_digits = []; 9 | 10 | leading_digits = str2double(regexp(sprintf('%e ',I.'), '\d\.', 'match')); 11 | 12 | sat_digits = tabulate(leading_digits); 13 | if length(sat_digits) == 9 14 | dist = (sat_digits(:,3)-benf_stb).^2; 15 | else 16 | dist = (sat_digits(2:10,3)-benf_stb).^2; 17 | end 18 | 19 | output = sqrt(sum(dist)); 20 | 21 | -------------------------------------------------------------------------------- /dct_feats/co_energy_subband_ratio.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GZHU-Image-Lab/NBIQA/ffd916af97cb4b42393becf7b83dfbe99ede5656/dct_feats/co_energy_subband_ratio.m -------------------------------------------------------------------------------- /dct_feats/co_frequency_varication.m: -------------------------------------------------------------------------------- 1 | function fv = co_frequency_varication (I) 2 | %% Block_Computation Energy Subband Ratio 3 | 4 | dct_I = dct2(I); 5 | non_dc_dct_I = dct_I(2:end); 6 | std_ggd = std(abs(non_dc_dct_I)); 7 | mean_ggd = mean(abs(non_dc_dct_I)); 8 | frequency_varication_coefficient = std_ggd/(mean_ggd+0.0000001); 9 | fv = frequency_varication_coefficient; -------------------------------------------------------------------------------- /dct_feats/co_orientation.m: -------------------------------------------------------------------------------- 1 | function var_o = co_orientation(I) 2 | %% Frequency Variation in Three Orientations 3 | 4 | dct_I = dct2(I); 5 | %% n=1,Frequency Variation 6 | 7 | F1 = [0 1 1 1 1;0 0 1 1 1; 0 0 0 0 1; 0 0 0 0 0;0 0 0 0 0]; 8 | temp=dct_I(F1~=0); 9 | std_gauss=std(abs(temp(:))); 10 | mean_abs=mean(abs(temp(:))); 11 | o1 = std_gauss/(mean_abs+0.00000001); 12 | 13 | %% n=2,Frequency Variation 14 | 15 | F2 = [0 0 0 0 0; 0 1 0 0 0; 0 0 1 1 0; 0 0 1 1 1; 0 0 0 1 1]; 16 | temp=dct_I(F2~=0); 17 | std_gauss=std(abs(temp(:))); 18 | mean_abs=mean(abs(temp(:))); 19 | o2 = std_gauss/(mean_abs+0.00000001); 20 | 21 | %% n=3,Frequency Variation 22 | 23 | F3 = [0 1 1 1 1;0 0 1 1 1; 0 0 0 0 1; 0 0 0 0 0;0 0 0 0 0]'; 24 | temp=dct_I(F3~=0); 25 | std_gauss=std(abs(temp(:))); 26 | mean_abs=mean(abs(temp(:))); 27 | o3 = std_gauss/(mean_abs+0.00000001); 28 | 29 | var_o = var([o1,o2,o3]); 30 | 31 | -------------------------------------------------------------------------------- /dct_feats/ext_feats_DCT.m: -------------------------------------------------------------------------------- 1 | function features = ext_feats_DCT(I) 2 | %% Extract Features in DCT Domain 3 | 4 | h = fspecial('gaussian',3); 5 | Img = double(I(:,:,1)); 6 | 7 | disp('Time of extracting features in the transform domain') 8 | tic 9 | %% 1st scale 10 | %% Benford's Law 11 | 12 | ben = co_benford(Img); 13 | 14 | %% Energy Subband Ratio 15 | 16 | all_en_rto = blkproc(Img,[3,3],[1,1],@co_energy_subband_ratio); 17 | en_rto_temp = sort(all_en_rto(:),'descend'); 18 | en_rto_mean100 = mean(en_rto_temp); 19 | en_rto_mean10 = mean(en_rto_temp(1:ceil(length(en_rto_temp)/10))); 20 | 21 | %% Frequency Variation in Three Orientations 22 | 23 | var_orientation = blkproc(Img,[3 3],[1,1],@co_orientation); 24 | all_ori_temp = sort(var_orientation(:),'descend'); 25 | all_ori_mean100 = mean(all_ori_temp); 26 | all_ori_mean10 = mean(all_ori_temp(1:ceil(length(all_ori_temp)/10))); 27 | 28 | features1 = [ben,en_rto_mean100,en_rto_mean10,all_ori_mean100,all_ori_mean10]; 29 | 30 | %% 2nd scale 31 | 32 | Img1_filtered=double(imfilter(Img,h)); 33 | Img2 = Img1_filtered(2:2:end,2:2:end); 34 | 35 | %% Benford's Law 36 | 37 | ben = co_benford(Img2); 38 | 39 | %% Energy Subband Ratio 40 | 41 | all_en_rto = blkproc(Img2,[3,3],[1,1],@co_energy_subband_ratio); 42 | en_rto_temp = sort(all_en_rto(:),'descend'); 43 | en_rto_mean100 = mean(en_rto_temp); 44 | en_rto_mean10 = mean(en_rto_temp(1:ceil(length(en_rto_temp)/10))); 45 | 46 | %% Frequency Variation in Three Orientations 47 | 48 | var_orientation = blkproc(Img2,[3 3],[1,1],@co_orientation); 49 | all_ori_temp = sort(var_orientation(:),'descend'); 50 | all_ori_mean100 = mean(all_ori_temp); 51 | all_ori_mean10 = mean(all_ori_temp(1:ceil(length(all_ori_temp)/10))); 52 | 53 | features2 = [ben,en_rto_mean100,en_rto_mean10,all_ori_mean100,all_ori_mean10]; 54 | 55 | clear en_rto_temp all_ori_temp 56 | 57 | %% 3th scale 58 | 59 | Img2_filtered=double(imfilter(Img2,h)); 60 | Img3 = Img2_filtered(2:2:end,2:2:end); 61 | 62 | %% Energy Subband Ratio 63 | 64 | all_en_rto = blkproc(Img3,[3,3],[1,1],@co_energy_subband_ratio); 65 | en_rto_temp = sort(all_en_rto(:),'descend'); 66 | en_rto_mean100 = mean(en_rto_temp); 67 | en_rto_mean10 = mean(en_rto_temp(1:ceil(length(en_rto_temp)/10))); 68 | 69 | %% Frequency Variation in Three Orientations 70 | 71 | var_orientation = blkproc(Img3,[3 3],[1,1],@co_orientation); 72 | all_ori_temp = sort(var_orientation(:),'descend'); 73 | all_ori_mean100 = mean(all_ori_temp); 74 | all_ori_mean10 = mean(all_ori_temp(1:ceil(length(all_ori_temp)/10))); 75 | 76 | features3 = [en_rto_mean100,en_rto_mean10,all_ori_mean100,all_ori_mean10]; 77 | 78 | clear en_rto_temp all_ori_temp 79 | toc; 80 | features = [features1,features2,features3]; 81 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | clc; 2 | clear; 3 | 4 | addpath('spa_feats\'); 5 | addpath('dct_feats\'); 6 | addpath('pred_model'); 7 | %% Extract The Features of Image 8 | 9 | img = imread('test_aut(MOS=46.47).bmp'); 10 | %img = imread('test_syn(DMOS=61.18).bmp'); 11 | 12 | 13 | feats = [ext_feats_DCT(img) ext_feats_Spa(img)]; 14 | 15 | %% Predict The Score 16 | % If The input image is a synthetically distorted image, 17 | % input 1 as the second parameter 18 | % For example: score = pred_score(feats,1); 19 | 20 | % Else, The input image is a theauthentically distorted image, 21 | % ipnut 2 as the second parameter 22 | % For example: score = pred_score(feats,2); 23 | 24 | score = pred_score(feats,2); 25 | % score = pred_score(feats,1); 26 | -------------------------------------------------------------------------------- /pred_model/pred_score.m: -------------------------------------------------------------------------------- 1 | function score = pred_score(feat,dist_kind) 2 | %% predict the quality score of image 3 | 4 | features = [feat]; 5 | 6 | fid = fopen('predict_features','w'); 7 | fprintf(fid,'1 '); 8 | 9 | for k = 1:51 10 | fprintf(fid,'%d:%f ',k,features(1,k)); 11 | end 12 | 13 | warning off; 14 | delete 'predict_features_scale' 'output' 'dump' 15 | 16 | if dist_kind == 1 % Synthetically Distorted Image 17 | system('svm-scale -r allrange_syn predict_features > predict_features_scale'); 18 | system('svm-predict predict_features_scale allmodel_syn output > dump'); 19 | load('output'); 20 | end 21 | 22 | if dist_kind == 2 % Theauthentically Distorted Image 23 | system('svm-scale -r allrange_aut predict_features > predict_features_scale'); 24 | system('svm-predict predict_features_scale allmodel_aut output > dump'); 25 | load('output'); 26 | end 27 | 28 | fclose(fid); 29 | score = output; 30 | -------------------------------------------------------------------------------- /spa_feats/ext_feats_Spa.m: -------------------------------------------------------------------------------- 1 | function spatial_features = ext_feats_Spa(img) 2 | %% Extract Features in Spatial Domain 3 | disp('Time of extracting features in the spatial domain'); 4 | tic 5 | 6 | if(size(img,3)==3) 7 | img = uint8(img); 8 | e_temp = entropy(img); %Compute image entropy in three-channel 9 | img = double(rgb2gray(img)); 10 | end 11 | 12 | % window = fspecial('gaussian',3,7/6); %7/6 13 | window = fspecial('gaussian',3); 14 | window = window/sum(sum(window)); 15 | 16 | spatial_features = []; 17 | 18 | for scale = 1:2 19 | %% Generalized Gaussian Model Parameters 20 | 21 | mu = filter2(window, img, 'same'); 22 | sigma = sqrt(abs(filter2(window, img.*img, 'same') - mu.*mu)); 23 | LNL = (img-mu)./(sigma+1); 24 | [sharp_param ggd_std] = param_ggd(LNL(:)); 25 | spatial_features = [spatial_features sharp_param ggd_std^2]; 26 | 27 | %% Coefficients of Asymmetrical GGD Model 28 | 29 | shifts = [ 0 1;1 0 ; 1 1; -1 1]; 30 | for itr_shift =1:4 31 | shifted_structdis = circshift(LNL,shifts(itr_shift,:)); 32 | pair_LNL = LNL(:).*shifted_structdis(:); 33 | [sharp_param l_std r_std] = param_asyggd(pair_LNL); 34 | const = (sqrt(gamma(1/sharp_param))/sqrt(gamma(3/sharp_param))); 35 | meanparam = (r_std-l_std) * (gamma(2/sharp_param) / gamma(1/sharp_param)) * const; 36 | spatial_features =[spatial_features sharp_param meanparam l_std^2 r_std^2]; 37 | end 38 | 39 | %% Gaussian Probability-density of Entropy 40 | if scale == 1 41 | e_p = (1/(sqrt(2*pi)*0.8732)) * exp(-(e_temp-7.4600)^2/2*0.8732^2); 42 | spatial_features = [spatial_features e_p]; 43 | end 44 | %% 2nd scale 45 | img = imresize(img,0.5); 46 | end 47 | toc; 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /spa_feats/param_asyggd.m: -------------------------------------------------------------------------------- 1 | function [sharp_param l_std r_std] = estimateaggdparam(data) 2 | %% Generalized Gaussian Distribution 3 | 4 | gam = 0.2:0.001:10; 5 | r_gam = ((gamma(2./gam)).^2)./(gamma(1./gam).*gamma(3./gam)); 6 | l_std = sqrt(mean((data(data<0)).^2)); 7 | r_std = sqrt(mean((data(data>0)).^2)); 8 | gammahat = l_std/r_std; 9 | rhat = (mean(abs(data)))^2/mean((data).^2); 10 | rhatnorm = (rhat*(gammahat^3 +1)*(gammahat+1))/((gammahat^2 +1)^2); 11 | [min_difference, array_position] = min((r_gam - rhatnorm).^2); 12 | sharp_param = gam(array_position); 13 | 14 | 15 | -------------------------------------------------------------------------------- /spa_feats/param_ggd.m: -------------------------------------------------------------------------------- 1 | function [sharp_param ggd_std] = param_ggd(data) 2 | %% Asymmetric Generalized Gaussian Distribution 3 | 4 | gam = 0.2:0.001:10; 5 | r_gam = (gamma(1./gam).*gamma(3./gam))./((gamma(2./gam)).^2); 6 | ggd_std = sqrt(mean((data).^2)); 7 | E = mean(abs(data)); 8 | rho = ggd_std^2/E^2; 9 | [min_difference, array_position] = min(abs(rho - r_gam)); 10 | sharp_param = gam(array_position); 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /svm-predict.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GZHU-Image-Lab/NBIQA/ffd916af97cb4b42393becf7b83dfbe99ede5656/svm-predict.exe -------------------------------------------------------------------------------- /svm-scale.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GZHU-Image-Lab/NBIQA/ffd916af97cb4b42393becf7b83dfbe99ede5656/svm-scale.exe -------------------------------------------------------------------------------- /test_aut(MOS=46.47).bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GZHU-Image-Lab/NBIQA/ffd916af97cb4b42393becf7b83dfbe99ede5656/test_aut(MOS=46.47).bmp -------------------------------------------------------------------------------- /test_syn(DMOS=61.18).bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GZHU-Image-Lab/NBIQA/ffd916af97cb4b42393becf7b83dfbe99ede5656/test_syn(DMOS=61.18).bmp --------------------------------------------------------------------------------