python图像音频处理-通过图像傅里叶变换判断相位和幅度的重要性

Posted 小草莓爸爸

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python图像音频处理-通过图像傅里叶变换判断相位和幅度的重要性相关的知识,希望对你有一定的参考价值。

python图像音频处理-判断相位和幅度的重要性

这一步骤思想很简单。分别将两个图像或两个音频做FFT,再选取图像1/音频1的幅度,结合上图像2/音频2的相位,再做IFFT。看返回的图像或音频更接近图像1/音频1,还是图像2/音频2。

若是前者,则说明幅度的信息量更重要;若是后者,则说明相位的信息量更重要。


目录

1.图像处理

头文件:

import cv2
import numpy as np
from scipy.fftpack import fft,ifft
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
import IPython.display as ipd

第一步:两张图片做FFT

img = cv2.imread('D:/classofmathpicture/sample_pic.tiff',1)
plt.figure(figsize=(30, 20)); 
plt.subplot(231),plt.imshow(img),plt.title('picture')
 
 #根据公式转成灰度图
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#显示灰度图
plt.subplot(232),plt.imshow(img,'gray'),plt.title('original')
 
 #进行傅立叶变换,并显示结果
fft2 = np.fft.fft2(img)
plt.subplot(233),plt.imshow(np.abs(fft2),'gray'),plt.title('fft2')
 
 #将图像变换的原点移动到频域矩形的中心,并显示效果
shift2center = np.fft.fftshift(fft2)
plt.subplot(234),plt.imshow(np.abs(shift2center),'gray'),plt.title('shift2center')
 
 #对傅立叶变换的结果进行对数变换,并显示效果
log_fft2 = np.log(1 + np.abs(fft2))
plt.subplot(235),plt.imshow(log_fft2,'gray'),plt.title('log_fft2')
 
 #对中心化后的结果进行对数变换,并显示结果
log_shift2center = np.log(1 + np.abs(shift2center))
plt.subplot(236),plt.imshow(log_shift2center,'gray'),plt.title('log_shift2center')
plt.show()

img1:

img2
程序和上述一样。唯一不同的是这里需要将img2尺寸改成和img1一样,所以需要在做完灰度化要加上该语句:

img2=cv2.resize(img2,(img.shape[1],img.shape[0]))   #把尺寸换成上个图像一样当,方便后面幅度和相位当错位相乘

第二步:比较幅度和相位信息量的重要性

P1=np.abs(shift22center)*np.exp2(np.angle(shift2center)*1j)
P2=np.abs(shift2center)*np.exp2(np.angle(shift22center)*1j)
ifft_1=np.fft.ifft2(fft2)
ifft_2=np.fft.ifft2(fft22)
p1=np.fft.ifft2(P1)
p2=np.fft.ifft2(P2)
plt.figure(figsize=(30, 20))
plt.subplot(221)
plt.imshow(np.abs(ifft_1),cmap='gray'),plt.title('img1')
plt.subplot(222)
plt.imshow(np.abs(ifft_2),cmap='gray'),plt.title('img2')
plt.subplot(223)
p1=np.log(1 + np.abs(p1))
plt.imshow(np.abs(p1),cmap='gray'),plt.title('img1_angle+img2_abs')
plt.subplot(224)
p2=np.log(1 + np.abs(p2))
plt.imshow(np.abs(p2),cmap='gray'),plt.title('img1_abs+img2_angle');

结论: 可以从这张图看出,合成图与选取相位的图像更接近,说明相位信息更重要

2.音频处理

第一步:读取音频

import librosa
import librosa.display
# 读取音频文件
filepath = 'D:\\\\CloudMusic\\\\'
filename = filepath + 'summertime.mp3'
x, sr = librosa.load(filename, sr=None)  # x--音频时间序列(一维数组) ; sr--音频的采样率

filename1 = filepath + 'test2.mp3'
y, sr = librosa.load(filename1, sr=None,duration=len(x)/sr)  # x--音频时间序列(一维数组) ; sr--音频的采样率
plt.subplot(211),plt.title('music1 and music2')
plt.plot(x)
plt.subplot(212)
plt.plot(y)
print('总时长为:',len(y)/sr)

