仅供自己学习、复习需要,有任何问题可在评论区提出。
一、高斯金字塔
高斯金字塔主要有两部分组成:高斯滤波和下采样操作。
1.1 高斯噪声
高斯噪声是指噪声密度函数服从高斯分布的一类噪声。由于高斯噪声在空间和频域中数学上的易处理性,这种噪声(也称为正态噪声)模型经常被用于实践中。高斯随机变量z的概率密度函数由下式给出:
P
(
z
)
=
1
2
π
σ
e
−
(
z
−
μ
)
2
2
σ
2
P(z) = \frac{1}{\sqrt{2π}\sigma}e^{ \frac{-(z-\mu)^2}{2\sigma ^2}}
P(z)=2π
σ1e2σ2−(z−μ)2
其中z表示灰度值,μ表示z的平均值或期望值,σ表示z的标准差。标准差的平方
σ
2
\sigma ^2
σ2
称为z的方差。高斯函数的曲线如图所示
1.2 图像平滑
图像平滑从信号处理的角度看就是去除其中的高频信息,保留低频信息。因此我们可以对图像实施低通滤波。低通滤波可以去除图像中的噪声,对图像进行平滑。
根据滤波器的不同可分为均值滤波,高斯滤波,中值滤波, 双边滤波。
1.2.1 均值滤波
采用均值滤波模板对图像噪声进行滤除。令
S
x
y
S_{xy}
Sxy表示中心在(x, y)点,尺寸为m×n 的矩形子图像窗口的坐标组。 均值滤波器可表示为:
f
2
(
x
,
y
)
=
1
m
n
∑
(
s
,
t
)
⊂
S
x
y
g
(
s
,
t
)
f^2(x,y) = \frac{1}{mn}\sum_{(s,t)\subset S_{xy}} g(s,t)
f2(x,y)=mn1∑(s,t)⊂Sxyg(s,t)
由一个归一化卷积框完成的。它只是用卷积框覆盖区域所有像素的平均值来代替中心元素。
例如,3x3标准化的平均过滤器如下所示:
均值滤波的优点是算法简单,计算速度较快,缺点是在去噪的同时去除了很多细节部分,将图像变得模糊。
API:
cv.blur(src, ksize, anchor, borderType)
参数:
src:输入图像
ksize:卷积核的大小
anchor:默认值 (-1,-1) ,表示核中心
borderType:边界类型
代码如下(示例):
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 图像读取
img = cv.imread('./image/dogsp.jpeg')
# 2 均值滤波
blur = cv.blur(img,(5,5))
# 3 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur[:,:,::-1]),plt.title('均值滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()
1.2.2高斯滤波
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到
二维高斯是构建高斯滤波器的基础,其概率分布函数如下所示:
G
(
x
,
y
)
=
1
2
π
σ
2
e
−
x
2
+
y
2
2
σ
2
G(x,y) = \frac {1}{2π\sigma^2}e^{-\frac {x^2+y^2}{2\sigma^2}}
G(x,y)=2πσ21e−2σ2x2+y2
G(x,y)的分布是一个突起的帽子的形状。这里的σ可以看作两个值,一个是x方向的标准差
σ
x
\sigma_x
σx,另一个是y方向的标准差
σ
y
\sigma_y
σy
当
σ
x
\sigma_x
σx和
σ
y
\sigma_y
σy取值越大,关注区域越分散,也就是往两边,整个形状趋近于扁平;当
σ
x
\sigma_x
σx和
σ
y
\sigma_y
σy越小,整个形状越突起,关注区域越集中。
正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。计算平滑结果时,只需要将"中心点"作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。
高斯平滑在从图像中去除高斯噪声方面非常有效。
高斯平滑的流程:
- 首先确定权重矩阵
假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:
更远的点以此类推。
为了计算权重矩阵,需要设定σ的值。假定σ=1.5,则模糊半径为1的权重矩阵如下(将上图中的坐标点带入到高斯分布中得到的权重矩阵):
这9个点的权重总和等于0.4787147,如果只计算这9个点的加权平均,还必须让它们的权重之和等于1,因此上面9个值还要分别除以0.4787147,得到最终的权重矩阵。
- 计算高斯模糊
有了权重矩阵,就可以计算高斯模糊的值了。
假设现有9个像素点,灰度值(0-255)如下:
每个点乘以对应的权重值:
得到
将这9个值加起来,就是中心点的高斯模糊的值。
对所有点重复这个过程,就得到了高斯模糊后的图像。如果原图是彩色图片,可以对RGB三个通道分别做高斯平滑。
API:
cv2.GaussianBlur(src,ksize,sigmaX,sigmay,borderType)
参数:
- src: 输入图像
- ksize:高斯卷积核的大小,注意 : 卷积核的宽度和高度都应为奇数,且可以不同
- sigmaX: 水平方向的标准差
- sigmaY: 垂直方向的标准差,默认值为0,表示与sigmaX相同
- borderType:填充边界类型
代码如下(示例)
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 图像读取
img = cv.imread('./image/dogGasuss.jpeg')
# 2 高斯滤波
blur = cv.GaussianBlur(img,(3,3),1)
# 3 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur[:,:,::-1]),plt.title('高斯滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()
1.2.3中值滤波
中值滤波是一种典型的非线性滤波技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值。
中值滤波对椒盐噪声(salt-and-pepper noise)来说尤其有用,因为它不依赖于邻域内那些与典型值差别很大的值。
API:
cv.medianBlur(src, ksize )
参数:
- src:输入图像
- ksize:卷积核的大小
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 图像读取
img = cv.imread('./image/dogsp.jpeg')
# 2 中值滤波
blur = cv.medianBlur(img,5)
# 3 图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur[:,:,::-1]),plt.title('中值滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()
1.3 小总结
1.图像噪声
-
椒盐噪声:图像中随机出现的白点或者黑点
-
高斯噪声:噪声的概率密度分布是正态分布
2.图像平滑
-
均值滤波:算法简单,计算速度快,在去噪的同时去除了很多细节部分,将图像变得模糊
cv.blur() -
高斯滤波: 去除高斯噪声
cv.GaussianBlur()
-
中值滤波: 去除椒盐噪声
cv.medianBlur()
2.下采样
高斯金字塔主要有两部分组成:高斯滤波和下采样操作,高斯滤波上面已经介绍,降采样其实就是提取特征的过程,简单的,如下图我们都是将每四个像素选取左上角的一个,构成下面的新的像素图。
如下图,如果我们只进行降采样而不进行高斯模糊,会导致一些特征的丢失,使图像看起来很粗糙,而利用了高斯模糊的图像就看起来柔和、连贯了很多。高斯金字塔本质上为信号的多尺度表达方式
二、拉普拉斯金字塔
1.1 Sobel滤波
Sobel是最常见的一种检验垂直或者水平边缘的滤波器。梯度就是不同方向的一阶导数拼到一起。它是一个二维向量,向量的元素是横竖两个方向的函数一阶导数: g r a d ( I ) = [ ∂ I ∂ x , ∂ I ∂ y ] T grad(I) = [\frac {\partial I}{\partial x},\frac {\partial I}{\partial y}]^T grad(I)=[∂x∂I,∂y∂I]T
1.2拉普拉斯滤波
如果不是一阶导数,我们取二阶导数呢?
二阶导数其实就是拉普拉斯算子:
Δ
f
=
∂
2
f
∂
x
2
+
∂
2
f
∂
y
2
\Delta f= \frac {\partial^2 f}{\partial x^2}+\frac {\partial^2 f}{\partial y^2}
Δf=∂x2∂2f+∂y2∂2f
作用:
- 团块检测:周边高于(低于)中心点
- 边缘检测:像素值快速变化的区域
拉普拉斯滤波器的基本条件,相加必须为零,并且拉普拉斯滤波器能够使原始图像变得锐化,细节凸显明显。
1.3拉普拉斯金字塔
- 高频细节信息在卷积和下采样中丢失
- 保留所有层所丢失的高频信息,用于图像恢复
L i = G i − U P ( G i + 1 ⨂ g n ∗ n ) L_i = G_i-UP(G_{i+1}\bigotimes g_{n*n}) Li=Gi−UP(Gi+1⨂gn∗n)
G i + 1 G_{i+1} Gi+1表示进行高斯模糊之后的小图。 U P ( G i + 1 ) UP(G_{i+1}) UP(Gi+1)表示将这个小图上采样放大。 g n ∗ n g_{n*n} gn∗n代表高斯模糊。所以 L i L_i Li就是将高斯模糊以后的小图再次上采样放大与原图的差,就是拉普拉斯金字塔。过程如下:
∗ * ∗代表高斯模糊
↓ \downarrow ↓代表下采样
↑ \uparrow ↑代表下采样
上采样后再进行高斯模糊化可保留高频细节,叠加拉普拉斯金字塔可精确恢复原图。
代码如下:
import cv2 # 我只用它来做图像读写和绘图,没调用它的其它函数哦
import numpy as np # 进行数值计算
# padding 函数
def padding(img, K_size=3):
# img 为需要处理图像
# K_size 为滤波器也就是卷积核的尺寸,这里我默认设为3*3,基本上都是奇数
# 获取图片尺寸
H, W, C = img.shape
pad = K_size // 2 # 需要在图像边缘填充的0行列数,
# 之所以我要这样设置,是为了处理图像边缘时,滤波器中心与边缘对齐
# 先填充行
rows = np.zeros((pad, W, C), dtype=np.uint8)
# 再填充列
cols = np.zeros((H+2*pad, pad, C), dtype=np.uint8)
# 进行拼接
img = np.vstack((rows, img, rows)) # 上下拼接
img = np.hstack((cols, img, cols)) # 左右拼接
return img
# Prewitt 滤波函数
def laplacian(img, K_size=3):
# 获取图像尺寸
H, W, C = img.shape
# 进行padding
pad = K_size // 2
out = padding(img, K_size=3)
# 滤波器系数
K = np.array([[0., 1., 0.],[1., -4., 1.], [0., 1., 0.]])
# 进行滤波
tem = out.copy()
for h in range(H):
for w in range(W):
for c in range(C):
out[pad+h, pad+w, c] = np.sum(K * tem[h:h+K_size, w:w+K_size, c], dtype=np.float)
out = np.clip(out, 0, 255)
out = out[pad:pad+H, pad:pad+W].astype(np.uint8)
return out
# 这里需要把图像先灰度化
# 直接用之前的灰度化代码
# 灰度化函数
def BGR2GRAY(img):
# 获取图片尺寸
H, W, C = img.shape
# 灰度化
out = np.ones((H,W,3))
for i in range(H):
for j in range(W):
out[i,j,:] = 0.299*img[i,j,0] + 0.578*img[i,j,1] + 0.114*img[i,j,2]
out = out.astype(np.uint8)
return out
# 读取图片
path = 'C:/Users/86187/Desktop/image/'
file_in = path + 'cake.jpg'
file_out = path + 'laplacian_filter.jpg'
img = cv2.imread(file_in)
# 调用函数进行灰度化
img = BGR2GRAY(img)
# 调用函数进行sobel滤波
out = laplacian(img)
# 保存图片
cv2.imwrite(file_out, out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
)
结果如下:
代码来源:https://blog.csdn.net/qq_42662568/article/details/105494853?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-105494853-blog-91167438.235%5Ev43%5Epc_blog_bottom_relevance_base4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-105494853-blog-91167438.235%5Ev43%5Epc_blog_bottom_relevance_base4&utm_relevant_index=2