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

在上一篇图像解析力算法—SFR(Spatial Frequency Response)源码分析(一)中介绍了SFR的几个重要函数,接下来我们看一下主流程和其他函数。

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

short sfrProc (double **freq, double **sfr, 
	       int *len,
	       double *farea,
	       unsigned short size_x, int *nrows,
	       double *slope, int *numcycles, int *pcnt2, double *off, double *R2,
	       int version, int iterate, int user_angle)
{
  unsigned short i, j, col, err = 0;
  long pcnt;
  double dt, dt1, sfrc, tmp, tmp2;
  double *temp=NULL, *shifts=NULL, *edgex=NULL, *Signal=NULL;
  double *AveEdge=NULL, *AveTmp=NULL;
  long *counts=NULL;
  int nzero;
  unsigned short size_y;
  unsigned int bin_len;
  double avar, bvar, offset1, offset2, offset;
  double centroid;
  int start_row, center_row;
  double *farea_old;
  double cyclelimit;
  FILE *fp = NULL;
 
  size_y = *nrows;
 
  /* Verify input selection dimensions are EVEN */
  if (size_x%2 != 0) { 
    fprintf(stderr, "ROI width is not even.  Does this really matter???\n");
    return 1;
  }
 
  /* At least this many cycles required. */
  /* For special iterative versions of the code, it can go lower */
  if (iterate) cyclelimit = 1.0;
  else cyclelimit = 5.0;
 
  /* Allocate memory */
  shifts = (double *)malloc(size_y*sizeof(double));
  temp = (double *)malloc(size_y*sizeof(double));
  edgex = (double *)malloc(size_y*size_x*sizeof(double));
  Signal = (double *)malloc(size_y*size_x*sizeof(double));
 
  if( !user_angle ) {
     //定位矩心位置
    err = locate_centroids(farea, temp, shifts, size_x, size_y, &offset1); 
    if (err != 0)     { return 2; }
 
    /* Calculate the best fit line to the centroids */
    /*计算矩心的拟合曲线*/
    err = fit(size_y, temp, shifts, slope, &offset2, R2, &avar, &bvar);
    if (err != 0)     { return 3; }
    
    if (version)
      MTFPRINT4("\nLinear Fit:  R2 = %.3f SE_intercept = %.2f  SE_angle = %.3f\n",  
	      *R2, avar, atan(bvar)*(double)(180.0/M_PI))
  }
 
  /* Check slope is OK, and set size_y to be full multiple of cycles */
  //检查刀口斜率,以确保后面超采样的质量
  err = check_slope(*slope, &size_y, numcycles, cyclelimit, 1);
 
  /* Start image at new location, so that same row is center */
  //调整ROI的行
  center_row = *nrows/2;
  start_row = center_row - size_y/2;
  farea_old = farea;
  farea = farea + start_row*size_x;
  /* On center row how much shift to get edge centered in row. */
  /* offset = 0.;  Original code effectively used this (no centering)*/
  if(user_angle)
    offset = *off - size_x/2;
  else
    offset = offset1 + 0.5 + offset2  - size_x/2; 
 
  *off = offset;
  if(version & ROUND || version & DER3)
    offset += 0.125;
 
  if (err != 0)     {   /* Slopes are bad.  But send back enough
			   data, so a diagnostic image has a chance. */
    *pcnt2 = 2*size_x;  /* Ignore derivative peak */
    return 4; 
  }
 
  /* reference the temp and shifts values to the new y centre */
  /* Instead of using the values in shifts, synthesize new ones based on 
     the best fit line. */
  // 基于拟合结果更新shifts
  col = size_y/2;
  for (i=0; i < size_y; i++) {
    shifts[i] = (*slope) * (double)(i-col) + offset;
  }
 
  /* Don't normalize the data.  It gets normalized during dft process */
  //不要对数据进行归一化,数据在DFT处理过程中会被归一化
  /* To normalize here, set dt = min and dt1 = max of farea data      */
  //如果要在这里初始化,将dt设置为最小值,dt1设置为最大值
  dt = 0.0;
  dt1 = 1.0;
 
  if (version & ESFFILE)
    fp = fopen("esf.txt","w");
 
  /* Calculate a long paired list of x values and signal values */
  pcnt = 0;
  for (j = 0; j < size_y; j++) {
    for (i = 0; i < size_x; i++) {
      edgex[pcnt] = (double)i - shifts[j];//计算每个点到刀口的距离
      Signal[pcnt] = ((farea[((j*(long)size_x)+i)]) - dt)/(dt1-dt); //归一化每个点的亮度
      if ((version & ESFFILE) && edgex[pcnt] < size_x/2 + 3 &&
	  edgex[pcnt] > size_x/2 - 3)
	fprintf(fp, "%f %f\n", edgex[pcnt], Signal[pcnt]);
      pcnt++;
    }
  }
 
  if (version & ESFFILE)
    fclose(fp);
 
  /* Allocate more memory */
  bin_len = (unsigned int)(ALPHA*size_x);
  AveEdge = (double *)malloc(bin_len*sizeof(double));
  AveTmp = (double *)malloc(bin_len*sizeof(double));
  counts = (long *)malloc(bin_len*sizeof(long));
 
  /* Project ESF data into supersampled bins */
  //进行超采样,生成长度为size_x*ALPHA(4)的当行图像(ESF),保存在AveEdge中
  nzero = bin_to_regular_xgrid((unsigned short)ALPHA, edgex, Signal, 
			       AveEdge, counts, 
			       size_x, size_y); 
  free(counts);
  free(Signal);
  free(edgex);
 
  /* Compute LSF from ESF.  Not yet centered or windowed. */
  // 将ESF转换为差分图LSF, 并计算LSF的矩心
  if ( (version&DER3) ) 
    calculate_derivative( bin_len, AveTmp, AveEdge, &centroid, 1);
  else
    calculate_derivative( bin_len, AveTmp, AveEdge, &centroid, 0);
 
  if (iterate == 0) {
    /* Copy ESF to output area */
    for ( i=0; i<bin_len; i++ )
      farea_old[i] = AveTmp[i];
  }
 
  /* Find the peak/center of LSF */
  //寻找LSF的最大值
  locate_max_PSF( bin_len, AveEdge, &pcnt);//这里获得了最大值的中心
 
  free(shifts);
  free(temp);
 
  if(version)
    MTFPRINT3("Off center distance (1/4 pixel units): Peak %ld  Centroid %.2f\n", 
	      pcnt-bin_len/2, centroid-bin_len/2)
 
  if((version & PEAK) == 0)//忽略差分后的最大值
    pcnt = bin_len/2;  /* Ignore derivative peak */
  else
    MTFPRINT("Shifting peak to center\n")
 
  /* Here the array length is shortened to ww_in_pixels*ALPHA,
     and the LSF peak is centered and Hamming windowed. */
  //将LSF的最大值移到中心位置,并加上汉明窗
  apply_hamming_window((unsigned short)ALPHA, bin_len,
		       (unsigned short)size_x, 
		       AveEdge, &pcnt);
 
  /* From now on this is the length used. */
  *len = bin_len/2;
 
  if (iterate == 0) {
    /* Copy LSF_w to output area */
    for ( i=0; i<bin_len; i++ )
      farea_old[size_x*(int)ALPHA+i] = AveEdge[i];
  }
 
  tmp = 1.0;
  tmp2 = 1.0/((double)bin_len) ;
 
  /* Now perform the DFT on AveEdge */
  /* ftwos ( nx, dx, lsf(x), nf, df, sfr(f) ) */
  //ftwos( number, dx, *lsf, ns, ds, *sfr)
  (void) ftwos(bin_len, tmp, AveEdge, (long)(*len), 
	       tmp2, AveTmp); 
 
  if(*freq==NULL)
    (*freq) = (double *)malloc((*len)*sizeof(double));
  if(*sfr==NULL)
    (*sfr) = (double *)malloc((*len)*sizeof(double));
 
  for (i=0; i<(*len); i++) {
    sfrc = AveTmp[i];
    (*freq)[i]= ((double)i/(double)size_x);   //每个点对应的频率
    (*sfr)[i] = (double) (sfrc/AveTmp[0]);    //归一化sfr
  }
 
  /* Free */
  free(AveEdge);
  free(AveTmp);
 
  *nrows = size_y;
  *pcnt2 = pcnt;
 
  return(0);
}

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

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

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

unsigned short ftwos(long number, double dx, double *lsf, 
		     long ns, double ds, double *sfr)
{
  double a, b, twopi, g;
  long i,j;
 
    //                n-1              k
    // DFT ==> X[k] = Σ  x[n]e^(-j2π - n)
    //                n=0              N
 
  twopi = 2.0 * M_PI;
  for (j = 0; j < ns; j++){//ns=1/2*bin_len  前一半
    g = twopi * dx * ds * (double)j;
    for (i = 0, a = 0, b = 0; i < number; i++) { 
      a += lsf[i] * cos(g * (double)(i));
      b += lsf[i] * sin(g * (double)(i)); 
    }
    sfr[j] = sqrt(a * a + b * b); 
  }
  return 0;
}

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



————————————————

版权声明:本文为CSDN博主「Dylan_young」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_38419133/article/details/100726062



本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864