第4章 Python 数字图像处理(DIP) - 频率域滤波9 - 频率域滤波基础、频率域的滤波过程、低通、高通

目录

    • 频率域滤波基础
      • 频率域的其他特性
      • 频率域滤波基础知识
      • 频率域滤波步骤小结
      • 空间域和频率域滤波之间的对应关系

频率域滤波基础

频率域的其他特性

  • 频率域中的滤波过程如下:
    • 首先修改傅里叶变换以在到特定目的
    • 然后计算IDFT,返回到空间域
# 频率域中的其他特性
img = cv2.imread('DIP_Figures/DIP3E_Original_Images_CH04/Fig0429(a)(blown_ic).tif', -1)# FFT
img_fft = np.fft.fft2(img.astype(np.float32))# 非中心化的频谱
spectrum = spectrum_fft(img_fft)
spectrum = np.uint8(normalize(spectrum) * 255)# 中心化
fshift = np.fft.fftshift(img_fft)            # 将变换的频率图像四角移动到中心# 中心化后的频谱
spectrum_fshift = spectrum_fft(fshift)
spectrum_fshift_n = np.uint8(normalize(spectrum_fshift) * 255)# 对频谱做对数变换
spectrum_log = np.log(1 + spectrum_fshift)plt.figure(figsize=(15, 8))
plt.subplot(1, 2, 1), plt.imshow(img, cmap='gray'), plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(spectrum_log, cmap='gray'), plt.title('FFT Shift log'), plt.xticks([]), plt.yticks([])
plt.tight_layout()
plt.show()

在这里插入图片描述

频率域滤波基础知识

已知大小为P×QP \times QP×Q像素的一幅数字图像f(x,y)f(x, y)f(x,y),则我们感兴趣取的基本滤波公式是:
g(x,y)=Real{J−1[H(u,v)F(u,v)]}(4.104)g(x, y) = Real\{ \mathfrak{J}^{-1}[H(u, v) F(u, v)] \} \tag{4.104}g(x,y)=Real{J1[H(u,v)F(u,v)]}(4.104)

J−1\mathfrak{J}^{-1}J1是IDFT,H(u,v)H(u, v)H(u,v)是滤波器传递函数(经常称为滤波器或滤波器函数),F(u,v)F(u, v)F(u,v)是输入图像f(x,y)f(x, y)f(x,y)的DFT,g(x,y)g(x, y)g(x,y)是滤波后的图像。

中以化:用(−1)x+y(-1)^{x + y}(1)x+y乘以输入图像来完成的

  • 低通滤波器

    • 会衰减高频而通过低频的函数,会模糊图像
  • 高通滤波器

    • 将使图像的细节更清晰,但会降低图像的对比度
