本站使用了 Pjax 等基于 JavaScript 的开发技术,但您的浏览器已禁用 JavaScript,请开启 JavaScript 以保证网站正常显示!

卷积滤波算子可视化

卷积滤波

许多2d的图像滤波算法都是基于图像空域滤波,此类滤波方法基本思想是先创建一个滤波模板作为卷积核,然后以滑动窗口的方式遍历图像进行卷积运算。所以基于空域的滤波算法(如高斯滤波、均值滤波)在运算上的区别就是卷积核的不同,不同的卷积核决定了计算的不同结果从而决定了不同的滤波效果。所以,接下来将这些卷积核绘制出来,直观地从卷积核方面来看看几种滤波算法之间的差异所在。

卷积核可视化

高斯滤波

高斯滤波的卷积核元素呈现高斯分布(正态分布),所以可以通过高斯分布公式将卷积核创建出来。首先,一维的高斯分布数学描述是这样子的:

$$f(x) = \frac{1}{\sqrt{2\pi}\sigma} exp(-\frac{(x - \mu)^2}{2\sigma^2})$$

其中:

(1) $\mu$ 为位置参数,为分布图的对称轴所在
(2) $\sigma$ 为尺度参数(标准差),描述分布元素向对称中心聚拢的程度,$\sigma$越大,元素分布越散,反之越聚拢。用python将一维的高斯分布绘制如下:

gaussian-1d.png

接下来再看卷积滤波中所用到的二维的高斯分布,其数学描述为:
在x、y独立的前提下,二维的高斯分布可以表示为

$$f(x,y) = f(x)f(y)$$

可以推导出

$$f(x, y) = \frac{1}{2\pi\sigma_1\sigma_2} exp(-\frac{1}{2}( \frac{(x-\mu_1)^2}{\sigma_1^2} + \frac{(y - \mu_2)^2}{\sigma_2^2}))$$

令$\sigma_1 = \sigma_2, \mu_1 = \mu_2 = 0$,公式可以进一步简化为

$$f(x, y) = \frac{1}{2\pi\sigma^2}exp(- \frac{x^2 + y^2}{2\sigma^2})$$

使用python绘制出的二维的高斯分布图如下:

gaussian-2d.png

在图像空域滤波中用的是离散的高斯分布,绘制离散的高斯分布图如下:

gaussian-2d-scatter.png

均值滤波

均值滤波则是非常简单,卷积核的元素都是相等的值,

$$\frac{1}{mn}\begin{bmatrix} 1&1&..1_{1n}\\ 1&1&..1_{2n}\\...&...&...\\ 1&..1_{m(n-1)}&..1_{mn} \end{bmatrix}$$

绘制出来的图表如下:

average.png

拉普拉斯算子

拉普拉斯算子定义:

$$\nabla^2f = \frac{\partial^2f}{\partial x^2} + \frac{\partial^2f}{\partial y^2}$$

x方向上有:

$$\frac{\partial^2f}{\partial x^2} = f(x+1,y) + f(x-1,y) - 2f(x,y)$$

y方向上有:

$$\frac{\partial^2f}{\partial y^2} = f(x,y+1) + f(x,y-1) - 2f(x,y)$$

所以拉普拉斯算子在离散的情况下,可以近似为

$$\nabla^2f = f(x+1,y) + f(x-1,y) + f(x,y+1) + f(x,y-1) -4f(x,y)$$

用矩阵的形式就可以表示为:

$$\begin{bmatrix} 0&-1&0\\ -1&4&-1\\ 0&-1&0 \end{bmatrix}$$
laplace.png

散点图可能看得不够明显,换成柱状图会好一些
laplace-bar.png

Sobel算子

$$Gx =\begin{bmatrix} -1&0&1\\ -2&0&2\\ -1&0&1 \end{bmatrix}$$

$$Gy = \begin{bmatrix} 1&2&1\\ 0&0&0\\ -1&-2&-1 \end{bmatrix}$$

sobel.png
sobel-bar.png

Roberts算子

Roberts算子求解的是对角线方向的梯度

