【OpenCV 学习笔记】第十四章: 傅里叶变换

第十四章: 傅里叶变换

 前置知识补充,参考博文:傅里叶分析之掐死教程(完整版)更新于2014.06.06 - 知乎

这篇博文写得非常好!先把博文理解透了,再看本笔记。

  • 在图像处理过程中,傅里叶变换就是将图像分解成正弦分量和余弦分量两个部分,就是将图像从空间域转换到频率域。
    数字图像经过傅里叶变换后,得到的频域值是复数,所以显示傅里叶变换的结果要用实数图像(real image)+虚数图像(complex image)的形式,
    或者是幅度图像(magnitude image)+相位图像(phase image)的形式。

  • 幅度图像已经包含了原图像中我们所需要的大部分信息,所以在图像处理过程中,通常我们仅使用幅度图像。
    但是如果我们想先在频域内对图像进行处理,再通过逆傅里叶变换得到修改后的空域图像,就必须得同时保存幅度图像和相位图像。

  • 对图像进行傅里叶变换后,我们得到的是图像中的低频信息和高频信息。
    低频信息对应的是图像内变化缓慢的灰度分量。高频信息对应图像内变化越来越块的灰度分量,是由灰度的尖锐过渡造成的。
    例如,一幅大草原中有一头狮子的图像,低频信息就对应着颜色趋于一致的草原的细节信息,高频信息则对应着狮子的轮廓等各种边缘及噪声信息。

  • 傅里叶变换就是将图像从空域转换到频域,目的是在频域内实现对图像内特定对象的处理,然后再对经过处理的频域图像进行逆傅里叶变换得到空域图像。
    傅里叶变换在图像处理领域有着非常关键的作用,可以实现图像增强、图像去噪、边缘检测、特征提取、图像压缩和加密等操作。

一、用Numpy实现傅里叶变换

1、傅里叶变换

  • 傅里叶变换函数:f = np.fft.fft2(img)
    img:原始图像,必须是灰度图像!!
    f:函数的返回值,是一个复数数组complex ndarray。这个返回对象就是图像img的频谱信息,也是一个频谱图像,也叫频域图像。

  • 将频谱图像中的零频率分量移动到频谱图像的中心位置:fshift = np.fft.fftshift(f)
    f:上面傅里叶变换函数的返回值。
    fshift:函数的返回值,也还是一个复数数组,就是把零频率分量移动到图像的中心位置,这样方便观察傅里叶变换后频谱中的零频率。

  • 显示频谱图像:magnitude_spectrum(新像素值) = 20 x np.log(np.abs(fshift)) , 然后再plt.imshow(magnitude_spectrum)

2、逆傅里叶变换

  • 将频谱图像中的零频率分量移动到原位,原位就是频谱图像的左上角。
    ishift = np.fft.ifftshift(原始频谱)
    ishift就是调整会原位后的频谱图像
    不管是原始频谱图像还是调整后的频谱图像都是复数数组。

  • 逆傅里叶变换:iimg = np.fft.ifft2(ishift)
    ishift是频域数据,就是上面函数的返回值
    iimg:是空域信息,但还是一个复数数组,需要将信息调整到[0,256]灰度空间内

  • 显示逆傅里叶变换图像:img_inv = np.abs(iimg) , 然后再plt.imshow(img_inv)

3、分离高频信号和低频信号
一幅灰度图像经过傅里叶变换、再经过零频率往图像中心移动后,得到的频域图像,这个频域图像的中间部分是低频信号,四周是高频信号。
那我们就可以以频域图像的中心为中心,上下左右各取30个像素点的区域,作为高低频信号的分界线,让这个区域的像素值置为零,就得到低频信号的频域图。反之其他区域置为零,就得到高频信号的频域图。 然后再对高低频域图像进行逆傅里叶变换,就得到原图的高低频分离图像了。

#例14.1 用Numpy实现傅里叶变换、逆变换、分离高频信号和低频信号      
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp',0)  #img.shape返回(512, 512)

#------------------生成并显示频谱图像-------------------------------------
f = np.fft.fft2(img)   #生成频谱图像, f是一个浮点型的数组,是一个复数数组。  f.shape返回(512, 512)
fshift = np.fft.fftshift(f)   #将零频率分量移动到中心位置, fshift也是一个浮点型的复数数组。fshift.shape返回(512, 512)
magnitude_spectrum = 20*np.log(np.abs(fshift))   #为显示图像,将复数值调到[0,256]的灰度空间内。  magnitude_spectrum.shape返回(512, 512)
magnitude_spectrum1 = 20*np.log(np.abs(f)) #假如不移动零频率分量,看看图像呈现什么样子  

#-------------------------实现傅里叶逆变换-----------------------------------
ishift = np.fft.ifftshift(fshift)  #将零频率分量还原      (ishift == f).sum() = 512*512
iimg = np.fft.ifft2(ishift)  #逆傅里叶变换,变换后的结果还是一个复数数组
img_inv = np.abs(iimg)    #将复数数组转换到[0,256]灰度区间内

#---------------------------分离高低频信号-------------------------------
center_row = int(img.shape[1]/2)      #生成中心点
center_col = int(img.shape[0]/2)

fshift1 = fshift.copy()
fshift1[center_row-30:center_row+30, center_col-30:center_col+30]=0   #把中间的区域置为0,生成高频信号频域图
ifshift1 = np.fft.ifftshift(fshift1)
iimg = np.fft.ifft2(ifshift1)
img_inv1 = np.abs(iimg)

