python图像的频域(傅里叶变换、低通滤波)
计算机视觉
课程实验2图像的频域
- 请叙述傅里叶变换的作用并编程实现图像的傅里叶变换,对比时域和频域的结果。如果采用zero padding方式改变图片大小,此时分析零填充对傅里叶变换的影响。
傅里叶变换的作用:
1.图像增强与图像去噪
绝大部分噪音都是图像的高频分量,通过低通滤波器来滤除高频—噪声; 边缘也是图像的高频分量,可以通过添加高频分量来增强原始图像的边缘;
2.图像分割之边缘检测提取图像高频分量
3.图像特征提取:
形状特征:傅里叶描述子
纹理特征:直接通过傅里叶系数来计算纹理特征
其他特征:将提取的特征值进行傅里叶变换来使特征具有平移、伸缩、旋转不变性
4.图像压缩
可以直接通过傅里叶系数来压缩数据;常用的离散余弦变换是傅立叶变换的实变换;傅立叶变换。
傅里叶变换是将时域信号分解为不同频率的正弦信号或余弦函数叠加之和。连续情况下要求原始信号在一个周期内满足绝对可积条件。离散情况下,傅里叶变换一定存在。冈萨雷斯版<图像处理>里面的解释非常形象:一个恰当的比喻是将傅里叶变换比作一个玻璃棱镜。棱镜是可以将光分解为不同颜色的物理仪器,每个成分的颜色由波长(或频率)来决定。傅里叶变换可以看作是数学上的棱镜,将函数基于频率分解为不同的成分。当我们考虑光时,讨论它的光谱或频率谱。同样,傅立叶变 换使我们能通过频率成分来分析一个函数。
代码:
#傅里叶库函数使用
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取图像
img=cv2.imread("D:/tz/fingerprint.jpg",0)
#进行图像裁剪,加快傅里叶运算速率。将原始尺寸缩放为100*100的尺寸
#OpneCV傅里叶变换函数
result =cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)#需要将图像进行一次float转换
#将频谱低频从左上角移动至中心位置
dft_shift = np.fft.fftshift(result)
#频谱图像双通道复数转换为0-255区间
result1 = 20*np.log(cv2.magnitude(dft_shift[:,:,0], dft_shift[:,:,1]))
#图像显示
plt.subplot(121), plt.imshow(img,'gray'), plt.title('原图像')
plt.axis('off')
plt.subplot(122), plt.imshow(result1,'gray'), plt.title('傅里叶变换')
plt.axis('off')
plt.show()
结果:
因为这样就能采用以2为基的FFT算法,提升运算性能。如果数据点数不是以2为基数的整数次方,处理方法有两种,一种是在原始数据开头或末尾补零,即将数据补到以2为基数的整数次方,这是“补零”的一个用处。
补零操作增加了频域的插值点数,让频域曲线看起来更加光滑,这是“补零”的另一个原因。
离散傅里叶变换补零能够提高分辨。
- 对选取的灰度图像旋转一定的角度,观察并分析灰度图像傅里叶频谱和旋转后图像的傅里叶频谱之间的对应关系(注意零频率部分需要在频谱的中心)。
图像在空域旋转90度后其频谱也旋转90 度
- 采用低通滤波器对频域空间进行滤波,并输出其对应的时域图像,观察结果,说明图片中的高频和低频区域分别反应出图片的什么特征。
代码:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
import skimage
def spectrum_show(img): # 定义一个用于计算灰度图的频谱图并显示的函数
f = np.fft.fft2(img) # 快速傅里叶变换算法得到频率分布
fshift = np.fft.fftshift(f) # 将图像中的低频部分移动到图像的中心,默认是在左上角
fimg = np.log(np.abs(fshift)) # fft结果是复数, 其绝对值结果是振幅,取对数的目的是将数据变换到0~255
# 展示结果
plt.subplot(121), plt.imshow(img, 'gray'), plt.title('Original Fourier')
plt.axis('off')
plt.subplot(122), plt.imshow(fimg, 'gray'), plt.title('Fourier Fourier')
plt.axis('off')
plt.show()
def ButterworthPassFilter(image, d, n): # 定义一个Butterworth低通滤波器
f = np.fft.fft2(image) # 快速傅里叶变换算法得到频率分布
fshift = np.fft.fftshift(f) # 将图像中的低频部分移动到图像的中心,默认是在左上角
# fft结果是复数, 其绝对值结果是振幅;取对数的目的是将数据变换到0~255
fimg = np.log(np.abs(fshift))
# Butterworth低通滤波器的实现函数的定义
def make_transform_matrix(d):
# 创建一个与输入图像同大小的全0矩阵,用于存储变化后的图像
transform_matrix = np.zeros(image.shape)
# 中心点值的计算,元组形式
center_point = tuple(map(lambda x: (x - 1) / 2, fimg.shape))
for i in range(transform_matrix.shape[0]): # 行遍历
for j in range(transform_matrix.shape[1]): # 列遍历
def cal_distance(pa, pb): # 欧拉距离计算函数的定义
from math import sqrt
dis = sqrt((pa[0] - pb[0]) ** 2 + (pa[1] - pb[1]) ** 2)
return dis
dis = cal_distance(center_point, (i, j)) # 求出每个点与中心点的距离
# 巴特沃斯低通滤波的数学公式实现
transform_matrix[i, j] = 1 / (1 + (dis / d) ** (2 * n))
return transform_matrix
d_matrix = make_transform_matrix(d) # 调用自定义函数
new_img = np.abs(np.fft.ifft2(np.fft.ifftshift(fshift * d_matrix))) # 生成新图
return new_img
if __name__ == '__main__':
# 计算其频谱图,并显示
img1 = cv.imread('D:/tz/fingerprint.jpg', 0) # 读取自备图像的图像的灰度图形式
spectrum_show(img1)
# 任选一个低通滤波器对图片采用频率域滤波的基本步骤进行滤波观察分析空域图象和频谱分布的变化。
img = cv.imread('D:/tz/fingerprint.jpg', 0) # 直接读为灰度图像
img=skimage.util.random_noise(img, mode='gaussian', seed=None, clip=True)
spectrum_show(img) # 原图及其频谱图的显示
butter_25_5 = ButterworthPassFilter(img,25, 5) # Butterworth低通滤波处理
spectrum_show( butter_25_5) # 显示低通滤波后的图及其频谱图
结果:
低通滤波后图像除了轮廓模糊了外,基本上没什么变化,图像的⼤部分信息基本上都保持了。
低频就是颜色缓慢地变化,也就是灰度缓慢地变化,就代表着那是连续渐变的一块区域,这部分就是低频. 对于一幅图像来说,除去高频的就是低频了,也就是边缘以内的内容为低频,而边缘内的内容就是图像的大部分信息,即图像的大致概貌和轮廓,是图像的近似信息。
反过来, 高频就是频率变化快.图像中什么时候灰度变化快?就是相邻区域之间灰度相差很大,这就是变化得快.图像中,一个影像与背景的边缘部位,通常会有明显的差别,也就是说变化那条边线那里,灰度变化很快,也即是变化频率高的部位.因此,图像边缘的灰度值变化快,就对应着频率高,即高频显示图像边缘。图像的细节处也是属于灰度值急剧变化的区域,正是因为灰度值的急剧变化,才会出现细节。
对图像进行二维傅立叶变换得到频谱图就是图像梯度的分布图,傅立叶频谱图上看到的明暗不一的亮点实际上图像上某一点与邻域点差异的强弱,即梯度的大小,也即该点的频率的大小,图像中的低频部分指低梯度的点,高频部分相反。梯度大则该点的亮度强,否则该点亮度弱。这样通过观察傅立叶变换后的频谱图可以看出图像的能量分布,如果频谱图中暗的点数更多,那么实际图像是比较柔和的(因为各点与邻域差异都不大,梯度相对较小),反之,如果频谱图中亮的点数多,那么实际图像一定是尖锐的,边界分明且边界两边像素差异较大的。