$$g_x = f(x+1,y+1) -f(x,y) $$

$$g_y = f(x, y+1) - f(x+1, y) $$

$$g_x =\begin{bmatrix} -1&0\\ 0&1 \end{bmatrix}$$

$$g_y =\begin{bmatrix} 0&-1\\ 1&0 \end{bmatrix}$$

robert.png
robert-bar.png

Robinson算子

Robinson算子8个模板,对应8个方向的梯度

$$K_E = \begin{bmatrix} -3&-3&5\\ -3&0&5\\ -3&-3&5 \end{bmatrix}$$

$$K_{SE} = \begin{bmatrix} -3&-3&-3\\ -3&0&5\\ -3&5&5 \end{bmatrix}$$

$$K_S = \begin{bmatrix} -3&-3&-3\\ -3&0&-3\\ 5&5&5 \end{bmatrix}$$

$$K_{SW} = \begin{bmatrix} -3&-3&-3\\ 5&0&-3\\ 5&5&-3 \end{bmatrix}$$

$$K_W = \begin{bmatrix} 5&-3&-3\\ 5&0&-3\\ 5&-3&-3 \end{bmatrix}$$

$$K_{NW} = \begin{bmatrix} 5&5&-3\\ 5&0&-3\\ -3&-3&-3 \end{bmatrix}$$

$$K_N = \begin{bmatrix} 5&5&5\\ -3&0&-3\\ -3&-3&-3 \end{bmatrix}$$

$$K_{NE} = \begin{bmatrix} -3&5&5\\ -3&0&5\\ -3&-3&-3 \end{bmatrix}$$

这里给出x、y方向与对角线方向的各一个图表绘制:

robinson.png
robinson-bar.png

Kirsch算子

与Robinson算子相同,Kirsch算子拥有8个模板,对应8个方向的梯度。

$$K_E = \begin{bmatrix} -1&0&1\\ -2&0&2\\ -1&0&1 \end{bmatrix}$$

$$K_{SE} = \begin{bmatrix} -2&-1&0\\ -1&0&1\\ 0&1&2 \end{bmatrix}$$

$$K_S = \begin{bmatrix} -1&-2&-1\\ 0&0&0\\1&2&1 \end{bmatrix}$$

$$K_{SW} = \begin{bmatrix} 0&-1&-2\\ 1&0&-1\\ 2&1&0 \end{bmatrix}$$

$$K_W = \begin{bmatrix} 1&0&-1\\ 2&0&-2\\1&0&-1 \end{bmatrix}$$

$$K_{NW} = \begin{bmatrix} 2&1&0\\ 1&0&-1\\ 0&-1&-2 \end{bmatrix}$$

$$K_N = \begin{bmatrix} 1&2&1\\ 0&0&0\\ -1&-2&-1 \end{bmatrix}$$

$$K_{NE} = \begin{bmatrix} 0&1&2\\ -1&0&1\\ -2&-1&0 \end{bmatrix}$$

可以发现Kirsch算子包含了sobel算子,只取南北方向的模板就是sobel算子的模板描述,所以这里只绘制一个对角线方式与东西方向,结果如下图所示:
kirsch.png
kirsch-bar.png

Prewitt算子

与sobel算子类似

x方向:

$$Px =\begin{bmatrix} -1&0&1\\ -1&0&1\\ -1&0&1 \end{bmatrix}$$

y方向:

$$Py = \begin{bmatrix} 1&1&1\\ 0&0&0\\ -1&-1&-1 \end{bmatrix}$$

prewitt.png
prewitt-bar.png

代码

最后给出本文的绘制代码

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# visualize convolution kernel
# author:mango
# copyright:https://mangoroom.cn

def gaussian1d():
    mu = 0
    sigma = 1
    x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
    y = np.exp(-((x - mu)**2 / (2 * sigma**2)) / (np.sqrt(2*np.pi) * sigma))
    plt.plot(x, y)
    plt.title('Gaussian-1d Distribution: $\mu = %.2f, $sigma=%.2f'%(mu,sigma))
    plt.show()