第二步:比较幅度和相位信息量的重要性

fft_x=np.fft.fft(x)
abs_x=np.abs(fft_x)                # 取复数的绝对值,即复数的模(双边频谱)
angle_x=np.angle(fft_x)              #取复数的角度

fft_y=np.fft.fft(y)
abs_y=np.abs(fft_y)                # 取复数的绝对值,即复数的模(双边频谱)
angle_y=np.angle(fft_y)              #取复数的角度

zz1=np.fft.ifft(np.exp2(angle_x*1j)*abs_y)
zz2=np.fft.ifft(abs_x*np.exp2(angle_y*1j))

for i in range(int(len(zz1)/50)):     #为了消去两边当尖峰,通过一个较为宽当窗,在不影响数据量当情况下使数据变平滑
    zz1[i]=0
    zz1[len(zz1)-i-1]=0
    zz2[i]=0
    zz2[len(zz1)-i-1]=0    
plt.figure(figsize=(10, 5))
plt.subplot(221)
plt.plot(zz1) 
plt.title('z1_abs+z2_angle')
 
plt.subplot(222)
plt.plot(zz2)   
plt.title('z1_angle+z2_abs')

plt.subplot(223)
plt.plot(x)
plt.title('z1')
plt.subplot(224)
plt.plot(y)
plt.title('z2');

通过图像,不是很能分辨合成音频更接近哪一种情况。所以下面输出合成音频进行试听

第三步:在Jupyter notebook上试听合成音频


CSDN不能上传音频,所以直接上传了资源

Python图像处理采样卷积与离散傅里叶变换

采样、卷积与离散傅里叶变换

0. 前言

采样 (Sampling) 是用于选择/丢弃图像像素的空间操作,通常用于增加/减小图像大小;而卷积是一种局部数学运算,通过将像素及其相邻像素的强度值乘以卷积核(通常是一个尺寸较小的窗口矩阵)实现;使用不同核执行图像卷积会在输出图像中产生不同的效果(例如,模糊、锐化、边缘提取等)。离散傅里叶变换 (Discrete Fourier Transform, DFT) 的基本思想是将图像视为二维函数,该函数可以表示为二维正弦和余弦(傅里叶基/系数)的加权和。DFT 可以用于将图像从空域变换到频域,因为卷积等操作在频域中可以更快地执行。在本节中,我们将使用常用 Python 库利用采样、卷积和 DFT 定理解决图像处理问题。

1. 图像傅里叶变换

在本节中,我们将介绍离散傅里叶变换 (Discrete Fourier Transform, DFT) 相关基础概念,并使用 Numpyfft 模块在图像中应用 DFT,也可以使用 Scipyfftpack 模块实现 DFT

1.1 傅里叶变换基础

我们首先介绍 2D 傅里叶变换及 2D 逆离散傅里叶变换。(灰度)图像可以被定义为 2D 函数 f ( x , y ) f(x,y) f(x,y),其中 ( x , y ) ∈ 0 , . . . , M − 1 × 0 , . . . , N − 1 (x,y)∈\\0,...,M-1\\×\\0,...,N-1\\ (x,y)0,...,M1×0,...,N1DFT 可以将图像从其空间表示 f ( x , y ) f(x,y) f(x,y) 改变为频域表示 f ( u , v ) f(u,v) f(u,v),其中 ( u , v ) ∈ 0 , . . . , M − 1 × 0 , . . . , N − 1 (u,v)∈\\0,...,M-1\\×\\0,...,N-1\\ (u,v)0,...,M1×0,...,N1 表示频率分量/傅里叶基向量:

1.2 傅里叶变换应用

(1) 首先,导入所有必需的库:

import numpy as np
import numpy.fft as fp
from skimage.io import imread
from skimage.color import rgb2gray
from skimage.metrics import peak_signal_noise_ratio
import matplotlib.pyplot as plt

(2) 定义函数 plot_image(),使用 matplotlib.pyplotimshow() 函数绘制图像:

def plot_image(im, title):
    plt.imshow(im, cmap='gray')
    plt.axis('off')
    plt.title(title, size=10)

