图像解析力算法—SFR(Spatial Frequency Response)源码分析(二)

  • Post author:
  • Post category:其他


在上一篇

图像解析力算法—SFR(Spatial Frequency Response)源码分析(一)

中介绍了SFR的几个重要函数,接下来我们看一下主流程和其他函数。

4、sfrProc作用:计算SFR数值的主流程函数


 
 
  1. short sfrProc (double **freq, double **sfr,
  2. int *len,
  3. double *farea,
  4. unsigned short size_x, int *nrows,
  5. double *slope, int *numcycles, int *pcnt2, double *off, double *R2,
  6. int version, int iterate, int user_angle)
  7. {
  8. unsigned short i, j, col, err = 0;
  9. long pcnt;
  10. double dt, dt1, sfrc, tmp, tmp2;
  11. double *temp= NULL, *shifts= NULL, *edgex= NULL, *Signal= NULL;
  12. double *AveEdge= NULL, *AveTmp= NULL;
  13. long *counts= NULL;
  14. int nzero;
  15. unsigned short size_y;
  16. unsigned int bin_len;
  17. double avar, bvar, offset1, offset2, offset;
  18. double centroid;
  19. int start_row, center_row;
  20. double *farea_old;
  21. double cyclelimit;
  22. FILE *fp = NULL;
  23. size_y = *nrows;
  24. /* Verify input selection dimensions are EVEN */
  25. if (size_x% 2 != 0) {
  26. fprintf( stderr, "ROI width is not even. Does this really matter???\n");
  27. return 1;
  28. }
  29. /* At least this many cycles required. */
  30. /* For special iterative versions of the code, it can go lower */
  31. if (iterate) cyclelimit = 1.0;
  32. else cyclelimit = 5.0;
  33. /* Allocate memory */
  34. shifts = ( double *) malloc(size_y* sizeof( double));
  35. temp = ( double *) malloc(size_y* sizeof( double));
  36. edgex = ( double *) malloc(size_y*size_x* sizeof( double));
  37. Signal = ( double *) malloc(size_y*size_x* sizeof( double));
  38. if( !user_angle ) {
  39. //定位矩心位置
  40. err = locate_centroids(farea, temp, shifts, size_x, size_y, &offset1);
  41. if (err != 0) { return 2; }
  42. /* Calculate the best fit line to the centroids */
  43. /*计算矩心的拟合曲线*/
  44. err = fit(size_y, temp, shifts, slope, &offset2, R2, &avar, &bvar);
  45. if (err != 0) { return 3; }
  46. if (version)
  47. MTFPRINT4( "\nLinear Fit: R2 = %.3f SE_intercept = %.2f SE_angle = %.3f\n",
  48. *R2, avar, atan(bvar)*( double)( 180.0/M_PI))
  49. }
  50. /* Check slope is OK, and set size_y to be full multiple of cycles */
  51. //检查刀口斜率,以确保后面超采样的质量
  52. err = check_slope(*slope, &size_y, numcycles, cyclelimit, 1);
  53. /* Start image at new location, so that same row is center */
  54. //调整ROI的行
  55. center_row = *nrows/ 2;
  56. start_row = center_row - size_y/ 2;
  57. farea_old = farea;
  58. farea = farea + start_row*size_x;
  59. /* On center row how much shift to get edge centered in row. */
  60. /* offset = 0.; Original code effectively used this (no centering)*/
  61. if(user_angle)
  62. offset = *off - size_x/ 2;
  63. else
  64. offset = offset1 + 0.5 + offset2 - size_x/ 2;
  65. *off = offset;
  66. if(version & ROUND || version & DER3)
  67. offset += 0.125;
  68. if (err != 0) { /* Slopes are bad. But send back enough
  69. data, so a diagnostic image has a chance. */
  70. *pcnt2 = 2*size_x; /* Ignore derivative peak */
  71. return 4;
  72. }
  73. /* reference the temp and shifts values to the new y centre */
  74. /* Instead of using the values in shifts, synthesize new ones based on
  75. the best fit line. */
  76. // 基于拟合结果更新shifts
  77. col = size_y/ 2;
  78. for (i= 0; i < size_y; i++) {
  79. shifts[i] = (*slope) * ( double)(i-col) + offset;
  80. }
  81. /* Don't normalize the data. It gets normalized during dft process */
  82. //不要对数据进行归一化,数据在DFT处理过程中会被归一化
  83. /* To normalize here, set dt = min and dt1 = max of farea data */
  84. //如果要在这里初始化,将dt设置为最小值,dt1设置为最大值
  85. dt = 0.0;
  86. dt1 = 1.0;
  87. if (version & ESFFILE)
  88. fp = fopen( "esf.txt", "w");
  89. /* Calculate a long paired list of x values and signal values */
  90. pcnt = 0;
  91. for (j = 0; j < size_y; j++) {
  92. for (i = 0; i < size_x; i++) {
  93. edgex[pcnt] = ( double)i - shifts[j]; //计算每个点到刀口的距离
  94. Signal[pcnt] = ((farea[((j*( long)size_x)+i)]) - dt)/(dt1-dt); //归一化每个点的亮度
  95. if ((version & ESFFILE) && edgex[pcnt] < size_x/ 2 + 3 &&
  96. edgex[pcnt] > size_x/ 2 - 3)
  97. fprintf(fp, "%f %f\n", edgex[pcnt], Signal[pcnt]);
  98. pcnt++;
  99. }
  100. }
  101. if (version & ESFFILE)
  102. fclose(fp);
  103. /* Allocate more memory */
  104. bin_len = ( unsigned int)(ALPHA*size_x);
  105. AveEdge = ( double *) malloc(bin_len* sizeof( double));
  106. AveTmp = ( double *) malloc(bin_len* sizeof( double));
  107. counts = ( long *) malloc(bin_len* sizeof( long));
  108. /* Project ESF data into supersampled bins */
  109. //进行超采样,生成长度为size_x*ALPHA(4)的当行图像(ESF),保存在AveEdge中
  110. nzero = bin_to_regular_xgrid(( unsigned short)ALPHA, edgex, Signal,
  111. AveEdge, counts,
  112. size_x, size_y);
  113. free(counts);
  114. free(Signal);
  115. free(edgex);
  116. /* Compute LSF from ESF. Not yet centered or windowed. */
  117. // 将ESF转换为差分图LSF, 并计算LSF的矩心
  118. if ( (version&DER3) )
  119. calculate_derivative( bin_len, AveTmp, AveEdge, &centroid, 1);
  120. else
  121. calculate_derivative( bin_len, AveTmp, AveEdge, &centroid, 0);
  122. if (iterate == 0) {
  123. /* Copy ESF to output area */
  124. for ( i= 0; i<bin_len; i++ )
  125. farea_old[i] = AveTmp[i];
  126. }
  127. /* Find the peak/center of LSF */
  128. //寻找LSF的最大值
  129. locate_max_PSF( bin_len, AveEdge, &pcnt); //这里获得了最大值的中心
  130. free(shifts);
  131. free(temp);
  132. if(version)
  133. MTFPRINT3( "Off center distance (1/4 pixel units): Peak %ld Centroid %.2f\n",
  134. pcnt-bin_len/ 2, centroid-bin_len/ 2)
  135. if((version & PEAK) == 0) //忽略差分后的最大值
  136. pcnt = bin_len/ 2; /* Ignore derivative peak */
  137. else
  138. MTFPRINT( "Shifting peak to center\n")
  139. /* Here the array length is shortened to ww_in_pixels*ALPHA,
  140. and the LSF peak is centered and Hamming windowed. */
  141. //将LSF的最大值移到中心位置,并加上汉明窗
  142. apply_hamming_window(( unsigned short)ALPHA, bin_len,
  143. ( unsigned short)size_x,
  144. AveEdge, &pcnt);
  145. /* From now on this is the length used. */
  146. *len = bin_len/ 2;
  147. if (iterate == 0) {
  148. /* Copy LSF_w to output area */
  149. for ( i= 0; i<bin_len; i++ )
  150. farea_old[size_x*( int)ALPHA+i] = AveEdge[i];
  151. }
  152. tmp = 1.0;
  153. tmp2 = 1.0/(( double)bin_len) ;
  154. /* Now perform the DFT on AveEdge */
  155. /* ftwos ( nx, dx, lsf(x), nf, df, sfr(f) ) */
  156. //ftwos( number, dx, *lsf, ns, ds, *sfr)
  157. ( void) ftwos(bin_len, tmp, AveEdge, ( long)(*len),
  158. tmp2, AveTmp);
  159. if(*freq== NULL)
  160. (*freq) = ( double *) malloc((*len)* sizeof( double));
  161. if(*sfr== NULL)
  162. (*sfr) = ( double *) malloc((*len)* sizeof( double));
  163. for (i= 0; i<(*len); i++) {
  164. sfrc = AveTmp[i];
  165. (*freq)[i]= (( double)i/( double)size_x); //每个点对应的频率
  166. (*sfr)[i] = ( double) (sfrc/AveTmp[ 0]); //归一化sfr
  167. }
  168. /* Free */
  169. free(AveEdge);
  170. free(AveTmp);
  171. *nrows = size_y;
  172. *pcnt2 = pcnt;
  173. return( 0);
  174. }