def gaussian2d():
    mu1 = 0
    mu2 = 0
    sigma1 = 1
    sigma2 = 1
    x = np.linspace(mu1 - 3*sigma1, mu1 + 3*sigma1, 100)
    y = np.linspace(mu2 - 3 * sigma2, mu2 + 3 * sigma2, 100)
    x, y = np.meshgrid(x, y)
    z = np.exp(-0.5 * ((x - mu1)**2 / sigma1**2 + (y - mu2)**2 / sigma2**2)) / (2*np.pi * sigma1 * sigma2)
    fig = plt.figure()
    ax = Axes3D(fig)
    ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap='rainbow')
    plt.title('Gaussian-2d Distribution: $\mu = %.2f, $sigma=%.2f' % (mu1, sigma1))
    plt.show()

def gaussian2d_scatter():
    mu1 = 0
    mu2 = 0
    sigma1 = 1
    sigma2 = 1
    x = np.linspace(mu1 - 3*sigma1, mu1 + 3*sigma1, 15)
    y = np.linspace(mu2 - 3 * sigma2, mu2 + 3 * sigma2, 15)
    x, y = np.meshgrid(x, y)
    z = np.exp(-0.5 * ((x - mu1)**2 / sigma1**2 + (y - mu2)**2 / sigma2**2)) / (2*np.pi * sigma1 * sigma2)
    ax = plt.subplot(111, projection='3d')
    ax.scatter(x, y, z, c='g')
    plt.title('Gaussian-2d Distribution: $\mu = %.2f, $sigma=%.2f' % (mu1, sigma1))
    plt.show()

def average_distribution():
    x = np.linspace(-3, 3, 15)
    y = np.linspace(-3, 3, 15)
    x, y = np.meshgrid(x, y)
    z = (x + y) - (x + y) + 1
    ax = plt.subplot(111, projection='3d')
    ax.scatter(x, y, z, c='g')
    plt.title('Average Distribution:')
    plt.show()

def laplace():
    ax = plt.subplot(111, projection='3d')
    # ax.scatter(x, y, z, c='g')
    ax.scatter([-1, 1, -1, 1], [-1, -1, 1, 1], [0, 0, 0, 0], c='g')
    ax.scatter([0, -1, 1,  0], [-1, 0, 0, 1], [-1, -1, -1, -1], c='r')
    ax.scatter([0], [0], [4], c='y')

    plt.title('Laplace:')
    plt.show()

def laplace_bar():
    ax = plt.subplot(111, projection='3d')
    # ax.scatter(x, y, z, c='g')
    ax.bar3d([-1, 1, -1, 1], [-1, -1, 1, 1], 0, 0.2, 0.2, [0, 0, 0, 0])
    ax.bar3d([0, -1, 1,  0], [-1, 0, 0, 1], 0, 0.2, 0.2, [-1, -1, -1, -1])
    ax.bar3d([0], [0], 0, 0.2, 0.2, [4])
    plt.title('Laplace:')
    plt.show()


def sobel():
    ax = plt.subplot(121, projection='3d')
    ax.scatter([-1, -1, -1], [-1, 0, 1], [-1, -2, -1], c='r')
    ax.scatter([0, 0, 0], [-1, 0, 1], [0, 0, 0], c='g')
    ax.scatter([1, 1, 1], [-1, 0, 1], [1, 2, 1], c='b')
    plt.title('Solel Gx:')
    bx = plt.subplot(122, projection='3d')
    bx.scatter([-1, 0, 1], [-1, -1, -1], [-1, -2, -1], c='r')
    bx.scatter([-1, 0, 1], [0, 0, 0], [0, 0, 0], c='g')
    bx.scatter([-1, 0, 1], [1, 1, 1], [1, 2, 1], c='b')
    plt.title('Solel Gy:')
    plt.show()