(3) 接下来,定义函数 plot_freq_spectrum() 以绘制图像的频(功率)谱,该函数可以通过可选参数控制是否显示颜色映射图和轴刻度。我们需要使用 numpy.fft.fftshift() 函数将零功率谱系数 (0,0) 移动到功率谱中心,然后可视化功率谱:

numpy.fft.fftshift(x, axes=None)

傅里叶变换会返回一复数数组;复数部分对应于相位,实数部分对应于我们感兴趣的幅度:

def plot_freq_spectrum(F, title, cmap=plt.cm.gray, show_axis=True, colorbar=False):
    plt.imshow((20*np.log10(0.1 + fp.fftshift(F))).real.astype(int), cmap=cmap)
    if not show_axis:
        plt.axis('off')
    if colorbar:
        plt.colorbar()
    plt.title(title, size=10)

(4) 接下来,创建一些简单图像并获取 DFT 的功率谱。首先分别生成一对大小为 100x100 且具有(等间距)水平和垂直条纹的周期图像:

h, w = 100, 100
images = list()
im = np.zeros((h,w))
for x in range(h):
    im[x,:] = np.sin(x)
images.append(im)
im = np.zeros((h,w))
for y in range(w):
    im[:,y] = np.sin(y)
images.append(im)

(5) 接下来,我们生成对角线周期图像,然后使用半径为 10 的圆形掩码(以图像的中心为圆心),从根据此图像中创建另一图像:

im = np.zeros((h,w))
for x in range(h):
    for y in range(w):
        im[x,y] = np.sin(x + y)
images.append(im)
im = np.zeros((h,w))
for x in range(h):
    for y in range(w):
        if (x-h/2)**2 + (y-w/2)**2 < 100:
            im[x,y] = np.sin(x + y)
images.append(im)

(7) 最后,生成另一对图像,第一个图像带有一个实心圆,第二个带有以图像中心为中心的实心正方形:

im = np.zeros((h,w))
for x in range(h):
    for y in range(w):
        if (x-h/2)**2 + (y-w/2)**2 < 25:
            im[x,y] = 1