5、apply_hamming_window作用:对lsf应用汉明窗,减少噪声


 
 
  1. void apply_hamming_window( unsigned short alpha,
  2. unsigned int oldlen, //size_x*4
  3. unsigned short newxwidth, //size_x
  4. double *AveEdge, long *pcnt2)
  5. {
  6. long i,j,k, begin, end, edge_offset;
  7. double sfrc;
  8. /* Shift the AvgEdge[i] vector to centre the lsf in the transform window */
  9. // 将Avgedge移到中心位置, 两边由于移动造成的空位由0补齐
  10. edge_offset = (*pcnt2) - (oldlen/ 2); //不能理解为什么一定要反着计算,pcnt2肯定是小于oldlen/2吧。。
  11. if (edge_offset != 0) { //cer=6
  12. if (edge_offset < 0 ) { //这里根据分析的话,应该edge_offset只会小于0啊。。 ↓
  13. for (i=oldlen -1; i > -edge_offset -1; i--) // [l l l l l l l max l l l l l]
  14. AveEdge[i] = (AveEdge[i+edge_offset]); // ↑ ↑ ↑
  15. for (i= 0; i < -edge_offset; i++) // left center=3 right
  16. AveEdge[i] = 0.00; /* last operation */ //offset = center-cer=-3
  17. } else { // cer=6
  18. // ↓
  19. for (i= 0; i < oldlen-edge_offset; i++) // [0 0 0 l l l l l l l max l l]
  20. AveEdge[i] = (AveEdge[i+edge_offset]); // ↑ ↑ ↑
  21. for (i=oldlen-edge_offset; i < oldlen; i++) // center=3
  22. AveEdge[i] = 0.00;
  23. }
  24. }
  25. /* Multiply the LSF data by a Hamming window of width NEWXWIDTH*alpha */
  26. //将begin和end两侧的值用0填充,但是感觉没啥用
  27. begin = (oldlen/ 2)-(newxwidth*alpha/ 2); //上下看来,begin只会等于0,因为oldlen=bin_len, bin_len=size_x*alpha == newxwidth*alpha
  28. if (begin < 0) begin = 0;
  29. end = (oldlen/ 2)+(newxwidth*alpha/ 2);
  30. if (end > oldlen ) end = oldlen;
  31. for (i= 0; i< begin; i++)
  32. AveEdge[i] = 0.0;
  33. for (i=end; i< oldlen; i++)
  34. AveEdge[i] = 0.0;
  35. // 给begin和end之间的数据加上汉明窗
  36. // 汉明窗 W(n,α ) = (1 -α ) - α cos(2*PI*n/(N-1)) ,(0≤n≤N-1)
  37. // 一般情况下,α取0.46
  38. // 下面计算方法等于窗发生了平移(故符号发生了变化), 结果是一样的
  39. for (i=begin,j = -newxwidth*alpha/ 2; i < end; i++,j++) {
  40. sfrc = 0.54 + 0.46* cos( (M_PI*( double)j)/(newxwidth*alpha/ 2) );
  41. AveEdge[i] = (AveEdge[i])*sfrc;
  42. }
  43. //将lsfbegin的位置左移到index0的位置
  44. //但在代码中应该是不会起作用的,
  45. if (begin != 0) /* Shift LSF to begin at index 0 (rather than begin) */
  46. for (k= 0, i=begin; k<newxwidth*alpha; i++,k++)
  47. AveEdge[k] = AveEdge[i];
  48. }

6、ftwos作用:计算DFT,将空域转换到频域范围上。


 
 
  1. unsigned short ftwos(long number, double dx, double *lsf,
  2. long ns, double ds, double *sfr)
  3. {
  4. double a, b, twopi, g;
  5. long i,j;
  6. // n-1 k
  7. // DFT ==> X[k] = Σ x[n]e^(-j2π - n)
  8. // n=0 N
  9. twopi = 2.0 * M_PI;
  10. for (j = 0; j < ns; j++){ //ns=1/2*bin_len 前一半
  11. g = twopi * dx * ds * ( double)j;
  12. for (i = 0, a = 0, b = 0; i < number; i++) {
  13. a += lsf[i] * cos(g * ( double)(i));
  14. b += lsf[i] * sin(g * ( double)(i));
  15. }
  16. sfr[j] = sqrt(a * a + b * b);
  17. }
  18. return 0;
  19. }

好了,整个SFR的重要代码的注释到这里也就结束了,拖了挺久的,主要是前段时间也是有点忙,大家有啥不清楚或者错误指正可以留言一下。大家互相探讨一波吧~