opencv-python学习(十):利用卷积对图像模糊处理

利用卷积对图像模糊处理

一、调用函数实现模糊

图像的模糊是图像处理中比较常用和简单的处理手段之一。那么使用这种手段的原因就是为了给图像进行去噪,便于后面的处理

根据我上文图像卷积的操作中可以想象,图像的模糊处理就是卷积的计算,拿一个3*3的卷积核在图像上做滑动操作,继而得到新图像

而不同类型的模糊背后其实对应的卷积核也不同
根据原理的不同,模糊的方式也有很多种,比如:均值模糊函数blur()、中值模糊函数medianBlur()、高斯平滑函数GaussianBlur()、双边滤波函数bilateralFilter()

  • 均值模糊函数blur()

均值模糊从字面意思就是去平均值,也就是卷积核中的系数全是1,与卷积核覆盖下的原图像素值相乘,再除以9(卷积核的大小为3*3),得到平均值,赋值给中心像素

它的缺点是在去噪的同时,不能很好的保留图像细节,因为全用均值代替了

blur(src,ksize,dst=None, anchor=None, borderType=None)
src:输入图像
ksize:卷积核大小,越大越模糊,一般来说是奇数,卷积核一般都是3x3,5x5或者7x7
其余参数可以不理会

  • 高斯平滑函数GaussianBlur()

相比于均值模糊,高斯模糊更好的保留图像的细节。因为高斯函数的特性,会有一定的权重配比

GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)
src:输入图像
ksize:模糊核大小,但它们必须是正的和奇数的
sigmaX:X方向上的高斯核标准差

  • 中值模糊函数medianBlur()

字面意思的话,就是取中间的值来代替中心像素。和均值类似,只不过均值是去平均值,而中值取得是中间的那个值。中值可以有效的去除椒盐噪声(比如说你在清水中,撒点盐,这些就是椒盐噪声。对应到图像上,在一副黑色图像上,有很多小白点,这些就是椒盐噪声)

那么它为什么可以去除椒盐噪声呢。因为椒盐噪声像素值要么很小为0,要么很大为255,而取中间值话,就会用替代这些,从而给图像去噪点。

medianBlur(src, ksize, dst=None)
src:输入图像
ksize:孔径线性尺寸;它必须是奇数并且大于1

  • 双边滤波函数bilateralFilter()

高斯滤波相对于均值模糊而言保留图像的一些细节,但是它是基于空阈的,就是基于空间分布的。但是它还是没有办法完全避免边缘信息的丢失。而双边滤波则是比高斯滤波多了一个高斯方差sigma-d,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。也就是说它们的像素值在设定落差之外,不给它进行模糊,比便于保留边缘。

bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)
src:输入图像
d:用于滤波的每个像素邻域的直径,直径内的所有像素均会被纳入计算。如果它是非正数,则从sigmaSpace计算
sigmaColor:决定多少差值内的像素会被计算,颜色标准差
sigmaSpace:如果d的值大于0则无效,否则会用来计算d的值,空间标准差

代码如下:

# 引入包
import cv2 as cv

def mo_image(src1):
    src2 = cv.blur(src1, (5, 5))
    cv.namedWindow("blur", cv.WINDOW_NORMAL)
    cv.imshow("blur", src2)

    src2 = cv.medianBlur(src1, 5)
    cv.namedWindow("mdBlur", cv.WINDOW_NORMAL)
    cv.imshow("mdBlur", src2)

    src2 = cv.GaussianBlur(src1, (5, 5), 2)
    cv.namedWindow("GaussBlur", cv.WINDOW_NORMAL)
    cv.imshow("GaussBlur", src2)

    src2 = cv.bilateralFilter(src1, 5, 5, 2)
    cv.namedWindow("bilFilter", cv.WINDOW_NORMAL)
    cv.imshow("bilFilter", src2)

src = cv.imread("./static/image/blur.jpg")
cv.namedWindow("image", cv.WINDOW_NORMAL)
cv.imshow("image", src)
mo_image(src)
cv.waitKey(0)
cv.destroyAllWindows()



二、自定义模糊

filter2D():定义为filter2D(src,ddepth,kernel)

  • src:输入图像
  • ddepth:深度,输入值为-1时,目标图像和原图像深度保持一致,一般设为-1即可。
  • kernel:卷积核(或者是相关核),一个单通道浮点型矩阵(修改kernel矩阵即可实现不同的模糊,有许多有趣的内核):

1、模糊(blur)
模糊内核消除了相邻像素值之间的差异。内核如下:
kernel = np.ones((5, 5), np.float)/25

# 自定义模糊
    kernel1 = np.ones((5, 5), np.float)/25 # 自定义矩阵,并防止数值溢出
    src2 = cv.filter2D(src1, -1, kernel1) # 自定义模糊
    cv.namedWindow("define", cv.WINDOW_NORMAL)
    cv.imshow("define", src2)

