图像的互相关

CrossCorrelation of images

我使用Accord Framework实现了两张图片的互相关。我的目标是找到第二张图像与第一张图像相比移动了多少(多少像素,以及在哪个方向)。

我使用的基本公式如下:

我会将整个代码放在消息的末尾,一切都发生在 Click 事件上。我的初始图像存储在 1024*768 位图中。所以这是我采取的步骤:

  1. 我将 2 个图像裁剪到我感兴趣的 4 个区域 (ExpInit, ExpFinal, RefInit, RefFinal),我想将它们两两关联起来(ExpInitExpFinalRefInitRefFinal)。这些裁剪后的图像尺寸为 1024*131。
  2. 我将这些裁剪后的图像放在 2^n 维 (2048*512) 的新位图的中心。
  3. 应用 Grayscaling 过滤器得到 8bppIndexed PixelFormat
  4. 将每个图像转换为 ComplexImage 格式并对 4 个图像应用前向 FFT。
  5. 复共轭 RefFinalExpFinal 傅立叶变换 ComplexImage.
  6. 中的每个元素
  7. 在我想要交叉关联的 ComplexImage 对象之间执行逐元素乘法(ExpInitExpFinalRefInitRefFinal)。
  8. 将反向 FFT 应用于逐元素乘法的乘积。 Tadaaa,我的互相关已完成,我有两个 Complex[,] 个对象,其尺寸为我的图像(2048*512 像素)

现在我想回答我最初的问题:与 ExpInit(分别为 ExpFinal)相比,ExpFinal(分别为 RefFinal)图像移动了多少(多少像素,在哪个方向)。到这里我就纳闷了。

我有直觉我应该用我的 Complex[,] 对象绘制 3D 图形,其中 x 和 y 是数组中的索引,z 是索引处的值,并搜索最大值,但是我该如何处理复数呢?我只使用 Re 部分吗?只有 Im 部分?振幅?还是我完全错了?

奖励问题:什么是绘制此类图形的好库?

