import numpy as np
def create_gaussian_kernel(k, sigma):
center = k // 2
kernel = np.zeros((k, k), dtype=np.float32)
for i in range(k):
for j in range(k):
kernel[i, j] = (1 / (2 * np.pi * sigma**2)) * np.exp(
-((i - center) ** 2 + (j - center) ** 2) / (2 * sigma**2)
)
kernel /= np.sum(kernel)
return kernel
def conv_2d(img, k, sigma=None):
assert k % 2 != 0, "卷積核應為奇數"
pad = k // 2
# 建立卷積核
if sigma is None: # 均值濾波
kernel = np.ones((k, k), dtype=np.float32) / (k * k)
else: # 高斯濾波
kernel = create_gaussian_kernel(k, sigma)
# 執行卷積操作
if len(img.shape) == 2: # 灰度影像
H, W = img.shape
# img_padded = np.pad(img, pad_width=pad, mode='constant')
img_padded = np.zeros((img.shape[0] + pad * 2, img.shape[1] + pad * 2))
img_padded[pad:-pad, pad:-pad] = img
out = np.zeros_like(img, dtype=np.float32)
for h in range(H):
for w in range(W):
out[h, w] = (img_padded[h : h + k, w : w + k] * kernel).sum()
else: # 彩色影像
H, W, C = img.shape
# img_padded = np.pad(img, pad_width=(pad, pad, (0, 0)), mode='constant')
img_padded = np.zeros((img.shape[0] + pad * 2, img.shape[1] + pad * 2, C))
img_padded[pad:-pad, pad:-pad] = img
out = np.zeros_like(img, dtype=np.float32)
for h in range(H):
for w in range(W):
for c in range(C):
out[h, w, c] = (img_padded[h : h + k, w : w + k, c] * kernel).sum()
out = np.clip(out, 0, 255).astype(np.uint8)
return out
def normalize_image(img):
# 找到影像的最小值和最大值
min_val = np.min(img)
max_val = np.max(img)
# 對影像進行歸一化
img_normalized = (img - min_val) * (255 / (max_val - min_val))
# 確保值在 0 到 255 之間
img_normalized = np.clip(img_normalized, 0, 255)
# 轉換資料型別為 uint8
img_normalized = img_normalized.astype(np.uint8)
return img_normalized
def my_filters(img, D=30, tag=None):
assert tag=='low-pass' or tag=='high-pass', "please choose a tag in 'low-pass' or 'high-pass'"
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
H, W = img.shape
crow, ccol = int(H/2), int(W/2)
if tag=='low-pass':
# 構造影像的低通濾波器
mask = np.zeros((H, W), np.uint8)
mask[crow-D:crow+D, ccol-D:ccol+D] = 1
md = fshift * mask
epsilon = 1e-10
magnitude_spectrum_md = 20 * np.log(np.abs(md) + epsilon)
# 低通濾波並顯示結果
ishift_low = np.fft.ifftshift(md)
iimg_low = np.fft.ifft2(ishift_low)
iimg_low = np.abs(iimg_low)
iimg_low = normalize_image(iimg_low)
return iimg_low, magnitude_spectrum_md
else:
# 構造A影像的高通濾波器
fshift[crow-D:crow+D, ccol-D:ccol+D] = 0
ishift_high = np.fft.ifftshift(fshift)
iimg_high = np.fft.ifft2(ishift_high)
iimg_high = np.abs(iimg_high)
iimg_high = normalize_image(iimg_high)
magnitude_spectrum_fshift = 20 * np.log(np.abs(fshift)+1)
return iimg_high, magnitude_spectrum_fshift
def blend_images(image1, image2, d1=30, d2=10, d3=20):
assert image1.shape == image2.shape, "image1 shape should equal to image2 shape"
# 計算影像A的頻譜
fA = np.fft.fft2(image1)
fshiftA = np.fft.fftshift(fA)
# 計算影像B的頻譜
fB = np.fft.fft2(image2)
fshiftB = np.fft.fftshift(fB)
# 獲取影像大小和頻譜中心點
rows, cols = image1.shape
crow, ccol = int(rows/2), int(cols/2)
# 構造A影像的低通濾波器
maskA = np.zeros((rows, cols), np.uint8)
maskA[crow-d1:crow+d1, ccol-d1:ccol+d1] = 1
md = fshiftA * maskA
# 構造B影像的高通濾波器
fshiftB[crow-d2:crow+d2, ccol-d2:ccol+d2] = 0
# A影像低頻與B影像高頻融合
fshiftB[crow-d3:crow+d3, ccol-d3:ccol+d3] = md[crow-d3:crow+d3, ccol-d3:ccol+d3]
ishiftC = np.fft.ifftshift(fshiftB)
iimgC = np.fft.ifft2(ishiftC)
iimgC = np.abs(iimgC)
iimgC = normalize_image(iimgC)
return iimgC
def gaussian_pyramid(image, levels=6):
pyramid_images = [image]
for _ in range(levels-1):
image = image[::2, ::2]
pyramid_images.append(image)
return pyramid_images