In the last image analysis force algorithm – SFR (Spatial Frequency Response) source analysis (A) introduced several important functions of SFR, next we look at the main process and other functions.

SfrProc is the main process function that calculates SFR values

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 ) {
     // Position the torque center
    err = locate_centroids(farea, temp, shifts, size_x, size_y, &offset1); 
    if(err ! =0)     { return 2; }

    /* Calculate the best fit line to the centroids */
    /* Calculate the fitting curve of the moment center */
    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 */
  // Check the edge slope to ensure the quality of the following oversampling
  err = check_slope(*slope, &size_y, numcycles, cyclelimit, 1);

  /* Start image at new location, so that same row is center */
  // Adjust the ROW of 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. */
  // Update shifts based on the fitting results
  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 */
  // Do not normalize the data. The data will be normalized during DFT processing
  /* To normalize here, set dt = min and dt1 = max of farea data */
  // If you want to initialize here, set dt to minimum and dT1 to maximum
  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];// Calculate the distance from each point to the knife edge
      Signal[pcnt] = ((farea[((j*(long)size_x)+i)]) - dt)/(dt1-dt); // Normalize the brightness of each point
      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 */
  // Oversampling the current line image (ESF) of size_x*ALPHA(4) and saving it in 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. */
  // Convert ESF to difference graph LSF, and calculate the moment center of 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 */
  // Find the maximum value of LSF
  locate_max_PSF( bin_len, AveEdge, &pcnt);// Here we get the center of the maximum

  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)// Ignore the maximum value after difference
    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. */
  // Move the maximum value of the LSF to the center and add the Hamming window
  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);   // The frequency corresponding to each point
    (*sfr)[i] = (double) (sfrc/AveTmp[0]);    // Normalize SFR
  }

  /* Free */
  free(AveEdge);
  free(AveTmp);

  *nrows = size_y;
  *pcnt2 = pcnt;

  return(0);
}
Copy the code

5. Apply_hamming_window function: Apply hamming window to LSF to reduce noise

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 */
  // Move the Avgedge to the center, and fill the space caused by the movement with 0
  edge_offset = (*pcnt2) - (oldlen/2);// Pcnt2 must be less than oldlen/2.
  if(edge_offset ! =0) {                                                   //cer=6
    if (edge_offset < 0 ) {  // Edge_offset should be less than 0. left
      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]);   / / write write write
      for (i=0; i < -edge_offset; i++)                     // left center=3 right
                  AveEdge[i] = 0.00; /* last operation */    //offset = center-cer=-3
    } else {                                               // cer=6
                                                           / / left
      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]);   / / write write write
      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 */
  // Fill the values for begin and end with 0, but feel useless
  begin = (oldlen/2)-(newxwidth*alpha/2);// Begin will only equal 0, because 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;

  // Add hamming window to the data between begin and end
  / / hamming window W (n, alpha) = (1 - alpha - alpha cos (2 * PI * n/(n - 1)), (0, n, n - 1 or less or less)
  // Generally, the value of α is 0.46
  // The window has been shifted (so the sign has changed) and the result is the same
  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; }// Move lsfBEGIN left to index0
  // This should not work in code,
  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];

}
Copy the code

6. Function of FTWOS: calculate DFT and convert airspace to frequency domain.

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 first half
    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;
}
Copy the code

Well, the whole SFR important code notes to here also ended, drag quite a long time, mainly the previous period of time is also a little busy, we have what is not clear or error correction can leave a message. Let’s talk about it