下面是所描述的互相关的完整代码:

        private void crosscorrButton_Click(object sender, EventArgs e)
    {
        // Cropping all 4 sections (RefInit, ExpInit, RefFinal, ExpFinal) and placing them in the center of new Bitmaps with 2^n dimensions
        Rectangle rExp = new Rectangle(1, 157, 1024, 131);
        Bitmap ExpInitCrop = new Bitmap(rExp.Width, rExp.Height);
        Graphics g = Graphics.FromImage(ExpInitCrop);
        g.DrawImage(BMInit, -rExp.X, -rExp.Y);
        Bitmap ExpInitLarge = new Bitmap(2048, 512);
        using (Graphics largeGraphics = Graphics.FromImage(ExpInitLarge))
        {
            largeGraphics.DrawImage(ExpInitCrop, 513, 190);
        }
        Rectangle rRef = new Rectangle(1, 484, 1024, 131);
        Bitmap RefInitCrop = new Bitmap(rRef.Width, rRef.Height);
        Graphics h = Graphics.FromImage(RefInitCrop);
        h.DrawImage(BMInit, -rRef.X, -rRef.Y);
        Bitmap RefInitLarge = new Bitmap(2048, 512);
        using (Graphics largeGraphics = Graphics.FromImage(RefInitLarge))
        {
            largeGraphics.DrawImage(RefInitCrop, 513, 190);
        }
        Bitmap ExpFinalCrop = new Bitmap(rExp.Width, rExp.Height);
        Graphics i = Graphics.FromImage(ExpFinalCrop);
        i.DrawImage(BMFinal, -rExp.X, -rExp.Y);
        Bitmap ExpFinalLarge = new Bitmap(2048, 512);
        using (Graphics largeGraphics = Graphics.FromImage(ExpFinalLarge))
        {
            largeGraphics.DrawImage(ExpFinalCrop, 513, 190);
        }
        Bitmap RefFinalCrop = new Bitmap(rRef.Width, rRef.Height);
        Graphics j = Graphics.FromImage(RefFinalCrop);
        j.DrawImage(BMFinal, -rRef.X, -rRef.Y);
        Bitmap RefFinalLarge = new Bitmap(2048, 512);
        using (Graphics largeGraphics = Graphics.FromImage(RefFinalLarge))
        {
            largeGraphics.DrawImage(RefFinalCrop, 513, 190);
        }

        // Grayscalling the 4 sections to get 8bppIndexed PixelFormat
        Accord.Imaging.Filters.Grayscale filterGS = new Accord.Imaging.Filters.Grayscale(0.2125, 0.7154, 0.0721);
        Bitmap RefFinalLargeGS = filterGS.Apply(RefFinalLarge);
        Bitmap ExpFinalLargeGS = filterGS.Apply(ExpFinalLarge);
        Bitmap RefInitLargeGS = filterGS.Apply(RefInitLarge);
        Bitmap ExpInitLargeGS = filterGS.Apply(ExpInitLarge);

        // FFT on the 4 sections
        Accord.Imaging.ComplexImage ExpInitComplex = Accord.Imaging.ComplexImage.FromBitmap(ExpInitLargeGS);
        ExpInitComplex.ForwardFourierTransform();
        Accord.Imaging.ComplexImage RefInitComplex = Accord.Imaging.ComplexImage.FromBitmap(RefInitLargeGS);
        RefInitComplex.ForwardFourierTransform();
        Accord.Imaging.ComplexImage ExpFinalComplex = Accord.Imaging.ComplexImage.FromBitmap(ExpFinalLargeGS);
        ExpFinalComplex.ForwardFourierTransform();
        Accord.Imaging.ComplexImage RefFinalComplex = Accord.Imaging.ComplexImage.FromBitmap(RefFinalLargeGS);
        RefFinalComplex.ForwardFourierTransform();

        //Conjugating the ExpFinal and RefFinal section
        Complex[,] CompConjExpFinal = new Complex[ExpFinalComplex.Height, ExpFinalComplex.Width];
        Complex[,] CompConjRefFinal = new Complex[RefFinalComplex.Height, RefFinalComplex.Width];
        for (int l = 0; l < ExpFinalComplex.Height; l++)
        {
            for (int m = 0; m < ExpFinalComplex.Width; m++)
            {
                CompConjExpFinal[l, m] = System.Numerics.Complex.Conjugate(ExpFinalComplex.Data[l, m]);
                ExpFinalComplex.Data[l, m] = CompConjExpFinal[l, m];
            }
        }
        for (int l = 0; l < RefFinalComplex.Height; l++)
        {
            for (int m = 0; m < RefFinalComplex.Width; m++)
            {
                CompConjRefFinal[l, m] = System.Numerics.Complex.Conjugate(RefFinalComplex.Data[l, m]);
                RefFinalComplex.Data[l, m] = CompConjRefFinal[l, m];
            }
        }

        //Element-wise multiplication of the complex arrays two by two
        Complex[,] ExpMultipliedMatrix = new Complex[ExpFinalComplex.Height, ExpFinalComplex.Width];
        Complex[,] RefMultipliedMatrix = new Complex[RefFinalComplex.Height, RefFinalComplex.Width];
        for (int l = 0; l < ExpFinalComplex.Height; l++)
        {
            for (int m = 0; m < ExpFinalComplex.Width; m++)
            {
                ExpMultipliedMatrix[l, m] = System.Numerics.Complex.Multiply(ExpInitComplex.Data[l, m], ExpFinalComplex.Data[l, m]);
                RefMultipliedMatrix[l, m] = System.Numerics.Complex.Multiply(RefInitComplex.Data[l, m], RefFinalComplex.Data[l, m]);
            }
        }

        //InverseFFT
        Complex[,] CrossCorrExpMatrix = new Complex[ExpFinalComplex.Height, ExpFinalComplex.Width];
        Complex[,] CrossCorrRefMatrix = new Complex[RefFinalComplex.Height, RefFinalComplex.Width];
        Accord.Math.FourierTransform.FFT2(ExpMultipliedMatrix, FourierTransform.Direction.Backward);
        Accord.Math.FourierTransform.FFT2(RefMultipliedMatrix, FourierTransform.Direction.Backward);
        CrossCorrExpMatrix = ExpMultipliedMatrix;
        CrossCorrRefMatrix = RefMultipliedMatrix;
    }

非常感谢!

结果的虚部应为0(或在数值误差范围内)。要找到偏移,您应该查看相关幅度峰值的位置(但除非您得到一个是另一个的负像,否则它很可能对应于相关实部的峰值)。需要注意的主要事项:由于您将两个图像都居中,因此将引入额外的偏移(图像大小的一半)。

至于查看图表,您可以相当轻松地将结果映射到灰度图像并使用您最喜欢的图像查看器进行查看。