一、原理
参考:【OpenCV-Python】:图像的傅里叶变换与逆傅里叶变换_envi进行傅里叶逆变换结果中间颜色不对-优快云博客
二、numpy 傅里叶变换
1.1 傅里叶变换 np.fft.fft2()
f = np.fft.fft2(src=*,s=None,axes=(-2,-1))
f:函数返回值,含复数的数组(complex,ndarray)。
src:输入图像的像素矩阵,灰度图。
s:整数序列,输出数组大小,默认为:与原始图像一样大。
axes:整数轴,默认为:使用最后2个轴。
fshift = np.fft.fftshift(f) # 0 频率中心化。
0 频率中心化。
fimg = 20*np.log(np.abs(fshift)) # 复数数组转 [0,256] 的灰度值。
复数数组转 [0,256] 的灰度值。
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family']=['Microsoft JhengHei']
img = cv2.imread('Lena.png',cv2.IMREAD_GRAYSCALE) # 灰度图像
# cv2.imshow('Lena',img)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121)
plt.imshow(img,cmap='gray')
plt.title('原始图像')
plt.axis('off')
plt.subplot(122)
plt.imshow(spectrum,cmap='gray')
plt.title('频谱图')
plt.axis('off')
plt.savefig('DFT.png',dpi=300,bbox_inches='tight')
plt.show()
1.2 逆傅里叶变换 np.fft.ifftshift()
ifshift = np.fft.ifftshift(fshift) # 0 频率移会左上角。
img_tmp = np.fft.ifft2(ifshift) # np.fft.fft2()的逆变换。
img_back = np.abs(img_tmp) # img_tmp仍是一个复数数组,需要取绝对值。
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family']=['Microsoft JhengHei']
img = cv2.imread('Lena.png',cv2.IMREAD_GRAYSCALE) # 灰度图像
# cv2.imshow('Lena',img)
# 正傅里叶变换
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
spectrum = 20*np.log(np.abs(fshift))
# 逆傅里叶变换
ifshift = np.fft.ifftshift(fshift)
img_tem = np.fft.ifft2(ifshift)
img_back = np.abs(img_tem)
plt.subplot(131)
plt.imshow(img,cmap='gray')
plt.title('原始图像')
plt.axis('off')
plt.subplot(132)
plt.imshow(spectrum,cmap='gray')
plt.title('频谱图')
plt.axis('off')
plt.subplot(133)
plt.imshow(img_back,cmap='gray')
plt.title('逆变换')
plt.axis('off')
plt.savefig('DFT1.png',dpi=300,bbox_inches='tight')
plt.show()
三、OpenCV傅里叶变换
3.1 傅里叶变换 cv2.dft()
dft = cv2.dft(src=*,flags=*)
dft:函数返回值,含复数的数组(complex,ndarray),含有两个通道,一个是实数部分,一个是虚数部分。
src:输入图像的像素矩阵,灰度图。
flags:傅里叶变换方法,常见方法如下:
方法 | 值 | 解释 |
DFT_INVERSE | 1 | 对一维或二维数组做逆变换 |
DFT_SCALE | 2 | 输出除以元素数目N |
DFT_ROWS | 4 | 对输入变量的每一行进行变换或逆变换 |
DFT_COMPLEX_OUTPUT | 16 | 输出含有实数和虚数 |
DFT_REAL_OUTPUT | 32 | 输出是复数矩阵 |
DFT_COMPLEX_INPUT | 64 | 输入是复数矩阵 |
dftshift = np.fft.fftshift(dft) # 0 频率中心化
# 将振幅值映射到 [0,255] 的灰度空间
dst = 20*np.log(cv2.magnitude(dftshift[:,:,0],dftshift[:,:,1]))
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family']=['Microsoft JhengHei']
img = cv2.imread('Lena.png',cv2.IMREAD_GRAYSCALE) # 灰度图像
# cv2.imshow('Lena',img)
# 正傅里叶变换
dft = cv2.dft(src=np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
dftshift = np.fft.fftshift(dft)
img1 = 20*np.log(cv2.magnitude(dftshift[:,:,0],dftshift[:,:,1]))
# 画图
plt.subplot(121)
plt.imshow(img,cmap='gray')
plt.title('原始图像')
plt.axis('off')
plt.subplot(122)
plt.imshow(img1,cmap='gray')
plt.title('频谱图')
plt.axis('off')
plt.savefig('OpenCV_DFT1.png',dpi=300,bbox_inches='tight')
plt.show()
3.2 逆傅里叶变换 cv2.idft()
dst = cv2.idft(src=*,flags)
参数与 cv2.dft() 函数基本相同。
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family']=['Microsoft JhengHei']
img = cv2.imread('Lena.png',cv2.IMREAD_GRAYSCALE) # 灰度图像
# cv2.imshow('Lena',img)
# 正傅里叶变换
dft = cv2.dft(src=np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
dftshift = np.fft.fftshift(dft)
img1 = 20*np.log(cv2.magnitude(dftshift[:,:,0],dftshift[:,:,1]))
# 逆傅里叶变换
idftshift = np.fft.ifftshift(dftshift)
tmp = cv2.idft(idftshift)
img2 = cv2.magnitude(tmp[:,:,0],tmp[:,:,1])
# 画图
plt.subplot(131)
plt.imshow(img,cmap='gray')
plt.title('原始图像')
plt.axis('off')
plt.subplot(132)
plt.imshow(img1,cmap='gray')
plt.title('频谱图')
plt.axis('off')
plt.subplot(133)
plt.imshow(img2,cmap='gray')
plt.title('逆变换')
plt.axis('off')
plt.savefig('OpenCV_DFT2.png',dpi=300,bbox_inches='tight')
plt.show()
3.3 高通滤波器
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family']=['Microsoft JhengHei']
img = cv2.imread('Lena.png',cv2.IMREAD_GRAYSCALE) # 灰度图像
# 正傅里叶变换
dft = cv2.dft(src=np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
dftshift = np.fft.fftshift(dft)
# 高通滤波器
h,w = img.shape[:2]
row,col = h//2,w//2 # 中心点坐标
mask = np.ones((h,w,2),float)*255
mask[row-30:row+30,col-30:col+30]=0 # 可以自行控制滤波器的大小
# 滤波
fshift = dftshift * mask
img1 = 20*np.log(cv2.magnitude(fshift[:,:,0]+0.01,fshift[:,:,1]+0.01))
# 逆傅里叶变换
idftshift = np.fft.ifftshift(fshift)
tmp = cv2.idft(idftshift)
img2 = cv2.magnitude(tmp[:,:,0],tmp[:,:,1])
# 画图
plt.subplot(141)
plt.imshow(img,cmap='gray')
plt.title('原始图像')
plt.axis('off')
plt.subplot(142)
plt.imshow(img1,cmap='gray')
plt.title('高通滤波器')
plt.axis('off')
plt.subplot(143)
plt.imshow(img2,cmap='gray')
plt.title('高通滤波器灰度图')
plt.axis('off')
plt.subplot(144)
plt.imshow(img2,)
plt.title('高通滤波图像')
plt.axis('off')
plt.savefig('OpenCV_DFT3.png',dpi=300,bbox_inches='tight')
plt.show()
3.4 低通滤波器
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family']=['Microsoft JhengHei']
img = cv2.imread('Lena.png',cv2.IMREAD_GRAYSCALE) # 灰度图像
# 正傅里叶变换
dft = cv2.dft(src=np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
dftshift = np.fft.fftshift(dft)
# 低通滤波器
h,w = img.shape[:2]
row,col = h//2,w//2 # 中心点坐标
mask = np.zeros((h,w,2),float)
mask[row-30:row+30,col-30:col+30]=255 # 可以自行控制滤波器的大小
# 滤波
fshift = dftshift * mask
img1 = 20*np.log(cv2.magnitude(fshift[:,:,0]+0.01,fshift[:,:,1]+0.01))
# 逆傅里叶变换
idftshift = np.fft.ifftshift(fshift)
tmp = cv2.idft(idftshift)
img2 = cv2.magnitude(tmp[:,:,0],tmp[:,:,1])
# 画图
plt.subplot(141)
plt.imshow(img,cmap='gray')
plt.title('原始图像')
plt.axis('off')
plt.subplot(142)
plt.imshow(img1,cmap='gray')
plt.title('低通滤波器')
plt.axis('off')
plt.subplot(143)
plt.imshow(img2,cmap='gray')
plt.title('低通滤波器灰度图')
plt.axis('off')
plt.subplot(144)
plt.imshow(img2,)
plt.title('低通滤波图像')
plt.axis('off')
plt.savefig('OpenCV_DFT4.png',dpi=300,bbox_inches='tight')
plt.show()