OpenCV 4.12.0
开源计算机视觉
加载中...
搜索中...
无匹配项
离散傅里叶变换

上一个教程: 改变图像的对比度和亮度!
下一个教程: 使用XML / YAML / JSON文件进行文件输入和输出

原始作者Bernát Gábor
兼容性OpenCV >= 3.0

目标

我们将寻找以下问题的答案

  • 什么是傅里叶变换,为什么要使用它?
  • 如何在OpenCV中实现?
  • 使用以下函数: copyMakeBorder()merge()dft()getOptimalDFTSize()log()normalize()

源代码

以下是 dft() 的示例用法

解释

傅里叶变换将图像分解为正弦和余弦分量。换句话说,它将图像从空间域转换到频率域。其思想是任何函数都可以通过无限多个正弦和余弦函数的和来精确近似。傅里叶变换就是实现这一目的的一种方法。在数学上,二维图像的傅里叶变换是

\[F(k,l) = \displaystyle\sum\limits_{i=0}^{N-1}\sum\limits_{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

将图像扩展到最佳尺寸

DFT的性能取决于图像大小。对于尺寸是2、3和5倍数的图像,它的速度往往最快。因此,为了获得最佳性能,通常最好在图像上填充边界值,以获得具有这些特性的尺寸。 getOptimalDFTSize() 函数返回此最佳尺寸,我们可以使用 copyMakeBorder() 函数来扩展图像的边界(附加的像素用零初始化)

为复数值和实数值腾出空间

傅里叶变换的结果是复数。这意味着对于每个图像值,结果是两个图像值(每个分量一个)。此外,频率域的范围比其空间域对应物大得多。因此,我们通常至少以*浮点*格式存储这些值。因此,我们会将输入图像转换为此类型,并用另一个通道来存储复数值。

进行离散傅里叶变换

可以进行原地计算(输入和输出相同)

将实数值和复数值转换为幅度

复数有一个实部(Re)和一个复(虚部 - Im)部分。DFT的结果是复数。DFT的幅度是

\[M = \sqrt[2]{ {Re(DFT(I))}^2 + {Im(DFT(I))}^2}\]

转换为OpenCV代码

切换到对数尺度

傅里叶系数的动态范围太大,无法在屏幕上显示。我们有一些小值和一些变化大的值,无法这样观察。因此,高值将全部显示为白点,而小值将显示为黑点。为了使用灰度值进行可视化,我们可以将线性尺度转换为对数尺度

\[M_1 = \log{(1 + M)}\]

转换为OpenCV代码

裁剪和重排

还记得第一步中我们扩展了图像吗?现在是时候丢弃新引入的值了。为了可视化目的,我们还可以重新排列结果的象限,以便原点(零,零)与图像中心对应。

归一化

再次这样做是为了可视化目的。我们现在有了幅度,但这些值仍然超出我们图像显示范围(0到1)。我们使用 cv::normalize() 函数将我们的值归一化到此范围。

结果

一个应用想法是确定图像中存在的几何方向。例如,我们能否判断一段文本是水平的还是倾斜的?观察一些文本,你会发现文本行会形成水平线,而字母会形成垂直线。文本片段的这两个主要组成部分也可以在傅里叶变换中看到。让我们使用这张水平文本图像和这张旋转文本图像

对于水平文本

对于旋转文本

你可以看到频率域中最具影响力的分量(幅度图像上最亮点)遵循图像上物体的几何旋转。由此我们可以计算偏移量并执行图像旋转以纠正最终的未对齐。