尝试用刀刃法计算MTF
高等数学没学好,使用网上的源码跑了一遍,尝试理解MTF计算过程。
ROI图片选取一个60*30的区域
数据归一化
gamma处理的原因是人眼对暗色更敏感,但是亮度只能存0~255,所以我们希望挤压量的部分,多存一点暗的部分。没错,就是 非线性存储。
如果是直接取的raw图,就不需要做这个处理了(我下面的图片数据没有做gamma处理)。
图片数据
对应图片原始数据,这里用excel色阶功能做了下处理。
表格中取值为Blue通道(这里是调试时候为了图省事弄的,后面应该要取灰度值算最终的MTF)
找准确的刃边(找重心的方式)
// 求质心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; // 质心
}
找质心的目的是为了拟合“黑白分界线”。
计算“刀刃”的直线
// 线性回归 y = a + bx
unsigned short SfrDataProces::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;