def sobel_bar():
    ax = plt.subplot(121, projection='3d')
    ax.bar3d([-1, -1, -1], [-1, 0, 1], 0, 0.2, 0.2, [-1, -2, -1])
    ax.bar3d([0, 0, 0], [-1, 0, 1], 0, 0.2, 0.2, [0, 0, 0])
    ax.bar3d([1, 1, 1], [-1, 0, 1], 0, 0.2, 0.2, [1, 2, 1])
    plt.title('Solel Gx:')
    bx = plt.subplot(122, projection='3d')
    bx.bar3d([-1, 0, 1], [-1, -1, -1], 0, 0.2, 0.2, [-1, -2, -1])
    bx.bar3d([-1, 0, 1], [0, 0, 0], 0, 0.2, 0.2, [0, 0, 0])
    bx.bar3d([-1, 0, 1], [1, 1, 1], 0, 0.2, 0.2, [1, 2, 1])
    plt.title('Solel Gy:')
    plt.show()

def robinson():
    ax = plt.subplot(121, projection='3d')
    ax.scatter([-1, -1, -1], [-1, 0, 1], [-3, -3, -3], c='r')
    ax.scatter([0, 0, 0], [-1, 0, 1], [-3, 0, -3], c='g')
    ax.scatter([1, 1, 1], [-1, 0, 1], [5, 5, 5], c='b')
    plt.title('Robinson Gx:')
    bx = plt.subplot(122, projection='3d')
    bx.scatter([-1, 0, 1], [-1, -1, -1], [-3, -3, -3], c='r')
    bx.scatter([-1, 0, 1], [0, 0, 0], [-3, 0, 5], c='g')
    bx.scatter([-1, 0, 1], [1, 1, 1], [-3, 5, 5], c='b')
    plt.title('Robinson diagonal line:')
    plt.show()

def robinson_bar():
    ax = plt.subplot(121, projection='3d')
    ax.bar3d([-1, -1, -1], [-1, 0, 1],0, 0.2, 0.2, [-3, -3, -3])
    ax.bar3d([0, 0, 0], [-1, 0, 1],0, 0.2, 0.2, [-3, 0, -3])
    ax.bar3d([1, 1, 1], [-1, 0, 1],0, 0.2, 0.2, [5, 5, 5])
    plt.title('Robinson Gx:')
    bx = plt.subplot(122, projection='3d')
    bx.bar3d([-1, 0, 1], [-1, -1, -1],0, 0.2, 0.2, [-3, -3, -3])
    bx.bar3d([-1, 0, 1], [0, 0, 0],0, 0.2, 0.2, [-3, 0, 5])
    bx.bar3d([-1, 0, 1], [1, 1, 1],0, 0.2, 0.2, [-3, 5, 5])
    plt.title('Robinson diagonal line:')
    plt.show()

def kirsch():
    ax = plt.subplot(121, projection='3d')
    ax.scatter([-1, -1, -1], [-1, 0, 1], [-1, 0, 1], c='r')
    ax.scatter([0, 0, 0], [-1, 0, 1], [-2, 0, 2], c='g')
    ax.scatter([1, 1, 1], [-1, 0, 1], [-1, 0, 1], c='b')
    plt.title('kirsch KN:')
    bx = plt.subplot(122, projection='3d')
    bx.scatter([-1, 0, 1], [-1, -1, -1], [-2, -1, 0], c='r')
    bx.scatter([-1, 0, 1], [0, 0, 0], [-1, 0, 1], c='g')
    bx.scatter([-1, 0, 1], [1, 1, 1], [0, 1, 2], c='b')
    plt.title('kirsch KES:')
    plt.show()

def kirsch_bar():
    ax = plt.subplot(121, projection='3d')
    ax.bar3d([-1, -1, -1], [-1, 0, 1], 0, 0.2, 0.2, [-1, 0, 1])
    ax.bar3d([0, 0, 0], [-1, 0, 1], 0, 0.2, 0.2, [-2, 0, 2])
    ax.bar3d([1, 1, 1], [-1, 0, 1], 0, 0.2, 0.2, [-1, 0, 1])
    plt.title('kirsch KN:')
    bx = plt.subplot(122, projection='3d')
    bx.bar3d([-1, 0, 1], [-1, -1, -1], 0, 0.2, 0.2, [-2, -1, 0])
    bx.bar3d([-1, 0, 1], [0, 0, 0], 0, 0.2, 0.2, [-1, 0, 1])
    bx.bar3d([-1, 0, 1], [1, 1, 1], 0, 0.2, 0.2, [0, 1, 2])
    plt.title('kirsch KES:')
    plt.show()
