笔者学识有限。 本博客旨在对mitre_sfr核心代码进行简单注解, 详细内容读者仁者见仁智者见智。
ESF一条白变黑(黑变白)的线。IOS SFR算法希望通过对刀口进行超采样, 生成一条更平滑的的变化曲线, 降低计算的误差。
1. locate_centroids函数用于定位ROI每一行的质心;
2. fit函数拟合locate_centroids定位出来的质心, 确定刀口的斜率;
3. 然后bin_to_regular_xgrid函数基于前面两个函数的结果把ROI区域超采样为单行的ESF。
/*****************************************************************************/
// 寻找质心
// shifts --> 当前行与中心行的距离
// temp --> 当前行的质心与中心行的质心的距离
// offset --> 中心行质心的位置
unsigned short locate_centroids(double *farea, double *temp,
double *shifts,
unsigned short size_x, unsigned short size_y,
double *offset) {
unsigned long i, j;
double dt, dt1, dt2;
/* Compute the first difference on each line. Interpolate to find the
centroid of the first derivatives. */
// 求质心C
// C = Σx*(f(x+1)-f(x))/Σ(f(x+1)-f(x))
for (j = 0; j < size_y; j++) {
dt = 0.0;
dt1 = 0.0;
for (i = 0; i < size_x-1; i++) {
dt2 = farea[(j*(long)size_x)+(i+1)] - farea[(j*(long)size_x)+i]; // 计算每个点的导数
dt += dt2 * (double)i; //
dt1 += dt2;
}
shifts[j]=dt/dt1; // 质心
}
/* check again to be sure we aren't too close to an edge on the corners.
If the black to white transition is closer than 2 pixels from either
side of the data box, return an error of 5; the calling program will
display an error message (the same one as if there were not a difference
between the left and right sides of the box ) */
// 确保刀口不要太靠近左右边界(> 2 pixels)
if (shifts[size_y-1] < 2 || size_x - shifts[size_y-1] < 2) {
fprintf(stderr,"** WARNING: Edge comes too close to the ROI corners.\n");
return 5;
}
if (shifts[0] < 2 || size_x - shifts[0] < 2){
fprintf(stderr,"** WARNING: Edge comes too close to the ROI corners.\n");
return 5;
}
/* Reference rows to the vertical centre of the data box */
j = size_y/2;
dt = shifts[j];
for (i = 0; i < size_y; i++) {
temp[i] = (double)i - (double)j; // 当前行与中心行的距离 delta Col
shifts[i] -= dt; // 当前行的质心与中心行的质心的距离delta C
}
*offset = dt; // 中心行质心的位置
return 0;
}
/***************************************************************************/
// 线性回归 y = a + bx
unsigned short fit(unsigned long ndata, double *x, double *y, double *b,
double *a, double *R2, double *avar, double *bvar)
{
unsigned long i;
double t,sxoss,syoss,sx=0.0,sy=0.0,st2=0.0;
double ss,sst,sigdat,chi2,siga,sigb;
*b=0.0;
for ( i=0; i < ndata; i++ ) {
sx += x[i];
sy += y[i];
}
ss=(double)ndata;
sxoss=sx/ss;
syoss=sy/ss;
for ( i=0; i < ndata; i++ ) {
t = x[i] - sxoss;
st2 += t*t;
*b += t * y[i];
}
*b /= st2; /* slope */
*a =(sy-sx*(*b))/ss; /* intercept */
siga=sqrt((1.0+sx*sx/(ss*st2))/ss);
sigb=sqrt(1.0/st2);
chi2=0.0;
sst=0.0;
for (i=0; i < ndata; i++) {
chi2 += SQR( y[i] - (*a) - (*b) * x[i]);
sst += SQR( y[i] - syoss);
}
sigdat=sqrt(chi2/(ndata-2));
siga *= sigdat;
sigb *= sigdat;
*R2 = 1.0 - chi2/sst;
*avar = siga;
*bvar = sigb;
return 0;
}
/*****************************************************************************/
/* Notes: this part gets averages and puts them in a number of bins, equal to
size_x times alpha. Next a long check is done in case one bin gets no values
put into it: if this is the case, it will keep checking previous bins until it
finds one with non-zero counts and will use that value as its current bin
average. If the first bin has zero counts the program checks bins in the
forward rather than reverse direction. If, in any case, the end of the array
of bins is reached before finding a non-zero count, the program starts
checking in the opposite direction. A bin with zero counts is not allowed,
since each bin will be divided by counts at the end. */
unsigned short bin_to_regular_xgrid(unsigned short alpha,
double *edgex, double *Signal,
double *AveEdge, long *counts,
unsigned short size_x,
unsigned short size_y)
{
long i, j, k,bin_number;
long bin_len;
int nzeros;
bin_len = size_x * alpha;
// 进行超采样, 把所有数据超采样到长度为size_x * alpha(4)的一行数据中
for (i=0; i= 0) // 下界之内
{
if (bin_number <= (bin_len - 1) ) // 上界之内
{
AveEdge[bin_number] = AveEdge[bin_number] + Signal[i]; // 累加到对应距离内的容器
counts[bin_number] = (counts[bin_number])+1; // 计数器加一
}
}
}
// 检查是否每个点都有数据
nzeros = 0;
for (i=0; i= 0) ) // 向前寻找计数非0的点, 并将第一个计数非0的点的均值赋值给当前点
{
if ( counts[i-k] != 0)
{
AveEdge[i] = AveEdge[i-k]; /* Don't divide by counts since it already happened in previous iteration */
j = 1;
}
else k++;
}
if ( (i-k) < 0 ) // 如果向前没找到计数非0的点, 则开始向后寻找, 并将第一个计数非0的点的均值赋值给当前点
{
k = 1;
while (!j)
{
if (counts[i+k] != 0)
{
AveEdge[i] = AveEdge[i+k]/((double) counts[i+k]);
j = 1;
}
else k++;
}
}
}
}
else
AveEdge[i] = (AveEdge[i])/ ((double) counts[i]); // 计算计数非0点均值
}
if (nzeros > 0) {
fprintf(stderr, "\nWARNING: %d Zero counts found during projection binning.\n", nzeros);
fprintf(stderr, "The edge angle may be large, or you may need more lines of data.\n\n");
}
return nzeros;
}