离散傅里叶变换(DFT)原理与 OpenCV 实现
目标
本文旨在解答以下核心问题:
- 什么是傅里叶变换,为什么要使用它?
- 如何在 OpenCV 中高效地实现离散傅里叶变换?
- 涉及的关键函数有哪些?
我们将通过 C++ 代码示例,演示如何计算图像的 DFT 并显示其功率谱。
理论基础
傅里叶变换会将图像分解为正弦和余弦分量。换句话说,它将图像从其空间域转换为其频域。这个想法是,任何函数都可以用无限正弦和余弦函数的总和精确近似。傅里叶变换是一种如何做到这一点的方法。
在数学上,二维图像傅里叶变换公式为:
$$F(k, l) = \sum_{i=0}^{N-1} \sum_{j=0}^{N-1} f(i, j) e^{-i2\pi(\frac{ki}{N} + \frac{lj}{N})}$$
其中 $e^{ix} = \cos x + i \sin x$。
这里 $f$ 是其空间域中的图像值,$F$ 是其频域中的图像值。变换的结果是复数。可以通过实部和虚部图像或幅度和相位图像来显示这一点。然而,在整个图像处理算法中,只有幅度图像是有趣的,因为它包含我们需要的有关图像几何结构的所有信息。但是,如果您打算以这些形式对图像进行一些修改,然后需要重新转换它,则需要保留这两种形式。
在此示例中,我将演示如何计算和显示傅里叶变换的幅度图像。在数字图像的情况下是离散的。这意味着它们可能会占用给定域值中的值。例如,在基本灰度中,图像值通常介于 0 和 255 之间。因此,傅里叶变换也需要是离散类型,从而产生离散傅里叶变换(DFT)。每当您需要从几何角度确定图像的结构时,您都需要使用它。
实现步骤
以下是处理灰度输入图像 $I$ 的标准流程:
1. 将图像扩展到最佳大小
DFT 的性能取决于图像大小。对于数字 2、3 和 5 的倍数的图像大小,它往往是最快的。因此,为了实现最佳性能,通常最好将边框值填充到图像上,以获得具有此类特征的大小。getOptimalDFTSize() 返回这个最佳大小,我们可以使用 copyMakeBorder 函数来扩展图像的边框(附加的像素初始化为零)。
Mat padded;
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols); // 在边框上添加零值
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
2. 为复杂和真实的价值腾出空间
傅里叶变换的结果很复杂。这意味着对于每个图像值,结果是两个图像值(每个组件一个)。此外,频域范围远大于其空间对应范围。因此,我们通常至少以浮点格式存储这些内容。因此,我们将输入图像转换为此类型,并使用另一个通道对其进行扩展以保存复数值:
Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI);


