用python实现数字图像处理(1)

图像的傅里叶变换

  • (一)显示图像的频谱图
  • (二)高斯噪声与椒盐噪声频谱图
  • (三)理想高斯高通与低通滤波、巴特沃斯高通与低通滤波
  • (四)结语

(一)显示图像的频谱图

首先读取一幅图像,然后对图像做二维离散傅立叶变换,然后做快速傅里叶变换,即直流分量移到频谱中心,让正半轴部分和负半轴部分的图像分别关于各自的中心对称,然后取傅立叶变换的实部,然后做频谱对数变换,就得到原图像的频谱图,最后将原图像和对应的频谱图显示出来

#计算一维傅里叶变换
numpy.fft.fft(a, n=None, axis=-1, norm=None)

#计算二维的傅里叶变换
numpy.fft.fft2(a, n=None, axis=-1, norm=None)

#计算n维的傅里叶变换
numpy.fft.fftn()

#计算n维实数的傅里叶变换
numpy.fft.rfftn()

#返回傅里叶变换的采样频率
numpy.fft.fftfreq()

#将FFT输出中的直流分量移动到频谱中央
numpy.fft.shift()

numpy.log()是一个数学函数, 用于计算x(x属于所有输入数组元素)的自然对数。它是指数函数的倒数, 也是元素自然对数。自然对数对数是指数函数的逆函数, 因此log(exp(x))= x。以e为底的对数是自然对数。


import cv2
import numpy as np
from matplotlib import pyplot as plt

# 读取图像
img = cv2.imread('lena.png', 0)

# 快速傅里叶变换算法得到频率分布
f = np.fft.fft2(img)


fshift = np.fft.fftshift(f)# 默认结果中心点位置是在左上角,调用fftshift()函数转移到中间位置

# fft结果是复数, 其绝对值结果是振幅
fimg = np.log(np.abs(fshift))

# 展示结果
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()


效果如下

用python实现数字图像处理(1)_第1张图片

(二)高斯噪声与椒盐噪声频谱图

得到原始图像的频谱图的方法同上,然后对原图像模拟叠加密度为0.04的椒盐噪声,然后添加模拟均值为0方差为0.02的高斯噪声,然后得到噪声图像的频谱图,方法同上,最后显示所有图像

numpy.clip(a, a_min, a_max, out=None)[source]
clip这个函数将将数组中的元素限制在a_min, a_max之间,大于a_max的就使得它等于 a_max,小于a_min,的就使得它等于a_min

看看代码吧:

import numpy as np
import random
import cv2

from matplotlib import pyplot as plt

def sp_noise(image,prob):#添加椒盐噪声, prob:噪声比例

    output = np.zeros(image.shape,np.uint8)

    thres = 1 - prob

    for i in range(image.shape[0]):
        for j in range(image.shape[1]):

            rdn = random.random()
            if rdn < prob:
                output[i][j] = 0
            elif rdn > thres:
                output[i][j] = 255
            else:
                output[i][j] = image[i][j]
    return output

def gasuss_noise(image, mean=0, var=0.001):#添加高斯噪声,mean : 均值,var : 方差

    image = np.array(image/255, dtype=float)
    noise = np.random.normal(mean, var ** 0.5, image.shape)
    out = image + noise
    
    if out.min() < 0:
        low_clip = -1.
    else:
        low_clip = 0.

    out = np.clip(out, low_clip, 1.0)
    out = np.uint8(out*255)

    return out


img = cv2.imread("lena.bmp",0)#读取图像
out1 = sp_noise(img, prob=0.04)# 添加椒盐噪声,噪声比例为 0.04
out2 = gasuss_noise(img, mean=0, var=0.02)# 添加高斯噪声,均值为0,方差为0.02


# 快速傅里叶变换算法得到频率分布
f = np.fft.fft2(img)
f1 = np.fft.fft2(out1)
f2 = np.fft.fft2(out2)

# 默认结果中心点位置是在左上角,,调用fftshift()函数转移到中间位置
fshift = np.fft.fftshift(f)
fshift1 = np.fft.fftshift(f1)
fshift2 = np.fft.fftshift(f2)

# fft结果是复数, 其绝对值结果是振幅
fimg = np.log(np.abs(fshift))
fimg1 = np.log(np.abs(fshift1))
fimg2 = np.log(np.abs(fshift2))
# 显示图像

