互相关的最大值不动

信息处理 fft 信号分析 傅里叶变换 互相关 C#
2022-02-23 14:38:05

我昨天已经在这里问过这个问题,但我认为它的措辞非常糟糕。我做了一个更详细的帖子来解释我的 stackoverflow 问题,因为它也可能是一个代码问题。

这是这篇文章的复制粘贴:

我正在研究一个涉及计算数组之间的互相关的 C# 项目。目标是精确跟踪图像上存在的图案的变化(具有亚像素精度)。我正在使用 MathNet 库。

这是用于互相关的公式:

corr(a, b) = ifft(fft(a_and_zeros) * conj(fft(b_and_zeros)))

我正在处理的双 [1024] 数组是通过计算每个 768 像素行旁边的信号平均值从 1024*768 灰度图像派生的。这是图像和相应数组的示例:

这是图像

这是数组

(绿色曲线在这里无关紧要,请注意,这些只是一个例子,对于我的实际实验,我使用不饱和图像)

这是我正在使用的“算法”:

  1. 从相机中分离出一张 1024 * 768 的图像
  2. 将相机移动已知距离(例如 3 个像素)
  3. 从相机中分离出另一个图像
  4. 通过对 1024 行中每一行的 768 个像素的像素颜色进行平均来从每个图像中获取数据(我获得了两个 double[1024] 数组)
  5. 对两个信号进行零填充:将每个 double[1024] 数组放在 double[2048] 数组的中心
  6. 计算两个信号的互相关
  7. 寻找互相关的最大值
  8. 为子样本精度应用抛物线拟合函数

我的问题如下:当初始阵列的边缘有强信号时(如您在示例中所见),并且图像的偏移很小(我会说小于 10 个像素,但我不能确定这是实际限制),互相关将指示偏移小于 0.1 像素。

我知道这可能来自使用 FFT/IFFT,但不应该使用零填充来避免这种行为吗?我能做些什么来避免它?

由于我的目标是测量非常小的变化,这完全阻碍了我的进步。

这是我为互相关编写的代码(ExperimentInit 和 ExperimentFinal 是我的 2 个首字母数组):

ExperimentInitWindowed = new double[ExperimentInit.Length];
ExperimentFinalWindowed = new double[ExperimentFinal.Length];
ExpInitLarge = new Complex[2 * ExperimentInit.Length];
ExpFinalLarge = new Complex[2 * ExperimentFinal.Length];
CrossCorrExpArrayReShifted = new double[RefInitLarge.Length];

//Zero-padding
for (int i = 0; i < ExpFinalLarge.Length / 2; i++)
{
    ExpInitLarge[i + ExpInitLarge.Length / 4] = ExperimentInit[i];
    ExpFinalLarge[i + ExpFinalLarge.Length / 4] = ExperimentFinal[i];
}

//FFT
Accord.Math.Transforms.FourierTransform2.FFT(ExpInitLarge, FourierTransform.Direction.Forward);
Accord.Math.Transforms.FourierTransform2.FFT(ExpFinalLarge, FourierTransform.Direction.Forward);

//Conjugating ExpFinal
Complex[] CompConjExpFinal = new Complex[RefInitLarge.Length];
for (int l = 0; l < ExpInitLarge.Length; l++)
{
    CompConjExpFinal[l] = Complex.Conjugate(ExpFinalLarge[l]);
    ExpFinalLarge[l] = CompConjExpFinal[l];
}

//Element-wise multiplication of the complex arrays
Complex[] ExpMultipliedArray = new Complex[ExpFinalLarge.Length];
for (int l = 0; l < RefFinalLarge.Length; l++)
{
    ExpMultipliedArray[l] = Complex.Multiply(ExpInitLarge[l], ExpFinalLarge[l]);
}

//InverseFFT
Accord.Math.Transforms.FourierTransform2.FFT(ExpMultipliedArray, FourierTransform.Direction.Backward);
double[] CrossCorrExpArrayRe = ExpMultipliedArray.Re();

//Reorganizing the data inside the array to center the zero frequency component
double[] LeftHalfExp = new double[ExpFinalLarge.Length / 2];
double[] RightHalfExp = new double[ExpFinalLarge.Length / 2];
double[] LeftHalfRef = new double[ExpFinalLarge.Length / 2];
double[] RightHalfRef = new double[ExpFinalLarge.Length / 2];

for (int l = 0; l < ExpFinalLarge.Length / 2; l++)
{
    LeftHalfExp[l] = CrossCorrExpArrayRe[l];
    RightHalfExp[l] = CrossCorrExpArrayRe[l + (ExpFinalLarge.Length / 2)];
    LeftHalfRef[l] = CrossCorrRefArrayRe[l];
    RightHalfRef[l] = CrossCorrRefArrayRe[l + (ExpFinalLarge.Length / 2)];
    CrossCorrExpArrayReShifted[l] = RightHalfExp[l];
    CrossCorrExpArrayReShifted[l + (ExpFinalLarge.Length / 2)] = LeftHalfExp[l];
}

这是查找互相关最大值和位移的代码:

//Finding max of the CrossCorr, and index of it
CrossCorrExpArrayReShiftedMax = CrossCorrExpArrayReShifted.Max();
CrossCorrExpArrayReShiftedMaxIndex = Array.IndexOf(CrossCorrExpArrayReShifted, CrossCorrExpArrayReShiftedMax);

//Performing LeastSquare Parabolic fitting
double[] xExp = { CrossCorrExpArrayReShiftedMaxIndex - 1, CrossCorrExpArrayReShiftedMaxIndex, CrossCorrExpArrayReShiftedMaxIndex + 1 };
double[] yExp = { CrossCorrExpArrayReShifted[CrossCorrExpArrayReShiftedMaxIndex - 1], CrossCorrExpArrayReShiftedMax, CrossCorrExpArrayReShifted[CrossCorrExpArrayReShiftedMaxIndex + 1] };
double[] CoefficientsExp = Fit.Polynomial(xExp, yExp, 2);
AtermExp = CoefficientsExp[2];
BtermExp = CoefficientsExp[1];
CtermExp = CoefficientsExp[0];

//Calculating shift
shiftLeastSquareExp = (-BtermExp / (2 * AtermExp)) - (CrossCorrExpArrayReShifted.Length / 2);

我很乐意提供您可能需要的任何其他信息。谢谢 !

编辑:我刚刚尝试使用此处描述的互相关方法,得到的结果与我自制的代码完全相同。这表明问题不是来自代码,而是来自我对互相关工作方式的理解,我认为。任何人都可以对此有所了解吗?

1个回答

我怀疑您需要对图像进行预美白。

这是一个有和没有预白的例子。

我找到了一种进行预白化的简单方法(尽管绝不是最佳方法),即首先对图像进行逐列比较。

这里还有一些文字。

图片版本

网格版本