1.影像濾波與影像融合

真真夜夜發表於2024-04-20
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

相關文章