手动实现图像滤波

图像滤波

要求

实现卷积
基于Python实现函数完成用滤波器h对灰度图像img0进行滤波,返回
滤波后的图像img1,即

i m g 1 = m y I m a g e F i l t e r ( i m g 0 , h ) img1 = myImageFilter(img0, h) img1=myImageFilter(img0,h)

要求滤波后的图像img1与原始输入图像具有相同的尺寸,滤波器h每个维度的大小为奇数(2k + 1, k = 1, 2, · · · )。在进行图像填充的时候可以使用课堂上讲过的任何一种填充方式均可。可以调用Python中NumPy的填充函数,但不能调用任何包括convolve, correlate, fftconvolve等函数(仅可以使用他们来与你自己的实现结果进行对比)。函数的实现需采用矢量化,关于矢量化的例子可参考https://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/VectorizedOperations.html.
(提示:尽可能减少for循环的个数)

实现

分析步骤:

  1. 创建高斯滤波卷积核,并做归一化处理
  2. 获取图片的形状(高、宽、通道数)
  3. 图片零填充处理,得到图片副本
  4. 遍历图片副本所有像素点,将卷积核与图片副本的切片进行点乘求和运算,得到输出图片
  5. 输出图片切片,恢复原图形状

创建高斯滤波卷积核

高斯滤波器将中心像素周围的像素按照高斯分布加权平均进行平滑化。
按下面的高斯分布公式计算权值:
g ( x , y , σ ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 g(x,y,\sigma) = \frac{1}{2\pi\sigma^2}e^{-\frac{x^2+y^2}{2\sigma^2}} g(x,y,σ)=2πσ21e2σ2x2+y2
并对权值 g g g进行归一化操作。

标准差 σ \sigma σ=1.3的8−近邻高斯滤波器如下:
k = 1 16 [ 1 2 1 2 4 2 1 2 1 ] k = \frac{1}{16} \begin{bmatrix} 1 & 2 &1 \\ 2 & 4 & 2 \\ 1 & 2 & 1 \\ \end{bmatrix} k=161121242121

示例
def gaussian_kernal_maker(k_size, sigma):
    """
    Create a Gaussian kernel
    :param k_size: size of the Gaussian kernel
    :param sigma: standard deviation
    :return k: Gaussian kernel
    """
    pad = k_size // 2
    k = np.zeros((k_size, k_size), dtype=np.float)
    for x in range(-pad, -pad + k_size):
        for y in range(-pad, -pad + k_size):
            k[y + pad, x + pad] = np.exp(-(x ** 2 + y ** 2) / (2 * (sigma ** 2)))

    k /= (2 * np.pi * sigma * sigma)
    k /= k.sum()
    return k

零填充

滤波后的图像img1需要与原始输入图像具有相同的尺寸,但是由于图像的长宽可能不是卷积核大小的整数倍,因此我们需要在图像的边缘补上 1 2 \frac{1}{2} 21 倍卷积核宽度的0像素点。
在这里插入图片描述

示例
    # Zero padding
    k_size = k.shape[0]
    pad = k_size // 2
    img1 = np.zeros((h + pad * 2, w + pad * 2, c), dtype=np.float)
    img1[pad: pad + h, pad: pad + w] = img0.copy().astype(np.float)

代码

import numpy as np
import cv2 as cv


def myImageFilter(img0, k):
    # YOUR CODE HERE
    """
    Filtering using a given kernel k
    :param img0: image
    :param k: kernel
    :return img1: filtered image
    """
    # Get the image shape.h:height w:width c:channels
    if len(img0.shape) == 3:
        h, w, c = img0.shape
    else:
        img0 = np.expand_dims(img0, axis=-1)
        h, w, c = img0.shape

    # Zero padding
    k_size = k.shape[0]
    pad = k_size // 2
    img1 = np.zeros((h + pad * 2, w + pad * 2, c), dtype=np.float)
    img1[pad: pad + h, pad: pad + w] = img0.copy().astype(np.float)

    # Filtering
    tmp = img1.copy()
    # Traversing the pixels of the image
    for y in range(h):  # h:height
        for x in range(w):  # w:width
            for i in range(c):  # c:channels
                img1[pad + y, pad + x, i] = np.sum(k * tmp[y: y + k_size, x: x + k_size, i])

    img1 = np.clip(img1, 0, 255)
    img1 = img1[pad: pad + h, pad: pad + w].astype(np.uint8)
    return img1


def gaussian_kernal_maker(k_size, sigma):
    """
    Create a Gaussian kernel
    :param k_size: size of the Gaussian kernel
    :param sigma: standard deviation
    :return k: Gaussian kernel
    """
    pad = k_size // 2
    k = np.zeros((k_size, k_size), dtype=np.float)
    for x in range(-pad, -pad + k_size):
        for y in range(-pad, -pad + k_size):
            k[y + pad, x + pad] = np.exp(-(x ** 2 + y ** 2) / (2 * (sigma ** 2)))

    k /= (2 * np.pi * sigma * sigma)
    k /= k.sum()
    return k


if __name__ == '__main__':
    # Read image
    # image = cv.imread("../image/example.png")
    image = cv.imread("../image/example_gray.png")
    cv.imshow("input", image)
    # Create Gaussian kernel
    kernel = gaussian_kernal_maker(k_size=3, sigma=1.3)
    # Gaussian Filter
    image_filtered = myImageFilter(img0=image, k=kernel)
    # Save result
    # cv.imwrite("output.jpg", image_filtered)
    cv.imshow("output", image_filtered)
    cv.waitKey(0)
    cv.destroyAllWindows()

结果

input
在这里插入图片描述
output
在这里插入图片描述

项目文件

imageFilter.zip

相关内容

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咬着棒棒糖闯天下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值