├── +bliinds2 ├── bliinds2_feature_extraction.m ├── bliinds2_score.m ├── bliinds_prediction.m ├── dct_freq_bands.m ├── fitting.m ├── gama_dct.m ├── gama_gen_gauss.m ├── oriented1_dct_rho_config3.m ├── oriented2_dct_rho_config3.m ├── oriented3_dct_rho_config3.m ├── parameters_from_training.mat ├── rho_dct.m └── rho_gen_gauss.m ├── +brisque ├── allmodel ├── allrange ├── brisque_feature.m ├── brisquescore.m ├── estimateaggdparam.m ├── estimateggdparam.m └── readme.txt ├── +divine ├── data_live_trained.mat ├── divine.m ├── divine_feature_extract.m ├── divine_overall_quality.m ├── find_spatial_hist_fast.m ├── map_matrix_to_closest_vec.m ├── norm_sender_normalized.m ├── readme.txt └── ssim_index_new.m ├── .gitignore ├── LICENSE ├── README.md ├── degraded.png ├── dmos_fit_fns.mat ├── foveateCutoffFreq.m ├── foveateFilterBank.m ├── foveateSensitivity.m ├── foveateSeperableOperator.m ├── foveateWaveletMask.m ├── foveateWaveletSensitivity.m ├── foveateWaveletSensitivityTest.m ├── foveation_test.m ├── fssim.m ├── fssim_test.m ├── image_mse_foveated.m ├── msssim.m ├── reference.png ├── ssim_index_m.m ├── ssim_index_new.m ├── testQualityMetrics.m └── testQualityMetricsTest.m /+bliinds2/bliinds2_feature_extraction.m: -------------------------------------------------------------------------------- 1 | function features = bliinds2_feature_extraction(I) 2 | 3 | import bliinds2.* 4 | 5 | h=fspecial('gaussian',3); 6 | 7 | Img = double(I(:,:,1)); 8 | 9 | coeff_freq_var_L1 = blkproc(Img,[3,3],[1,1],@rho_dct); 10 | gama_L1 = blkproc(Img,[3,3],[1,1],@gama_dct); 11 | ori1_rho_L1 = blkproc(Img,[3 3],[1,1],@oriented1_dct_rho_config3); 12 | ori2_rho_L1 = blkproc(Img,[3 3],[1,1],@oriented2_dct_rho_config3); 13 | ori3_rho_L1 = blkproc(Img,[3 3],[1,1],@oriented3_dct_rho_config3); 14 | subband_energy_L1 = blkproc(Img,[3 3],[1,1],@dct_freq_bands); 15 | 16 | rho_sorted_temp = sort(coeff_freq_var_L1(:),'descend'); 17 | rho_count = length(rho_sorted_temp); 18 | percentile10_coeff_freq_var_L1=mean(rho_sorted_temp(1:ceil(rho_count/10))); 19 | percentile100_coeff_freq_var_L1=mean(rho_sorted_temp(:)); 20 | clear rho_sorted_temp rho_count 21 | 22 | gama_sorted_temp = sort(gama_L1(:),'ascend'); 23 | gama_count = length(gama_sorted_temp); 24 | percentile10_gama_L1=mean(gama_sorted_temp(1:ceil(gama_count/10))); 25 | percentile100_gama_L1=mean(gama_sorted_temp(:)); 26 | clear gama_sorted_temp gama_count 27 | 28 | subband_energy_sorted_temp = sort(subband_energy_L1(:),'descend'); 29 | subband_energy_count = length(subband_energy_sorted_temp); 30 | percentile10_subband_energy_L1=mean(subband_energy_sorted_temp(1:ceil(subband_energy_count/10))); 31 | percentile100_subband_energy_L1=mean(subband_energy_sorted_temp(:)); 32 | clear freq_bands_sorted_temp freq_bands_count 33 | 34 | temp_size=size(ori1_rho_L1); 35 | var_temp=zeros(temp_size); 36 | 37 | for i=1:temp_size(1) 38 | for j=1:temp_size(2) 39 | var_temp(i,j)=var([ori1_rho_L1(i,j) ori2_rho_L1(i,j) ori3_rho_L1(i,j)]); 40 | end 41 | end 42 | ori_rho_L1=var_temp; 43 | 44 | ori_sorted_temp = sort(ori_rho_L1(:),'descend'); 45 | ori_count = length(ori_sorted_temp); 46 | percentile10_orientation_L1=mean(ori_sorted_temp(1:ceil(ori_count/10))); 47 | percentile100_orientation_L1=mean(ori_sorted_temp(:)); 48 | clear var_ori_sorted_temp rho_count 49 | 50 | features_L1 = [percentile100_coeff_freq_var_L1;percentile10_coeff_freq_var_L1;percentile100_gama_L1;percentile10_gama_L1;percentile100_subband_energy_L1;percentile10_subband_energy_L1;percentile100_orientation_L1;percentile10_orientation_L1]; 51 | 52 | %% 53 | 54 | Img1_filtered=double(imfilter(Img,h)); 55 | Img2 = Img1_filtered(2:2:end,2:2:end); 56 | 57 | coeff_freq_var_L2 = blkproc(Img2,[3,3],[1,1],@rho_dct); 58 | gama_L2 = blkproc(Img2,[3,3],[1,1],@gama_dct); 59 | ori1_rho_L2 = blkproc(Img2,[3 3],[1,1],@oriented1_dct_rho_config3); 60 | ori2_rho_L2 = blkproc(Img2,[3 3],[1,1],@oriented2_dct_rho_config3); 61 | ori3_rho_L2 = blkproc(Img2,[3 3],[1,1],@oriented3_dct_rho_config3); 62 | subband_energy_L2 = blkproc(Img2,[3 3],[1,1],@dct_freq_bands); 63 | 64 | rho_sorted_temp = sort(coeff_freq_var_L2(:),'descend'); 65 | rho_count = length(rho_sorted_temp); 66 | percentile10_coeff_freq_var_L2=mean(rho_sorted_temp(1:ceil(rho_count/10))); 67 | percentile100_coeff_freq_var_L2=mean(rho_sorted_temp(:)); 68 | clear rho_sorted_temp rho_count 69 | 70 | gama_sorted_temp = sort(gama_L2(:),'ascend'); 71 | gama_count = length(gama_sorted_temp); 72 | percentile10_gama_L2=mean(gama_sorted_temp(1:ceil(gama_count/10))); 73 | percentile100_gama_L2=mean(gama_sorted_temp(:)); 74 | clear gama_sorted_temp gama_count 75 | 76 | subband_energy_sorted_temp = sort(subband_energy_L2(:),'descend'); 77 | subband_energy_count = length(subband_energy_sorted_temp); 78 | percentile10_subband_energy_L2=mean(subband_energy_sorted_temp(1:ceil(subband_energy_count/10))); 79 | percentile100_subband_energy_L2=mean(subband_energy_sorted_temp(:)); 80 | clear freq_bands_sorted_temp freq_bands_count 81 | 82 | temp_size=size(ori1_rho_L2); 83 | var_temp=zeros(temp_size); 84 | 85 | for i=1:temp_size(1) 86 | for j=1:temp_size(2) 87 | var_temp(i,j)=var([ori1_rho_L2(i,j) ori2_rho_L2(i,j) ori3_rho_L2(i,j)]); 88 | end 89 | end 90 | ori_rho_L2=var_temp; 91 | 92 | ori_sorted_temp = sort(ori_rho_L2(:),'descend'); 93 | ori_count = length(ori_sorted_temp); 94 | percentile10_orientation_L2=mean(ori_sorted_temp(1:ceil(ori_count/10))); 95 | percentile100_orientation_L2=mean(ori_sorted_temp(:)); 96 | clear var_ori_sorted_temp rho_count 97 | 98 | features_L2 = [percentile100_coeff_freq_var_L2;percentile10_coeff_freq_var_L2;percentile100_gama_L2;percentile10_gama_L2;percentile100_subband_energy_L2;percentile10_subband_energy_L2;percentile100_orientation_L2;percentile10_orientation_L2]; 99 | 100 | %% 101 | Img2_filtered=double(imfilter(Img2,h)); 102 | Img3 = Img2_filtered(2:2:end,2:2:end); 103 | 104 | coeff_freq_var_L3 = blkproc(Img3,[3,3],[1,1],@rho_dct); 105 | gama_L3 = blkproc(Img3,[3,3],[1,1],@gama_dct); 106 | ori1_rho_L3 = blkproc(Img3,[3 3],[1,1],@oriented1_dct_rho_config3); 107 | ori2_rho_L3 = blkproc(Img3,[3 3],[1,1],@oriented2_dct_rho_config3); 108 | ori3_rho_L3 = blkproc(Img3,[3 3],[1,1],@oriented3_dct_rho_config3); 109 | subband_energy_L3 = blkproc(Img3,[3 3],[1,1],@dct_freq_bands); 110 | 111 | rho_sorted_temp = sort(coeff_freq_var_L3(:),'descend'); 112 | rho_count = length(rho_sorted_temp); 113 | percentile10_coeff_freq_var_L3=mean(rho_sorted_temp(1:ceil(rho_count/10))); 114 | percentile100_coeff_freq_var_L3=mean(rho_sorted_temp(:)); 115 | clear rho_sorted_temp rho_count 116 | 117 | gama_sorted_temp = sort(gama_L3(:),'ascend'); 118 | gama_count = length(gama_sorted_temp); 119 | percentile10_gama_L3=mean(gama_sorted_temp(1:ceil(gama_count/10))); 120 | percentile100_gama_L3=mean(gama_sorted_temp(:)); 121 | clear gama_sorted_temp gama_count 122 | 123 | subband_energy_sorted_temp = sort(subband_energy_L3(:),'descend'); 124 | subband_energy_count = length(subband_energy_sorted_temp); 125 | percentile10_subband_energy_L3=mean(subband_energy_sorted_temp(1:ceil(subband_energy_count/10))); 126 | percentile100_subband_energy_L3=mean(subband_energy_sorted_temp(:)); 127 | clear freq_bands_sorted_temp freq_bands_count 128 | 129 | temp_size=size(ori1_rho_L3); 130 | var_temp=zeros(temp_size); 131 | 132 | for i=1:temp_size(1) 133 | for j=1:temp_size(2) 134 | var_temp(i,j)=var([ori1_rho_L3(i,j) ori2_rho_L3(i,j) ori3_rho_L3(i,j)]); 135 | end 136 | end 137 | ori_rho_L3=var_temp; 138 | 139 | ori_sorted_temp = sort(ori_rho_L3(:),'descend'); 140 | ori_count = length(ori_sorted_temp); 141 | percentile10_orientation_L3=mean(ori_sorted_temp(1:ceil(ori_count/10))); 142 | percentile100_orientation_L3=mean(ori_sorted_temp(:)); 143 | clear var_ori_sorted_temp rho_count 144 | 145 | features_L3 = [percentile100_coeff_freq_var_L3;percentile10_coeff_freq_var_L3;percentile100_gama_L3;percentile10_gama_L3;percentile100_subband_energy_L3;percentile10_subband_energy_L3;percentile100_orientation_L3;percentile10_orientation_L3]; 146 | 147 | %% 148 | features = [features_L1' features_L2' features_L3']; -------------------------------------------------------------------------------- /+bliinds2/bliinds2_score.m: -------------------------------------------------------------------------------- 1 | function [ score ] = bliinds2_score( image ) 2 | %BLIINDS2_SCORE Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | import bliinds2.* 6 | 7 | features = bliinds2_feature_extraction(image); 8 | score = bliinds_prediction(features); 9 | 10 | end 11 | 12 | -------------------------------------------------------------------------------- /+bliinds2/bliinds_prediction.m: -------------------------------------------------------------------------------- 1 | function predicted_score = bliinds_prediction(features) 2 | 3 | 4 | % features: needs to be a ROW vector of features 5 | 6 | b = 1.0168; 7 | gama = 0.4200; 8 | mu = [1.4526,2.6063,1.5189,0.4061,0.7595,1.0661,0.1668,0.5942,1.3617,2.4291,1.359,0.4069,0.7489,1.0642,0.1261,0.4472,1.3117,2.3635,1.2518,0.3962,0.7488,1.0442,0.1111,0.4005,38.4298]; 9 | sigma_inv = [1142.0558,-432.1755,149.2329,-717.0836,-416.2206,31.8536,-1336.523,410.0095,-1081.7624,272.0877,-177.6223,399.9886,-102.9389,34.606,282.7366,-108.438,818.5531,-188.9166,70.6472,-77.8053,-343.2404,-12.5055,395.2466,-18.7065,-0.8141;-432.1755,433.8229,-54.84,641.2262,85.5863,-2.75,558.4171,-457.0072,421.0835,-411.2758,47.5459,-899.064,-221.2799,17.1216,-305.5351,460.9747,-159.8047,145.0255,-27.7132,370.6197,-75.8506,-63.6843,-22.494,-133.3571,0.0219;149.2329,-54.84,187.937,7.9333,632.977,-65.6098,25.8639,-66.0151,-80.4984,31.3319,-343.8075,-92.8136,-1181.0285,134.916,17.2939,-62.572,82.6342,-43.0662,181.3199,4.9145,495.4434,-58.1347,-75.9212,119.1007,0.0772;-717.0836,641.2262,7.9333,4797.5444,1717.8011,-128.6028,1157.9108,-475.5831,377.5675,-591.4465,35.8215,-7387.9628,-1030.6953,147.5468,125.754,-216.0778,-362.3661,438.113,-17.5266,4347.0248,668.3571,-251.9599,145.5076,251.7237,-0.495;-416.2206,85.5863,632.977,1717.8011,4477.6629,-468.3493,1037.7334,-469.0415,506.389,-74.3401,-1199.5867,-2036.4113,-6609.5733,701.0935,75.109,-63.5547,-538.0178,86.1049,684.5736,891.7386,3917.7429,-291.5712,-375.5885,275.662,2.5356;31.8536,-2.75,-65.6098,-128.6028,-468.3493,98.8632,-113.4991,40.0324,-44.7143,3.3637,134.8988,149.7918,773.201,-101.4789,107.5409,-30.7392,50.436,-11.1299,-79.6877,-79.7793,-487.2088,32.5063,199.6138,-55.8805,-0.2938;-1336.523,558.4171,25.8639,1157.9108,1037.7334,-113.4991,11066.3771,-2760.6397,95.7434,89.966,-198.1993,-67.4954,-1619.3719,245.3796,76.5486,-244.2315,-1264.4597,341.7784,165.1558,724.7502,3235.1716,-226.0946,-2393.0874,774.8213,0.288;410.0095,-457.0072,-66.0151,-475.5831,-469.0415,40.0324,-2760.6397,1158.3839,-138.1918,343.2445,198.5439,453.623,1166.1971,-138.1524,598.2122,-817.5906,132.0554,-137.9952,-113.7796,-209.1552,-771.1506,138.5616,510.3357,168.2711,-0.29;-1081.7624,421.0835,-80.4984,377.5675,506.389,-44.7143,95.7434,-138.1918,1915.4103,-655.0341,153.5997,-627.1194,-322.4587,-7.3923,-2162.1359,538.0409,-1025.2009,308.3455,-129.4954,168.873,-209.339,69.8181,-452.5079,124.0219,0.0884;272.0877,-411.2758,31.3319,-591.4465,-74.3401,3.3637,89.966,343.2445,-655.0341,826.2931,-91.2498,1647.7299,163.0693,-2.7738,1239.8022,-944.4377,94.8178,-357.1419,76.4646,-957.8153,343.644,-0.2534,128.5456,323.3975,0.1007;-177.6223,47.5459,-343.8075,35.8215,-1199.5867,134.8988,-198.1993,198.5439,153.5997,-91.2498,764.6647,-0.7828,2728.3511,-298.1473,-163.2537,37.1566,-92.0854,103.2661,-467.0539,118.3362,-1561.5375,187.4717,749.0445,-339.9817,-0.7412;399.9886,-899.064,-92.8136,-7387.9628,-2036.4113,149.7918,-67.4954,453.623,-627.1194,1647.7299,-0.7828,15752.7595,1976.6379,-197.003,832.5406,-34.3484,108.2804,-1057.2645,84.3704,-10282.9364,202.5549,332.7627,-1940.4479,41.3643,0.5778;-102.9389,-221.2799,-1181.0285,-1030.6953,-6609.5733,773.201,-1619.3719,1166.1971,-322.4587,163.0693,2728.3511,1976.6379,14915.6954,-1537.3351,-864.4597,-612.9677,733.9263,-58.5232,-1684.4262,-949.8378,-9235.8741,903.1342,2388.4858,-630.6582,-5.3337;34.606,17.1216,134.916,147.5468,701.0935,-101.4789,245.3796,-138.1524,-7.3923,-2.7738,-298.1473,-197.003,-1537.3351,298.4816,272.9144,-2.214,-80.2759,14.4577,180.0449,121.1852,975.5485,-209.6239,-250.0557,74.7275,0.4619;282.7366,-305.5351,17.2939,125.754,75.109,107.5409,76.5486,598.2122,-2162.1359,1239.8022,-163.2537,832.5406,-864.4597,272.9144,24284.4755,-6669.3766,-1532.0103,270.1864,95.4222,398.1832,2160.278,47.5033,1761.0822,-172.2217,-0.2626;-108.438,460.9747,-62.572,-216.0778,-63.5547,-30.7392,-244.2315,-817.5906,538.0409,-944.4377,37.1566,-34.3484,-612.9677,-2.214,-6669.3766,4040.7993,557.8029,164.0227,14.2624,-443.5659,-224.9072,-38.6544,159.202,-1533.4954,0.6494;818.5531,-159.8047,82.6342,-362.3661,-538.0178,50.436,-1264.4597,132.0554,-1025.2009,94.8178,-92.0854,108.2804,733.9263,-80.2759,-1532.0103,557.8029,1641.2223,-456.9275,66.8667,-448.1533,-1107.5629,-67.5189,-3176.3697,656.7044,-0.4248;-188.9166,145.0255,-43.0662,438.113,86.1049,-11.1299,341.7784,-137.9952,308.3455,-357.1419,103.2661,-1057.2645,-58.5232,14.4577,270.1864,164.0227,-456.9275,415.1508,-77.733,1060.393,213.199,-7.8851,1016.6317,-532.7717,0.0241;70.6472,-27.7132,181.3199,-17.5266,684.5736,-79.6877,165.1558,-113.7796,-129.4954,76.4646,-467.0539,84.3704,-1684.4262,180.0449,95.4222,14.2624,66.8667,-77.733,331.5003,-114.2755,1293.5639,-139.5878,-864.2833,240.3795,0.7383;-77.8053,370.6197,4.9145,4347.0248,891.7386,-79.7793,724.7502,-209.1552,168.873,-957.8153,118.3362,-10282.9364,-949.8378,121.1852,398.1832,-443.5659,-448.1533,1060.393,-114.2755,8411.2137,752.0714,-241.4548,989.9951,-82.2795,-0.8877;-343.2404,-75.8506,495.4434,668.3571,3917.7429,-487.2088,3235.1716,-771.1506,-209.339,343.644,-1561.5375,202.5549,-9235.8741,975.5485,2160.278,-224.9072,-1107.5629,213.199,1293.5639,752.0714,10202.2973,-860.8491,-6453.1128,921.0346,5.639;-12.5055,-63.6843,-58.1347,-251.9599,-291.5712,32.5063,-226.0946,138.5616,69.8181,-0.2534,187.4717,332.7627,903.1342,-209.6239,47.5033,-38.6544,-67.5189,-7.8851,-139.5878,-241.4548,-860.8491,525.8328,1781.4998,-336.3702,-0.3643;395.2466,-22.494,-75.9212,145.5076,-375.5885,199.6138,-2393.0874,510.3357,-452.5079,128.5456,749.0445,-1940.4479,2388.4858,-250.0557,1761.0822,159.202,-3176.3697,1016.6317,-864.2833,989.9951,-6453.1128,1781.4998,61706.1511,-14545.9815,-1.5038;-18.7065,-133.3571,119.1007,251.7237,275.662,-55.8805,774.8213,168.2711,124.0219,323.3975,-339.9817,41.3643,-630.6582,74.7275,-172.2217,-1533.4954,656.7044,-532.7717,240.3795,-82.2795,921.0346,-336.3702,-14545.9815,5166.6137,-0.4822;-0.8141,0.0219,0.0772,-0.495,2.5356,-0.2938,0.288,-0.29,0.0884,0.1007,-0.7412,0.5778,-5.3337,0.4619,-0.2626,0.6494,-0.4248,0.0241,0.7383,-0.8877,5.639,-0.3643,-1.5038,-0.4822,0.0112]; 10 | 11 | iVect=[0:0.5:100]; 12 | 13 | count=0; 14 | for i=1:0.5:100 15 | count=count+1; 16 | p_temp(count)=exp(-(b*(([features i]-mu)*sigma_inv*([features i]-mu)'))^(gama/1)); 17 | end 18 | [ttt IXX]=max(p_temp); 19 | dm=iVect(IXX); 20 | clear p_temp* IXX 21 | 22 | predicted_score=dm; 23 | -------------------------------------------------------------------------------- /+bliinds2/dct_freq_bands.m: -------------------------------------------------------------------------------- 1 | function f = dct_freq_bands(In) 2 | 3 | I=dct2(In); 4 | eps=0.00000001; 5 | 6 | %% 5x5 freq band 1 7 | var_band1=var([I(1,2) I(2,1) I(1,3) I(3,1) I(2,2)]); 8 | 9 | 10 | %% 5x5 freq band 2 11 | var_band2=var([I(4,1) I(5,1) I(3,2) I(4,2) I(5,2) I(2,3) I(3,3) I(4,3) I(1,4) I(2,4) I(3,4) I(1,5) I(2,5)]); 12 | 13 | %% 5x5 freq band 3 14 | var_band3=var([I(3,5) I(4,4) I(5,3) I(4,5) I(5,4) I(5,5)]); 15 | 16 | r1 = abs(var_band3 - mean([var_band1 var_band2]))/(var_band3 + mean([var_band1 var_band2])+eps); 17 | r2 = abs(var_band2 - var_band1)/(var_band3 + var_band1+eps); 18 | 19 | f = (r1+r2)/2; -------------------------------------------------------------------------------- /+bliinds2/fitting.m: -------------------------------------------------------------------------------- 1 | function yhat = fitting(beta,x) 2 | 3 | b1 = beta(1); 4 | b2 = beta(2); 5 | b3 = beta(3); 6 | b4 = beta(4); 7 | b5 = beta(5); 8 | 9 | yhat = b1*(0.5 - 1./(1+exp(b2*(x-b3)))) + b4.*x + b5; 10 | -------------------------------------------------------------------------------- /+bliinds2/gama_dct.m: -------------------------------------------------------------------------------- 1 | function g = gama_dct(I) 2 | 3 | temp1=dct2(I); 4 | temp2=temp1(:); 5 | temp3=temp2(2:end); 6 | 7 | %g=kurtosis(temp3); 8 | g=bliinds2.gama_gen_gauss(temp3); -------------------------------------------------------------------------------- /+bliinds2/gama_gen_gauss.m: -------------------------------------------------------------------------------- 1 | function gama =gama_gen_gauss(I) 2 | 3 | mean_gauss=mean(I(:)); 4 | var_gauss=var(I(:)); 5 | mean_abs=mean(abs(I(:)-mean_gauss))^2; 6 | rho=var_gauss/(mean_abs+0.0000001); 7 | 8 | g=[0.03:0.001:10]; 9 | r=gamma(1./g).*gamma(3./g)./(gamma(2./g).^2); 10 | 11 | gamma_gauss=11; 12 | for j=1:length(g)-1 13 | if rho<=r(j) && rho>r(j+1) 14 | %j 15 | gamma_gauss=g(j); 16 | break 17 | end 18 | end 19 | gama=gamma_gauss; 20 | 21 | % %b=(1/sqrt(var_gauss))*sqrt(gamma(3/gama)/gamma(1/gama)); 22 | % %a=b*gama/(2*gamma(1/gama)); -------------------------------------------------------------------------------- /+bliinds2/oriented1_dct_rho_config3.m: -------------------------------------------------------------------------------- 1 | function g1 = oriented1_dct_rho_config3(I) 2 | 3 | %H=fspecial('gaussian',[7 7]); 4 | 5 | temp=dct2(I); 6 | eps=0.00000001; 7 | %% 3x3 8 | % temp1=[temp(1,3) temp(2,3)]; 9 | 10 | 11 | %% 7x7 12 | % temp1=[temp(1,2:end) temp(2,3:end) temp(3,5:end) temp(4,6:end)]; 13 | 14 | 15 | %% 5x5 16 | 17 | F = [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]; 18 | temp1=temp(F~=0); 19 | 20 | %% 9x9 21 | % temp1=[temp(1,2:end) temp(2,3:end) temp(3,5:end) temp(4,6:end) temp(5,8:end) temp(6,9:end)]; 22 | 23 | std_gauss=std(abs(temp1(:))); 24 | mean_abs=mean(abs(temp1(:))); 25 | g1=std_gauss/(mean_abs+0.0000001); 26 | 27 | % g1=var(temp1)/mean(temp1); 28 | -------------------------------------------------------------------------------- /+bliinds2/oriented2_dct_rho_config3.m: -------------------------------------------------------------------------------- 1 | function g2 = oriented2_dct_rho_config3(I) 2 | 3 | %H=fspecial('gaussian',[7 7]); 4 | temp=dct2(I); 5 | eps=0.00000001; 6 | %% 3x3 7 | % temp2=[temp(2,2) temp(3,3)]; 8 | 9 | %% 7x7 10 | % temp2=[temp(2,2) temp(3,3) temp(4,4) temp(5,5) temp(6,6) temp(7,7) temp(3,4) temp(4,3) temp(4,5) temp(5,4) temp(5,6) temp(6,5) temp(6,7) temp(7,6) temp(5,7) temp(7,5)]; 11 | 12 | %% 5x5 13 | F = [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]; 14 | temp2=temp(F~=0); 15 | 16 | %% 9x9 17 | % temp2=[temp(2,2) temp(3,3) temp(4,4) temp(5,5) temp(6,6) temp(7,7) temp(8,8) temp(9,9) temp(3,4) temp(4,3) temp(4,5) temp(5,4) temp(5,6) temp(6,5) temp(6,7) temp(7,6) temp(5,7) temp(7,5) temp(6,8) temp(8,6) temp(7,8) temp(8,7) temp(7,9) temp(9,7) temp(8,9) temp(9,8)]; 18 | 19 | 20 | std_gauss=std(abs(temp2(:))); 21 | mean_abs=mean(abs(temp2(:))); 22 | g2=std_gauss/(mean_abs+0.0000001); 23 | 24 | % g2=var(temp2)/(mean(temp2)+eps); -------------------------------------------------------------------------------- /+bliinds2/oriented3_dct_rho_config3.m: -------------------------------------------------------------------------------- 1 | function g3 = oriented3_dct_rho_config3(I) 2 | 3 | %H=fspecial('gaussian',[7 7]); 4 | 5 | eps=0.00000001; 6 | temp=dct2(I); 7 | 8 | %% 3x3 9 | % temp3=[temp(2,1) temp(3,1) temp(3,2)]; 10 | 11 | %% 7x7 12 | % temp3=[temp(2:end,1)' temp(3:end,2)' temp(5:end,3)' temp(6:end,4)']; 13 | 14 | %% 5x5 15 | F = [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]'; 16 | temp3=temp(F~=0); 17 | 18 | %% 9x9 19 | % temp3=[temp(2:end,1)' temp(3:end,2)' temp(5:end,3)' temp(6:end,4)' temp(8:end,5)' temp(9:end,6)']; 20 | 21 | std_gauss=std(abs(temp3(:))); 22 | mean_abs=mean(abs(temp3(:))); 23 | g3=std_gauss/(mean_abs+0.0000001); 24 | 25 | % g3=var(temp3)/mean(temp3); -------------------------------------------------------------------------------- /+bliinds2/parameters_from_training.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/+bliinds2/parameters_from_training.mat -------------------------------------------------------------------------------- /+bliinds2/rho_dct.m: -------------------------------------------------------------------------------- 1 | function g = rho_dct(I) 2 | 3 | temp1=dct2(I); 4 | temp2=temp1(:); 5 | temp3=temp2(2:end); 6 | 7 | %g=kurtosis(temp3); 8 | g=bliinds2.rho_gen_gauss(temp3); -------------------------------------------------------------------------------- /+bliinds2/rho_gen_gauss.m: -------------------------------------------------------------------------------- 1 | function rho =rho_gen_gauss(I) 2 | %% we know this one works well 3 | % mean_gauss=mean(I(:)); 4 | % var_gauss=var(I(:)); 5 | % mean_abs=mean(abs(I(:)-mean_gauss))^2; 6 | % rho=var_gauss/(mean_abs+0.0000001); 7 | 8 | %% let's see how well this one does 9 | 10 | % mean_gauss=mean(I(:)); 11 | % std_gauss=std(abs(I(:))); 12 | % mean_abs=mean(abs(I(:)-mean_gauss)); 13 | % rho=std_gauss/(mean_abs+0.0000001); 14 | 15 | %% Third thing to test 16 | 17 | std_gauss=std(abs(I(:))); 18 | mean_abs=mean(abs(I(:))); 19 | rho=std_gauss/(mean_abs+0.0000001); 20 | -------------------------------------------------------------------------------- /+brisque/allrange: -------------------------------------------------------------------------------- 1 | x 2 | -1 1 3 | 1 0.338 10 4 | 2 0.017204 0.806612 5 | 3 0.236 1.642 6 | 4 -0.123884 0.20293 7 | 5 0.000155 0.712298 8 | 6 0.001122 0.470257 9 | 7 0.244 1.641 10 | 8 -0.123586 0.179083 11 | 9 0.000152 0.710456 12 | 10 0.000975 0.470984 13 | 11 0.249 1.555 14 | 12 -0.135687 0.100858 15 | 13 0.000174 0.684173 16 | 14 0.000913 0.534174 17 | 15 0.258 1.561 18 | 16 -0.143408 0.100486 19 | 17 0.000179 0.685696 20 | 18 0.000888 0.536508 21 | 19 0.471 3.264 22 | 20 0.012809 0.703171 23 | 21 0.218 1.046 24 | 22 -0.094876 0.187459 25 | 23 1.5e-005 0.442057 26 | 24 0.001272 0.40803 27 | 25 0.222 1.042 28 | 26 -0.115772 0.162604 29 | 27 1.6e-005 0.444362 30 | 28 0.001374 0.40243 31 | 29 0.227 0.996 32 | 30 -0.117188 0.09832299999999999 33 | 31 3e-005 0.531903 34 | 32 0.001122 0.369589 35 | 33 0.228 0.99 36 | 34 -0.12243 0.098658 37 | 35 2.8e-005 0.530092 38 | 36 0.001118 0.370399 39 | -------------------------------------------------------------------------------- /+brisque/brisque_feature.m: -------------------------------------------------------------------------------- 1 | function feat = brisque_feature(imdist) 2 | 3 | import brisque.* 4 | 5 | %------------------------------------------------ 6 | % Feature Computation 7 | %------------------------------------------------- 8 | scalenum = 2; 9 | window = fspecial('gaussian',7,7/6); 10 | window = window/sum(sum(window)); 11 | 12 | feat = []; 13 | % tic 14 | for itr_scale = 1:scalenum 15 | 16 | mu = filter2(window, imdist, 'same'); 17 | mu_sq = mu.*mu; 18 | sigma = sqrt(abs(filter2(window, imdist.*imdist, 'same') - mu_sq)); 19 | structdis = (imdist-mu)./(sigma+1); 20 | 21 | 22 | [alpha overallstd] = estimateggdparam(structdis(:)); 23 | feat = [feat alpha overallstd^2]; 24 | 25 | 26 | shifts = [ 0 1;1 0 ; 1 1; -1 1]; 27 | 28 | for itr_shift =1:4 29 | 30 | shifted_structdis = circshift(structdis,shifts(itr_shift,:)); 31 | pair = structdis(:).*shifted_structdis(:); 32 | [alpha leftstd rightstd] = estimateaggdparam(pair); 33 | const =(sqrt(gamma(1/alpha))/sqrt(gamma(3/alpha))); 34 | meanparam =(rightstd-leftstd)*(gamma(2/alpha)/gamma(1/alpha))*const; 35 | feat =[feat alpha meanparam leftstd^2 rightstd^2]; 36 | 37 | end 38 | 39 | 40 | imdist = imresize(imdist,0.5); 41 | 42 | 43 | end 44 | % toc -------------------------------------------------------------------------------- /+brisque/brisquescore.m: -------------------------------------------------------------------------------- 1 | function qualityscore = brisquescore(imdist) 2 | 3 | import brisque.* 4 | 5 | fullpath = mfilename('fullpath'); 6 | idx = find(fullpath == filesep); 7 | bfolder = fullpath(1:(idx(end)-1)); 8 | 9 | if(size(imdist,3)==3) 10 | imdist = uint8(imdist); 11 | imdist = rgb2gray(imdist); 12 | end 13 | 14 | imdist = double(imdist); 15 | 16 | if(nargin<2) 17 | feat = brisque_feature(imdist); 18 | % disp('feat computed') 19 | end 20 | 21 | 22 | %--------------------------------------------------------------------- 23 | %Quality Score Computation 24 | %--------------------------------------------------------------------- 25 | 26 | if 0 27 | fid = fopen(fullfile(bfolder,'test_ind'),'w'); 28 | 29 | for jj = 1:size(feat,1) 30 | 31 | fprintf(fid,'1 '); 32 | for kk = 1:size(feat,2) 33 | fprintf(fid,'%d:%f ',kk,feat(jj,kk)); 34 | end 35 | fprintf(fid,'\n'); 36 | end 37 | 38 | fclose(fid); 39 | 40 | % warning off all 41 | % delete output test_ind_scaled dump 42 | 43 | delete (fullfile(bfolder,'output')) 44 | delete (fullfile(bfolder,'test_ind_scaled')) 45 | delete (fullfile(bfolder,'dump')) 46 | 47 | % system('svm-scale -r allrange test_ind >> test_ind_scaled'); 48 | cmd=sprintf('"%s/svm-scale" -r "%s/allrange" "%s/test_ind" >> "%s/test_ind_scaled"',bfolder,bfolder,bfolder,bfolder); 49 | disp(cmd) 50 | system(cmd) 51 | 52 | % system('svm-predict -b 1 test_ind_scaled allmodel output >>dump'); 53 | cmd=sprintf('"%s/svm-predict" -b 1 "%s/test_ind_scaled" "%s/allmodel" "%s/output"',bfolder,bfolder,bfolder,bfolder); 54 | disp(cmd) 55 | system(cmd) 56 | 57 | load(fullfile(bfolder,'output')) 58 | else 59 | % use `git clone git://github.com/gregfreeman/libsvm.git -b new_matlab_interface` 60 | [range,lu]=libsvmreadrange(fullfile(bfolder,'allrange')); 61 | sfeat=libsvmscale(feat,range,lu); 62 | allmodel=libsvmreadmodel(fullfile(bfolder,'allmodel'),36); 63 | [output,desc] = svmpredict(sfeat, allmodel); 64 | % disp(output) 65 | % disp(desc) 66 | end 67 | 68 | qualityscore = output; 69 | -------------------------------------------------------------------------------- /+brisque/estimateaggdparam.m: -------------------------------------------------------------------------------- 1 | function [alpha leftstd rightstd] = estimateaggdparam(vec) 2 | 3 | 4 | gam = 0.2:0.001:10; 5 | r_gam = ((gamma(2./gam)).^2)./(gamma(1./gam).*gamma(3./gam)); 6 | 7 | 8 | leftstd = sqrt(mean((vec(vec<0)).^2)); 9 | rightstd = sqrt(mean((vec(vec>0)).^2)); 10 | gammahat = leftstd/rightstd; 11 | rhat = (mean(abs(vec)))^2/mean((vec).^2); 12 | rhatnorm = (rhat*(gammahat^3 +1)*(gammahat+1))/((gammahat^2 +1)^2); 13 | [min_difference, array_position] = min((r_gam - rhatnorm).^2); 14 | alpha = gam(array_position); 15 | 16 | 17 | -------------------------------------------------------------------------------- /+brisque/estimateggdparam.m: -------------------------------------------------------------------------------- 1 | function [gamparam sigma] = estimateggdparam(vec) 2 | 3 | 4 | 5 | gam = 0.2:0.001:10; 6 | r_gam = (gamma(1./gam).*gamma(3./gam))./((gamma(2./gam)).^2); 7 | 8 | sigma_sq = mean((vec).^2); 9 | sigma = sqrt(sigma_sq); 10 | E = mean(abs(vec)); 11 | rho = sigma_sq/E^2; 12 | [min_difference, array_position] = min(abs(rho - r_gam)); 13 | gamparam = gam(array_position); 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /+brisque/readme.txt: -------------------------------------------------------------------------------- 1 | RISQUEE Software release. 2 | 3 | 4 | ======================================================================== 5 | 6 | -----------COPYRIGHT NOTICE STARTS WITH THIS LINE------------ 7 | Copyright (c) 2011 The University of Texas at Austin 8 | All rights reserved. 9 | 10 | Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, 11 | modify, and distribute this code (the source files) and its documentation for 12 | any purpose, provided that the copyright notice in its entirety appear in all copies of this code, and the 13 | original source of this code, Laboratory for Image and Video Engineering (LIVE, http://live.ece.utexas.edu) 14 | and Center for Perceptual Systems (CPS, http://www.cps.utexas.edu) at the University of Texas at Austin (UT Austin, 15 | http://www.utexas.edu), is acknowledged in any publication that reports research using this code. The research 16 | is to be cited in the bibliography as: 17 | 18 | 1) A. Mittal, A. K. Moorthy and A. C. Bovik, "BRISQUE Software Release", 19 | URL: http://live.ece.utexas.edu/research/quality/BRISQUE_release.zip, 2011 20 | 21 | 2) A. Mittal, A. K. Moorthy and A. C. Bovik, "No Reference Image Quality Assessment in the Spatial Domain" 22 | submitted 23 | 24 | IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT AUSTIN BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, 25 | OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS DATABASE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF TEXAS 26 | AT AUSTIN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | THE UNIVERSITY OF TEXAS AT AUSTIN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE DATABASE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, 30 | AND THE UNIVERSITY OF TEXAS AT AUSTIN HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 31 | 32 | -----------COPYRIGHT NOTICE ENDS WITH THIS LINE------------% 33 | 34 | Author : Anish Mittal 35 | Version : 1.0 36 | 37 | The authors are with the Laboratory for Image and Video Engineering 38 | (LIVE), Department of Electrical and Computer Engineering, The 39 | University of Texas at Austin, Austin, TX. 40 | 41 | Kindly report any suggestions or corrections to mittal.anish@gmail.com 42 | 43 | ======================================================================== 44 | 45 | This is a demonstration of the Blind/Referenceless Image Spatial Quality Evaluator (BRISQUE) index. 46 | The algorithm is described in: 47 | 48 | A. Mittal, A. K. Moorthy and A. C. Bovik, "No Reference Image Quality Assessment in the Spatial Domain" 49 | 50 | 51 | You can change this program as you like and use it anywhere, but please 52 | refer to its original source (cite our paper and our web page at 53 | http://live.ece.utexas.edu/research/quality/BRISQUE_release.zip). 54 | 55 | ======================================================================== 56 | 57 | Running on Matlab 58 | 59 | 60 | Input : A test image loaded in an array 61 | 62 | Output: A quality score of the image. The score typically has a value 63 | between 0 and 100 (0 represents the best quality, 100 the worst). 64 | 65 | Usage: 66 | 67 | 1. Load the image, for example 68 | 69 | image = imread('testimage1.bmp'); 70 | 71 | 2. Call this function to calculate the quality score: 72 | 73 | qualityscore = brisquescore(image) 74 | 75 | Dependencies: 76 | 77 | Binaries: svm-predict, svm-scale (from LibSVM) - provided with release 78 | MATLAB files: brisquescore.m, estimateggdparam.m, estimateaggdparam.m, brisque_feature.m (provided with release) 79 | 80 | Data files: range_all, model_all (provided with release) 81 | 82 | Image Files: testimage1.bmp, testimage2.bmp 83 | 84 | NOTE: Please rename the .exe1 files to .exe files -- this code will work only on WINDOWS systems. 85 | 86 | ======================================================================== 87 | 88 | Note on training: 89 | This release version of BRISQUE was trained on the entire LIVE database. 90 | 91 | 92 | This program uses LibSVM binaries. 93 | Below is the requried copyright notice for the binaries distributed with this release. 94 | 95 | ==================================================================== 96 | LibSVM tools: svm-predict, svm-scale (binaries) 97 | -------------------------------------------------------------------- 98 | 99 | 100 | Copyright (c) 2000-2009 Chih-Chung Chang and Chih-Jen Lin 101 | All rights reserved. 102 | 103 | Redistribution and use in source and binary forms, with or without 104 | modification, are permitted provided that the following conditions 105 | are met: 106 | 107 | 1. Redistributions of source code must retain the above copyright 108 | notice, this list of conditions and the following disclaimer. 109 | 110 | 2. Redistributions in binary form must reproduce the above copyright 111 | notice, this list of conditions and the following disclaimer in the 112 | documentation and/or other materials provided with the distribution. 113 | 114 | 3. Neither name of copyright holders nor the names of its contributors 115 | may be used to endorse or promote products derived from this software 116 | without specific prior written permission. 117 | 118 | 119 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 120 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 121 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 122 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 123 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 124 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 125 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 126 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 127 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 128 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 129 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 130 | ==================================================================== -------------------------------------------------------------------------------- /+divine/data_live_trained.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/+divine/data_live_trained.mat -------------------------------------------------------------------------------- /+divine/divine.m: -------------------------------------------------------------------------------- 1 | function q = divine(im) 2 | % DIIVINE Software release. 3 | % 4 | % 5 | % ======================================================================== 6 | % 7 | % -----------COPYRIGHT NOTICE STARTS WITH THIS LINE------------ 8 | % Copyright (c) 2010 The University of Texas at Austin 9 | % All rights reserved. 10 | % 11 | % Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, 12 | % modify, and distribute this code (the source files) and its documentation for 13 | % any purpose, provided that the copyright notice in its entirety appear in all copies of this code, and the 14 | % original source of this code, Laboratory for Image and Video Engineering (LIVE, http://live.ece.utexas.edu) 15 | % and Center for Perceptual Systems (CPS, http://www.cps.utexas.edu) at the University of Texas at Austin (UT Austin, 16 | % http://www.utexas.edu), is acknowledged in any publication that reports research using this code. The research 17 | % is to be cited in the bibliography as: 18 | % 19 | % 1. A. K. Moorthy and A. C. Bovik, "Blind Image Quality Assessment: From Natural 20 | % Scene Statistics to Perceptual Quality", IEEE Transactions on Image Processing, to appear (2011). 21 | % 22 | % 2. A. K. Moorthy and A. C. Bovik, "DIVINE Software Release", 23 | % URL: http://live.ece.utexas.edu/research/quality/DIIVINE_release.zip, 2010 24 | % 25 | % IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT AUSTIN BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, 26 | % OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS DATABASE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF TEXAS 27 | % AT AUSTIN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | % 29 | % THE UNIVERSITY OF TEXAS AT AUSTIN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 | % WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE DATABASE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, 31 | % AND THE UNIVERSITY OF TEXAS AT AUSTIN HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 32 | % 33 | % -----------COPYRIGHT NOTICE ENDS WITH THIS LINE------------% 34 | % 35 | % Author : Anush Krishna Moorthy 36 | % Version : 1.1 37 | % 38 | % The authors are with the Laboratory for Image and Video Engineering 39 | % (LIVE), Department of Electrical and Computer Engineering, The 40 | % University of Texas at Austin, Austin, TX. 41 | % 42 | % Kindly report any suggestions or corrections to anushmoorthy@gmail.com 43 | % 44 | % ======================================================================== 45 | % 46 | % This is a demonstration of the Distortion Identification based image Verity and INtegrity Evaluation (DIVINE) index. 47 | % It is an implementation of the BIQI in the reference. 48 | % The algorithm is described in: 49 | % A. K. Moorthy and A. C. Bovik, "Blind Image Quality Assessment: From Natural 50 | % Scene Statistics to Perceptual Quality", IEEE Transactions on Image Processing, to appear (2011). 51 | % 52 | % You can change this program as you like and use it anywhere, but please 53 | % refer to its original source (cite our paper and our web page at 54 | % http://live.ece.utexas.edu/research/quality/DIIVINE_release.zip). 55 | % 56 | % Input : A test 8bits/pixel grayscale image loaded in a 2-D array 57 | % Output: A quality score of the image. The score typically has a value 58 | % between 0 and 100 (0 represents the best quality, 100 the worst). 59 | % 60 | % Usage: 61 | % 62 | % 1. Load the image, for example 63 | % 64 | % image = rgb2gray(imread('testimage.jpg')); 65 | % 66 | % 2. Call this function to calculate the quality score: 67 | % 68 | % quality = divine(image) 69 | % 70 | % Dependencies: 71 | % Steerable Pyramid Toolbox, Download from: http://www.cns.nyu.edu/~eero/steerpyr/ 72 | % LibSVM package for MATLAB, Download from: http://www.csie.ntu.edu.tw/~cjlin/libsvm/ 73 | % You may need the MATLAB Image Processing Toolbox 74 | % 75 | % Dependencies-- 76 | % 77 | % MATLAB files: ssim_index_new.m, norm_sender_normalized.m, find_spatial_hist_fast.m, divine_overall_quality.m 78 | % divine_feature_extract.m, map_matrix_to_closest_vec.m (provided with release) 79 | % 80 | % Data files: data_live_trained.mat (provided with release) 81 | % 82 | % This code has been tested on Windows and Mac OSX (Snow Leopard) 83 | % 84 | % ========================================================================% 85 | % Note on training: 86 | % This release version of BIQI was trained on the entire LIVE database. 87 | % 88 | % 89 | 90 | import divine.* 91 | 92 | 93 | 94 | f = divine_feature_extract(im); 95 | q = divine_overall_quality(f); -------------------------------------------------------------------------------- /+divine/divine_feature_extract.m: -------------------------------------------------------------------------------- 1 | function f = divine_feature_extract(im) 2 | import divine.* 3 | 4 | % Function to extract features given an image 5 | %% Constants 6 | num_or = 6; 7 | num_scales = 2; 8 | gam = 0.2:0.001:10; 9 | r_gam = gamma(1./gam).*gamma(3./gam)./(gamma(2./gam)).^2; 10 | 11 | %% Wavelet Transform + Div. Norm. 12 | 13 | if(size(im,3)~=1) 14 | im = (double(rgb2gray(im))); 15 | end 16 | [pyr pind] = buildSFpyr(im,num_scales,num_or-1); 17 | 18 | [subband size_band] = norm_sender_normalized(pyr,pind,num_scales,num_or,1,1,3,3,50); 19 | 20 | 21 | 22 | f = []; 23 | 24 | %% Marginal Statistics 25 | 26 | 27 | h_horz_curr = []; 28 | for ii = 1:length(subband) 29 | t = subband{ii}; 30 | mu_horz = mean(t); 31 | sigma_sq_horz(ii) = mean((t-mu_horz).^2); 32 | E_horz = mean(abs(t-mu_horz)); 33 | rho_horz = sigma_sq_horz(ii)/E_horz^2; 34 | [min_difference, array_position] = min(abs(rho_horz - r_gam)); 35 | gam_horz(ii) = gam(array_position); 36 | end 37 | f = [f sigma_sq_horz gam_horz]; % ind. subband stats f1-f24 38 | 39 | %% Joint Statistics 40 | 41 | 42 | clear sigma_sq_horz gam_horz 43 | for ii = 1:length(subband)/2 44 | t = [subband{ii}; subband{ii+num_or}]; 45 | mu_horz = mean(t); 46 | sigma_sq_horz(ii) = mean((t-mu_horz).^2); 47 | E_horz = mean(abs(t-mu_horz)); 48 | rho_horz = sigma_sq_horz(ii)/E_horz^2; 49 | [min_difference, array_position] = min(abs(rho_horz - r_gam)); 50 | gam_horz(ii) = gam(array_position); 51 | end 52 | f = [f gam_horz]; 53 | t = cell2mat(subband'); 54 | mu = mean(t); 55 | sigma_sq = mean((t-mu_horz).^2); 56 | E_horz = mean(abs(t-mu_horz)); 57 | rho_horz = sigma_sq/E_horz^2; 58 | [min_difference, array_position] = min(abs(rho_horz - r_gam)); 59 | gam_horz = gam(array_position); 60 | 61 | f = [f gam_horz]; 62 | 63 | %% Hp-BP correlations 64 | 65 | 66 | hp_band = pyrBand(pyr,pind,1); 67 | for ii = 1:length(subband) 68 | curr_band = pyrBand(pyr,pind,ii+1); 69 | [ssim_val(ii), ssim_map, cs_val(ii)] = ssim_index_new(imresize(curr_band,size(hp_band)),hp_band); 70 | end 71 | f = [f cs_val]; 72 | 73 | 74 | %% Spatial Correlation 75 | 76 | b = []; 77 | for i = 1:length(subband)/2 78 | b = [b find_spatial_hist_fast(reshape(subband{i},(size_band(i,:))))]; 79 | end 80 | f = [f b]; 81 | 82 | %% Orientation feature... 83 | 84 | l = 1; clear ssim_val cs_val 85 | for i = 1:length(subband)/2 86 | for j = i+1:length(subband)/2 87 | [ssim_val(l), ssim_map, cs_val(l)] = ssim_index_new(reshape(subband{i},size_band(i,:)),reshape(subband{j},size_band(j,:))); 88 | l = l + 1; 89 | end 90 | end 91 | f = [f cs_val]; 92 | 93 | 94 | -------------------------------------------------------------------------------- /+divine/divine_overall_quality.m: -------------------------------------------------------------------------------- 1 | function q = divine_overall_quality(r) 2 | 3 | fullpath = mfilename('fullpath'); 4 | idx = find(fullpath == filesep); 5 | dfolder = fullpath(1:(idx(end)-1)); 6 | 7 | % Function to compute overall quality given feature vector 'r' 8 | 9 | load(fullfile(dfolder,'data_live_trained.mat')) 10 | 11 | %% Classification 12 | atrain = repmat(a_class,[size(r,1) 1]);btrain = repmat(b_class,[size(r,1) 1]); 13 | x_curr = atrain.*r+btrain; 14 | 15 | % [pred_class acc p] = svmpredict(1,x_curr,model_class,'-b 1'); 16 | % use `git clone git://github.com/gregfreeman/libsvm.git -b new_matlab_interface` 17 | 18 | [pred_class p] = svmpredict(x_curr,model_class,struct('output','probability')); 19 | 20 | 21 | %% Regression 22 | for i = 1:5 23 | atrain = repmat(a_reg(i,:),[size(r,1) 1]);btrain = repmat(b_reg(i,:),[size(r,1) 1]); 24 | x_curr = atrain.*r+btrain; 25 | % [q(i) reg_acc(i,:)] = svmpredict(1,x_curr,model_reg{i}); 26 | [q(i)] = svmpredict(x_curr,model_reg{i}); 27 | end 28 | %% Final Score 29 | % clc 30 | q = sum(p.*q); 31 | -------------------------------------------------------------------------------- /+divine/find_spatial_hist_fast.m: -------------------------------------------------------------------------------- 1 | function [b rho ypred matrix xval] = find_spatial_hist_fast(x) 2 | % Function to find the spatial histogram for IMAGE and then compute Corr 3 | % and fit 3-parameter logistic. returns logistic fitting value. 4 | import divine.* 5 | 6 | [nrows ncolms] = size(x); 7 | im = x; 8 | nbins = 100; 9 | max_x = 25; 10 | ss_fact = 4; 11 | [hval bins] = hist(x(:),nbins); 12 | x = map_matrix_to_closest_vec(im,bins); 13 | for j = 1:ss_fact:max_x 14 | matrix = zeros(nbins); 15 | 16 | for i = 1:nbins 17 | 18 | [r c] = find(x==bins(i)); 19 | 20 | if(isempty(r)~=1) 21 | h = zeros(1,nbins); 22 | 23 | ctemp = c-j; 24 | rtemp = r;rtemp(ctemp<1) = []; 25 | ctemp(ctemp<1) = []; 26 | ind = sub2ind(size(im),rtemp,ctemp); 27 | if(~isempty(ind)) 28 | h = h+hist(im(ind),bins); 29 | end 30 | 31 | ctemp = c+j; rtemp = r;rtemp(ctemp>ncolms) = []; 32 | ctemp(ctemp>ncolms) = []; 33 | ind = sub2ind(size(im),rtemp,ctemp); 34 | if(~isempty(ind)) 35 | h = h+hist(im(ind),bins); 36 | end 37 | 38 | rtemp = r-j;ctemp = c;ctemp(rtemp<1) = []; 39 | rtemp(rtemp<1) = []; 40 | ind = sub2ind(size(im),rtemp,ctemp); 41 | if(~isempty(ind)) 42 | h = h+hist(im(ind),bins); 43 | end 44 | 45 | rtemp = r+j; 46 | ctemp = c;ctemp(rtemp>nrows) = []; 47 | rtemp(rtemp>nrows) = []; 48 | ind = sub2ind(size(im),rtemp,ctemp); 49 | if(~isempty(ind)) 50 | h = h+hist(im(ind),bins); 51 | end 52 | 53 | rtemp = r+j;ctemp = c;ctemp(rtemp>nrows) = [];rtemp(rtemp>nrows) = []; 54 | ctemp = ctemp+j;rtemp(ctemp>ncolms) = []; ctemp(ctemp>ncolms) = []; 55 | ind = sub2ind(size(im),rtemp,ctemp); 56 | if(~isempty(ind)) 57 | h = h+hist(im(ind),bins); 58 | end 59 | 60 | rtemp = r+j;ctemp = c;ctemp(rtemp>nrows) = [];rtemp(rtemp>nrows) = []; 61 | ctemp = ctemp-j; rtemp(ctemp<1) = [];ctemp(ctemp<1) = []; 62 | ind = sub2ind(size(im),rtemp,ctemp); 63 | if(~isempty(ind)) 64 | h = h+hist(im(ind),bins); 65 | end 66 | 67 | rtemp = r-j;ctemp = c;ctemp(rtemp<1) = [];rtemp(rtemp<1) = []; 68 | ctemp = ctemp+j;rtemp(ctemp>ncolms) = []; ctemp(ctemp>ncolms) = []; 69 | ind = sub2ind(size(im),rtemp,ctemp); 70 | if(~isempty(ind)) 71 | h = h+hist(im(ind),bins); 72 | end 73 | 74 | rtemp = r-j;ctemp = c; ctemp(rtemp<1) = []; rtemp(rtemp<1) = []; 75 | ctemp = ctemp-j;rtemp(ctemp<1) = []; ctemp(ctemp<1) = []; 76 | ind = sub2ind(size(im),rtemp,ctemp); 77 | if(~isempty(ind)) 78 | h = h+hist(im(ind),bins); 79 | end 80 | 81 | matrix(i,:) = h; 82 | end 83 | 84 | end 85 | X = [bins]'; Y = X; matrix = matrix/sum(sum(matrix)); 86 | px = sum(matrix,2); py = sum(matrix,1)'; 87 | mu_x = sum(X.*px); mu_y = sum(Y.*py); 88 | sigma2_x = sum((X-mu_x).^2.*px); sigma2_y = sum((Y-mu_x).^2.*py); 89 | [xx yy] = meshgrid(X,Y); 90 | rho(j) = (sum(sum(xx.*yy.*matrix))-mu_x.*mu_y)/(sqrt(sigma2_x)*sqrt(sigma2_y)); 91 | 92 | end 93 | 94 | rho = [rho(1:ss_fact:end)]; 95 | xval = [1:ss_fact:max_x]; 96 | % b = nlinfit([0 1:4:100],rho,@fit_spatial_corr,ones(1,5)); 97 | pp = polyfit([1:ss_fact:max_x],rho,3); 98 | % ypred = fit_spatial_corr(b,1:4:100); 99 | ypred = polyval(pp,[1:ss_fact:max_x]); 100 | err = sum((ypred-rho).^2); 101 | b = [pp err]; 102 | % 103 | % figure 104 | % plot(rho,'r','LineWidth',3); hold on 105 | % plot(ypred,'k'); title(['Error:',num2str( sum((ypred-rho).^2))]); 106 | % toc 107 | % subplot(1,3,1) 108 | % imagesc(log(matrix+1));colormap(gray);axis xy 109 | % subplot(1,3,2) 110 | % bar(bins,sum(matrix,1)); axis([1 255 0 max(sum(matrix,1))]) 111 | % subplot(1,3,3) 112 | % bar(bins,sum(matrix,2));axis([1 255 0 max(sum(matrix,2))]) 113 | -------------------------------------------------------------------------------- /+divine/map_matrix_to_closest_vec.m: -------------------------------------------------------------------------------- 1 | function x = map_matrix_to_closest_vec(matrix,vec) 2 | % Function to map the values in the matrix to a value from the vector so 3 | % that the values in x are the same as those in vec 4 | % vec is a 1xm vector and x is a pxq matrix 5 | [nrows ncolms ] = size(matrix); 6 | x = zeros(size(matrix)); 7 | if(nrows<=ncolms) 8 | for i = 1:nrows 9 | curr = matrix(i,:)'; 10 | [minval ind] = min(abs(repmat(curr,[1,length(vec)])-repmat(vec,([ncolms 1]))),[],2); 11 | x(i,:) = vec(ind); 12 | end 13 | elseif(nrows>ncolms) 14 | for i = 1:ncolms 15 | curr = matrix(:,i); 16 | [minval ind] = min(abs(repmat(curr,[1,length(vec)])-repmat(vec,([nrows 1]))),[],2); 17 | x(:,i) = vec(ind); 18 | end 19 | end -------------------------------------------------------------------------------- /+divine/norm_sender_normalized.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | % try to fix the range of z field 5 | function [subband size_band] = norm_sender_normalized(pyro,pind,Nsc,Nor,parent,neighbor,blSzX,blSzY,nbins) 6 | guardband = 16; 7 | pyro = real(pyro); 8 | Nband = size(pind,1)-1; 9 | band = [1 3 6 8 9 11]; 10 | zRange = 15; 11 | 12 | p = 1; 13 | for scale=1:Nsc 14 | for orien=1:Nor 15 | nband = (scale-1)*Nor+orien+1; % except the ll 16 | % if(prod(band-nband-1) ~=0) 17 | % continue; 18 | % end 19 | aux = pyrBand(pyro, pind, nband); 20 | [Nsy,Nsx] = size(aux); 21 | 22 | prnt = parent & (nband < Nband-Nor); % has the subband a parent? 23 | BL = zeros(size(aux,1),size(aux,2),1 + prnt); 24 | BL(:,:,1) = aux; 25 | if prnt, 26 | auxp = pyrBand(pyro, pind, nband+Nor); 27 | % if nband>Nor+1, % resample 2x2 the parent if not in the high-pass oriented subbands. 28 | % auxp = real(imenlarge2(auxp)); % this was uncommented 29 | auxp = real(imresize(auxp,2)); % 30 | % end 31 | % fprintf('parent band and size is %d %d %d \n',nband+Nor,Nsy,Nsx) 32 | BL(:,:,2) = auxp(1:Nsy,1:Nsx); 33 | end 34 | y=BL; 35 | [nv,nh,nb] = size(y); 36 | block = [blSzX blSzY]; 37 | 38 | nblv = nv-block(1)+1; % Discard the outer coefficients 39 | nblh = nh-block(2)+1; % for the reference (centrral) coefficients (to avoid boundary effects) 40 | nexp = nblv*nblh; % number of coefficients considered 41 | N = prod(block) + prnt; % size of the neighborhood 42 | 43 | Ly = (block(1)-1)/2; % block(1) and block(2) must be odd! 44 | Lx = (block(2)-1)/2; 45 | if (Ly~=floor(Ly))|(Lx~=floor(Lx)), 46 | error('Spatial dimensions of neighborhood must be odd!'); 47 | end 48 | Y = zeros(nexp,N); % It will be the observed signal (rearranged in nexp neighborhoods) 49 | % Rearrange observed samples in 'nexp' neighborhoods 50 | n = 0; 51 | for ny=-Ly:Ly, % spatial neighbors 52 | for nx=-Lx:Lx, 53 | n = n + 1; 54 | foo = shift(y(:,:,1),[ny nx]); 55 | foo = foo(Ly+1:Ly+nblv,Lx+1:Lx+nblh); 56 | Y(:,n) = (foo(:)); 57 | end 58 | end 59 | 60 | if prnt, % parent 61 | n = n + 1; 62 | foo = y(:,:,2); 63 | foo = foo(Ly+1:Ly+nblv,Lx+1:Lx+nblh); 64 | Y(:,n) = (foo(:)); 65 | end 66 | 67 | % including neighbor 68 | if neighbor, 69 | for neib=1:Nor 70 | if neib == orien 71 | continue; 72 | end 73 | n=n+1; 74 | nband1 = (scale-1)*Nor+neib+1; % except the ll 75 | aux1 = pyrBand(pyro, pind, nband1); 76 | aux1 = aux1(Ly+1:Ly+nblv,Lx+1:Lx+nblh); 77 | Y(:,n) = (aux1(:)); 78 | end 79 | end 80 | 81 | C_x = innerProd(Y)/nexp; 82 | % C_x is positive definete covariance matrix 83 | [Q,L] = eig(C_x); 84 | % correct possible negative eigenvalues, without changing the overall variance 85 | L = diag(diag(L).*(diag(L)>0))*sum(diag(L))/(sum(diag(L).*(diag(L)>0))+(sum(diag(L).*(diag(L)>0))==0)); 86 | C_x = Q*L*Q'; 87 | 88 | o_c = aux(Ly+1:Ly+nblv,Lx+1:Lx+nblh); 89 | o_c = (o_c(:)); 90 | o_c = o_c - mean(o_c); 91 | [hy rangeo] = hist(o_c,nbins); 92 | hy=hy/sum(hy); 93 | 94 | tempY = (Y*pinv(C_x)).*Y/N; 95 | z = sqrt(sum(tempY,2)); 96 | ind = find(z~=0); 97 | 98 | g_c =o_c(ind)./z(ind); 99 | 100 | 101 | % consider the guardband 102 | 103 | g_c=reshape(g_c,nblv,nblh); 104 | gb = guardband/(2^(scale-1)); 105 | g_c=g_c(gb+1:end-gb, gb+1:end-gb); 106 | size_band(p,:) = size(g_c); 107 | g_c= (g_c(:)); 108 | g_c = g_c - mean(g_c); 109 | 110 | subband{p} = g_c; 111 | 112 | % band_var(p) = var(g_c); 113 | p = p+1; 114 | 115 | % maxz = zRange*4^(scale-1); 116 | % 117 | % range = -maxz:2*maxz/(nbins-1):maxz; 118 | % 119 | % [hyg rangeg] = hist(g_c,range); 120 | % hyg=hyg/sum(hyg); 121 | % 122 | % mu=mean(g_c); 123 | % o_sigma(nband-1)=std(g_c); 124 | % o_range(nband-1,:)= rangeg; 125 | % 126 | % sigma = std(g_c); 127 | % hm = 1/sqrt(2*pi)/sigma*exp(-(range-mu).^2/2/(sigma^2)); 128 | % hm = hm/sum(hm); 129 | % distance(nband-1) = kld(hm,hyg); 130 | end 131 | end 132 | return; 133 | 134 | -------------------------------------------------------------------------------- /+divine/readme.txt: -------------------------------------------------------------------------------- 1 | DIIVINE Software release. 2 | 3 | 4 | ======================================================================== 5 | 6 | -----------COPYRIGHT NOTICE STARTS WITH THIS LINE------------ 7 | Copyright (c) 2010 The University of Texas at Austin 8 | All rights reserved. 9 | 10 | Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, 11 | modify, and distribute this code (the source files) and its documentation for 12 | any purpose, provided that the copyright notice in its entirety appear in all copies of this code, and the 13 | original source of this code, Laboratory for Image and Video Engineering (LIVE, http://live.ece.utexas.edu) 14 | and Center for Perceptual Systems (CPS, http://www.cps.utexas.edu) at the University of Texas at Austin (UT Austin, 15 | http://www.utexas.edu), is acknowledged in any publication that reports research using this code. The research 16 | is to be cited in the bibliography as: 17 | 18 | 1. A. K. Moorthy and A. C. Bovik, "Blind Image Quality Assessment: From Natural 19 | Scene Statistics to Perceptual Quality", IEEE Transactions on Image Processing, to appear (2011). 20 | 21 | 2. A. K. Moorthy and A. C. Bovik, "DIVINE Software Release", 22 | URL: http://live.ece.utexas.edu/research/quality/DIIVINE_release.zip, 2010 23 | 24 | IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT AUSTIN BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, 25 | OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS DATABASE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF TEXAS 26 | AT AUSTIN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | THE UNIVERSITY OF TEXAS AT AUSTIN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE DATABASE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, 30 | AND THE UNIVERSITY OF TEXAS AT AUSTIN HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 31 | 32 | -----------COPYRIGHT NOTICE ENDS WITH THIS LINE------------% 33 | 34 | Author : Anush Krishna Moorthy 35 | Version : 1.1 36 | 37 | The authors are with the Laboratory for Image and Video Engineering 38 | (LIVE), Department of Electrical and Computer Engineering, The 39 | University of Texas at Austin, Austin, TX. 40 | 41 | Kindly report any suggestions or corrections to anushmoorthy@gmail.com 42 | 43 | ======================================================================== 44 | 45 | This is a demonstration of the Distortion Identification based image Verity and INtegrity Evaluation (DIVINE) index. 46 | It is an implementation of the BIQI in the reference. 47 | The algorithm is described in: 48 | A. K. Moorthy and A. C. Bovik, "Blind Image Quality Assessment: From Natural 49 | Scene Statistics to Perceptual Quality", IEEE Transactions on Image Processing, to appear (2011). 50 | 51 | You can change this program as you like and use it anywhere, but please 52 | refer to its original source (cite our paper and our web page at 53 | http://live.ece.utexas.edu/research/quality/DIIVINE_release.zip). 54 | 55 | Input : A test 8bits/pixel grayscale image loaded in a 2-D array 56 | Output: A quality score of the image. The score typically has a value 57 | between 0 and 100 (0 represents the best quality, 100 the worst). 58 | 59 | Usage: 60 | 61 | 1. Load the image, for example 62 | 63 | image = rgb2gray(imread('testimage.jpg')); 64 | 65 | 2. Call this function to calculate the quality score: 66 | 67 | quality = divine(image) 68 | 69 | Dependencies: 70 | Steerable Pyramid Toolbox, Download from: http://www.cns.nyu.edu/~eero/steerpyr/ 71 | LibSVM package for MATLAB, Download from: http://www.csie.ntu.edu.tw/~cjlin/libsvm/ 72 | You may need the MATLAB Image Processing Toolbox 73 | 74 | Dependencies-- 75 | 76 | MATLAB files: ssim_index_new.m, norm_sender_normalized.m, find_spatial_hist_fast.m, divine_overall_quality.m 77 | divine_feature_extract.m, map_matrix_to_closest_vec.m (provided with release) 78 | 79 | Data files: data_live_trained.mat (provided with release) 80 | 81 | This code has been tested on Windows and Mac OSX (Snow Leopard) 82 | 83 | ======================================================================== 84 | 85 | Note on training: 86 | This release version of BIQI was trained on the entire LIVE database. 87 | -------------------------------------------------------------------------------- /+divine/ssim_index_new.m: -------------------------------------------------------------------------------- 1 | function [mssim, ssim_map, mcs, cs_map,sigma1_sq,mu1] = ssim_index_new(img1, img2, K, wind) 2 | 3 | if (nargin < 2 | nargin > 4) 4 | ssim_index = -Inf; 5 | ssim_map = -Inf; 6 | return; 7 | end 8 | 9 | if (size(img1) ~= size(img2)) 10 | ssim_index = -Inf; 11 | ssim_map = -Inf; 12 | return; 13 | end 14 | 15 | [M N] = size(img1); 16 | 17 | if (nargin == 2) 18 | if ((M < 11) | (N < 11)) 19 | ssim_index = -Inf; 20 | ssim_map = -Inf; 21 | return 22 | end 23 | wind = fspecial('gaussian', 11, 1.5); % 24 | K(1) = 0.01; % default settings 25 | K(2) = 0.03; % 26 | end 27 | 28 | if (nargin == 3) 29 | if ((M < 11) | (N < 11)) 30 | ssim_index = -Inf; 31 | ssim_map = -Inf; 32 | return 33 | end 34 | wind = fspecial('gaussian', 11, 1.5); 35 | if (length(K) == 2) 36 | if (K(1) < 0 | K(2) < 0) 37 | ssim_index = -Inf; 38 | ssim_map = -Inf; 39 | return; 40 | end 41 | else 42 | ssim_index = -Inf; 43 | ssim_map = -Inf; 44 | return; 45 | end 46 | end 47 | 48 | if (nargin == 4) 49 | [H W] = size(wind); 50 | if ((H*W) < 4 | (H > M) | (W > N)) 51 | ssim_index = -Inf; 52 | ssim_map = -Inf; 53 | return 54 | end 55 | if (length(K) == 2) 56 | if (K(1) < 0 | K(2) < 0) 57 | ssim_index = -Inf; 58 | ssim_map = -Inf; 59 | return; 60 | end 61 | else 62 | ssim_index = -Inf; 63 | ssim_map = -Inf; 64 | return; 65 | end 66 | end 67 | 68 | C1 = (K(1)*255)^2; 69 | C2 = (K(2)*255)^2; 70 | wind = wind/sum(sum(wind)); 71 | % all 'same' s were 'valid' --anush 72 | mu1 = filter2(wind, img1, 'valid'); 73 | mu2 = filter2(wind, img2, 'valid'); 74 | mu1_sq = mu1.*mu1; 75 | mu2_sq = mu2.*mu2; 76 | mu1_mu2 = mu1.*mu2; 77 | sigma1_sq = filter2(wind, img1.*img1, 'valid') - mu1_sq; 78 | sigma2_sq = filter2(wind, img2.*img2, 'valid') - mu2_sq; 79 | sigma12 = filter2(wind, img1.*img2, 'valid') - mu1_mu2; 80 | 81 | if (C1 > 0 & C2 > 0) 82 | ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2)); 83 | cs_map = (2*sigma12 + C2)./(sigma1_sq + sigma2_sq + C2); 84 | else 85 | numerator1 = 2*mu1_mu2 + C1; 86 | numerator2 = 2*sigma12 + C2; 87 | denominator1 = mu1_sq + mu2_sq + C1; 88 | denominator2 = sigma1_sq + sigma2_sq + C2; 89 | 90 | ssim_map = ones(size(mu1)); 91 | index = (denominator1.*denominator2 > 0); 92 | ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index)); 93 | index = (denominator1 ~= 0) & (denominator2 == 0); 94 | ssim_map(index) = numerator1(index)./denominator1(index); 95 | 96 | cs_map = ones(size(mu1)); 97 | index = denominator2 > 0; 98 | cs_map(index) = numerator2(index)./denominator2(index); 99 | end 100 | 101 | mssim = mean2(ssim_map); 102 | mcs = mean2(cs_map); 103 | 104 | return -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | 10 | # Packages # 11 | ############ 12 | # it's better to unpack these files and commit the raw source 13 | # git has its own built in compression methods 14 | *.7z 15 | *.dmg 16 | *.gz 17 | *.iso 18 | *.jar 19 | *.rar 20 | *.tar 21 | *.zip 22 | 23 | # Logs and databases # 24 | ###################### 25 | *.log 26 | *.sql 27 | *.sqlite 28 | 29 | # OS generated files # 30 | ###################### 31 | .DS_Store? 32 | ehthumbs.db 33 | Icon? 34 | Thumbs.db 35 | 36 | # Matlab/Other # 37 | ################### 38 | *.asv 39 | *.bak -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | Performs MATLAB experiments 294 | Copyright (C) 2012 University of Texas at Austin 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | 311 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gf_image_quality_toolbox 2 | ==================================== 3 | 4 | This matlab toolbox contains utilities for assessing image quality 5 | 6 | 7 | DIVINE: 8 | ---------------------------------------------------------------------- 9 | A. K. Moorthy and A. C. Bovik, "Blind Image Quality Assessment: From Natural 10 | Scene Statistics to Perceptual Quality", IEEE Transactions on Image Processing, to appear (2011). 11 | 12 | A. K. Moorthy and A. C. Bovik, "DIVINE Software Release", 13 | URL: http://live.ece.utexas.edu/research/quality/DIIVINE_release.zip, 2010 14 | 15 | BRISQUE: 16 | ---------------------------------------------------------------------- 17 | A. Mittal, A. K. Moorthy and A. C. Bovik, "BRISQUE Software Release", 18 | URL: http://live.ece.utexas.edu/research/quality/BRISQUE_release.zip, 2011 19 | 20 | A. Mittal, A. K. Moorthy and A. C. Bovik, "No Reference Image Quality Assessment in the Spatial Domain" 21 | submitted 22 | 23 | BLIINDS-2: 24 | ---------------------------------------------------------------------- 25 | M.A Saad and A. C. Bovik, "Blind Image Quality Assessment: A Natural Scene Statistics Approach in the DCT Domain, " 26 | IEEE Transactions on Image Processing, vol. pp, no. 99, pp. 1, Mar. 2012. (early access) 27 | 28 | M.A. Saad, A. C. Bovik, and C. Charrier, "DCT Statistics Model-Based Blind Image Quality Assessment," 29 | Proceedings of the IEEE International Conference on image Processing (ICIP), pp. 3093-3096, Sep. 2011. 30 | 31 | 32 | MS-SSIM 33 | ---------------------------------------------------------------------- 34 | Multi-scale Structural Similarity Index (MS-SSIM) 35 | Z. Wang, E. P. Simoncelli and A. C. Bovik, "Multi-scale structural similarity 36 | for image quality assessment," Invited Paper, IEEE Asilomar Conference on 37 | Signals, Systems and Computers, Nov. 2003 38 | 39 | Z. Wang, A. C. Bovik, H. R. Sheikh, and E. P. Simoncelli, "Image 40 | quality assessment: From error measurement to structural similarity" 41 | IEEE Transactios on Image Processing, vol. 13, no. 1, Jan. 2004. 42 | 43 | 44 | 45 | Copyright notice from SSIM Index 46 | ---------------------------------------------------------------------- 47 | SSIM Index, Version 1.0 48 | Copyright(c) 2003 Zhou Wang 49 | All Rights Reserved. 50 | 51 | The author is with Howard Hughes Medical Institute, and Laboratory 52 | for Computational Vision at Center for Neural Science and Courant 53 | Institute of Mathematical Sciences, New York University. 54 | 55 | Permission to use, copy, or modify this software and its documentation 56 | for educational and research purposes only and without fee is hereby 57 | granted, provided that this copyright notice and the original authors' 58 | names appear on all copies and supporting documentation. This program 59 | shall not be used, rewritten, or adapted as the basis of a commercial 60 | software or hardware product without first obtaining permission of the 61 | authors. The authors make no representations about the suitability of 62 | this software for any purpose. It is provided "as is" without express 63 | or implied warranty. 64 | ---------------------------------------------------------------------- 65 | 66 | 67 | -------------------------------------------------------------------------------- /degraded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/degraded.png -------------------------------------------------------------------------------- /dmos_fit_fns.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/dmos_fit_fns.mat -------------------------------------------------------------------------------- /foveateCutoffFreq.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/foveateCutoffFreq.m -------------------------------------------------------------------------------- /foveateFilterBank.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/foveateFilterBank.m -------------------------------------------------------------------------------- /foveateSensitivity.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/foveateSensitivity.m -------------------------------------------------------------------------------- /foveateSeperableOperator.m: -------------------------------------------------------------------------------- 1 | % self=foveateSeperableOperator(imgSize,foveaLocations, numBands, filterHalfSize) 2 | % creates a fovation operator with precomputed filter banks and masks 3 | % for specific fovea fixation locations. 4 | % imgSize - a 1x2 vector of the image size 5 | % foveaLocation - an nx2 vector of the location each of the fovea or 6 | % fixation points in [row column] form 7 | % numBands - the number of spatial filter banks to use when computing 8 | % the foveated image 9 | % filterHalfSize - 1/2 the size (pixels) of the filter banks filters 10 | % 11 | % returns an object with the foveate method. 12 | % call the foveate method with the actual image 13 | % i.e. foveatedImage=self.fovate(image); 14 | % 15 | % this operator uses the separability of the gaussian kernel for efficient 16 | % computation 17 | % 18 | % the foveation masks are computed from a half power roll off distance and 19 | % a plateau size. 20 | % The two parameters are related to the viewing distance and image size 21 | 22 | function self=foveateSeperableOperator(imgSize,foveaLocations, numBands, filterHalfSize) 23 | 24 | if(nargin<2) 25 | foveaLocations=imgSize./2; 26 | end 27 | if(nargin<3) 28 | numBands=floor(log2(imgSize(1)))-5; 29 | if(numBands<2) 30 | numBands=2; 31 | end 32 | end 33 | if(nargin<4) 34 | filterHalfSize=20; 35 | end 36 | self.imgSize=imgSize; 37 | self.foveaLocations=foveaLocations; 38 | self.numBands=numBands; 39 | self.filterHalfSize=filterHalfSize; 40 | 41 | self.foveate=@foveate; 42 | filterBanks=setupFilters(numBands, filterHalfSize); 43 | masks=setupMasks(imgSize,foveaLocations); 44 | 45 | function masks=setupMasks(imgSize,foveaLocations) 46 | %size of the plateau in the foveation region as a pixel radius. 47 | %platSize = 32; 48 | platSize = imgSize(2)/8; 49 | %minBandwidth = 0.2; 50 | minBandwidth = 0.1; 51 | %HPBW = 10; 52 | % half power bandwidth as a distance in pixels. 53 | % The cutoff frequency rolls off exponentially as eccentricity increases. 54 | % the HPBW distance is the number of pixels over which the cutoff 55 | % frequency halfs. 56 | HPBW = imgSize(1)/16; 57 | f_cutoff = repmat(minBandwidth, imgSize); % cutoff frequency (relative scaled by Fs/2) 58 | % Fs is the pixel spatial freq 59 | lambda = log(2)/HPBW; 60 | rval = @(x,y,x0,y0) sqrt((x-x0).^2+(y-y0).^2)-platSize; 61 | 62 | %Place all of the foveae 63 | [c,r] = meshgrid(1:imgSize(2),1:imgSize(1)); 64 | for iLocation=1:size(foveaLocations,1) 65 | %Note: x=col, y = row; 66 | % distance of each point to the fixation point (minus plateau radius) 67 | d = rval(c,r,foveaLocations(iLocation,2),foveaLocations(iLocation,1)); 68 | d(d <0)=0; 69 | f_cutoff_i= exp(-d*lambda); 70 | 71 | %Use this number in areas where it exceeds the existing bandwidth 72 | f_cutoff= max(f_cutoff_i,f_cutoff); 73 | end 74 | 75 | % create binary masks for which filter corresponds with each point in 76 | % the image 77 | % 78 | % mask index is an index of the filter bank for each point 79 | % band 80 | maskIndex=ceil(f_cutoff*numBands); 81 | maskIndex(maskIndex<1)=1; 82 | maskIndex(maskIndex>numBands)=numBands; 83 | 84 | masks=false([imgSize numBands]); 85 | for iBand=1:numBands 86 | masks(:,:,iBand)=maskIndex==iBand; 87 | end 88 | end 89 | 90 | function filterBanks=setupFilters(numBands, filterHalfSize) 91 | bandStep = 1/(numBands); 92 | fullSize = filterHalfSize*2 - 1; 93 | 94 | filterBanks = zeros([fullSize (numBands-1)]); 95 | cutoffs = NaN(numBands-1, 1); 96 | 97 | for iBand = 1:numBands 98 | cutoffs(iBand) = iBand * bandStep; 99 | sigma = sqrt(-2*log(0.5)) / (pi*cutoffs(iBand)); 100 | f=fspecial('gaussian', fullSize, sigma); 101 | stencil = rot90(f,2); 102 | [u,s,v] = svd(stencil); 103 | hcol = u(:,1) * sqrt(s(1)); 104 | hrow = conj(v(:,1)) * sqrt(s(1)); 105 | if(hcol~=hrow) 106 | disp('Why are the vectors not the same') 107 | end 108 | 109 | filterBanks(:,iBand) = hcol; 110 | end 111 | 112 | end 113 | 114 | function foveated=foveate(image) 115 | 116 | foveated=zeros(size(image)); 117 | filterLength=filterHalfSize-1; 118 | padded=zeros(size(image) + [1 1].*filterLength.*2); 119 | padded(filterLength+1:end-filterLength,filterLength+1:end-filterLength)=image; 120 | % corners 121 | padded(1:filterLength ,1:filterLength )=image(1 ,1 ); 122 | padded(1:filterLength ,end-filterLength+1:end)=image(1 ,end); 123 | padded(end-filterLength+1:end,1:filterLength )=image(end,1 ); 124 | padded(end-filterLength+1:end,end-filterLength+1:end)=image(end,end); 125 | 126 | % sides 127 | %top/bottom 128 | padded(1:filterLength ,filterLength+1:end-filterLength )=repmat(image(1, :),[filterLength 1]); 129 | padded(end-filterLength+1:end,filterLength+1:end-filterLength )=repmat(image(end,:),[filterLength 1]); 130 | %left/right 131 | padded(filterLength+1:end-filterLength ,1:filterLength )=repmat(image(:,1 ),[1 filterLength]); 132 | padded(filterLength+1:end-filterLength ,end-filterLength+1:end)=repmat(image(:,end),[1 filterLength]); 133 | 134 | for iBand=1:numBands-1 135 | f= conv2(filterBanks(:,iBand),filterBanks(:,iBand),padded,'valid'); 136 | foveated(masks(:,:,iBand))=f(masks(:,:,iBand)); 137 | %figure(2), imagesc(foveated), colorbar 138 | end 139 | % no filtering for center of fovea 140 | foveated(masks(:,:,numBands))=image(masks(:,:,numBands)); 141 | 142 | end 143 | end 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /foveateWaveletMask.m: -------------------------------------------------------------------------------- 1 | % self=foveateSeperableOperator(imgSize,foveaLocations, numBands, filterHalfSize) 2 | % creates a fovation operator with precomputed filter banks and masks 3 | % for specific fovea fixation locations. 4 | % imgSize - a 1x2 vector of the image size 5 | % foveaLocation - an nx2 vector of the location each of the fovea or 6 | % fixation points in [row column] form 7 | % numBands - the number of spatial filter banks to use when computing 8 | % the foveated image 9 | % filterHalfSize - 1/2 the size (pixels) of the filter banks filters 10 | % 11 | % returns an object with the foveate method. 12 | % call the foveate method with the actual image 13 | % i.e. foveatedImage=self.fovate(image); 14 | % 15 | % this operator uses the separability of the gaussian kernel for efficient 16 | % computation 17 | 18 | function self=foveateWaveletMask(imgSize,foveaLocations, numBands, filterHalfSize) 19 | 20 | if(nargin<2) 21 | foveaLocations=imgSize./2; 22 | end 23 | if(nargin<3) 24 | numBands=floor(log2(imgSize(1)))-5; 25 | if(numBands<2) 26 | numBands=2; 27 | end 28 | end 29 | if(nargin<4) 30 | filterHalfSize=20; 31 | end 32 | self.imgSize=imgSize; 33 | self.foveaLocations=foveaLocations; 34 | self.numBands=numBands; 35 | self.filterHalfSize=filterHalfSize; 36 | 37 | self.getMask=@getMask; 38 | filterBanks=setupFilters(numBands, filterHalfSize); 39 | masks=setupMasks(imgSize,foveaLocations); 40 | 41 | function masks=setupMasks(imgSize,foveaLocations) 42 | %platSize = 32; 43 | platSize = imgSize(2)/8; 44 | %minBandwidth = 0.2; 45 | minBandwidth = 0.1; 46 | %HPBW = 10; 47 | HPBW = imgSize(1)/16; 48 | maskBins = repmat(minBandwidth, imgSize); 49 | lambda = log(2)/HPBW; 50 | rval = @(x,y,x0,y0) sqrt((x-x0).^2+(y-y0).^2)-platSize; 51 | 52 | %Place all of the foveae 53 | [c,r] = meshgrid(1:imgSize(2),1:imgSize(1)); 54 | for iLocation=1:size(foveaLocations,1) 55 | %Note: x=col, y = row; 56 | curr = rval(c,r,foveaLocations(iLocation,2),foveaLocations(iLocation,1)); 57 | fovControl = exp(-curr*lambda); 58 | fovControl(curr<0) = 1; 59 | 60 | %Use this number in areas where it exceeds the existing bandwidth 61 | maskBins(fovControl>maskBins) = fovControl(fovControl>maskBins); 62 | end 63 | maskIndex=ceil(maskBins*numBands); 64 | maskIndex(maskIndex<1)=1; 65 | maskIndex(maskIndex>numBands)=numBands; 66 | masks=false([imgSize numBands]); 67 | %figure(1), imagesc(maskIndex), colorbar 68 | for iBand=1:numBands 69 | masks(:,:,iBand)=maskIndex==iBand; 70 | end 71 | end 72 | 73 | function filterBanks=setupFilters(numBands, filterHalfSize) 74 | bandStep = 1/(numBands); 75 | fullSize = filterHalfSize*2 - 1; 76 | 77 | filterBanks = zeros([fullSize (numBands-1)]); 78 | cutoffs = NaN(numBands-1, 1); 79 | 80 | for iBand = 1:numBands 81 | cutoffs(iBand) = iBand * bandStep; 82 | sigma = sqrt(-2*log(0.5)) / (pi*cutoffs(iBand)); 83 | f=fspecial('gaussian', fullSize, sigma); 84 | stencil = rot90(f,2); 85 | [u,s,v] = svd(stencil); 86 | hcol = u(:,1) * sqrt(s(1)); 87 | hrow = conj(v(:,1)) * sqrt(s(1)); 88 | if(hcol~=hrow) 89 | disp('Why are the vectors not the same') 90 | end 91 | 92 | filterBanks(:,iBand) = hcol; 93 | end 94 | 95 | end 96 | 97 | 98 | function mask=getMask 99 | 100 | mask=zeros(self.imgSize); 101 | mask(1,1)=1; 102 | 103 | for k=1:(log2(self.imgSize(1))-1) 104 | k2=2.^k; 105 | end 106 | % no filtering for center of fovea 107 | % foveated(masks(:,:,numBands))=image(masks(:,:,numBands)); 108 | 109 | end 110 | end 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /foveateWaveletSensitivity.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/foveateWaveletSensitivity.m -------------------------------------------------------------------------------- /foveateWaveletSensitivityTest.m: -------------------------------------------------------------------------------- 1 | function foveateWaveletSensitivityTest 2 | 3 | w1=foveateWaveletSensitivity([512,512],[],4,1); 4 | w3=foveateWaveletSensitivity([512,512],[],4,3); 5 | w7=foveateWaveletSensitivity([512,512],[],4,7); 6 | figure(1),imagesc(w3) 7 | colormap gray 8 | axis off 9 | axis square 10 | % title('\nu=3, p_f=[256 256]') 11 | outputFigure(1,'wavelet_foveation_sensitivity',1,'-depsc2') 12 | 13 | t=median(w1(:)); 14 | t 15 | t=max(w1(:))*0.01; 16 | t 17 | m1=w1>t; 18 | 19 | t=median(w3(:)); 20 | t 21 | t=max(w3(:))*0.01; 22 | t 23 | m3=w3>t; 24 | 25 | t=median(w7(:)); 26 | t 27 | t=max(w7(:))*0.01; 28 | t 29 | m7=w7>t; 30 | 31 | a1=sum(m1(:))/512^2; 32 | a3=sum(m3(:))/512^2; 33 | a7=sum(m7(:))/512^2; 34 | a1 35 | a3 36 | a7 37 | 38 | 39 | 40 | % figure(2),imagesc(m) 41 | % colormap gray 42 | 43 | 44 | figure(2) 45 | colormap gray 46 | subplot(3,1,1) 47 | imagesc(w1) 48 | title('v=1') 49 | subplot(3,1,2) 50 | imagesc(w3) 51 | title('v=3') 52 | subplot(3,1,3) 53 | imagesc(w7) 54 | title('v=7') 55 | 56 | 57 | figure(3) 58 | colormap gray 59 | subplot(3,1,1) 60 | imagesc(m1) 61 | title('\nu=1') 62 | subplot(3,1,2) 63 | imagesc(m3) 64 | title('v=3') 65 | subplot(3,1,3) 66 | imagesc(m7) 67 | title('v=7') 68 | 69 | sum(m1(:)) 70 | sum(m3(:)) 71 | sum(m7(:)) 72 | 73 | foveateWaveletSensitivity([512,512],[],4,7,struct('use_band_weighting',0,'plot_band_weighting',0)); 74 | foveateWaveletSensitivity([512,512],[],4,7,struct('use_band_weighting',0,'plot_band_weighting',1)); 75 | foveateWaveletSensitivity([512,512],[],4,7,struct('use_band_weighting',1,'plot_band_weighting',0)); 76 | foveateWaveletSensitivity([512,512],[],4,7,struct('use_band_weighting',1,'plot_band_weighting',1)); 77 | 78 | w=foveateSensitivity([512,512],[],3); 79 | imagesc(w) 80 | colorbar 81 | -------------------------------------------------------------------------------- /foveation_test.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %% test that the filter frequency response has the appropriate cutoff 5 | N=10; 6 | figure(1) 7 | hold off 8 | for i=1:N 9 | sigma=sqrt(2*log(2))/pi*N/i; 10 | sigmas(i)=sigma; 11 | l=ceil(sigma*3+1); 12 | t1=-l:l; 13 | h1=exp(-(t1.^2)./2./sigma./sigma)./sqrt(2*pi*sigma*sigma); 14 | sum(h1) 15 | h1=h1./sum(h1); 16 | % fvtool(h1,[1]) 17 | n=512; 18 | h2=[h1 zeros(1,n-length(h1))]; 19 | f=linspace(-1,1,n+1); 20 | f=f(1:n); 21 | plot(f,fftshift(abs(fft(h2)).^2)) 22 | if i==1 23 | hold on 24 | end 25 | 26 | pass=fftshift(abs(fft(h2)).^2)>0.5; 27 | epass=fftshift(abs(fft(h2)))>0.5; 28 | fc=max(abs(f(pass))); 29 | fc2=max(abs(f(epass))); 30 | fcs(i)=fc; 31 | fcs2(i)=fc2; 32 | end 33 | 34 | fcs=fcs(1:end-2); 35 | fcs2=fcs2(1:end-2); 36 | sigmas=sigmas(1:end-2); 37 | 38 | figure(2) 39 | % hold off 40 | plot(fcs,1./sigmas,'b') 41 | xlabel 'freq (cutoff)' 42 | ylabel '1/\sigma' 43 | 44 | 45 | ratio=sqrt(2*log(2))/pi; 46 | 47 | figure(3) 48 | % hold off 49 | plot(fcs.*sigmas.*pi./sqrt(2*log(2)),'b*-') 50 | xlabel 'case' 51 | ylabel 'ratio' 52 | 53 | figure(4) 54 | % hold off 55 | plot(fcs2.*sigmas.*pi./sqrt(2*log(2)),'b*-') 56 | xlabel 'case' 57 | ylabel 'ratio' 58 | 59 | % hold on 60 | % plot(fcs,sigmas.^2,'g') 61 | % plot(fcs.^2,sigmas,'r') 62 | % plot(sqrt(fcs),sigmas,'c') 63 | % plot(fcs,sqrt(sigmas),'k') 64 | 65 | %% compare different models of foveation rolloff 66 | 67 | x=(-n/2):(n/2-1); 68 | 69 | platSize = n/4; 70 | minBandwidth = 0.1; 71 | HPBW = n/4; 72 | maskBins = minBandwidth .*ones(size(x)); 73 | lambda = log(2)/HPBW; 74 | r1=@(x) sqrt((x).^2); 75 | r2=@(x) sqrt((x).^2)-platSize; 76 | 77 | 78 | curr = r2(x); 79 | curr(curr<0) =0; 80 | fovControl = exp(-curr*lambda); 81 | 82 | maskBins(fovControl>maskBins) = fovControl(fovControl>maskBins); 83 | 84 | figure(5) 85 | hold off 86 | h1=plot(maskBins.*0.5,'g') 87 | 88 | numBands=8; 89 | %Use this number in areas where it exceeds the existing bandwidth 90 | maskIndex=ceil(maskBins*numBands); 91 | maskIndex(maskIndex<1)=1; 92 | maskIndex(maskIndex>numBands)=numBands; 93 | 94 | d = r1(x); 95 | 96 | view_dist=1; 97 | alpha=0.106; 98 | e_2=2.3; 99 | CT_0=1/64; 100 | 101 | e=atan(d./view_dist./n).*180./pi; % eccentricity in degrees. 102 | 103 | % f[i] = s/pow(sep,-i)*0.0175*viewDistance/pixelWidth; 104 | % norm = max(norm,exp(-alpha*f[i])); 105 | % e[y][x] = min(e[y][x],atan(sqrt(pow(fovea[i]*a.cols-x,2)+pow(fovea[numFovea+i]*a.rows-y,2))*pixelWidth/viewDistance)*180.0/PI); 106 | % double w = exp(-alpha*f[i]*(e[y+5][x+5]+e2)/e2)/norm; 107 | % e_prime = atan(d*pixelWidth/viewDistance)*180.0/pi; 108 | 109 | % Sf_prime = exp(-alpha.*f.*(e+e_2)./e_2); 110 | 111 | %CT=CT_0*exp(alpha.*f.*(e+e_2)./e_2); 112 | %CS=1./CT; 113 | f_c=e_2*log(1/CT_0)./(alpha*(e+e_2));% cycles/degree 114 | 115 | res=pi*n*view_dist./180; % spatial resolution in cycles/degree 116 | 117 | f_m=min(f_c,res./2); 118 | hold on 119 | h2=plot(f_m./view_dist./n.*180./pi)% cycles/degree to cycles per pixel 120 | 121 | legend([h1,h2],{'Larcom','Wang'}) 122 | 123 | 124 | %% compare different fit functions 125 | 126 | figure(6) 127 | t=0:0.01:3; 128 | a=exp(-t); 129 | e2=2; 130 | b=e2./(e2+3.*t); 131 | c=1-t+t.*t./2-t.^3./6; % taylor series 132 | % plot(t,[a;b;c]') 133 | plot(t,[a;b]') 134 | 135 | 136 | 137 | %% compare foveated images with 2 methods 138 | 139 | data=FoveatedImageData(2); 140 | image=data.image; 141 | 142 | imageSize=size(image); 143 | 144 | options1=struct(); 145 | options1.viewDist=1; 146 | options1.numBands=20; 147 | options1.filterHalfSize=20; 148 | foveator1=foveateFilterBank(imageSize,data.fovea,options1); 149 | 150 | options2=struct(); 151 | options2.numBands=20; 152 | options2.filterHalfSize=20; 153 | options2.cutoffMethod='Larcom'; 154 | 155 | options4=struct(); 156 | options4.numBands=20; 157 | options4.filterHalfSize=20; 158 | options4.cutoffMethod='Larcom'; 159 | n=min(imageSize); 160 | options4.platSize=n/4; 161 | options4.HPBW=n/4; 162 | options4.minBandwidth = 0.1; 163 | 164 | foveator2=foveateFilterBank(imageSize,data.fovea,options2); 165 | foveator3=foveateSeperableOperator(imageSize,data.fovea, 20, 20); 166 | foveator4=foveateFilterBank(imageSize,data.fovea,options4); 167 | image1=foveator1.foveate(image); 168 | image2=foveator2.foveate(image); 169 | image3=foveator3.foveate(image); 170 | image4=foveator4.foveate(image); 171 | 172 | figure(7) 173 | subplot(2,3,1) 174 | imagesc(image1) 175 | colormap gray 176 | axis square off 177 | 178 | subplot(2,3,2) 179 | imagesc(image4) 180 | % imagesc(image) 181 | colormap gray 182 | axis square off 183 | 184 | subplot(2,3,3) 185 | imagesc(image) 186 | colormap gray 187 | axis square off 188 | 189 | subplot(2,3,4) 190 | imagesc(image2) 191 | colormap gray 192 | axis square off 193 | 194 | subplot(2,3,5) 195 | imagesc(image3) 196 | colormap gray 197 | axis square off 198 | 199 | subplot(2,3,6) 200 | imagesc(image) 201 | colormap gray 202 | axis square off 203 | -------------------------------------------------------------------------------- /fssim.m: -------------------------------------------------------------------------------- 1 | % overall_mssim = fssim(img1, img2, options) 2 | % computes the foveated structural similarity index 3 | % 4 | % 5 | % 6 | function [overall_fssim,fssim_map,debug_data] = fssim(img1, img2, options) 7 | 8 | % Foveated Structural Similarity Index (F-SSIM) 9 | % 10 | % 11 | % 12 | % Z. Wang, E. P. Simoncelli and A. C. Bovik, "Multi-scale structural similarity 13 | % for image quality assessment," Invited Paper, IEEE Asilomar Conference on 14 | % Signals, Systems and Computers, Nov. 2003 15 | 16 | if (nargin < 2 || nargin > 3) 17 | overall_ssim = -Inf; 18 | return; 19 | end 20 | 21 | if(~exist('options','var') || isempty(options)) 22 | options=struct(); 23 | end 24 | if(~isfield(options,'K')) 25 | options.K = [0.01 0.03]; 26 | end 27 | 28 | if(~isfield(options,'win')) 29 | options.win = fspecial('gaussian', 11, 1.5); 30 | end 31 | 32 | if(~isfield(options,'levels')) 33 | options.levels = 5; 34 | end 35 | 36 | if(~isfield(options,'weight')) 37 | options.weight = [0.0448 0.2856 0.3001 0.2363 0.1333]; 38 | end 39 | 40 | if(~isfield(options,'method')) 41 | options.method = 'product'; 42 | end 43 | 44 | [M N] = size(img1); 45 | if(~isfield(options,'fovea')) 46 | options.fovea = [floor(M/2) floor(N/2)]; 47 | end 48 | 49 | if(~isfield(options,'viewDist')) 50 | options.viewDist = 3; 51 | end 52 | 53 | K=options.K; 54 | win=options.win; 55 | levels=options.levels; 56 | weight=options.weight; 57 | method=options.method; 58 | fovea=options.fovea; 59 | viewDist=options.viewDist; 60 | 61 | imgSize=size(img1); 62 | 63 | if (size(img1) ~= size(img2)) 64 | overall_mssim = -Inf; 65 | return; 66 | end 67 | 68 | [M N] = size(img1); 69 | if ((M < 11) || (N < 11)) 70 | overall_mssim = -Inf; 71 | return 72 | end 73 | 74 | if (length(K) ~= 2) 75 | overall_mssim = -Inf; 76 | return; 77 | end 78 | 79 | if (K(1) < 0 || K(2) < 0) 80 | overall_mssim = -Inf; 81 | return; 82 | end 83 | 84 | [H W] = size(win); 85 | 86 | if ((H*W)<4 || (H>M) || (W>N)) 87 | overall_mssim = -Inf; 88 | return; 89 | end 90 | 91 | if (levels < 1) 92 | overall_mssim = -Inf; 93 | return 94 | end 95 | 96 | 97 | min_img_width = min(M, N)/(2^(levels-1)); 98 | max_win_width = max(H, W); 99 | if (min_img_width < max_win_width) 100 | overall_mssim = -Inf; 101 | return; 102 | end 103 | 104 | if (length(weight) ~= levels || sum(weight) == 0) 105 | overall_mssim = -Inf; 106 | return; 107 | end 108 | 109 | if ~((strcmp(method,'wtd_sum') || strcmp(method,'product'))) 110 | overall_mssim = -Inf; 111 | return; 112 | end 113 | 114 | im1 = double(img1); 115 | im2 = double(img2); 116 | 117 | %levels = 5; 118 | k_band = 5; 119 | s = 0.5; 120 | sep = 0.41; 121 | 122 | bands1=subbands(im1,levels,sep,k_band,s); 123 | bands2=subbands(im2,levels,sep,k_band,s); 124 | 125 | normalize=0; 126 | f=zeros(levels,1); 127 | pixelWidth = 1/max(imgSize); 128 | alpha = 0.106; 129 | for iLevel = 1:levels 130 | f(iLevel) = s/(sep^-(iLevel-1))*0.0175*viewDist/pixelWidth; 131 | normalize = max(normalize,exp(-alpha*f(iLevel))); 132 | end 133 | 134 | fssim_map=ones(imgSize-[10 10]); 135 | fssim_band=zeros([(imgSize-[10 10]) levels]); 136 | ssim_array=zeros(levels,1); 137 | ssim_map_array=cell(levels,1); 138 | cs_array=zeros(levels,1); 139 | cs_map_array=cell(levels,1); 140 | Sf_array=zeros([(imgSize-[10 10]) levels]); 141 | debug_data=cell(3,1); 142 | debug_data{1}=cell(levels,1); 143 | debug_data{2}=cell(levels,1); 144 | debug_data{3}=cell(levels,1); 145 | 146 | for iLevel = 1:levels 147 | [ssim_array(iLevel) ssim_map_array{iLevel} cs_array(iLevel) cs_map_array{iLevel}] = ... 148 | ssim_index_new(bands1{iLevel}, bands2{iLevel}, K, win); 149 | debug_data{1}{iLevel}= ssim_map_array{iLevel}; 150 | [Sf,e]=foveateSensitivity(imgSize,fovea, f(iLevel), viewDist); 151 | Sf=Sf./normalize; 152 | % Sf(f(iLevel)>f_m)=0; 153 | mapSize=size(ssim_map_array{iLevel}); 154 | offset=(imgSize-mapSize)./2; 155 | SfTrim=Sf(offset(1)+1:offset(1)+mapSize(1), ... 156 | offset(2)+1:offset(2)+mapSize(2)); 157 | debug_data{2}{iLevel}= SfTrim; 158 | map=ssim_map_array{iLevel}; 159 | map(map<0)=0; 160 | Sf_array(:,:,iLevel)=SfTrim; 161 | fssim_band(:,:,iLevel)=map.^SfTrim; 162 | debug_data{3}{iLevel}= fssim_band(:,:,iLevel); 163 | fssim_map=fssim_map.*fssim_band(:,:,iLevel); 164 | debug_data{4}=e; 165 | end 166 | 167 | overall_fssim =mean2(fssim_map); 168 | 169 | 170 | function bands=subbands(img,levels,sep,k,s) 171 | bands=cell(levels,1); 172 | sp = sqrt(log(k))/(pi*s*sqrt(k^2-1)); 173 | % hsize=[11 11]; 174 | for iLevel=1:(levels-1) 175 | sigma1=sp*sep^(-(iLevel-1)); 176 | sigma2=sp*k*sep^(-(iLevel-1)); 177 | % hsize=ceil(sigma1*3); 178 | ksize=floor(sigma2*8+1+0.5); 179 | % if(ksize>hsize(1)) 180 | % warning('small kernel size') 181 | % end 182 | 183 | kernel1=fspecial('gaussian', [ksize ksize],sigma1); 184 | kernel2=fspecial('gaussian', [ksize ksize],sigma2); 185 | 186 | m1=imfilter(img,kernel1,'symmetric','same'); 187 | m2=imfilter(img,kernel2,'symmetric','same'); 188 | bands{iLevel}=m2-m1; 189 | end 190 | sigma1=s*sep^(-(levels-1)); 191 | ksize=floor(sigma1*8+1+0.5); 192 | % if(ksize>hsize(1)) 193 | % warning('small kernel size') 194 | % end 195 | kernel1=fspecial('gaussian', [ksize ksize],sigma1); 196 | bands{levels}=imfilter(img,kernel1); 197 | -------------------------------------------------------------------------------- /fssim_test.m: -------------------------------------------------------------------------------- 1 | %testing for fsbssim_index 2 | 3 | addpath('C:/Development/Contracts/RFCode/branches/diagnostics/cpp/SB-SSIM/Release') 4 | addpath('C:/Development/Contracts/RFCode/branches/diagnostics/cpp/SB-SSIM/Debug') 5 | addpath('C:/Development/Contracts/RFCode/branches/diagnostics/cpp/SB-SSIM/MexTest') 6 | 7 | fov = [180/512 256/512]; 8 | 9 | nTests=2; 10 | q=zeros(1,nTests); 11 | Qarray=cell(1,nTests); 12 | t=zeros(1,nTests); 13 | k=5; 14 | sep=0.41; 15 | l=5; 16 | weights=[0.0448,0.2856,0.3001,0.2363,0.1333]; 17 | 18 | fName ='Cameraman.BMP'; 19 | image1= imread(fName); 20 | fName2 = 'Cameraman_MS0.BMP'; 21 | image2=imread(fName2); 22 | 23 | % offset=128+64; 24 | % image1s=image1(offset+1:offset+128,offset+1:offset+128); 25 | % image2s=image2(offset+1:offset+128,offset+1:offset+128); 26 | 27 | iCase = 1; 28 | %refs={ image1, double(image1) , uint16(image1) } ; 29 | %tests={ image2, double(image2), image1 } ; 30 | for refs={ double(image1) } 31 | %for iRef=1:2 32 | % for iTest=1:2 33 | % for tests={ double(image2s), double(image1s) } 34 | for tests={ double(image2) } 35 | % ref=refs{iRef}; 36 | % test=tests{iTest}; 37 | test=tests{1}; 38 | ref=refs{1}; 39 | 40 | whos test 41 | whos ref 42 | 43 | % try 44 | display fsbssim_index 45 | tic 46 | imgSize=size(test); 47 | [q(iCase) ,Qarray{iCase},debug_data_mex]=fsbssim_indexd(test,ref,fov); 48 | t(iCase)=toc; 49 | iCase=iCase+1; 50 | % catch exception 51 | % disp(exception) 52 | % disp(exception.stack) 53 | % end 54 | % 55 | 56 | % try 57 | display fssim 58 | tic 59 | [q(iCase) ,Qarray{iCase},debug_data_m]=fssim(test,ref,struct('fovea',fov.*imgSize)); 60 | t(iCase)=toc; 61 | iCase=iCase+1; 62 | % catch exception 63 | % disp(exception) 64 | % end 65 | 66 | end 67 | end 68 | 69 | imagesc([Qarray{1} Qarray{2}.*255]) 70 | colormap gray 71 | colorbar 72 | 73 | 74 | debug_data_mex=debug_data_mex([3,1,2,4]); 75 | 76 | figure(1) 77 | for i=1:5 78 | subplot(3,1,1) 79 | imagesc([debug_data_mex{1}{i} debug_data_m{1}{i}]) 80 | colormap gray 81 | colorbar 82 | subplot(3,1,2) 83 | imagesc([debug_data_mex{2}{i} debug_data_m{2}{i}]) 84 | colormap gray 85 | colorbar 86 | subplot(3,1,3) 87 | imagesc([debug_data_mex{3}{i} debug_data_m{3}{i}]) 88 | colormap gray 89 | colorbar 90 | %pause(0.5) 91 | end 92 | 93 | figure(2) 94 | e=debug_data_m{4}(6:507,6:507); 95 | imagesc([debug_data_mex{4} e]) 96 | colormap gray 97 | colorbar 98 | 99 | % stack image levels together 100 | sz=502; 101 | a=zeros(sz*5,sz*2); 102 | b=zeros(sz*5,sz*2); 103 | c=zeros(sz*5,sz*2); 104 | for i=1:5 105 | a(1+(i-1)*sz:i*sz,:)=[debug_data_mex{1}{i} debug_data_m{1}{i}]; 106 | b(1+(i-1)*sz:i*sz,:)=[debug_data_mex{2}{i} debug_data_m{2}{i}]; 107 | c(1+(i-1)*sz:i*sz,:)=[debug_data_mex{3}{i} debug_data_m{3}{i}]; 108 | end 109 | figure(3) 110 | imagesc(a) 111 | colormap gray 112 | colorbar 113 | axis off 114 | axis square 115 | % figure(4) 116 | % imagesc(b) 117 | % colormap gray 118 | % colorbar 119 | % axis off 120 | % axis square 121 | figure(5) 122 | imagesc(c) 123 | colormap gray 124 | colorbar 125 | axis off 126 | axis square 127 | %pause(0.5) 128 | 129 | figure(6) 130 | imagesc([Qarray{1} Qarray{2}.*255]) 131 | colormap gray 132 | colorbar 133 | axis off 134 | axis square 135 | -------------------------------------------------------------------------------- /image_mse_foveated.m: -------------------------------------------------------------------------------- 1 | function [mse,mse2,fmse]=image_mse_foveated(inputImage,outputImage,fovea,foveator) 2 | %[mse,mse2,fmse]=image_mse_foveated(inputImage,outputImage,fovea,foveator) 3 | % mse is the mse between the foveated reference and foveated output 4 | % mse2 is the mse between the foveated reference and unaltered output 5 | % fmse is the mse between the unaltered reference and unaltered output 6 | % weighted by the foveation cutoff frequency 7 | % 8 | 9 | [n1,n2]=size(inputImage); 10 | if ~exist('foveator','var') 11 | options1=struct(); 12 | options1.viewDist=1; 13 | options1.numBands=20; 14 | options1.filterHalfSize=20; 15 | foveator=foveateFilterBank([n1,n2],fovea,options1); 16 | end 17 | foveatedInputImage=foveator.foveate(inputImage); 18 | foveatedOutputImage=foveator.foveate(outputImage); 19 | 20 | sqerror=(foveatedInputImage-foveatedOutputImage).^2; 21 | mse=mean(sqerror(:)); 22 | sqerror2=(foveatedInputImage-outputImage).^2; 23 | mse2=mean(sqerror2(:)); 24 | 25 | f_cutoff=foveateCutoffFreq([n1,n2],fovea, foveator.options); 26 | f_cutoff_sum=sum(f_cutoff(:)); 27 | sqerror3=(inputImage-outputImage).^2; 28 | sqerror3_weighted=sqerror3.*f_cutoff.^2./f_cutoff_sum; 29 | fmse=sum(sqerror3_weighted(:)); 30 | -------------------------------------------------------------------------------- /msssim.m: -------------------------------------------------------------------------------- 1 | function overall_mssim = msssim(img1, img2, K, win, level, weight, method) 2 | 3 | % Multi-scale Structural Similarity Index (MS-SSIM) 4 | % Z. Wang, E. P. Simoncelli and A. C. Bovik, "Multi-scale structural similarity 5 | % for image quality assessment," Invited Paper, IEEE Asilomar Conference on 6 | % Signals, Systems and Computers, Nov. 2003 7 | 8 | if (nargin < 2 || nargin > 7) 9 | overall_mssim = -Inf; 10 | return; 11 | end 12 | 13 | if (~exist('K')) 14 | K = [0.01 0.03]; 15 | end 16 | 17 | if (~exist('win')) 18 | win = fspecial('gaussian', 11, 1.5); 19 | end 20 | 21 | if (~exist('level')) 22 | level = 5; 23 | end 24 | 25 | if (~exist('weight')) 26 | weight = [0.0448 0.2856 0.3001 0.2363 0.1333]; 27 | end 28 | 29 | if (~exist('method')) 30 | method = 'product'; 31 | end 32 | 33 | if (size(img1) ~= size(img2)) 34 | overall_mssim = -Inf; 35 | return; 36 | end 37 | 38 | [M N] = size(img1); 39 | if ((M < 11) || (N < 11)) 40 | overall_mssim = -Inf; 41 | return 42 | end 43 | 44 | if (length(K) ~= 2) 45 | overall_mssim = -Inf; 46 | return; 47 | end 48 | 49 | if (K(1) < 0 || K(2) < 0) 50 | overall_mssim = -Inf; 51 | return; 52 | end 53 | 54 | [H W] = size(win); 55 | 56 | if ((H*W)<4 || (H>M) || (W>N)) 57 | overall_mssim = -Inf; 58 | return; 59 | end 60 | 61 | if (level < 1) 62 | overall_mssim = -Inf; 63 | return 64 | end 65 | 66 | 67 | min_img_width = min(M, N)/(2^(level-1)); 68 | max_win_width = max(H, W); 69 | if (min_img_width < max_win_width) 70 | overall_mssim = -Inf; 71 | return; 72 | end 73 | 74 | if (length(weight) ~= level || sum(weight) == 0) 75 | overall_mssim = -Inf; 76 | return; 77 | end 78 | 79 | if (method ~= 'wtd_sum' & method ~= 'product') 80 | overall_mssim = -Inf; 81 | return; 82 | end 83 | 84 | downsample_filter = ones(2)./4; 85 | im1 = double(img1); 86 | im2 = double(img2); 87 | for l = 1:level 88 | [mssim_array(l) ssim_map_array{l} mcs_array(l) cs_map_array{l}] = ssim_index_new(im1, im2, K, win); 89 | % [M N] = size(im1); 90 | filtered_im1 = imfilter(im1, downsample_filter, 'symmetric', 'same'); 91 | filtered_im2 = imfilter(im2, downsample_filter, 'symmetric', 'same'); 92 | clear im1, im2; 93 | im1 = filtered_im1(1:2:end, 1:2:end); 94 | im2 = filtered_im2(1:2:end, 1:2:end); 95 | end 96 | 97 | if (method == 'product') 98 | % overall_mssim = prod(mssim_array.^weight); 99 | overall_mssim = prod(mcs_array(1:level-1).^weight(1:level-1))*(mssim_array(level).^weight(level)); 100 | else 101 | weight = weight./sum(weight); 102 | overall_mssim = sum(mcs_array(1:level-1).*weight(1:level-1)) + mssim_array(level).*weight(level); 103 | end 104 | -------------------------------------------------------------------------------- /reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregfreeman/image_quality_toolbox/39c5b35fffbe69f5be0e8c28d5acb3c2960f503a/reference.png -------------------------------------------------------------------------------- /ssim_index_m.m: -------------------------------------------------------------------------------- 1 | function [mssim, ssim_map] = ssim_index(img1, img2, K, window, L) 2 | 3 | %======================================================================== 4 | %SSIM Index, Version 1.0 5 | %Copyright(c) 2003 Zhou Wang 6 | %All Rights Reserved. 7 | % 8 | %The author is with Howard Hughes Medical Institute, and Laboratory 9 | %for Computational Vision at Center for Neural Science and Courant 10 | %Institute of Mathematical Sciences, New York University. 11 | % 12 | %---------------------------------------------------------------------- 13 | %Permission to use, copy, or modify this software and its documentation 14 | %for educational and research purposes only and without fee is hereby 15 | %granted, provided that this copyright notice and the original authors' 16 | %names appear on all copies and supporting documentation. This program 17 | %shall not be used, rewritten, or adapted as the basis of a commercial 18 | %software or hardware product without first obtaining permission of the 19 | %authors. The authors make no representations about the suitability of 20 | %this software for any purpose. It is provided "as is" without express 21 | %or implied warranty. 22 | %---------------------------------------------------------------------- 23 | % 24 | %This is an implementation of the algorithm for calculating the 25 | %Structural SIMilarity (SSIM) index between two images. Please refer 26 | %to the following paper: 27 | % 28 | %Z. Wang, A. C. Bovik, H. R. Sheikh, and E. P. Simoncelli, "Image 29 | %quality assessment: From error measurement to structural similarity" 30 | %IEEE Transactios on Image Processing, vol. 13, no. 1, Jan. 2004. 31 | % 32 | %Kindly report any suggestions or corrections to zhouwang@ieee.org 33 | % 34 | %---------------------------------------------------------------------- 35 | % 36 | %Input : (1) img1: the first image being compared 37 | % (2) img2: the second image being compared 38 | % (3) K: constants in the SSIM index formula (see the above 39 | % reference). defualt value: K = [0.01 0.03] 40 | % (4) window: local window for statistics (see the above 41 | % reference). default widnow is Gaussian given by 42 | % window = fspecial('gaussian', 11, 1.5); 43 | % (5) L: dynamic range of the images. default: L = 255 44 | % 45 | %Output: (1) mssim: the mean SSIM index value between 2 images. 46 | % If one of the images being compared is regarded as 47 | % perfect quality, then mssim can be considered as the 48 | % quality measure of the other image. 49 | % If img1 = img2, then mssim = 1. 50 | % (2) ssim_map: the SSIM index map of the test image. The map 51 | % has a smaller size than the input images. The actual size: 52 | % size(img1) - size(window) + 1. 53 | % 54 | %Default Usage: 55 | % Given 2 test images img1 and img2, whose dynamic range is 0-255 56 | % 57 | % [mssim ssim_map] = ssim_index(img1, img2); 58 | % 59 | %Advanced Usage: 60 | % User defined parameters. For example 61 | % 62 | % K = [0.05 0.05]; 63 | % window = ones(8); 64 | % L = 100; 65 | % [mssim ssim_map] = ssim_index(img1, img2, K, window, L); 66 | % 67 | %See the results: 68 | % 69 | % mssim %Gives the mssim value 70 | % imshow(max(0, ssim_map).^4) %Shows the SSIM index map 71 | % 72 | %======================================================================== 73 | 74 | 75 | if (nargin < 2 || nargin > 5) 76 | ssim_index = -Inf; 77 | ssim_map = -Inf; 78 | return; 79 | end 80 | 81 | if (size(img1) ~= size(img2)) 82 | ssim_index = -Inf; 83 | ssim_map = -Inf; 84 | return; 85 | end 86 | 87 | [M N] = size(img1); 88 | 89 | if (nargin == 2) 90 | if ((M < 11) || (N < 11)) 91 | ssim_index = -Inf; 92 | ssim_map = -Inf; 93 | return 94 | end 95 | window = fspecial('gaussian', 11, 1.5); % 96 | K(1) = 0.01; % default settings 97 | K(2) = 0.03; % 98 | L = 255; % 99 | end 100 | 101 | if (nargin == 3) 102 | if ((M < 11) || (N < 11)) 103 | ssim_index = -Inf; 104 | ssim_map = -Inf; 105 | return 106 | end 107 | window = fspecial('gaussian', 11, 1.5); 108 | L = 255; 109 | if (length(K) == 2) 110 | if (K(1) < 0 || K(2) < 0) 111 | ssim_index = -Inf; 112 | ssim_map = -Inf; 113 | return; 114 | end 115 | else 116 | ssim_index = -Inf; 117 | ssim_map = -Inf; 118 | return; 119 | end 120 | end 121 | 122 | if (nargin == 4) 123 | [H W] = size(window); 124 | if ((H*W) < 4 || (H > M) || (W > N)) 125 | ssim_index = -Inf; 126 | ssim_map = -Inf; 127 | return 128 | end 129 | L = 255; 130 | if (length(K) == 2) 131 | if (K(1) < 0 || K(2) < 0) 132 | ssim_index = -Inf; 133 | ssim_map = -Inf; 134 | return; 135 | end 136 | else 137 | ssim_index = -Inf; 138 | ssim_map = -Inf; 139 | return; 140 | end 141 | end 142 | 143 | if (nargin == 5) 144 | [H W] = size(window); 145 | if ((H*W) < 4 || (H > M) || (W > N)) 146 | ssim_index = -Inf; 147 | ssim_map = -Inf; 148 | return 149 | end 150 | if (length(K) == 2) 151 | if (K(1) < 0 || K(2) < 0) 152 | ssim_index = -Inf; 153 | ssim_map = -Inf; 154 | return; 155 | end 156 | else 157 | ssim_index = -Inf; 158 | ssim_map = -Inf; 159 | return; 160 | end 161 | end 162 | 163 | C1 = (K(1)*L)^2; 164 | C2 = (K(2)*L)^2; 165 | window = window/sum(sum(window)); 166 | img1 = double(img1); 167 | img2 = double(img2); 168 | 169 | mu1 = filter2(window, img1, 'valid'); 170 | mu2 = filter2(window, img2, 'valid'); 171 | mu1_sq = mu1.*mu1; 172 | mu2_sq = mu2.*mu2; 173 | mu1_mu2 = mu1.*mu2; 174 | sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq; 175 | sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq; 176 | sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2; 177 | 178 | if (C1 > 0 & C2 > 0) 179 | ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2)); 180 | else 181 | numerator1 = 2*mu1_mu2 + C1; 182 | numerator2 = 2*sigma12 + C2; 183 | denominator1 = mu1_sq + mu2_sq + C1; 184 | denominator2 = sigma1_sq + sigma2_sq + C2; 185 | ssim_map = ones(size(mu1)); 186 | index = (denominator1.*denominator2 > 0); 187 | ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index)); 188 | index = (denominator1 ~= 0) & (denominator2 == 0); 189 | ssim_map(index) = numerator1(index)./denominator1(index); 190 | end 191 | 192 | mssim = mean2(ssim_map); 193 | 194 | return -------------------------------------------------------------------------------- /ssim_index_new.m: -------------------------------------------------------------------------------- 1 | function [mssim, ssim_map, mcs, cs_map] = ssim_index_new(img1, img2, K, win) 2 | 3 | if (nargin < 2 || nargin > 4) 4 | mssim = -Inf; 5 | ssim_map = -Inf; 6 | return; 7 | end 8 | 9 | if (size(img1) ~= size(img2)) 10 | mssim = -Inf; 11 | ssim_map = -Inf; 12 | return; 13 | end 14 | 15 | [M N] = size(img1); 16 | 17 | if (nargin == 2) 18 | if ((M < 11) || (N < 11)) 19 | mssim = -Inf; 20 | ssim_map = -Inf; 21 | return 22 | end 23 | win = fspecial('gaussian', 11, 1.5); % 24 | K(1) = 0.01; % default settings 25 | K(2) = 0.03; % 26 | end 27 | 28 | if (nargin == 3) 29 | if ((M < 11) || (N < 11)) 30 | mssim = -Inf; 31 | ssim_map = -Inf; 32 | return 33 | end 34 | win = fspecial('gaussian', 11, 1.5); 35 | if (length(K) == 2) 36 | if (K(1) < 0 || K(2) < 0) 37 | mssim = -Inf; 38 | ssim_map = -Inf; 39 | return; 40 | end 41 | else 42 | mssim = -Inf; 43 | ssim_map = -Inf; 44 | return; 45 | end 46 | end 47 | 48 | if (nargin == 4) 49 | [H W] = size(win); 50 | if ((H*W) < 4 || (H > M) || (W > N)) 51 | mssim = -Inf; 52 | ssim_map = -Inf; 53 | return 54 | end 55 | if (length(K) == 2) 56 | if (K(1) < 0 || K(2) < 0) 57 | mssim = -Inf; 58 | ssim_map = -Inf; 59 | return; 60 | end 61 | else 62 | mssim = -Inf; 63 | ssim_map = -Inf; 64 | return; 65 | end 66 | end 67 | 68 | C1 = (K(1)*255)^2; 69 | C2 = (K(2)*255)^2; 70 | win = win/sum(sum(win)); 71 | 72 | mu1 = filter2(win, img1, 'valid'); 73 | mu2 = filter2(win, img2, 'valid'); 74 | mu1_sq = mu1.*mu1; 75 | mu2_sq = mu2.*mu2; 76 | mu1_mu2 = mu1.*mu2; 77 | sigma1_sq = filter2(win, img1.*img1, 'valid') - mu1_sq; 78 | sigma2_sq = filter2(win, img2.*img2, 'valid') - mu2_sq; 79 | sigma12 = filter2(win, img1.*img2, 'valid') - mu1_mu2; 80 | 81 | if (C1 > 0 & C2 > 0) 82 | ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2)); 83 | cs_map = (2*sigma12 + C2)./(sigma1_sq + sigma2_sq + C2); 84 | else 85 | numerator1 = 2*mu1_mu2 + C1; 86 | numerator2 = 2*sigma12 + C2; 87 | denominator1 = mu1_sq + mu2_sq + C1; 88 | denominator2 = sigma1_sq + sigma2_sq + C2; 89 | 90 | ssim_map = ones(size(mu1)); 91 | index = (denominator1.*denominator2 > 0); 92 | ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index)); 93 | index = (denominator1 ~= 0) & (denominator2 == 0); 94 | ssim_map(index) = numerator1(index)./denominator1(index); 95 | 96 | cs_map = ones(size(mu1)); 97 | index = denominator2 > 0; 98 | cs_map(index) = numerator2(index)./denominator2(index); 99 | end 100 | 101 | mssim = mean2(ssim_map); 102 | mcs = mean2(cs_map); 103 | 104 | return -------------------------------------------------------------------------------- /testQualityMetrics.m: -------------------------------------------------------------------------------- 1 | function results=testQualityMetrics(results,inputImage,outputImage) 2 | % results=testQualityMetrics(results,inputImage,outputImage) 3 | % 4 | % results is a struct 5 | % the output results struct will contain fields for different metrics of 6 | % image quality 7 | % 8 | % inputImage - reference image 9 | % outputImage - degraded image 10 | % 11 | % full reference: 12 | % ms_ssim 13 | % ssim 14 | % mse 15 | % relative_error 16 | % 17 | % no reference (blind): 18 | % brisque 19 | % bliinds2 20 | % divine 21 | % 22 | % if results contains a 'settings' field with a struct containing a 'fovea' 23 | % field, foveation based quality metrics will also be computed 24 | % fssim 25 | % fvmse + variants 26 | % 27 | % 28 | % 29 | % 30 | 31 | %bound image pixels 0-255 32 | boundedOutputImage=min(outputImage,255.*ones(size(outputImage))); 33 | boundedOutputImage=max(boundedOutputImage,zeros(size(outputImage))); 34 | 35 | results.ssim=ssim_index_m(inputImage,outputImage); 36 | [n,m]=size(inputImage); 37 | if min(n,m) <= 128 38 | % adjust filter for ms_ssim to accomodate small images 39 | results.ms_ssim=msssim(inputImage,outputImage,[0.01 0.03],fspecial('gaussian', 7, 1.5)); 40 | results.bounded_ms_ssim=msssim(inputImage,boundedOutputImage,[0.01 0.03],fspecial('gaussian', 7, 1.5)); 41 | else 42 | results.ms_ssim=msssim(inputImage,outputImage); 43 | results.bounded_ms_ssim=msssim(inputImage,boundedOutputImage); 44 | end 45 | results.relative_error=norm(inputImage(:)-outputImage(:))/norm(inputImage(:)); 46 | sqerror2=(inputImage-outputImage).^2; 47 | results.mse=mean(sqerror2(:)); 48 | 49 | results.bounded_ssim=ssim_index_m(inputImage,boundedOutputImage); 50 | sqerror2=(inputImage-boundedOutputImage).^2; 51 | results.bounded_mse=mean(sqerror2(:)); 52 | results.bounded_relative_error=norm(inputImage(:)-boundedOutputImage(:))/norm(inputImage(:)); 53 | 54 | 55 | if isfield(results,'settings') && isfield(results.settings,'fovea') 56 | % fovea2=results.settings.fovea./size(inputImage); % fovea position relative to image frame 57 | % results.fvssim=fsbssim_index(inputImage,outputImage,fovea2); 58 | results.fssim=fssim(inputImage,outputImage,struct('fovea',results.settings.fovea,'viewDist',3)); 59 | if isfield(results.settings,'foveation_implementation') 60 | [results.fvmse,results.fvmse2,results.fvmse3]=image_mse_foveated(inputImage,outputImage,results.settings.fovea,results.settings.foveation_implementation); 61 | else 62 | warning('foveation_implementation is not available'); 63 | end 64 | %results.fvmse % mse (f (reference), f(output) ) 65 | %results.fvmse2 % mse (f (reference), output ) 66 | %results.fvmse3 % mse (reference , output ) weighted by cutoff 67 | %frequency 68 | end 69 | 70 | % add dmos mappings for mse,ssim,ms_ssim so that they are on same scale 71 | % as blind indices 72 | try 73 | fullpath = mfilename('fullpath'); 74 | idx = find(fullpath == filesep); 75 | thisfolder = fullpath(1:(idx(end)-1)); 76 | dmos_fit=load(fullfile(thisfolder,'dmos_fit_fns')); 77 | % uses LIVE database with logistic regression 78 | results.mse_dmos=dmos_fit.fns.mse(results.mse); 79 | % uses LIVE database with constrained polynomial regression 80 | results.ssim_dmos=dmos_fit.fns.ssim(results.ssim); % 81 | % uses LIVE database with logistic regression 82 | results.ms_ssim_dmos=dmos_fit.fns.ms_ssim(results.ms_ssim); 83 | catch exception 84 | results.mse_dmos=nan; 85 | results.ssim_dmos=nan; 86 | results.ms_ssim_dmos=nan; 87 | disp '*********** Error: ' 88 | disp (getReport(exception,'extended')) 89 | end 90 | 91 | %brisque blind index 92 | try 93 | results.brisque=brisque.brisquescore(outputImage); 94 | catch exception 95 | results.brisque=nan; 96 | disp '*********** Error: ' 97 | disp (getReport(exception,'extended')) 98 | end 99 | %bliinds2 blind index 100 | try 101 | results.bliinds2=bliinds2.bliinds2_score(outputImage); 102 | catch exception 103 | results.bliinds2=nan; 104 | disp '*********** Error: ' 105 | disp (getReport(exception,'extended')) 106 | end 107 | %divine blind index 108 | try 109 | results.divine=divine.divine(outputImage); 110 | catch exception 111 | results.divine=nan; 112 | disp '*********** Error: ' 113 | disp (getReport(exception,'extended')) 114 | end 115 | 116 | -------------------------------------------------------------------------------- /testQualityMetricsTest.m: -------------------------------------------------------------------------------- 1 | 2 | % testQualityMetricsTest test the testQualityMetrics function with a 3 | % simple case 4 | % 5 | inputImage=double(imread('reference.png')); 6 | outputImage=double(imread('degraded.png')); 7 | results=struct(); 8 | results=testQualityMetrics(results,inputImage,outputImage); 9 | disp(results) --------------------------------------------------------------------------------