def centralized_2d_loop(arr):"""centralized 2d array $f(x, y) (-1)^{x + y}$"""    #==================中心化=============================height, width = arr.shape[:2]dst = np.zeros([height, width])for h in range(height):for w in range(width):dst[h, w] = arr[h, w] * ((-1) ** (h + w))return dst
def centralized_2d_index(arr):"""centralized 2d array $f(x, y) (-1)^{x + y}$, about 35 times faster than loop"""def get_1_minus1(img):"""get 1 when image index is even, -1 while index is odd, same shape as input image, need this array to multiply with input imageto get centralized image for DFTParameter: img: input, here we only need img shape to create the arrayreturn such a [[1, -1, 1], [-1, 1, -1]] array, example is 3x3"""M, N = img.shapem, n = img.shape# 这里判断一个m, n是否是偶数,如果是偶数的话,结果不正确,需要变换为奇数if m % 2 == 0 :m += 1if n % 2 ==0 :n += 1temp = np.arange(m * n).reshape(m, n)dst = np.piecewise(temp, [temp % 2 == 0, temp % 2 == 1], [1, -1])dst = dst[:M, :N]return dst#==================中心化=============================mask = get_1_minus1(arr)dst = arr * maskreturn dst
def centralized_2d(arr):"""centralized 2d array $f(x, y) (-1)^{x + y}$, about 4.5 times faster than index, 160 times faster than loop,"""def get_1_minus1(img):"""get 1 when image index is even, -1 while index is odd, same shape as input image, need this array to multiply with input imageto get centralized image for DFTParameter: img: input, here we only need img shape to create the arrayreturn such a [[1, -1, 1], [-1, 1, -1]] array, example is 3x3"""dst = np.ones(img.shape)dst[1::2, ::2] = -1dst[::2, 1::2] = -1return dst#==================中心化=============================mask = get_1_minus1(arr)dst = arr * maskreturn dst
a = np.arange(25).reshape(5, 5)
a
array([[ 0,  1,  2,  3,  4],[ 5,  6,  7,  8,  9],[10, 11, 12, 13, 14],[15, 16, 17, 18, 19],[20, 21, 22, 23, 24]])
centralized_2d(a)
array([[  0.,  -1.,   2.,  -3.,   4.],[ -5.,   6.,  -7.,   8.,  -9.],[ 10., -11.,  12., -13.,  14.],[-15.,  16., -17.,  18., -19.],[ 20., -21.,  22., -23.,  24.]])
def idea_high_pass_filter(source, radius=5):M, N = source.shape[1], source.shape[0]u = np.arange(M)v = np.arange(N)u, v = np.meshgrid(u, v)D = np.sqrt((u - M//2)**2 + (v - N//2)**2)D0 = radiuskernel = D.copy()kernel[D > D0] = 1kernel[D <= D0] = 0kernel_normal = (kernel - kernel.min()) / (kernel.max() - kernel.min())return kernel_normal
# 频率域滤波基础知识
img = cv2.imread('DIP_Figures/DIP3E_Original_Images_CH04/Fig0429(a)(blown_ic).tif', -1)# FFT
img_fft = np.fft.fft2(img.astype(np.float32))# 中心化
fshift = np.fft.fftshift(img_fft)            # 将变换的频率图像四角移动到中心# 滤波器
h = idea_high_pass_filter(img, radius=1)# 滤波
res = fshift * h# 先反中以化,再反变换
f1shift = np.fft.ifftshift(res)
ifft = np.fft.ifft2(f1shift)# 取实数部分
recon = np.real(ifft)
# 小于0都被置为0
# recon = np.where(recon > 0, recon, 0)
recon = np.clip(recon, 0, recon.max())
recon = np.uint8(normalize(recon) * 255)plt.figure(figsize=(15, 8))
plt.subplot(1, 2, 1), plt.imshow(img, cmap='gray'), plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(recon, cmap='gray'), plt.title('FFT Shift log'), plt.xticks([]), plt.yticks([])
plt.tight_layout()
plt.show()

在这里插入图片描述

def gauss_high_pass_filter(source, center, radius=5):"""create gaussian high pass filter param: source: input, source imageparam: center: input, the center of the filter, where is the lowest value, (0, 0) is top left corner, source.shape[:2] is center of the source imageparam: radius: input, the radius of the lowest value, greater value, bigger blocker out range, if the radius is 0, then allvalue is 1return a [0, 1] value filter"""M, N = source.shape[1], source.shape[0]u = np.arange(M)v = np.arange(N)u, v = np.meshgrid(u, v)D = np.sqrt((u - center[1]//2)**2 + (v - center[0]//2)**2)D0 = radiusif D0 == 0:kernel = np.ones(source.shape[:2], dtype=np.float)else:kernel = 1 - np.exp(- (D**2)/(D0**2))   kernel = (kernel - kernel.min()) / (kernel.max() - kernel.min())return kernel
def plot_3d(ax, x, y, z):ax.plot_surface(x, y, z, antialiased=True, shade=True)ax.view_init(30, 60), ax.grid(b=False), ax.set_xticks([]), ax.set_yticks([]), ax.set_zticks([])def imshow_img(img, ax, cmap='gray'):ax.imshow(img, cmap=cmap), ax.set_xticks([]), ax.set_yticks([])
def frequency_filter(fshift, h):"""Frequency domain filtering using FFTparam: fshift: input, FFT shift to centerparam: h: input, filter, value range [0, 1]return a uint8 [0, 255] reconstruct image"""# 滤波res = fshift * h# 先反中以化,再反变换f1shift = np.fft.ifftshift(res)ifft = np.fft.ifft2(f1shift)# 取实数部分recon = np.real(ifft)# 小于0都被置为0# recon = np.where(recon > 0, recon, 0)recon = np.clip(recon, 0, recon.max())recon = np.uint8(normalize(recon) * 255)return recon
# 高斯核滤波器与对应的结果
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import cm# 显示多个3D高斯核函数
k = 3
sigma = 0.8
X = np.linspace(-k, k, 200)
Y = np.linspace(-k, k, 200)
x, y = np.meshgrid(X, Y)
z = np.exp(- ((x)**2 + (y)**2)/ (2 * sigma**2))fig = plt.figure(figsize=(15, 10))
ax_1 = fig.add_subplot(2, 3, 1, projection='3d')
plot_3d(ax_1, x, y, z)ax_2 = fig.add_subplot(2, 3, 2, projection='3d')
plot_3d(ax_2, x, y, 1 - z)# 这里只显示不明显,
a = 1
x = a + x
y = a + y
ax_3 = fig.add_subplot(2, 3, 3, projection='3d')
plot_3d(ax_3, x, y, 1 - z)img_ori = cv2.imread('DIP_Figures/DIP3E_Original_Images_CH04/Fig0431(d)(blown_ic_crop).tif', -1)# FFT
img_fft = np.fft.fft2(img_ori.astype(np.float32))# 中心化
fshift = np.fft.fftshift(img_fft)            # 将变换的频率图像四角移动到中心# 滤波器
radius = 20
center = img_ori.shape[:2]
h_high_1 = gauss_high_pass_filter(img_ori, center, radius=radius)
h_low = 1 - h_high_1
center = (1026, 872)
h_high_2 = gauss_high_pass_filter(img_ori, center, radius=radius)img_low = frequency_filter(fshift, h_low)
img_high_1 = frequency_filter(fshift, h_high_1)
img_high_2 = frequency_filter(fshift, h_high_2)ax_4 = fig.add_subplot(2, 3, 4)
imshow_img(img_low, ax_4)ax_5 = fig.add_subplot(2, 3, 5)
imshow_img(img_high_1, ax_5)ax_6 = fig.add_subplot(2, 3, 6)
imshow_img(img_high_2, ax_6)plt.tight_layout()
plt.show()

在这里插入图片描述

下面展示的是函数未填充时,会产生交叠错误;而函数填充0后,产生我们期望的结果,但是此时的滤波器应该是原来的2倍大小,如果是还是原来的大小的话,那么图像会比之前更模糊的。

这里采用的方法是对图像进行零填充,再直接在频率域中创建期望的滤波器传递函数,该函数的到底会给你个填充零后的图像的大小相同。这个明显降低交叠错误,只是会出现振铃效应

# 未填充与填充0的结果
img_ori = cv2.imread('DIP_Figures/DIP3E_Original_Images_CH04/Fig0432(a)(square_original).tif', -1)#================未填充===================
# FFT
img_fft = np.fft.fft2(img_ori.astype(np.float32))# 中心化
fshift = np.fft.fftshift(img_fft)            # 将变换的频率图像四角移动到中心# 滤波器
radius = 50
center = img_ori.shape[:2]
h_high_1 = gauss_high_pass_filter(img_ori, center, radius=radius)
h_low = 1 - h_high_1img_low = frequency_filter(fshift, h_low)fig = plt.figure(figsize=(15, 5))
ax_1 = fig.add_subplot(1, 3, 1)
imshow_img(img_ori, ax_1)ax_2 = fig.add_subplot(1, 3, 2)
imshow_img(img_low, ax_2)#================填充0====================
fp = np.zeros([img_ori.shape[0]*2, img_ori.shape[1]*2])
fp[:img_ori.shape[0], :img_ori.shape[1]] = img_oriimg_fft = np.fft.fft2(fp.astype(np.float32))
fshift = np.fft.fftshift(img_fft)   hp = 1 - gauss_high_pass_filter(fp, fp.shape, radius=100)img_low = frequency_filter(fshift, hp)
img_dst = img_low[:img_ori.shape[0], :img_ori.shape[1]]ax_3 = fig.add_subplot(1, 3, 3)
imshow_img(img_dst, ax_3)plt.tight_layout()
plt.show()

在这里插入图片描述

另一个合理的做法是:构建一个与未填充图像大小相同的函数,计算该函数的IDFT得到相应的空间表示,在空间域中对这一表示填充,然后计算其DFT返回到频率域。这也会出现振铃效应

def centralized(arr):"""centralized 1d array $f(x) (-1)^{n}$"""u = arr.shape[0]dst = np.zeros(arr.shape)# 中心化for n in range(u):dst[n] = arr[n] * ((-1) ** n)return dst
# 频率域反变换到空间域,再填充,再DFT,会出现振铃效应
h = np.zeros([256])
h[:9] = 1
h_c = np.fft.fftshift(h)fig = plt.figure(figsize=(15, 10))
grid = plt.GridSpec(2, 3, wspace=0.2, hspace=0.1)
ax_1 = fig.add_subplot(grid[0, 0])
ax_1.plot(h_c), ax_1.set_xticks([0, 128, 255]), ax_1.set_yticks(np.arange(-0.2, 1.4, 0.2)), ax_1.set_xlim([0, 255])# 用公式法的中以化才能得到理想的结果
h_pad = np.pad(h, (0, 256), mode='constant', constant_values=0)
ifshift = centralized_2d(h_pad.reshape(1, -1)).flatten() # 也可以用centralized_2d这个函数
ifft = np.fft.ifft(ifshift)
ifft = ifft.real * 2
ifft[:128] = 0
ifft[384:] = 0
ax_2 = fig.add_subplot(grid[0, 1:3])
ax_2.plot(ifft), ax_2.set_xticks([0, 128, 256, 384, 511]), ax_2.set_yticks(np.arange(-0.01, 0.05, 0.01)), ax_2.set_xlim([0, 511])f = ifft[128:384]
ax_3 = fig.add_subplot(grid[1, 0])
ax_3.plot(f), ax_3.set_xticks([0, 128, 255]), ax_3.set_yticks(np.arange(-0.01, 0.05, 0.01)), ax_3.set_xlim([0, 255])# 已经中心化,截取部分构成原函数,但出现的效果不是太好,但可以看出振铃效应
d = 120
f_ = np.zeros([h.shape[0]])
f_[:256-d] = f[d:]
f_pad = np.pad(f_, (0, 256), mode='constant', constant_values=0)
f_centralized = centralized(f_pad)
fft = np.fft.fft(f_centralized)
ax_4 = fig.add_subplot(grid[1, 1:3])
ax_4.plot(fft.real), ax_4.set_xticks([0, 128, 256, 384, 511]), ax_4.set_yticks(np.arange(-0.2, 1.4, 0.2)), ax_4.set_xlim([0, 511])plt.show()

在这里插入图片描述

零相移滤波器

  • 相角计算为复数的实部与虚部之比的反正切。因为H(u,v)H(u, v)H(u,v)同是乘以R,IR,IR,I,所以当这个比率形成后,它会被抵消。对实部和虚部的影响相同且对相角无影响的滤波器。
# 相角对反变换的影响
img_ori = cv2.imread('DIP_Figures/DIP3E_Original_Images_CH04/Fig0431(d)(blown_ic_crop).tif', -1)#================未填充===================
# FFT
img_fft = np.fft.fft2(img_ori.astype(np.float32))# 中心化
fshift = np.fft.fftshift(img_fft)            # 频谱与相角
spectrum = spectrum_fft(fshift)
phase = phase_fft(fshift)# 相角乘以-1
phase_1 = phase * -1
new_fshift = spectrum * np.exp(phase_1 * -1j)
new_fshift = np.fft.ifftshift(new_fshift)
recon_1 = np.fft.fft2(new_fshift)# 相角乘以0.5,需要乘以一个倍数,以便可视化
phase_2 = phase * 0.25
new_fshift = spectrum * np.exp(phase_2 * -1j)
new_fshift = np.fft.ifftshift(new_fshift)
recon_2 = np.fft.fft2(new_fshift)
recon_2 = np.uint8(normalize(recon_2.real) * 4000)fig = plt.figure(figsize=(15, 5))
ax_1 = fig.add_subplot(1, 3, 1)
imshow_img(img_ori, ax_1)ax_2 = fig.add_subplot(1, 3, 2)
imshow_img(recon_1.real, ax_2)ax_3 = fig.add_subplot(1, 3, 3)
ax_3.imshow(recon_2, cmap='gray')plt.tight_layout()
plt.show()

在这里插入图片描述

频率域滤波步骤小结

  1. 已知一幅大小为M×NM\times NM×N的输入图像f(x,y)f(x, y)f(x,y),分别得到填充零后的尺寸PPPQQQ,即P=2MP=2MP=2MQ=2NQ=2NQ=2N
  2. 使用零填充、镜像填充或复制填充,形成大小为P×QP\times QP×Q的填充后的图像fP(x,y)f_P(x, y)fP(x,y)
  3. fP(x,y)f_P(x, y)fP(x,y)乘以(−1)x+y(-1)^{x+y}(1)x+y,使用傅里叶变换位于P×QP\times QP×Q大小的频率矩形的中心。
  4. 计算步骤3得到的图像的DFT,即F(u,v)F(u, v)F(u,v)
  5. 构建一个实对称滤波器传递函数H(u,v)H(u, v)H(u,v),其大小为P×QP\times QP×Q,中心中(P/2,Q/2)(P/2, Q/2)(P/2,Q/2)处。
  6. 采用对应像素相乘得到G(u,v)=H(u,v)F(u,v)G(u, v) = H(u, v)F(u, v)G(u,v)=H(u,v)F(u,v)
  7. 计算G(u,v)G(u, v)G(u,v)的IDFT得到滤波后的图像(大小为P×QP\times QP×Q),gP(x,y)={Real[J−1[G(u,v)]]}(−1)x+yg_P(x, y) = \Big\{\text{Real} \big[\mathfrak{J}^{-1}[G(u, v)] \big]\Big\}(-1)^{x+y}gP(x,y)={Real[J1[G(u,v)]]}(1)x+y
  8. 最后,从gP(x,y)g_P(x, y)gP(x,y)的左上象限提取一个大小为M×NM\times NM×N的区域,得到与输入图像大小相同的滤波后的结果g(x,y)g(x, y)g(x,y)
def pad_image(img, mode='constant'):"""pad image into PxQ shape, orginal is in the top left corner.param: img: input imageparam: mode: input, str, is numpy pad parameter, default is 'constant'. for more detail please refere to Numpy padreturn PxQ shape image padded with zeros or other values"""dst = np.pad(img, ((0, img.shape[0]), (0, img.shape[1])), mode=mode)return dst    
# 频率域滤波过程
img_ori = cv2.imread('DIP_Figures/DIP3E_Original_Images_CH04/Fig0431(d)(blown_ic_crop).tif', -1)
M, N = img_ori.shape[:2]
fig = plt.figure(figsize=(15, 15))# 这里对原图像进行pad,以得到更好的显示
img_ori_show = np.ones([img_ori.shape[0]*2, img_ori.shape[1]*2]) * 255
img_ori_show[:img_ori.shape[0], img_ori.shape[1]:] = img_ori
ax_1 = fig.add_subplot(3, 3, 1)
imshow_img(img_ori_show, ax_1)fp = pad_image(img_ori, mode='constant')
ax_2 = fig.add_subplot(3, 3, 2)
imshow_img(fp, ax_2)fp_cen = centralized_2d(fp)
fp_cen_show = np.clip(fp_cen, 0, 255) # 负数的都截断为0
ax_3 = fig.add_subplot(3, 3, 3)
ax_3.imshow(fp_cen_show, cmap='gray'), ax_3.set_xticks([]), ax_3.set_yticks([])fft = np.fft.fft2(fp_cen)
spectrum = spectrum_fft(fft)
spectrum = np.log(1 + spectrum)
ax_4 = fig.add_subplot(3, 3, 4)
imshow_img(spectrum, ax_4)H = 1 - gauss_high_pass_filter(fp, center=fp.shape, radius=70)
ax_5 = fig.add_subplot(3, 3, 5)
imshow_img(H, ax_5)HF = fft * H
HF_spectrum = np.log(1 + spectrum_fft(HF))
ax_6 = fig.add_subplot(3, 3, 6)
imshow_img(HF_spectrum, ax_6)ifft = np.fft.ifft2(HF)
gp = centralized_2d(ifft.real)
ax_7 = fig.add_subplot(3, 3, 7)
imshow_img(gp, ax_7)# 最终结果有黑边
g = gp[:M, :N]
ax_8 = fig.add_subplot(3, 3, 8)
imshow_img(g, ax_8)plt.tight_layout()
plt.show()

在这里插入图片描述

def frequency_filter(fft, h):"""Frequency domain filtering using FFTparam: fshift: input, FFT shift to centerparam: h: input, filter, value range [0, 1]return a uint8 [0, 255] reconstruct image"""# 滤波res = fft * h# 先反中以化,再反变换ifft = np.fft.ifft2(res)# 取实数部分recon = centralized_2d(ifft.real)# 小于0都被置为0recon = np.clip(recon, 0, recon.max())recon = np.uint8(normalize(recon) * 255)return recon
# 频率域滤波
img_ori = cv2.imread('DIP_Figures/DIP3E_Original_Images_CH04/Fig0431(d)(blown_ic_crop).tif', -1)
M, N = img_ori.shape[:2]# 填充
fp = pad_image(img_ori, mode='reflect')
# 中心化
fp_cen = centralized_2d(fp)
# 正变换
fft = np.fft.fft2(fp_cen)
# 滤波器
H = 1 - gauss_high_pass_filter(fp, center=fp.shape, radius=100)
# 滤波
HF = fft * H
# 反变换
ifft = np.fft.ifft2(HF)
# 去中心化
gp = centralized_2d(ifft.real)
# 还回来与原图像的大小
g = gp[:M, :N]
fig = plt.figure(figsize=(15, 15))
ax_8 = fig.add_subplot(3, 3, 8)
imshow_img(g, ax_8)
plt.tight_layout()
plt.show()

在这里插入图片描述

空间域和频率域滤波之间的对应关系

空间域中的滤波器核与频率域傅里叶变换对:
h(x,y)⇔H(u,v)(4.106)h(x, y) \Leftrightarrow H(u, v) \tag{4.106}h(x,y)H(u,v)(4.106)

h(x,y)h(x, y)h(x,y)是空间核。这个核 可以由一个频率域滤波器对一个冲激的响应得到,因此有时我们称h(x,y)h(x, y)h(x,y)H(u,v)H(u, v)H(u,v)的冲激响应。

一维频率域高斯传递函数
H(u)=Ae−u2/2σ2(4.107)H(u) = A e^{-u^2/2\sigma^2} \tag{4.107}H(u)=Aeu2/2σ2(4.107)
空间域的核 由H(u)H(u)H(u)的傅里叶反变换得到
h(x)=2πσAe−2π2σ2x2(4.108)h(x) = \sqrt{2\pi}\sigma A e^{-2\pi^2\sigma^2 x^2} \tag{4.108}h(x)=2πσAe2π2σ2x2(4.108)

这是两个很重要的公式

  1. 它们是一个傅里叶变换对,两者都是高斯函数和实函数
  2. 两个函数的表现相反
  • 高斯差

    • 用一个常量减去低通函数,可以构建一个高通滤波器。
    • 因为使用所谓的高斯差(涉及两个低通函数)就可更好地控制滤波函数的形状
  • 频率域 A≥B,σ1>σ2A \ge B, \sigma_1 > \sigma_2AB,σ1>σ2
    H(u)=Ae−u2/2σ12−Be−u2/2σ22(4.109)H(u) = A e^{-u^2/2\sigma_1^2} - B e^{-u^2/2\sigma_2^2}\tag{4.109}H(u)=Aeu2/2σ12Beu2/2σ22(4.109)

  • 空间域
    h(x)=2πσ1Ae−2π2σ12x2−2πσ2Be−2π2σ22x2(4.110)h(x) = \sqrt{2\pi}\sigma_1 A e^{-2\pi^2\sigma_1^2 x^2} - \sqrt{2\pi}\sigma_2 B e^{-2\pi^2\sigma_2^2 x^2} \tag{4.110}h(x)=2πσ1Ae2π2σ12x22πσ2Be2π2σ22x2(4.110)

# 空间域与频率域的滤波器对应关系
u = np.linspace(-3, 3, 200)A = 1
sigma = 0.2
Hu = A * np.exp(-np.power(u, 2) / (2 * np.power(sigma, 2)))x = u
hx = np.sqrt(2 * np.pi) * sigma * A * np.exp(-2 * np.pi**2 * sigma**2 * x**2)fig = plt.figure(figsize=(10, 10))
ax_1 = setup_axes(fig, 221)
ax_1.plot(u, Hu), ax_1.set_title('H(u)', loc='center', y=1.05), ax_1.set_ylim([0, 1]), ax_1.set_yticks([])B = 1
sigma_2 = 4
Hu_2 = B * np.exp(-np.power(u, 2) / (2 * np.power(sigma_2, 2)))
Hu_diff = Hu_2 - Huax_2 = setup_axes(fig, 222)
ax_2.plot(x, Hu_diff), ax_2.set_title('H(u)', loc='center', y=1.05), ax_2.set_ylim([0, 1.1]), ax_2.set_yticks([])ax_3 = setup_axes(fig, 223)
ax_3.plot(x, hx), ax_3.set_title('h(x)', loc='center', y=1.05), ax_3.set_ylim([0, 0.8]), ax_3.set_yticks([])hx_2 = np.sqrt(2 * np.pi) * sigma_2 * B * np.exp(-2 * np.pi**2 * sigma_2**2 * x**2)
hx_diff = hx_2 - hxax_4 = setup_axes(fig, 224)
ax_4.plot(x, hx_diff), ax_4.set_title('h(x)', loc='center', y=1.05), ax_4.set_ylim([-1, 10]), ax_4.set_yticks([])plt.tight_layout()
plt.show()

在这里插入图片描述

# 空间核得到频率域
img_ori = cv2.imread('DIP_Figures/DIP3E_Original_Images_CH04/Fig0438(a)(bld_600by600).tif', -1)fp = pad_zero(img_ori)
fp_cen = centralized_2d(fp)
fft = np.fft.fft2(fp_cen)
spectrum = spectrum_fft(fft)
spectrum = np.log(1 + spectrum)plt.figure(figsize=(18, 15))
plt.subplot(1, 2, 1), plt.imshow(img, cmap='gray'), plt.title('No Log')
plt.subplot(1, 2, 2), plt.imshow(spectrum, cmap='gray'), plt.title('FFT')
plt.tight_layout()
plt.show()

在这里插入图片描述
注:频率域的Sobel滤波器还没有解决

# 频域
center = (fp.shape[0], fp.shape[1] + 300)
GHPF = gauss_high_pass_filter(fp, center, radius=200)
GHPF = (1 - np.where(GHPF > 1e-6, GHPF, 1)) * -2center = (fp.shape[0], fp.shape[1] - 300)
GHPF_1 = gauss_high_pass_filter(fp, center, radius=200)
GHPF_1 = (1 - np.where(GHPF_1 > 1e-6, GHPF_1, 1)) * 2sobel_f = GHPF + GHPF_1plt.figure(figsize=(15, 5))plt.subplot(1, 3, 1), plt.imshow(GHPF, 'gray')
plt.subplot(1, 3, 2), plt.imshow(GHPF_1, 'gray')
plt.subplot(1, 3, 3), plt.imshow(sobel_f, 'gray')plt.tight_layout()
plt.show()

在这里插入图片描述

# 频域
fig = plt.figure(figsize=(15, 5))
HF = fft * sobel_f
HF_spectrum = np.log(1 + spectrum_fft(HF))
ax_6 = fig.add_subplot(1, 3, 1)
imshow_img(HF_spectrum, ax_6)ifft = np.fft.ifft2(HF)
gp = centralized_2d(ifft.real)
ax_7 = fig.add_subplot(1, 3, 2)
imshow_img(gp, ax_7)# 最终结果有黑边
g = gp[:M, :N]
ax_8 = fig.add_subplot(1, 3, 3)
imshow_img(g, ax_8)# plt.figure(figsize=(15, 5))# plt.subplot(1, 3, 1), plt.imshow(GHPF, 'gray')
# plt.subplot(1, 3, 2), plt.imshow(GHPF_1, 'gray')
# plt.subplot(1, 3, 3), plt.imshow(sobel_f, 'gray')plt.tight_layout()
plt.show()

在这里插入图片描述

空间域的Sobel滤波器

def kernel_seperate(kernel):"""这里的分离核跟之前不太一样get kernel seperate vector if separableparam: kernel: input kerel of the filterreturn two separable vector c, r"""rank = np.linalg.matrix_rank(kernel)if rank == 1:#-----------------Numpy------------------# here for sobel kernel seperatec = kernel[:, -1]r = kernel[-1, :]else:print('Not separable')#     c = np.array(c).reshape(-1, 1)
#     r = np.array(r).reshape(-1, 1)return c, r
def separate_kernel_conv2D(img, kernel):"""separable kernel convolution 2D, if 2D kernel not separable, then canot use this fuction. in the fuction. first need toseperate the 2D kernel into two 1D vectors.param: img: input image you want to implement 2d convolution with 2d kernelparam: kernel: 2D separable kernel, such as Gaussian kernel, Box Kernelreturn image after 2D convolution"""m, n = kernel.shape[:2]pad_h = int((m - 1) / 2)pad_w = int((n - 1) / 2)w_1, w_2 = kernel_seperate(kernel)
#     w_1 = np.array([-1, 0, 1])
#     w_2 = np.array([1, 2, 1])convovle = np.vectorize(np.convolve, signature='(x),(y)->(k)')r_2 = convovle(img, w_2)r_r = np.rot90(r_2)r_1 = convovle(r_r, w_1)r_1 = r_1.Tr_1 = r_1[:, ::-1]img_dst = img.copy().astype(np.float)img_dst = r_1[pad_h:-pad_h, pad_w:-pad_w]return img_dst
# Sobel梯度增强边缘
img_ori = cv2.imread("DIP_Figures/DIP3E_Original_Images_CH04/Fig0438(a)(bld_600by600).tif", 0)sobel_x = np.zeros([3, 3], np.int)
sobel_x[0, :] = np.array([-1, -2, -1])
sobel_x[2, :] = np.array([1, 2, 1])sobel_y = np.zeros([3, 3], np.int)
sobel_y[:, 0] = np.array([-1, -2, -1])
sobel_y[:, 2] = np.array([1, 2, 1])gx = separate_kernel_conv2D(img_ori, kernel=sobel_x)
gy = separate_kernel_conv2D(img_ori, kernel=sobel_y)# gx = cv2.filter2D(img_ori, ddepth=-1, kernel=sobel_x)
# gy = cv2.filter2D(img_ori, ddepth=-1, kernel=sobel_y)# 先对gx gy做二值化处理再应用下面的公式
img_sobel = np.sqrt(gx**2 + gy**2)   # 二值化后,平方根的效果与绝对值很接近
img_sobel = abs(gx) + abs(gy)
img_sobel = np.uint8(normalize(img_sobel) * 255)plt.figure(figsize=(15, 12))
plt.subplot(1, 2, 1), plt.imshow(img_ori,   'gray', vmax=255), plt.title("Original"), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(img_sobel, 'gray', vmax=255), plt.title("Sobel"), plt.xticks([]), plt.yticks([])
plt.tight_layout()
plt.show()

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/260705.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# :试玩EventLog

1. 专门创建Source的Log   创建了Source&#xff0c;log显示在 Event viewer/Applications and Services logs/ 自定义Source 中&#xff0c;待遇比较高&#xff0c;专门显示的。 创建Source需要管理员身份&#xff0c;否则Crash。 如果已经打开了 Computer Management,请关闭…

css 宋体_Java前端基础(一)之html/css

1.1 htmlHTML:超文本标记语言(Hyper Text Markup Language)&#xff0c;标准通用标记语言下的一个应用。HTML 不是一种编程语言&#xff0c;而是一种标记语言 (markup language)&#xff0c;是网页制作所必备的WEB开发工具&#xff1a;hbuilder/webstorm/vs code/eclpise最简单…

View Controller Programming Guide for iOS---(七)---Resizing the View Controller’s Views

Resizing the View Controller’s Views A view controller owns its own view and manages the view’s contents. In the process, the view controller also manages the view’s subviews. But in most cases, the view’s frame is not set directly by the view controll…

基于百度地图js进行地理定位

http://www.mengxiangchaoren.com/jquery.select.position.min.js 使用方法 $("#myCity").renderSelect({posByGps:true,bdAk:BD_AK});转载于:https://www.cnblogs.com/Brose/p/jquery_select_position.html

C#接口-接口作用

C#接口是一个让很多初学C#者容易迷糊的东西&#xff0c;用起来好像很简单&#xff0c;定义接口&#xff0c;里面包含方法&#xff0c;但没有方法具体实现的代码&#xff0c;然后在继承该接口的类里面要实现接口的所有方法的代码&#xff0c;但没有真正认识到接口的作用的时候就…

gpio的8种工作模式_Stm32之GPIO工作模式简介

GPIO的8种工作模式GPIO初始化结构体的时候&#xff0c;必须要配置合适的工作模式&#xff0c;这样才能使得IO口发挥应有的作用。工作模式大体上共分为输入输出两类&#xff0c;共8种&#xff0c;下面将介绍这8种工作模式。GPIO工作模式输入模式GPIO_Mode_AIN 模拟输入 GPIO_Mod…

vagrant,流浪汉,我又来啦。

最近学个DEVOPS2.0&#xff0c;讲微服务&#xff0c;容器华&#xff0c;持续部署&#xff0c;很到位&#xff0c;就一个一个工具撸一撸。。。 vagrant&#xff0c;以前接触过&#xff0c;所以上手快&#xff0c;&#xff0c;哈哈&#xff0c;&#xff0c;用时再具体配置。 virt…

dedecms最新版本修改任意管理员漏洞

此漏洞无视gpc转义&#xff0c;过80sec注入防御。 补充下&#xff0c;不用担心后台找不到。这只是一个demo&#xff0c;都能修改任意数据库了&#xff0c;还怕拿不到SHELL&#xff1f; 起因是全局变量$GLOBALS可以被任意修改&#xff0c;随便看了下&#xff0c;漏洞一堆&#x…

第4章 Python 数字图像处理(DIP) - 频率域滤波10 - 使用低通频率域滤波器平滑图像 - 理想、高斯、巴特沃斯低通滤波器

目录使用低通频率域滤波器平滑图像理想低通滤波器(ILPF)高斯低通滤波器(GLPF)巴特沃斯低通滤波器低通滤波的例子使用低通频率域滤波器平滑图像 理想低通滤波器(ILPF) 在以原点为中心的一个圆内无衰减地通过所有频率&#xff0c;而在这个圆外“截止”所有的频率的二维低通滤波…

vs2008中combox用法总结

1、判断是否为空 m_CheckPoint.GetCurSel()-1; 2、清空 m_CheckPoint.ResetContent(); 3、添加 m_CheckPoint.AddString(str); 4、获取某一索引的值 m_CheckPoint.GetLBText(j,str1);//j为索引&#xff0c;str1为存储变量 5、删除某一索引的值 m_CheckPoint.DeleteString(j);//…

bluecam连接步骤说明_厂家详解旋片式真空泵使用说明

旋片式真空泵是有区分单双极高速直联结构的真空泵&#xff0c;是用来对密封容器抽除气体的基本设备之一。旋片式真空泵的泵与电机连轴&#xff0c;有着高转速、外型小、结构紧凑、流动性工作方便的优点。本文所使用旋片式真空泵使用说明资料&#xff0c;是台冠真空泵技术团队工…

python函数中可变参数的传递方式是_Python函数可变参数定义及其参数传递方式实例详解...

本文实例讲述了Python函数可变参数定义及其参数传递方式。分享给大家供大家参考。具体分析如下&#xff1a; python中 函数不定参数的定义形式如下&#xff1a; 1、func(*args) 传入的参数为以元组形式存在args中&#xff0c;如&#xff1a; def func(*args): print args >&…

加载中做法

一个网页在加载时&#xff0c;可给静态部分加个加载中&#xff0c;而动态部分也即是真正内容用jq来改&#xff0c;这样就有那个效果了转载于:https://www.cnblogs.com/yedeying/p/3618815.html

Junit4常用注解

Junit4注解 JUnit4的测试类不用再继承TestCase类了。使用注解会方便很多。 Before&#xff1a;初始化方法After&#xff1a;释放资源Test&#xff1a;测试方法&#xff0c;在这里可以测试期望异常和超时时间Ignore&#xff1a;忽略的测试方法BeforeClass&#xff1a;针对所有测…

第4章 Python 数字图像处理(DIP) - 频率域滤波11 - 使用高通滤波器锐化图像

目录使用高通滤波器锐化图像由低通滤波器得到理想、高斯和巴特沃斯高通滤波器指纹增强频域中的拉普拉斯钝化掩蔽、高提升滤波和高频强调滤波同态滤波使用高通滤波器锐化图像 由低通滤波器得到理想、高斯和巴特沃斯高通滤波器 HHP(u,v)1−HLP(u,v)(4.118)H_{HP}(u, v) 1 - H_{…

值类型 引用类型 堆栈 堆 之 异想

看了很多值类型 和 引用类型的文章&#xff08;谷歌能搜索出来的&#xff09;看了越多疑问越大&#xff0c;而这些资料中没有具体的说明。问题&#xff1a;1、堆栈 和 堆 分别存于计算机的哪个硬件&#xff08;CPU缓存&#xff0c;内存&#xff0c;硬盘&#xff09;&#xff1f…

漫步者lollipods如何调节音量_漫步者MF5扩音器体验:老师值得入手

对于教师职业来说&#xff0c;保护好嗓子是很重要的。每天为学生操劳&#xff0c;频繁的讲课&#xff0c;很多老师都遇上了喉咙沙哑的问题。怎么样才能保护好老师的嗓子呢&#xff1f;“小蜜蜂”是很多老师们的选择&#xff0c;这种扩音器可以挂在腰间&#xff0c;通过麦克风&a…

数据库之间数据转换最快方法

用txt导入的方式是最快的&#xff0c;一般是秒级。 以ACCESS数据库到SQLite数据库为例&#xff1a; 第一步&#xff1a;导出ACCESS数据库到txt文件&#xff1a; 一、将表中数据导出到文本文件&#xff08;TXT&#xff09;&#xff1a; Select * INTO [TEXT;DATABASEE:\TEMP].TE…

pandas删除某列有空值的行_Python-零基础学习Pandas知识点整理(2)

DataFrame数据的清洗--预处理操作import pandas as pdimport numpy as np#DataFrame数据框行或列的删除#df.drop(labelsNone,axis0,indexNone,columnsNone,levelNone,inplaceFalse,error"raise")#labels 表示需要删除的行或列的标签&#xff0c;多行或多列用列表传入…

JavaScript中的闭包

什么是闭包&#xff1f; 当函数可以记住并访问所在的词法作用域时&#xff0c;就产生了闭包&#xff0c;即使函数是在当前词法作用域之外执行的。下面用一些代码来解释这个定义&#xff1a; function foo() {var a 2;function bar() {console.log(a); // 2}bar(); }foo(); 这…