fshift2 = fshift.copy()   #把四周区域都置为0,生成低频信号频域图
fshift2[0:center_row-30]=0
fshift2[center_row+30:]=0
fshift2[:, 0:center_col-30]=0
fshift2[:, center_col+30:]=0
ifshift2 = np.fft.ifftshift(fshift2)
iimg2 = np.fft.ifft2(ifshift2)
img_inv2 = np.abs(iimg2)

#可视化:
plt.figure(figsize=(16,6))
plt.subplot(161), plt.imshow(img, cmap='gray')    #原图
plt.subplot(162), plt.imshow(magnitude_spectrum, cmap='gray')   #频域图
plt.subplot(163), plt.imshow(magnitude_spectrum1, cmap='gray')  #不移动零频率分量的频域图
plt.subplot(164), plt.imshow(img_inv, cmap='gray')     #频域图逆变换的结果
plt.subplot(165), plt.imshow(img_inv1, cmap='gray')   #高频信号频域图的逆傅里叶变换结果图,都是边缘,都是像素变换较大的区域。比如脸里面、帽子里面、皮肤里面变化较小的区域都过滤掉了。
plt.subplot(166), plt.imshow(img_inv2, cmap='gray')   #低频信号频域图的逆傅里叶变换结果图,边缘模糊了,都是一些变换较缓的区域。和前面图的情况正好相反。  
plt.show()

二、用opencv实现傅里叶变换

  • 1、傅里叶变换函数:f = cv2.dft(img, flags)       #对比np:f = np.fft.fft2(img)
    img:原始图像,首先要使用np.float32()函数将图像转化为np.float32格式。
    flags:转换标识,通常flags = cv2.DFT_COMPLEX_OUTPUT,用来输出一个复数阵列。
    函数的返回结果和使用numpy的结果是一样的,但形式不一样,这里返回的值是双通道的,第一个通道是结果的实数部分,第二个通道是结果的虚数部分。
    通过这个函数我们就得到一幅图像的频谱信息。但是零频率分量也是不在中心位置,所以要移动零频率分量到中心位置。

  • 将频谱图像中的零频率分量移动到频谱图像的中心位置:fshift = np.fft.fftshift(f)       #同numpy里面的操作
    f:上面函数的返回值。
    fshift:函数的返回值,还是一个双通道复数数组。

  • 计算频谱信息的幅度:dst = cv2.magnitude(fshift[:,:,0], fshift[:,:,1])
    参数1:浮点型x坐标值,也就是实部
    参数2:浮点型y坐标值,也就是虚部
    dst:返回值,是参数1的平方和参数2的平方的开方。

  • 将频谱信息映射到[0,256]之间,方便以图像的形式展示出来:result = 20 x np.log(dst)      #numpy里面是20 x np.log(np.abs(fshift))
    然后再plt.imshow(result)

  • 2、傅里叶逆变换:iimg = cv2.idft(f) f是频域数据
    iimg:是空域信息,但仍旧是一个复数数组,需要用函数cv2.magnitude()计算幅度。

说明:如果一幅灰度图像进了傅里叶变换,并且移动了零频率向量,那用上面函数进行逆变换时,要先把零频率向量恢复到原来的位置后,再作为参数传入。

#例14.2 用opencv实现傅里叶变换、逆变换、分离高频信号和低频信号      
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp',0)  #img.shape返回(512, 512)
#----------------进行傅里叶变换-------------------------------------------
f = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)   #傅里叶变换, f是一个float32类型的array数组,f.shape返回(512, 512, 2)
fshift = np.fft.fftshift(f)   #零频率分量向中心移动。 fshift也f数据类型一样,数据结构也一样。  
dst = cv2.magnitude(fshift[:,:,0], fshift[:,:,1])   #计算频谱幅度。dst.shape返回(512, 512)
result = 20*np.log(dst)  #映射到[0,256]
#----------------进行傅里叶逆变换-----------------------------------------
iimg = cv2.idft(f)   #逆变换
dst1 = cv2.magnitude(iimg[:,:,0], iimg[:,:,1])   #计算幅度

#---------------------------分离高低频信号-------------------------------
center_row = int(img.shape[1]/2)      #生成中心点
center_col = int(img.shape[0]/2)

fshift1 = fshift.copy()
fshift1[center_row-30:center_row+30, center_col-30:center_col+30,:]=0   #把中间的区域置为0,生成高频信号频域图
ifshift1 = np.fft.ifftshift(fshift1)
iimg = cv2.idft(ifshift1)
img_inv1 = cv2.magnitude(iimg[:,:,0], iimg[:,:,1])

fshift2 = fshift.copy()   #把四周区域都置为0,生成低频信号频域图
fshift2[0:center_row-30]=0
fshift2[center_row+30:]=0
fshift2[:, 0:center_col-30]=0
fshift2[:, center_col+30:]=0
ifshift2 = np.fft.ifftshift(fshift2)
iimg2 = cv2.idft(ifshift2)
img_inv2 = cv2.magnitude(iimg2[:,:,0], iimg2[:,:,1])

#可视化:
plt.figure(figsize=(16,6))
plt.subplot(161), plt.imshow(img, cmap='gray')    #原图
plt.subplot(162), plt.imshow(result, cmap='gray')   #频域图
plt.subplot(163), plt.imshow(dst1, cmap='gray')  #逆傅里叶变换后的图像
plt.subplot(164), plt.imshow(img_inv1, cmap='gray')  #
plt.subplot(165), plt.imshow(img_inv2, cmap='gray')  #
plt.show()

猜你喜欢

转载自blog.csdn.net/friday1203/article/details/125078590