plt.figure(figsize=(11,10),facecolor='green')#创建figure
plt.rcParams['font.sans-serif']='STXINWEI'#设置中文字体为华文新魏


titles = ['原始图像', '原始图像频谱图', '椒盐噪声图像', '椒盐噪声频谱图','高斯噪声图像','高斯噪声频谱图']
images = [img, fimg, out1,fimg1,out2,fimg2]

for i in range(6):
    plt.subplot(3, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=15)

plt.show()

效果如上图

(三)理想高斯高通与低通滤波、巴特沃斯高通与低通滤波

巴特沃斯低通滤波器变换函数
用python实现数字图像处理(1)_第2张图片
巴特沃斯高通滤波器变换函数
在这里插入图片描述

对于高斯低通频域滤波,首先求原图像的频谱图,然后根据二维高斯低通滤波器(GLPF)定义,对频谱图做高斯低通滤波,使低频通过而使高频衰减,最后做快速傅里叶逆变换,结果发现滤波后的图像变模糊,比原始图像减少尖锐的细节部分而突出平滑过渡部分;对于巴特沃兹低通频域滤波,然后根据二级巴特沃思低通滤波器(BLPF)定义,对频谱图做巴特沃兹低通滤波,使低频通过而使高频衰减,最后做快速傅里叶逆变换,结果发现滤波后的图像变模糊,比原始图像减少尖锐的细节部分而突出平滑过渡部分;经对比图像后发现,经过巴特沃思低通滤波的图像比经过高斯低通频域滤波的图像更平滑。

对于高斯高通频域滤波,首先求原图像的频谱图,然后根据截频距原点为D0的高斯高通滤波器(GHPF)定义,对频谱图做高斯高通滤波,使高频通过而使低频衰减,最后做快速傅里叶逆变换,结果发现滤波后的图像变锐化,比原始图像减少平滑过渡而突出边缘等细节部分;对于巴特沃兹高通频域滤波,然后根据二阶且截至频率距原点的距离为D0的巴特沃思高通滤波器(BHPF)定义,对频谱图做巴特沃兹高通滤波,使高频通过而使低频衰减,最后做快速傅里叶逆变换,结果发现滤波后的图像变锐化,比原始图像减少平滑过渡而突出边缘等细节部分;经对比图像后发现,经过高斯低通滤波的图像比经过高斯低通巴特沃思低通频域滤波的图像更平滑。

np.sqrt返回数组的平方根
np.multiply函数是将数组和矩阵对应位置相乘,输出与相乘数组/矩阵的大小一致


import numpy as np
import cv2
import matplotlib.pyplot as plt

def IdealHighPassFiltering(f_shift):   #高斯高通滤波,PS:老师的文档上没有高斯高通滤波器的代码,所以这里自己在网上搜了一个,并做了2相关改动
    D0 = 30# 设置滤波半径
    # 初始化
    m = f_shift.shape[0]
    n = f_shift.shape[1]
    h1 = np.zeros((m, n))
    x0 = np.floor(m/2)
    y0 = np.floor(n/2)
    for i in range(m):
        for j in range(n):
            D = np.sqrt((i - x0)**2 + (j - y0)**2)
            if D >= D0:
                h1[i][j] = 1
    result = np.multiply(f_shift, h1)#数组和矩阵对应位置相乘,输出与相乘数组/矩阵的大小一致
    return result

def GaussLowPassFiltering(f_shift): #高斯低通滤波
    D0 = 30# 设置滤波半径
    # 初始化
    m = f_shift.shape[0]
    n = f_shift.shape[1]
    h1 = np.zeros((m, n))
    x0 = np.floor(m/2)
    y0 = np.floor(n/2)
    for i in range(m):
        for j in range(n):
            D = np.sqrt((i - x0)**2 + (j - y0)**2)
            h1[i][j] = np.exp((-1)*D**2/2/(D0**2))
    result = np.multiply(f_shift, h1)#数组和矩阵对应位置相乘,输出与相乘数组/矩阵的大小一致
    return result