images.append(im)
im = np.zeros((h,w))
im[h//2 -5:h//2 + 5, w//2 -5:w//2 + 5] = 1
images.append(im)

(8) 我们将所有图像都存储在列表中,使用 numpy.fftfft2() 函数使用快速傅里叶变换算法来计算 DFT,并绘制生成的每个输入图像的输出功率谱:

numpy.fft.fft2(a, s=None, axes=(-2, -1), norm=None)

下图显示了相应图像及其 DFT

plt.figure(figsize=(25,10))
i = 1
for im in images:
    plt.subplot(2,6,i), plot_image(im, 'image '.format(i))
    plt.subplot(2,6,i+6), plot_freq_spectrum(fp.fft2(im), 'DFT '.format(i), show_axis=False)
    i += 1
plt.tight_layout()
plt.show()


理想情况下,对于图像 12,水平和垂直周期模式的 DFT 应分别为垂直和水平对齐的点(对应于频率)。但是,如上图所示,由于边缘效应,结果为一条垂直和水平线(线上的亮点对应于相应的频率)。同样,对于图像 3,周期对角线模式应在垂直对角线方向上产生两个对角线点,但由于边缘效应,得到了其他许多线。如果使用二值圆形掩码处理图像 3 中心的圆,则会降低边缘效应,我们可以看到沿主对角线方向的亮点,对应于频率分量。

1.3 逆傅里叶变换应用

我们已经了解不同频率对图像的不同作用,如果我们在功率谱上应用逆傅里叶变换 (Inverse Discrete Fourier Transform ,IDFT`),可以在数值精度内恢复原始图像,下图展示了如何在图像上应用傅立叶变换:


如果我们从功率谱中删除一部分频率并应用 IDFT 以重建图像时会发生什么?接下来,我们使用函数 numpy.fft.ifft2() 执行逆傅立叶变换,函数调用方式如下:

numpy.fft.ifft2(a, s=None, axes=(-2, -1), norm=None)

(1) 读取输入图像并将其转换为灰度图像,然后计算图像的 DFT,并移动频率中心:

im = rgb2gray(imread("1.png"))
h, w = im.shape
F = fp.fft2(im)
F_shifted = fp.fftshift(F)

(2) 为了观察消除频率分量对 IDFT 输出图像的影响,我们仅选择几个具有较小(绝对)值的频率,即位于 (0,0) 周围的频率,并过滤其他频率。换句话说,只允许介于 (−k1, − k2)(+k1, +k2) 之间的频率,即允许频率 (Fx, Fy),其中 |Fx|, |Fy|≤(k1,k2),并且在利用 IDFT 变换回空间域之前过滤该区间之外的其他频率:

xs = list(map(int, np.linspace(1, h//5, 10)))
ys = list(map(int, np.linspace(1, w//5, 10)))
plt.figure(figsize=(20,8))
plt.gray()
for i in range(10):
    F_mask = np.zeros((h, w))
    F_mask[h//2-xs[i]:h//2+xs[i]+1, w//2-ys[i]:w//2+ys[i]+1] = 1 
    F1 = F_shifted*F_mask
    im_out =  fp.ifft2(fp.ifftshift(F1)).real #np.abs()
    plt.subplot(2,5,i+1), plt.imshow(im_out), plt.axis('off')
    plt.title('x,PSNR='.format(2*xs[i]+1, 2*ys[i]+1, round(peak_signal_noise_ratio(im, im_out),2)), size=10)
plt.suptitle('Fourier reconstruction by keeping first few frequency basis vectors', size=15)
plt.show()


从上图可以看出,与较低频率相对应的系数值保留了均值信息,并且随着频率的增加,可以捕获图像中的更多边缘和细节,并且 PSNR 也随之增加。从 143x213 频率开始,我们可以较好的重建图像而不会导致明显的细节丢失。

2. 利用采样改变图像分辨率

采样 (Sampling) 可以通过选择/丢弃图像像素来增加/减少图像的分辨率。在本节中,我们将解决两个问题,包括上采样 (Upsampling) 与下采样 (Downsampling)。

2.1 上采样

在本小节,我们将学习如何使用离散傅里叶变换 (Discrete Fourier Transform, DFT) 执行上采样并增加图像分辨率。上采样通常在空域中进行,通过使用最近邻、双线性或双立方插值来推测新增的像素值。但在这里,我们将尝试使用 DFT 实现上采样,并在频域中应用低通滤波器( Low Pass Filter, LPF)。

2.1.1 离散傅里叶变换与低通滤波器

为了充分理解离散傅里叶变换与低通滤波器,我们首先了解如何在空域和频域中使用卷积实现 LPF。我们已经知道,滤波是指改变像素强度值以发现某些图像特征,例如平滑或锐化等。
LPF 仅允许通过来自图像频域表示的低频(使用 DFT 获得)部分,并过滤所有超出截止值的高频部分。可以在空间域中使用合适的核(例如高斯核)执行卷积实现 LPF,起始时核窗口位于(灰度)图像左上角,核的尺寸大小不能超过图像尺寸。输出图像中的像素值是通过在输入图像中滑动核窗口进行计算的:

接下来,我们将在频域中实现 LPF,根据卷积定理,我们只需要进行元素乘法操作,因此算法运算速度很快:

f ( x , y ) ∗ h ( x , y ) ⇔ F ( u , v ) ⋅ H ( u , v ) f(x,y)*h(x,y)⇔F(u,v)\\cdot H(u,v) f(x,y)h(x,y)F(u,v)H(u,v)

根据卷积定理,我们可以将空间卷积转换为频域逐元素乘法操作。

2.1.2 使用离散傅里叶变换和低通滤波器对图像执行上采样

接下来,我们将使用尺寸为 400x600 的输入图像,并计算得到两倍尺寸的图像 (800x1200)。

(1) 首先,读取图像,将其转换为灰度图像,并在每个交替的行/列上填充零,从而令图像的尺寸大小扩大两倍:

import numpy as np
import numpy.fft as fp
from skimage.io import imread
from skimage.color import rgb2gray
import matplotlib.pyplot as plt

im = 255*rgb2gray(imread('1.png'))
im1 = np.zeros((2*im.shape[0], 2*im.shape[1]))
print(im.shape, im1.shape)
for i in range(im.shape[0]):
    for j in range(im.shape[1]):
        im1[2*i,2*j] = im[i,j]

def plot_image(im, title):
    plt.imshow(im, cmap='gray')
    plt.axis('off')
    plt.title(title, size=10)
def plot_freq_spectrum(F, title, cmap=plt.cm.gray, show_axis=True, colorbar=False):
    plt.imshow((20*np.log10(0.1 + fp.fftshift(F))).real.astype(int), cmap=cmap)
    if not show_axis:
        plt.axis('off')
    if colorbar:
        plt.colorbar()
    plt.title(title, size=10)

(2) 我们将使用以下 LPF 核,可以看出,它的中心权重最高,而远离中心的权重较小:

kernel = [[0.25, 0.5, 0.25], [0.5, 1, 0.5], [0.25, 0.5, 0.25]]

(3) 要在频域中实现滤波器,我们需要将图像乘以核,为此,核的形状需要完全等于图像的形状。为了使用 NumPy 库的函数 pad(),我们首先定义填充函数 pad_with_zeros() 用值零填充核:

def pad_with_zeros(vector, pad_width, iaxis, kwargs):
    vector[:pad_width[0]] = 0
    vector[-pad_width[1]:] = 0
    return vector

kernel = np.pad(kernel, (((im1.shape[0]-3)//2,(im1.shape[0]-3)//2+1), ((im1.shape[1]-3)//2,(im1.shape[1]-3)//2+1)), pad_with_zeros)

(4) 接下来,计算输入图像和扩展核的功率谱。由于核已经居中,因此,在应用 DFT 之前,我们需要应用 fftshift() 的逆函数 ifftshift()

freq = fp.fft2(im1)
freq_kernel = fp.fft2(fp.ifftshift(kernel))

(5) 通过频域中的逐元素乘法计算 LPF

freq_LPF = freq*freq_kernel # 卷积理论

(6) 最后,使用逆 DFT 获得输出图像,我们需要提取复数输出中的实数部分:

im2 = fp.ifft2(freq_LPF).real

(7) 绘制输入、核和输出图像以及它们的功率谱:

plt.figure(figsize=(15,10))
plt.gray()
cmap = 'nipy_spectral'
plt.subplot(231), plot_image(im, 'Original Input Image')
plt.subplot(232), plot_image(im1, 'Padded Input Image')
plt.subplot(233), plot_freq_spectrum(freq, 'Original Image Spectrum', cmap=cmap)
plt.subplot(234), plot_freq_spectrum(freq_kernel, 'Image Spectrum of the LPF', cmap=cmap)
plt.subplot(235), plot_freq_spectrum(fp.fft2(im2), 'Image Spectrum after LPF', cmap=cmap)
plt.subplot(236), plot_image(im2.astype(np.uint8), 'Output Image')
plt.show()

2.2 下采样

为了减少图像的尺寸大小,我们需要对图像执行下样本。得到的尺寸较小的新图像中的每个像素对应于原始大图像中的多个像素。直接从原始图像中删除像素有助于减少图像的分辨率,但是它会引入空间混叠效应(例如摩尔纹),并且导致输出图像质量较差。为了防止这种情况,需要使用抗混叠滤波器(在下采样之前)以过滤图像高频分量。

2.2.1 使用高斯滤波器实现抗锯齿下采样

在本节中,我们将学习一种简单的抗锯齿技术,该方法通过在下采样前应用低通滤波器( LPF )来实现。

(1) 导入所需的库,读取输入图像并将其转换为 float 类型(使所有像素值均在 01 之间),我们的目标是通过将高度和宽度减少三倍,将图像大小减少九倍:

from skimag

以上是关于python图像音频处理-通过图像傅里叶变换判断相位和幅度的重要性的主要内容,如果未能解决你的问题,请参考以下文章

跟我学Python图像处理丨傅里叶变换之高通滤波和低通滤波

跟我学Python图像处理丨带你掌握傅里叶变换原理及实现

图片处理-opencv-12.图像傅里叶变换

[OpenCV-Python] OpenCV 中的图像处理 部分 IV

数字图像处理课程实习——傅里叶变换与频域滤波

图像处理之图像傅里叶变换