PSI.m 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. function s = PSI( I, percentile )
  2. % PSI(I) determines the perceptual sharpness s of an image I
  3. %
  4. %Reference:
  5. %
  6. % C Feichtenhofer, H Fassold, P Schallauer
  7. % "A perceptual image sharpness metric based on local edge gradient
  8. % analysis", IEEE Signal Processing Letters, 20 (4), 379-382, 2013
  9. %
  10. %
  11. % Written by Christoph Feichtenhofer (cfeichtenhofer AT gmail.com)
  12. % feichtenhofer.github.io
  13. %
  14. %% Parameters
  15. if nargin < 2
  16. percentile=22; % percentage of blocks to use for metric
  17. end
  18. % BLOCKSIZE [Def:32] Size for averaging of width measurements
  19. % THRESHOLD_W [Def:2] Sum of widths in block to proccess block further
  20. BLOCKSIZE = 32;
  21. THRESHOLD_W = 2;
  22. if ( size(I,3) > 1 )
  23. I = rgb2gray(I);
  24. end
  25. % sobel_tr [Def: []] If value is assigned, this is the constant sobel threshold,
  26. sobel_tr = [];
  27. [edges] = edge(I,'Sobel',sobel_tr);
  28. I = double(I) / 255;
  29. QUOTA_W = percentile/100;
  30. row_blocks = floor(size(I,1)/BLOCKSIZE);
  31. col_blocks = floor(size(I,2)/BLOCKSIZE);
  32. %% calculate angles and round them, then calc. horz/vert widths.
  33. [m, n] = size(I);
  34. edge_widths = zeros(m,n);
  35. widths_count = 0;
  36. % calculate gradient
  37. Ix = [I(:,2)-I(:,1), 0.5*(I(:,3:end)-I(:,1:end-2)), I(:,end)-I(:,end-1)];
  38. Iy = [I(2,:)-I(1,:); 0.5*(I(3:end,:)-I(1:end-2,:)); I(end,:)-I(end-1,:)];
  39. %% calculate gradient angle
  40. phi = atan2(Iy,Ix)*180/pi;
  41. %% calculate length for horizontal / vertical edges
  42. t = 8; %angle tolerance t
  43. w_JNB = 3;
  44. [row_idx, col_idx] = find(edges);
  45. for k=1:length(row_idx)
  46. i = row_idx(k);
  47. j = col_idx(k);
  48. width_up=0; width_down=0;
  49. if (Ix(i,j) == 0 && Iy(i,j) == 0)
  50. continue; % not really neccesary
  51. end
  52. %% check for horizontal edge, gradient pointing upwards -> ~ 90°, ~ -270°
  53. if( abs(phi(i,j)+90) < t )
  54. min = 0;
  55. max = 0;
  56. for d = 1:m
  57. up = i-d;
  58. if (up < 1)
  59. width_up = - 1;
  60. break;
  61. end
  62. if( I(up,j) <= I(up+1,j) ) %up+1 is max
  63. width_up = d - 1;
  64. max = I(up+1,j);
  65. break;
  66. end
  67. end
  68. for d = 1:m
  69. down = i+d;
  70. if (down > m)
  71. width_down = - 1;
  72. break;
  73. end
  74. if( I(down,j) >= I(down-1,j) ) % down-1 is min
  75. width_down = d - 1;
  76. min = I(down-1,j);
  77. break;
  78. end
  79. end
  80. if(width_up ~= -1 && width_down ~= -1)
  81. widths_count = widths_count+1;
  82. phi2 = (phi(i,j)+90)*pi/180;
  83. edge_widths(i,j) = (width_up+width_down)/cos(phi2);
  84. slope = (max-min) / edge_widths(i,j);
  85. if (edge_widths(i,j) >= w_JNB)
  86. edge_widths(i,j) = edge_widths(i,j) - slope;
  87. end
  88. end
  89. end
  90. %% check for horizontal edge, gradient pointing downwards - -> ~ -90°, ~ 270°
  91. if( abs(phi(i,j)-90) < t )
  92. min = 0;
  93. max = 0;
  94. for d = 1:m
  95. up = i-d;
  96. if (up < 1)
  97. width_up = - 1;
  98. break;
  99. end
  100. if( I(up,j) >= I(up+1,j) ) % up+1 is min
  101. width_up = d - 1;
  102. min = I(up+1,j);
  103. break;
  104. end
  105. end
  106. for d = 1:m
  107. down = i+d;
  108. if (down > m)
  109. width_down = - 1;
  110. break;
  111. end
  112. if( I(down,j) <= I(down-1,j) ) %down-1 is max
  113. width_down = d - 1;
  114. max = I(down-1,j);
  115. break;
  116. end
  117. end
  118. if(width_up ~= -1 && width_down ~= -1)
  119. widths_count = widths_count+1;
  120. phi2 = (phi(i,j)-90) *pi/180;
  121. edge_widths(i,j) = (width_up+width_down)/cos(phi2);
  122. slope = (max-min) / edge_widths(i,j);
  123. if (edge_widths(i,j) >= w_JNB)
  124. edge_widths(i,j) = edge_widths(i,j) - slope;
  125. end
  126. end
  127. end
  128. end
  129. %% calculate average edge widths in each block
  130. avg_w = zeros(row_blocks,col_blocks);
  131. for i=2:row_blocks-1 % skipping image borders
  132. for j=2:col_blocks-1
  133. block_row = (i-1)*BLOCKSIZE;
  134. block_col = (j-1)*BLOCKSIZE;
  135. block_widths = edge_widths(block_row+1:block_row+BLOCKSIZE,block_col+1:block_col+BLOCKSIZE);
  136. w_sum = sum(sum(block_widths));
  137. if ( w_sum >= THRESHOLD_W ) % enough widths found
  138. % calculate average width of the whole block
  139. avg_w(i,j) = w_sum / (sum(sum(block_widths ~= 0)));
  140. end
  141. end
  142. end
  143. avg_w = avg_w(avg_w ~= 0);
  144. avg_w = avg_w(:);
  145. nr_of_used_blocks = ceil( numel(avg_w) * QUOTA_W );
  146. if (nr_of_used_blocks == 0)
  147. s = 0;
  148. return;
  149. end
  150. avg_sorted = sort(avg_w);
  151. sharpest_edges = avg_sorted(1:nr_of_used_blocks);
  152. if (widths_count == 0)
  153. s=0;
  154. else
  155. s = numel(sharpest_edges) / sum(sharpest_edges);
  156. end
  157. end