def butter_worth_LowPassFiltering(f_shift): #巴特沃斯低通滤波器
    p=2#参数赋初始值
    d0 = 30
    # 初始化
    m = f_shift.shape[0]
    n = f_shift.shape[1]
    h1 = np.zeros((m, n))
    x0 = np.floor(m/2)
    y0 = np.floor(n/2)
    for i in range(m):
        for j in range(n):
            D = np.sqrt((i - x0)**2 + (j - y0)**2)
            h1[i][j] = 1 / (1 + 0.414*(D / d0) ** (2 * p))#计算传递函数
    result = np.multiply(f_shift, h1)#数组和矩阵对应位置相乘,输出与相乘数组/矩阵的大小一致
    return result

def butter_worth_HighPassFiltering(f_shift): #巴特沃斯高通滤波器
    p=2#参数赋初始值
    d0 = 30
    # 初始化
    m = f_shift.shape[0]
    n = f_shift.shape[1]
    h1 = np.zeros((m, n))
    x0 = np.floor(m/2)
    y0 = np.floor(n/2)
    for i in range(m):
        for j in range(n):

            D = np.sqrt((i - x0)**2 + (j - y0)**2)

            if D==0:
                h1[i][j]=0
            else:
                h1[i][j] = 1 / (1 + 0.414* (D / d0) **(2 * p))#计算传递函数

    result = np.multiply(f_shift, h1)#数组和矩阵对应位置相乘,输出与相乘数组/矩阵的大小一致
    return result

img =cv2.imread('lena.bmp',0)
f=np.fft.fft2(img)#计算二维的傅里叶变换
f_shift=np.fft.fftshift(f)#将图像中的低频部分移动到图像的中心

img1 =cv2.imread('test.jpg',0)
f1=np.fft.fft2(img1)##计算二维的傅里叶变换
f_shift1=np.fft.fftshift(f1)#将图像中的低频部分移动到图像的中心

# 显示图像

plt.figure(figsize=(17,10),facecolor='green')#创建figure
plt.rcParams['font.sans-serif']='STXINWEI'#设置中文字体为华文新魏


# 高斯低通滤波
GLPF = GaussLowPassFiltering(f_shift)
new_f1 = np.fft.ifftshift(GLPF)#进图像的低频和高频部分移动到图像原来的位置
new_image1 = np.uint8(np.real(np.fft.ifft2(new_f1)))#先将移频后的信号还原成之前的然后对复数进行操作,返回复数类型参数的实部,

#巴特沃斯低通滤波
BLPF = butter_worth_LowPassFiltering(f_shift)
new_f2 = np.fft.ifftshift(BLPF)#进图像的低频和高频部分移动到图像原来的位置
new_image2 = np.uint8(np.real(np.fft.ifft2(new_f2)))#先将移频后的信号还原成之前的然后对复数进行操作,返回复数类型参数的实部,



#巴特沃斯高通滤波
BHPF = butter_worth_HighPassFiltering(f_shift1)
new_f3 = np.fft.ifftshift(BHPF)#进图像的低频和高频部分移动到图像原来的位置
new_image3 = np.uint8(np.real(np.fft.ifft2(new_f3)))#先将移频后的信号还原成之前的然后对复数进行操作,返回复数类型参数的实部,


# 理想高斯高通滤波
IHPF = IdealHighPassFiltering(f_shift1)
new_f4 = np.fft.ifftshift(IHPF)#进图像的低频和高频部分移动到图像原来的位置
new_image4 = np.uint8(np.abs(np.fft.ifft2(new_f4)))#先将移频后的信号还原成之前的然后对复数进行操作,返回复数类型参数的实部,


titles = ['原始图像', '原始图像', '原始图像', '原始图像','高斯低通滤波图像','巴特沃斯低通滤波图像','巴特沃斯高通滤波图像','高斯高通滤波图像']
images = [img, img, img1, img1,new_image1,new_image2,new_image3,new_image4]

for i in range(8):
    plt.subplot(2, 4, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=15)

plt.show()

效果如上,其中上面的代码中np.uint8(np.abs(np.fft.ifft2(new_f1))),注意到中间调用了np.abs()函数,由于经过滤波变换之后所得的数值是复数,而不是实数,若将np.abs()替换为np.real(),即只取其实部,虚部舍掉,这样不太好,尤其是在上面最后一个高斯高通滤波中。

(四)结语

木有了

如果有什么错误的地方,还请大家批评指正,不过错了也没啥关系,反正也没什么人看
最后,希望小伙伴们都能有所收获。码字不易,喜欢的话,关注一波在走吧

你可能感兴趣的:(数字图像处理,python,图像处理)