OpenCV(31)---傅里叶变换原理

669 阅读6分钟

前言

要理解傅里叶变换,我们首先需要了解图像处理。在图像处理的过程中,一般分为空间域处理和频率域处理。

空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰度变换和空间滤波两种形式。灰度变换是对图像内的单个像素进行处理,比如调节对比度和处理阈值等。控制滤波处理涉及图像质量的改变,例如前面的图像平滑处理。空间域处理的优点:计算简单方便,运算速度更快

频率域处理时先将图像变换到频率域,然后在频率域对图像进行处理,最后在通过反变换将图像从频率域变换到空间域。傅里叶变换是应用最广泛的一种频率域变换,它能够将图像从空间域变换到频率域,而逆傅里叶变换能够将频率域信息变换到空间域内。

傅里叶变化

法国数学家傅里叶指出,任何周期函数都可以表示为不同频率的正弦函数和的形式。

在图像的处理中,傅里叶变换就是将图像分解为正弦分量和余弦分量两部分,即将图像从空间域转换到频率域。数字图像经过傅里叶变化后,得到的频率域的值是复数。因此显示傅里叶变换的结果需要使用实数图像加虚数图像,或者幅度图像加相位图像的形式。

因为幅度图像包含了原图像中我们所需要的大部分信息,所以在图像的处理过程中,通常仅使用幅度图像。当然,如果希望先在频率域内对图像进行处理,再通过傅里叶变换得到修改后的空间域图像,就必须同时保留幅度图像和相位图像。

对图像进行傅里叶变换后,我们会得到图像中的低频与高频信息。低频信息对应图像内变化缓慢的灰度分量。高频信息对应图像内变换越来越快的灰度分量,是由灰度的尖锐过度造成的。例如,在一副大草原的图像中有一头狮子,低频信息就对应着广袤的草原,而高频信息对应着狮子的轮廓等各种边界及噪声信息。

傅里叶变换的作用,就是为了将图像从空域转换到频域,并在频率域内实现对图像内特定对象的处理,然后再对经过处理的频率域图像进行逆傅里叶变换得到空间域图像。其主要用处包括:图像增强,图像去噪,边缘检测,特征提取,图像压缩,图像加密等。

实现傅里叶变化

在Numpy包中,它给我们提供了numpy.fft.fft2()函数实现傅里叶变换。其完整定义如下:

def fft2(原始图像):

需要注意的是,原始图像必须是灰度图像,其返回值是ndarray类型。

下面,我们来实现傅里叶变换,并观察得到的频谱图像:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("4.jpg", 0)#1
f = np.fft.fft2(img)#2
fshift = np.fft.fftshift(f)#3
spectrum = 20 * np.log(np.abs(fshift))#4
#5
plt.subplot(121)
plt.imshow(img)
plt.axis('off')
#6
plt.subplot(122)
plt.imshow(spectrum)
plt.axis('off')
#7
plt.show()

上面代码以此代表的意思如下:

1.使用OpenCV以灰度图像的形式读取

2.实现傅里叶变换

3.经过2傅里叶变换函数处理之后。此时,图像频谱中的零频率分量位于频谱图像的左上角,为了便于观察,这里通过函数np.fft.fftshift将零频谱成分移动到频域图像的中心位置。

4.对图像进行傅里叶变换之后,得到的是一个复数数组。为了显示为图像,需要将它们的值调整到[0,255]的灰度空间内,通过20 * np.log(np.abs(fshift))实现。

5.以灰度图像的形式绘制原图

6.以灰度图像的形式绘制频域图

7.显示2个图

运行之后,效果如下:

图像

实现逆傅里叶变化

既然我们在实现傅里叶变换之时,将零频谱移动到了图像中间。那么,在逆变换的时候,我我们就需要将其移回去,该移回去的逆函数是np.fft.ifftshift()。而移回去之后,才可以进行逆傅里叶变换。

逆傅里叶变换函数为np.fft.ifft2()。它返回空域信息是一个复数数组,同样需要我们将信息调整到[0,255]之间。使用公式为:np.abs(逆傅里叶变换结果)。

下面,我们实现傅里叶变换以及逆傅里叶变换。代码如下所示:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("4.jpg", 0)
#傅里叶变换
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)

ishift=np.fft.ifftshift(fshift)
iimg=np.fft.ifft2(ishift)
iimg=np.abs(iimg)
print(iimg)
print(img)

plt.subplot(121)
plt.imshow(img,cmap="gray")
plt.axis('off')
plt.subplot(122)
plt.imshow(iimg,cmap="gray")
plt.axis('off')
plt.show()

高通滤波与低通滤波

经过前文的介绍,我们知道在一副图像内,同时存在着高频信号和低频信号。而滤波器你可以把它想象成平时生活中的漏斗,它能够允许一定频率的分量通过或者拒绝其通过。

我们通过滤波器的作用方式,将其分为低通滤波器与高通滤波器。(题外话,此高通非彼高通,皮一下)

低通滤波器:允许低频信号通过。低通滤波器使高频信号衰减而对低频信号放行,会使图像变得模糊

高通滤波器:允许高频信号通过。高通滤波器使低频信号衰减而让高频信号通过,将增强图像中尖锐的细节,但是会导致图像的对比度降低。

频域处理就是对图像的高频或低频信号进行处理后,再进行逆傅里叶变换返回空间域。

下面,我们来通过傅里叶的正逆操作,实现高通滤波。代码如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("4.jpg", 0)
# 傅里叶变换
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)

#屏蔽低频信号
rows, cols = img.shape
row_half, col_half = int(rows / 2), int(cols / 2)
fshift[row_half-20:row_half+20,col_half-20:col_half+20]=0

#逆傅里叶变换
ishift=np.fft.ifftshift(fshift)
iimg=np.fft.ifft2(ishift)
iimg=np.abs(iimg)

plt.subplot(121)
plt.imshow(img, cmap="gray")
plt.axis('off')
plt.subplot(122)
plt.imshow(iimg, cmap="gray")
plt.axis('off')
plt.show()

上面的代码中,主要通过3行代码屏蔽低频信号,代码如下:

rows, cols = img.shape
row_half, col_half = int(rows / 2), int(cols / 2)
fshift[row_half-20:row_half+20,col_half-20:col_half+20]=0

我们通过前文知道,np.fft.fftshift会将零频率分量移动到图像的中心区域,那么从中心区域向外扩散就是从低到高。所以,我们只要将中心周围部分的低频信号屏蔽,就保留的高频信号,也就是实现了高通滤波。

这里我们选择从中心向外扩散30半径,将其内部的所有低频信号全部赋值为0即可。运行之后,我们会得到高通滤波的图像,同时该图像的边缘信息得以保留。

高通滤波图像