图像平滑处理

发布于:2024-07-11 ⋅ 阅读:(23) ⋅ 点赞:(0)

图像平滑从信号处理的角度看就是去除其中的高频信息,保留低频信息。因此我们可以对图像实施低通滤波。低通滤波可以去除图像中的噪音,模糊图像(噪音是图像中变化比较大的区域,也就是高频信息)。而高通滤波能够提取图像的边缘(边缘也是高频信息集中的区域)。

根据滤波器的不同又可以分为均值滤波,高斯加权滤波,中值滤波, 双边滤波。

1. 均值滤波

平均滤波是将一个m*n(m, n为奇数)大小的kernel放在图像上,中间像素的值用kernel覆盖区域的像素平均值替代。平均滤波对高斯噪声的表现比较好。

OpenCV提供了cv2.blur()函数用于处理平均滤波,使用方法如下:

In [ ]:

%matplotlib inline

import numpy as np

import matplotlib.pyplot as plt

import cv2

img = cv2.imread('./lena.jpg')

output = cv2.blur(img,(10,10))

原图和效果图比较如下:

In [ ]:

img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

plt.imshow(img2)

plt.show()

output2 = cv2.cvtColor(output, cv2.COLOR_BGR2RGB)

plt.imshow(output2)

plt.show()

可以明显的看到,图像相比原图变得模糊。

2. 高斯滤波

即假设某一位置的像素和其邻域像素符合高斯分布.具体的说的话,就是每一位置的像素的权重符合高斯分布.这样的话,给定一个高斯分布,及高斯核的大小,则可以计算出周边n个像素的权重值。

OpenCV中获取高斯核心的函数为cv2.getGaussianKernel,但是这个获取的一维的高斯核.对图像来说,以3 x 3邻域而言,我们应该得到一个3 x 3的权重矩阵.可以如下得到:

In [ ]:

kernal_x = cv2.getGaussianKernel(3,-1)

kernal_y = cv2.getGaussianKernel(3,-1)

kernal_filter = np.dot(kernal_x,kernal_y.T)

print(kernal_filter)

则中间元素的亮度值经高斯转换后为0.0625 x p(0,0) + 0.125 x p(0,1) + .... + 0.0625 x p(2,2),可以看到权重矩阵相加等于1。 这里,我们举例用了3 x 3的高斯核,实际上并不限定高斯核一定要是正方形。

接下来查看一下OpenCV提供的高斯滤波函数的定义:

GaussianBlur(

    InputArray src,

    OutputArray dst,

    Size ksize,

    double sigmaX,

    double singmaY = 0,

    int borderType = BORDER_DEFAULT

)

其参数sigmaX,sigmaY即x,y方向上的高斯分布的标准差。这样就可以求得不同方向上的高斯矩阵,再做矩阵乘法,即得到m x n的权重矩阵。进而求得高斯转换后的图像。

我们知道高斯分布(也叫正态分布)的特点为,标准差越大,分布越分散,标准差越小,分布越集中。所以调大GaussianBlur()中的sigmaX,sigmaY将使得图像中的每个像素更多地参考周边像素,即更为平滑或者说模糊。

In [ ]:

%matplotlib inline

import cv2

import numpy as np

import matplotlib.pyplot as plt

imgname = "./lena.jpg"

img = cv2.imread(imgname)

img2 = img.copy()

img2 = cv2.GaussianBlur(img,(5,7),1)

img3 = cv2.GaussianBlur(img,(5,7),100)

原图和效果图比较如下:

In [ ]:

output = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

output2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)

output3 = cv2.cvtColor(img3, cv2.COLOR_BGR2RGB)

plt.imshow(output)

plt.show()

plt.imshow(output2)

plt.show()

plt.imshow(output3)

plt.show()

通过比较可以感受到,高斯滤波效果较为柔和,标准差越大,图像就越模糊。

3. 中值滤波

即把像素值变为邻域像素值的中位数。OpenCV提供的中值滤波函数的定义如下:

medianBlur(

    InputArray src,

    OutputArray dst,

    int ksize

)

注意,ksize的大小必须为奇数。

In [ ]:

%matplotlib inline

import cv2

import numpy as np

import matplotlib.pyplot as plt

imgname = "./lena.jpg"

img = cv2.imread(imgname)

dst = cv2.medianBlur(img, 1)

dst2 = cv2.medianBlur(img, 11)

原图和效果图对比如下:

In [ ]:

img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

plt.imshow(img2)

plt.show()

output2 = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)

plt.imshow(output2)

plt.show()

output3 = cv2.cvtColor(dst2, cv2.COLOR_BGR2RGB)

plt.imshow(output3)

plt.show()

通过比较可以发现,ksize的大小越大,图像越模糊,画面呈现出油画感。

4. 双边滤波

双边滤波能在保持边界清晰的情况下有效的去除噪音。但是这种操作与其他滤波器相比会比较慢.我们已经知道高斯滤波器是求中心点邻近区域像素的高斯加权平均值。这种高斯滤波器只考虑像素之间的空间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会被模糊掉,而这不是我们想要的。

双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大。

简单滴说就是,在生成周边像素的权重矩阵时,如果发现旁边的像素值和当前的像素值差异很大,就只给差异很大的那个元素分配很小的权重,这样"大的突变差异就被保留了"。

OpenCV提供的双边滤波函数的定义如下:

bilateralFilter(

    InputArray src,

    OutputArray dst,

    int d,

    double sigmaColor,

    double sigmaSpave,

    int borderType = BORDER_DEFAULT

)

使用方法如下:

In [ ]:

%matplotlib inline

import numpy as np

import matplotlib.pyplot as plt

import cv2

img = cv2.imread('./lena.jpg')

dst = cv2.bilateralFilter(img, 9, 75, 75)

原图和效果图比较如下:

In [ ]:

img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

plt.imshow(img2)

plt.show()

output2 = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)

plt.imshow(output2)

plt.show()

由上图可以看出双边滤波能够较好的保留图像的边缘信息。