机器视觉Day2 | 傅里叶变换(高通低通滤波),小波变换

详细理论知识移步大佬教程:https://www.cnblogs.com/wj-1314/p/11983496.html

傅里叶变换在图像处理中的应用:

傅里叶变换是一种强大的数学工具,用于将信号(此处为数字图像)从时域(或空间域)转换到频域。在频域中,图像的信息被表示为不同频率的分量,这些分量对应于图像中的不同特征,如边缘、纹理和平滑区域。

低通滤波实现图像平滑:

  • 傅里叶变换:首先,对原始图像进行二维傅里叶变换,将其从空间域转换到频域。
  • 创建低通滤波器:在频域中,通过创建一个掩码(通常为圆形或椭圆形),该掩码在中心区域(低频部分)允许所有频率通过,而在边缘区域(高频部分)逐渐或完全抑制频率。这样可以去除或减弱图像中的高频信息,如边缘和细节。
  • 应用掩码:将创建的掩码与傅里叶变换后的图像相乘,从而仅保留低频部分。
  • 逆傅里叶变换:对经过掩码处理的频域图像进行二维逆傅里叶变换,得到平滑处理后的空间域图像。这个过程减少了图像的噪声和细节,使图像看起来更加平滑。

image

高通滤波实现图像细节增强:

  • 傅里叶变换:同样,首先对原始图像进行二维傅里叶变换。
  • 创建高通滤波器:在频域中,与低通滤波器相反,高通滤波器在中心区域(低频部分)抑制频率,而在边缘区域(高频部分)允许或增强频率通过。这样可以突出图像中的边缘和细节信息。
  • 应用掩码:将高通滤波器掩码与傅里叶变换后的图像相乘,以提取或增强高频部分。
  • 逆傅里叶变换:最后,对经过高通滤波处理的频域图像进行二维逆傅里叶变换,得到细节增强的空间域图像。

image

————————————————————————

具体代码如下(python)

-高通滤波-

1.将图像转换成np.float32类型(opencv中规定)并应用傅里叶变换
点击查看代码
    dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
    dft_shift = np.fft.fftshift(dft)

2.创造并应用掩码
点击查看代码
    rows, cols = img.shape
    crow, ccol = rows // 2, cols // 2
    cv2.namedWindow('High Pass Filtered Image')

    #radius = 2

    # 创建一个与dft_shift相同形状的掩码,并初始化为1(允许所有频率通过)
    fmask = np.ones((rows, cols), np.float32)

    # 在掩码中创建一个以图像中心为圆心、radius为半径的圆形区域,并将其值设置为0(阻止这些低频通过)
    cv2.circle(fmask, (ccol, crow), radius, 0, -1)

    #应用掩码
    fmask_complex = np.stack((fmask, np.zeros_like(fmask)), axis=-1)
    fshift = dft_shift * fmask_complex
3.逆傅里叶变换
点击查看代码
    # 逆傅里叶变换
    f_ishift = np.fft.ifftshift(fshift)
    img_back = cv2.idft(f_ishift)
    img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])  # 计算幅度
	#img_back[:, :, 0], img_back[:, :, 1]分别代表两个通道(实部、虚部),计算后只包含了一个通道,即幅度的值,它反映了原复数图像中每个像素点的能量或强度。
4.归一化处理(可选)
点击查看代码
    # 将幅度值归一化到0-255
    img_back = np.log(1 + img_back) # 对数变换 这里加上了1 (1 + img_back) 是为了避免对0或负数取对数
    img_back = (img_back - np.min(img_back)) / (np.max(img_back) - np.min(img_back)) * 255 # 通过减去最小值并除以值域范围(最大值减去最小值)来实现的,然后将结果乘以255以匹配常见的8位图像格式
    img_back = np.uint8(np.clip(img_back, 0, 255)) # 将数据类型转换为无符号8位整数
	


完整代码:(用了cv2.createTrackbar滑块来实时显示的高通滤波)
点击查看代码
import cv2
import numpy as np


def apply_high_pass_filter(img, radius):
    #傅里叶变换
    dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
    dft_shift = np.fft.fftshift(dft)


    rows, cols = img.shape
    crow, ccol = rows // 2, cols // 2
    cv2.namedWindow('High Pass Filtered Image')

    #radius = 2

    # 创建一个与dft_shift相同形状的掩码,并初始化为1(允许所有频率通过)
    fmask = np.ones((rows, cols), np.float32)

    # 在掩码中创建一个以图像中心为圆心、radius为半径的圆形区域,并将其值设置为0(阻止这些低频通过)
    cv2.circle(fmask, (ccol, crow), radius, 0, -1)

    #应用掩码
    fmask_complex = np.stack((fmask, np.zeros_like(fmask)), axis=-1)
    fshift = dft_shift * fmask_complex

    # 逆傅里叶变换
    f_ishift = np.fft.ifftshift(fshift)
    img_back = cv2.idft(f_ishift)
    img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])  # 计算幅度

    # 将幅度值归一化到0-255
    img_back = np.log(1 + img_back)
    img_back = (img_back - np.min(img_back)) / (np.max(img_back) - np.min(img_back)) * 255
    img_back = np.uint8(np.clip(img_back, 0, 255))

    return img_back