运行效果:
在这里插入图片描述

2、索贝尔(sobel)
sobel内核用于仅显示特定方向上相邻像素值的差异,分为left sobel、right sobel(检测梯度的水平变化)、top sobel、buttom sobel(检测梯度的垂直变化)。内核如下:

-1 -2 -1
0 0 0
1 2 1

代码与上面类似,只需修改krenel的值
在这里插入图片描述

3、浮雕(emboss)
通过强调像素的差在给定方向的Givens深度的错觉。在这种情况下,沿着从左上到右下的直线的方向。内核如下:

-2 -1 0
-1 1 1
0 1 2

运行效果:
在这里插入图片描述

4、大纲(outline)
一个轮廓内核(也称为“边缘”的内核)用于突出显示的像素值大的差异。具有接近相同强度的相邻像素旁边的像素在新图像中将显示为黑色,而与强烈不同的相邻像素相邻的像素将显示为白色。内核如下:

-1 -1 -1
-1 8 -1
-1 -1 -1

运行效果:
在这里插入图片描述

5、锐化(sharpen)
一个轮廓内核(也称为“边缘”的内核)用于突出显示的像素值大的差异。具有接近相同强度的相邻像素旁边的像素在新图像中将显示为黑色,而与强烈不同的相邻像素相邻的像素将显示为白色。内核如下:

0 -1 0
-1 5 -1
0 -1 0

运行效果:
在这里插入图片描述
6、拉普拉斯算子(laplacian operator)
拉普拉斯算子可以用于边缘检测,对于检测图像中的模糊也非常有用。内核如下:

0 1 0
1 -4 1
0 1 0

运行效果:
在这里插入图片描述

7、分身(identity)
这个非常简单,就是原图(不考虑边界时)。内核如下:

0 0 0
0 1 0
0 0 0

完整代码:

# 引入包
import cv2 as cv
import numpy as np

def define_image(src1):
    # 自定义模糊
    kernel1 = np.ones((9, 9), np.float)/80 # 自定义矩阵,并防止数值溢出
    src2 = cv.filter2D(src1, -1, kernel1) # 自定义模糊
    cv.namedWindow("define", cv.WINDOW_NORMAL)
    cv.imshow("define", src2)

    # 自定义锐化
    kernel2 = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32)
    src2 = cv.filter2D(src1, -1, kernel2) # 自定义锐化
    cv.namedWindow("define2", cv.WINDOW_NORMAL)
    cv.imshow("define2", src2)

    # 索贝尔(sobel)
    kernel3 = np.array([[-1, -2, -1],
        [0, 0, 0],
        [1, 2, 1]], np.float32)
    src2 = cv.filter2D(src1, -1, kernel3)
    cv.namedWindow("define2", cv.WINDOW_NORMAL)
    cv.imshow("define2", src2)

    # 浮雕
    kernel4 = np.array([[-2, -1, 0],
                        [-1, 1, 1],
                        [0, 1, 2]], np.float32)
    src2 = cv.filter2D(src1, -1, kernel4)
    cv.namedWindow("define2", cv.WINDOW_NORMAL)
    cv.imshow("define2", src2)

    # 大纲(outline)
    kernel5 = np.array([[-1, -1, -1],
                        [-1, 8, -1],
                        [-1, -1, -1]], np.float32)
    src2 = cv.filter2D(src1, -1, kernel5)
    cv.namedWindow("define2", cv.WINDOW_NORMAL)
    cv.imshow("define2", src2)

    # 拉普拉斯算子(laplacian operator)
    kernel6 = np.array([[0, 1, 0],
                        [1, -4, 1],
                        [0, 1, 0]], np.float32)
    src2 = cv.filter2D(src1, -1, kernel6)
    cv.namedWindow("define2", cv.WINDOW_NORMAL)
    cv.imshow("define2", src2)

    # 分身(identity)
    kernel7 = np.array([[0, 0, 0],
                        [0, 1, 0],
                        [0, 0, 0]], np.float32)
    src2 = cv.filter2D(src1, -1, kernel7)
    cv.namedWindow("define2", cv.WINDOW_NORMAL)
    cv.imshow("define2", src2)

src = cv.imread("./static/image/windows.jpg")
cv.namedWindow("image", cv.WINDOW_NORMAL)
cv.imshow("image", src)
define_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

例子参考:

https://blog.csdn.net/qq_42059060/article/details/107660265?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162520738216780271574301%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162520738216780271574301&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-2-107660265.pc_search_result_cache&utm_term=cv.filter2d&spm=1018.2226.3001.4187

猜你喜欢

转载自blog.csdn.net/weixin_33538887/article/details/118390924