def prewitt():
    ax = plt.subplot(121, projection='3d')
    ax.scatter([-1, -1, -1], [-1, 0, 1], [-1, -1, -1], c='r')
    ax.scatter([0, 0, 0], [-1, 0, 1], [0, 0, 0], c='g')
    ax.scatter([1, 1, 1], [-1, 0, 1], [1, 1, 1], c='b')
    plt.title('Prewitt Gx:')
    bx = plt.subplot(122, projection='3d')
    bx.scatter([-1, 0, 1], [-1, -1, -1], [-1, -1, -1], c='r')
    bx.scatter([-1, 0, 1], [0, 0, 0], [0, 0, 0], c='g')
    bx.scatter([-1, 0, 1], [1, 1, 1], [1, 1, 1], c='b')
    plt.title('Prewitt Gy:')
    plt.show()

def prewitt_bar():
    ax = plt.subplot(121, projection='3d')
    ax.bar3d([-1, -1, -1], [-1, 0, 1], 0, 0.2, 0.2, [-1, -1, -1])
    ax.bar3d([0, 0, 0], [-1, 0, 1], 0, 0.2, 0.2, [0, 0, 0])
    ax.bar3d([1, 1, 1], [-1, 0, 1], 0, 0.2, 0.2, [1, 1, 1])
    plt.title('Prewitt Gx:')
    bx = plt.subplot(122, projection='3d')
    bx.bar3d([-1, 0, 1], [-1, -1, -1], 0, 0.2, 0.2, [-1, -1, -1])
    bx.bar3d([-1, 0, 1], [0, 0, 0], 0, 0.2, 0.2, [0, 0, 0])
    bx.bar3d([-1, 0, 1], [1, 1, 1], 0, 0.2, 0.2, [1, 1, 1])
    plt.title('Prewitt Gy:')
    plt.show()
def robert():
    ax = plt.subplot(121, projection='3d')
    ax.scatter([0, 1], [0, 1], [1, -1], c='r')
    ax.scatter([1, 0], [0, 1], [0, 0], c='g')

    plt.title('Robert Gx:')
    bx = plt.subplot(122, projection='3d')
    bx.scatter([0, 1], [0, 1], [0, 0], c='r')
    bx.scatter([1, 0], [0, 1], [1, -1], c='g')
    plt.title('Robert Gy:')
    plt.show()

def robert_bar():
    ax = plt.subplot(121, projection='3d')
    ax.bar3d([0, 1], [0, 1], 0, 0.2, 0.2, [1, -1])
    ax.bar3d([1, 0], [0, 1], 0, 0.2, 0.2, [0, 0])

    plt.title('Robert Gx:')
    bx = plt.subplot(122, projection='3d')
    bx.bar3d([0, 1], [0, 1], 0, 0.2, 0.2, [0, 0])
    bx.bar3d([1, 0], [0, 1], 0, 0.2, 0.2, [1, -1])
    plt.title('Robert Gy:')
    plt.show()



if __name__ == '__main__':
    # gaussian1d()
    # gaussian2d()
    # gaussian2d_scatter()
    # average_distribution()
    # laplace()
    # sobel()
    # laplace_bar()
    # sobel_bar()
    # robert()
    # robert_bar()
    # prewitt()
    # prewitt_bar()
    # kirsch()
    # kirsch_bar()
    robinson()
    robinson_bar()

本文由芒果浩明发布,转载请注明出处。
本文链接:https://mangoroom.cn/python/visualize-convolution-kernel.html


 继续浏览关于 中值滤波滤波 的文章

 本文最后更新于:2020/03/14 22:21:37,可能因经年累月而与现状有所差异

 引用转载请注明:芒果的Blog > python,计算机视觉 > 卷积滤波算子可视化