1. 图像平滑
- 图像平滑是指受传感器和大气等因素的影响,遥感图像上会出现某些亮度变化过大的区域,或出现一些亮点(也称噪声)。这种为了抑制噪声,使图像亮度趋于平缓的处理方法就是图像平滑。图像平滑实际上是低通滤波,平滑过程会导致图像边缘模糊化。
- 图像平滑是一种区域增强的算法,主要目的是通过减少图像中的高频噪声来改善图像的质量。能够减少甚至消除噪声并保持高频边缘信息是图像平滑算法追求的目标。
- 平滑算法中有多种过滤方式,主要介绍以下三种。
? 均值滤波 ? 中值滤波 ? 高斯滤波
1.1 均值滤波
- 大部分噪声可以视为随机信号,对图像的影响可以看成是孤立的。如果某一像素点与周围像素点相比有明显的不同,即可认为该点被噪声感染。
- 基于噪声的孤立性,可以用邻域平均的方法判断每一点是否为噪声,并用适当的方法消除发现的噪声。假设原图像为f(x,y),经过S邻域的均值滤波后的图像为g(x,y),那么均值滤波如下式所示。
- 在上式中,M为S邻域中的像素数量,可知均值滤波是以图像的模糊为代价换取噪声的降低,邻域越大,降噪效果越好,同时图像模糊程度也越大。
- 实现均值滤波的方法:
cv2.blur(src, ksize)
img = cv2.imread('lena.jpg')
img_mean = cv2.blur(img, ksize=(3,3))
cv2.imshow('image', img)
cv2.imshow('image_mean', img_mean)
cv2.waitKey(0)
1.2 中值滤波
- 由均值滤波效果图可知,均值滤波虽然能够消除噪声,但是平滑操作也使图像中的边界信息变得模糊。
- 中值滤波是统计排序滤波器的一种。中值滤波过程中,采用像素周围某邻域内像素的中间值进行替换。尽管中值滤波也是对中心像素的邻域进行处理,但并非通过加权平均的方式处理,因此无法通过线性表达式得到处理的结果。
- 由于图像中的噪声几乎都是邻域像素的极值,因此通过中值滤波可以有效地过滤噪声,同时保留图像边缘信息。
- 实现中值滤波的方法:
cv2.medianBlur(src, ksize)
img_median = cv2.medianBlur(img, ksize=3)
cv2.imshow('image', img)
cv2.imshow('image_median', img_median)
cv2.waitKey(0)
1.3 高斯滤波
- 高斯分布又称正态分布。如下为高斯分布概率分布图。以及高斯分布的计算公式。
- μ指均值,σ指标准差,当μ=0,σ=1时为标准正态分布,公式如下:
- 实现高斯平滑可以使用:
cv2.GaussianBlur(src, ksize, sigmaX, sigmaY=None)
img_gauss = cv2.GaussianBlur(img, ksize=(3,3), sigmaX=1.2, sigmaY=0.8)
cv2.imshow('image', img)
cv2.imshow('image_gauss', img_gauss)
cv2.waitKey(0)
2. 图像锐化
- 图像锐化(image sharpening)是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空间域处理和频域处理两类。
- 图像锐化是为了突出图像的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强。
- 图像模糊的可能是图像受到平均或积分运算,因此对图像采用逆运算。例如对连续图像微分或对离散图像差分或者梯度运算,即可使模糊图像的质量得到改善。
- OpenCV 提供了多种不同的梯度滤波器,或者说高通滤波器:
Sobel算子 Scharr算子 Laplacian算子 Log算子 Canny算子 …
2.1 sobel算子
- 实现Sobel算子的方法:
cv2.Sobel(src, ddepth, dx, dy, ksize=None, scale=None, delta=None) - 图像深度是指存储每个像素值所用的位数,例如cv2.CV_8U,指的是8位无符号数,取值范围为0~255,超出范围则会被截断(即当数值大于255保留为255,当数值小于0保留为0,其余不变)。
- 具体还有:CV_16S(16位无符号数)、CV_16U(16位有符号数)CV_32F(32位浮点数)、CV_64F(64位浮点数)。
? 如果数据类型设置为16位无符号整数或者32位有符号整数,则将数据除以256,映射到[0,255];如果数据类型为32位或64位浮点数,则将数据乘以255,映射到[0,255] ? 当计算结果碰到负数时,首先取其绝对值,然后按照上述图像深度将超出数据范围的部分采取截断操作,最后映射到[0,255]显示图像。
sobelx = cv2.Sobel(src=img, ddepth=cv2.CV_64F, dx=1, dy=0,
ksize=3, scale=1.2, delta=20)
sobely = cv2.Sobel(src=img, ddepth=cv2.CV_64F, dx=0, dy=1,
ksize=3, scale=1.2, delta=20)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx, 0.8, sobely, 0.5, gamma=0)
cv2.imshow('image', img)
cv2.imshow('sobelx', sobelx)
cv2.imshow('sobely', sobely)
cv2.imshow('sobelxy', sobelxy)
cv2.waitKey(0)
2.2. Scharr算子
- Scharr算子看作对 Sobel算子的改进,只是x轴方向和y轴方向的权重矩阵有所改变。
- OpenCV实现Scharr的参数与Sobel算子几乎一致。
2. Scharr算子
cv2.Sobel(ksize=-1)
cv2.Scharr(src=, ddepth=, dx=, dy=, ksize=,
scale=, delta=)
2.3. 拉普拉斯算子
- Laplacian(拉普拉斯) 算子是一种二阶导数算子, 其具有旋转不变性, 可以满足不同方向的图像边缘锐化( 边缘检测)
的要求。通常情况下,Laplacian算子的系数之和为零。 - 像素点 P5 的近似导数值为:
- 实现Laplacian算子的方法:
cv2.Laplacian(src, ddepth, ksize=None, scale=None, delta=None)
img_lap = cv2.Laplacian(src=img, ddepth=cv2.CV_64F,
ksize=3, scale=1.2, delta=10)
img_lap = cv2.convertScaleAbs(img_lap)
cv2.imshow('image', img)
cv2.imshow('image_laplacian', img_lap)
cv2.waitKey(0)
2.4. Canny算子
-
Canny算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。 -
Canny的目标是找到一个最优的边缘检测算法。 ? Canny边缘检测算法可以分为以下5个步骤: -
应用高斯滤波来平滑图像,目的是去除噪声。 -
找寻图像的强度梯度(intensity gradients),即找寻一幅图像中灰度强度变化最强的位置。 -
应用非最大抑制(non-maximum suppression)技术来消除边误检(本来不是但检测出来是),保留了每个像素点上梯度强度的极大值,而删掉其他的值。 -
应用双阈值的方法来决定可能的(潜在的)边界。 -
利用滞后技术来跟踪边界。 -
应用高斯滤波来平滑图像后计算梯度幅值和方向。 -
图像的边缘可以指向不同方向,因此经典Canny算法用了四个梯度算子来分别计算水平,垂直和对角线方向的梯度。但是通常都不用四个梯度算子来分别计算四个方向。常用的边缘差分算子(如Rober,Prewitt,Sobel)计算水平和垂直方向的差分Gx和Gy。 -
非最大抑制是一种边缘细化方法。就是保留了每个像素点上梯度强度的极大值,而删掉其他的值。 -
即获得梯度和方向后,遍历所有像素点,比较当前点的梯度强度和正负梯度方向点的梯度强度:如果当前点的梯度强度和同方向的其他点的梯度强度相比较是最大,保留其值。否则抑制,即设为0。 -
Canny算法应用双阈值,即一个高阈值和一个低阈值来区分边缘像素。 -
如果边缘像素点梯度值大于高阈值,则被认为是强边缘点。如果边缘梯度值小于高阈值,大于低阈值,则标记为弱边缘点。小于低阈值的点则被抑制掉。 -
强边缘点可以认为是真的边缘,弱边缘点则可能是真的边缘,也可能是噪声或颜色变化引起的,后者引起的弱边缘点应该去掉。 -
所谓的滞后边界跟踪算法检查一个弱边缘点的8连通领域像素,只要有强边缘点存在,那么这个弱边缘点被认为是真是边缘保留下来。 -
实现Canny算子的方法: cv2.Canny(image, threshold1, threshold2, apertureSize=None, L2gradient=None)
img_canny = cv2.Canny(image=img, threshold1=100, threshold2=200,
apertureSize=3, L2gradient=False)
cv2.imshow('image', img)
cv2.imshow('image_canny', img_canny)
cv2.waitKey(0)
|