def on_trackbar_change(radius_val):
    # 将滑块位置转换为整数(如果需要的话)
    radius = int(radius_val)
    # 应用高通滤波
    filtered_img = apply_high_pass_filter(img, radius)
    # 显示结果
    cv2.imshow('High Pass Filtered Image', filtered_img)


# 加载图像
img = cv2.imread(r"C:\Users\ASUS\Desktop\PIC\GQggqz2akAAeYgx.jpg", 0)  # 以灰度模式加载图像
if img is None:
    print("Error: Image could not be read.")
    exit()

# 创建窗口
cv2.namedWindow('High Pass Filtered Image')

# 创建滑块
cv2.createTrackbar('Radius', 'High Pass Filtered Image', 0, 800, on_trackbar_change)

# 初始显示
on_trackbar_change(2)  # 初始化滑块位置为2时的图像


# 等待键盘事件
cv2.waitKey(0)
cv2.destroyAllWindows()

-低通滤波-

点击查看代码
import numpy as np
import cv2
from matplotlib import pyplot as plt

# 读取图像,并转换为灰度图
img = cv2.imread(r"C:\Users\ASUS\Desktop\PIC\GQggqz2akAAeYgx.jpg", 0)

# 傅里叶变换
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2

# 创建低通滤波器掩码
radius = 30
##########↓低通##########
fmask = np.zeros((rows, cols), np.uint8)#初始化为全0
cv2.circle(fmask, (ccol, crow), radius, 1, thickness=-1) #中心为1
##########↑低通##########

##########↓高通##########
#fmask = np.ones((rows, cols), np.float32)  # 初始化为全1
#cv2.circle(fmask, (ccol, crow), radius, 0, thickness=-1) #中心为0
##########↑高通##########

fmask = np.float32(fmask)  # 确保掩码与DFT结果的数据类型相同

# 应用掩码到频域图像的实部和虚部
fshift_masked_re = dft_shift[:, :, 0] * fmask
fshift_masked_im = dft_shift[:, :, 1] * fmask

# 合并实部和虚部
fshift_masked = np.dstack((fshift_masked_re, fshift_masked_im))

# 逆傅里叶变换
f_ishift = np.fft.ifftshift(fshift_masked)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])  # 计算幅度

# 将幅度值归一化到0-255
img_back = np.log(1 + img_back)  # 应用对数尺度增强可视性(可选)
img_back = (img_back - np.min(img_back)) / (np.max(img_back) - np.min(img_back)) * 255
img_back = np.uint8(np.clip(img_back, 0, 255))

# 显示结果
plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(img_back, cmap='gray')
plt.title('Low Pass Filtered Image'), plt.xticks([]), plt.yticks([])

plt.show()

傅里叶变换还可用于图片的叠加、不明显水印添加等。
拉普拉斯变换:

image

*注:图片引自《数字图像处理(第四版)》

小波变换:

小波变换的应用:
  • 图像压缩:小波变换可以将图像分解成不同频率的子带,通过丢弃高频子带中的信息,可以在保持图像质量的同时显著减少数据量,实现图像压缩。
  • 图像去噪:利用小波变换的局部化特性,可以有效地去除图像中的噪声,同时保留图像的边缘和细节信息。(小波更适合处理非平稳信号和需要保留图像边缘及细节的场景)
  • 图像融合:将不同来源的图像信息在多个尺度上进行融合,得到更加清晰和自然的融合结果。
使用:

可通过PyWavelets库实现(提供了多种小波变换的实现,包括离散小波变换(DWT)和连续小波变换(CWT)等)。

点击查看代码
import cv2  
import pywt  
import numpy as np  
  
# 读取图像  
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)  
  
# 进行二维小波变换  
coeffs = pywt.dwt2(img, wavelet='haar')  
cA, (cH, cV, cD) = coeffs  
  
# 显示原始图像和小波变换结果  
cv2.imshow("Original Image", img)  
cv2.imshow("Approximation (cA)", cA)  
cv2.imshow("Horizontal Detail (cH)", cH)  
cv2.imshow("Vertical Detail (cV)", cV)  
cv2.imshow("Diagonal Detail (cD)", cD)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

也可使用cv2.pyrDown()和cv2.pyrUp()函数进行图像的降采样和升采样

实例如下:

点击查看代码
import cv2  
import numpy as np  
  
# 读取图像  
img = cv2.imread('your_image.jpg')  
  
# 显示原始图像  
cv2.imshow('Original Image', img)  
  
# 对图像进行降采样  
img_pyrDown = cv2.pyrDown(img)  
cv2.imshow('PyrDown Image', img_pyrDown)  
  
# 注意:直接对降采样后的图像进行升采样不会得到原始图像,因为信息已经丢失  
# 但为了演示,我们还是这样做  
img_pyrUp = cv2.pyrUp(img_pyrDown)  
  
# 由于升采样是近似操作,所以结果可能与原始图像不完全相同  
# 我们可以通过比较它们的差异来看到这一点  
diff = cv2.absdiff(img, img_pyrUp)  
cv2.imshow('Difference Between Original and PyrUp Image', diff)  
  
# 等待按键操作后关闭所有窗口  
cv2.waitKey(0)  
cv2.destroyAllWindows()
posted @ 2024-07-14 10:36  三小花荷包蛋  阅读(127)  评论(0)    收藏  举报