123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- function s = PSI( I, percentile )
- % PSI(I) determines the perceptual sharpness s of an image I
- %
- %Reference:
- %
- % C Feichtenhofer, H Fassold, P Schallauer
- % "A perceptual image sharpness metric based on local edge gradient
- % analysis", IEEE Signal Processing Letters, 20 (4), 379-382, 2013
- %
- %
- % Written by Christoph Feichtenhofer (cfeichtenhofer AT gmail.com)
- % feichtenhofer.github.io
- %
- %% Parameters
- if nargin < 2
- percentile=22; % percentage of blocks to use for metric
- end
- % BLOCKSIZE [Def:32] Size for averaging of width measurements
- % THRESHOLD_W [Def:2] Sum of widths in block to proccess block further
- BLOCKSIZE = 32;
- THRESHOLD_W = 2;
- if ( size(I,3) > 1 )
- I = rgb2gray(I);
- end
- % sobel_tr [Def: []] If value is assigned, this is the constant sobel threshold,
- sobel_tr = [];
- [edges] = edge(I,'Sobel',sobel_tr);
- I = double(I) / 255;
-
- QUOTA_W = percentile/100;
- row_blocks = floor(size(I,1)/BLOCKSIZE);
- col_blocks = floor(size(I,2)/BLOCKSIZE);
- %% calculate angles and round them, then calc. horz/vert widths.
- [m, n] = size(I);
- edge_widths = zeros(m,n);
- widths_count = 0;
- % calculate gradient
- Ix = [I(:,2)-I(:,1), 0.5*(I(:,3:end)-I(:,1:end-2)), I(:,end)-I(:,end-1)];
- Iy = [I(2,:)-I(1,:); 0.5*(I(3:end,:)-I(1:end-2,:)); I(end,:)-I(end-1,:)];
- %% calculate gradient angle
- phi = atan2(Iy,Ix)*180/pi;
- %% calculate length for horizontal / vertical edges
- t = 8; %angle tolerance t
- w_JNB = 3;
- [row_idx, col_idx] = find(edges);
- for k=1:length(row_idx)
- i = row_idx(k);
- j = col_idx(k);
- width_up=0; width_down=0;
- if (Ix(i,j) == 0 && Iy(i,j) == 0)
- continue; % not really neccesary
- end
- %% check for horizontal edge, gradient pointing upwards -> ~ 90°, ~ -270°
- if( abs(phi(i,j)+90) < t )
- min = 0;
- max = 0;
- for d = 1:m
- up = i-d;
- if (up < 1)
- width_up = - 1;
- break;
- end
- if( I(up,j) <= I(up+1,j) ) %up+1 is max
- width_up = d - 1;
- max = I(up+1,j);
- break;
- end
- end
- for d = 1:m
- down = i+d;
- if (down > m)
- width_down = - 1;
- break;
- end
- if( I(down,j) >= I(down-1,j) ) % down-1 is min
- width_down = d - 1;
- min = I(down-1,j);
- break;
- end
- end
- if(width_up ~= -1 && width_down ~= -1)
- widths_count = widths_count+1;
- phi2 = (phi(i,j)+90)*pi/180;
- edge_widths(i,j) = (width_up+width_down)/cos(phi2);
- slope = (max-min) / edge_widths(i,j);
- if (edge_widths(i,j) >= w_JNB)
- edge_widths(i,j) = edge_widths(i,j) - slope;
- end
- end
- end
- %% check for horizontal edge, gradient pointing downwards - -> ~ -90°, ~ 270°
- if( abs(phi(i,j)-90) < t )
- min = 0;
- max = 0;
- for d = 1:m
- up = i-d;
- if (up < 1)
- width_up = - 1;
- break;
- end
- if( I(up,j) >= I(up+1,j) ) % up+1 is min
- width_up = d - 1;
- min = I(up+1,j);
- break;
- end
- end
- for d = 1:m
- down = i+d;
- if (down > m)
- width_down = - 1;
- break;
- end
- if( I(down,j) <= I(down-1,j) ) %down-1 is max
- width_down = d - 1;
- max = I(down-1,j);
- break;
- end
- end
- if(width_up ~= -1 && width_down ~= -1)
- widths_count = widths_count+1;
- phi2 = (phi(i,j)-90) *pi/180;
- edge_widths(i,j) = (width_up+width_down)/cos(phi2);
- slope = (max-min) / edge_widths(i,j);
- if (edge_widths(i,j) >= w_JNB)
- edge_widths(i,j) = edge_widths(i,j) - slope;
- end
- end
- end
- end
- %% calculate average edge widths in each block
- avg_w = zeros(row_blocks,col_blocks);
- for i=2:row_blocks-1 % skipping image borders
- for j=2:col_blocks-1
- block_row = (i-1)*BLOCKSIZE;
- block_col = (j-1)*BLOCKSIZE;
- block_widths = edge_widths(block_row+1:block_row+BLOCKSIZE,block_col+1:block_col+BLOCKSIZE);
- w_sum = sum(sum(block_widths));
- if ( w_sum >= THRESHOLD_W ) % enough widths found
- % calculate average width of the whole block
- avg_w(i,j) = w_sum / (sum(sum(block_widths ~= 0)));
- end
- end
- end
- avg_w = avg_w(avg_w ~= 0);
- avg_w = avg_w(:);
- nr_of_used_blocks = ceil( numel(avg_w) * QUOTA_W );
- if (nr_of_used_blocks == 0)
- s = 0;
- return;
- end
- avg_sorted = sort(avg_w);
- sharpest_edges = avg_sorted(1:nr_of_used_blocks);
- if (widths_count == 0)
- s=0;
- else
- s = numel(sharpest_edges) / sum(sharpest_edges);
- end
- end
|