图像噪点消除
噪声在图像处理中指的是图像中出现的干扰因素,通常由采集设备或传输过程引起。噪声使得图像的亮度变得不均匀或引入了随机的干扰点。常见的噪声类型包括:
-
高斯噪声:符合正态分布的噪声,会使图像变得模糊或出现噪点。其噪声值是从正态分布中随机生成的。
-
椒盐噪声:图像中出现的随机黑点或白点,类似于“椒盐”撒在图像上,使图像看起来像被打上了斑点。
滤波器(或卷积核)是一种用于处理图像的工具,通过在图像上滑动并计算周围像素的加权平均值来平滑或锐化图像。滤波器分为线性和非线性两类:
-
线性滤波器:对邻域像素进行线性运算,例如均值滤波和高斯滤波。均值滤波器通过计算邻域像素的平均值来平滑图像,高斯滤波器则通过高斯函数加权邻域像素来实现平滑。
-
非线性滤波器:根据像素间的逻辑关系处理图像,例如中值滤波和双边滤波。中值滤波器用邻域像素的中值替代中心像素值,适合去除椒盐噪声;双边滤波器结合了空间距离和像素值差异,能在平滑图像的同时保持边缘细节。
滤波与模糊的联系与区别:
-
联系:滤波和模糊都涉及卷积操作,线性滤波方法通过不同的卷积核实现各种效果。
-
区别:
-
低通滤波器(如均值滤波、高斯滤波)用于模糊图像,去除噪声和平滑图像,因为它们允许低频信号通过,滤除高频噪声。
-
高通滤波器用于锐化图像,增强边缘细节,因为它们允许高频信号通过,抑制低频信号。
-
简言之,椒盐噪声像图像上的黑白斑点,高斯噪声则像由光照等因素造成的随机干扰。滤波技术通过调整图像的频率成分来处理这些噪声,实现图像的清晰或模糊效果。
1.均值滤波:
-
原理:用固定大小的卷积核在图像上滑动,将核覆盖区域内所有像素的平均值作为中心像素的新值。
如3×3的卷积核:
-
效果:平滑图像,去除噪声,但可能会模糊细节和边缘。
2.方框滤波:
-
原理:类似均值滤波,使用一个形状为方框的卷积核。计算方框内所有像素的平均值,用于平滑图像。
如3×3的滤波核如下:
-
效果:简单有效的平滑技术,但对边缘处理不够好,可能导致边缘模糊。
3.高斯滤波:
-
原理:使用高斯函数生成的卷积核,对图像进行加权平均。中心像素权重最大,离中心越远权重越小。
高斯公式:
其中的值也是与自适应二值化里的一样,当时会取固定的系数,当kernel大于7并且没有设置时,会使用固定的公式进行计算$\sigma$的值:
以3*3的卷积核为例:
-
效果:平滑图像同时保留细节,相比均值滤波能更好地减少噪声。
4.中值滤波:
-
原理:在每个像素的邻域内,将所有像素值排序,选择中间值作为中心像素的新值。
-
效果:有效去除椒盐噪声,保持边缘锐利,但计算量较大。
5.双边滤波:
-
原理:结合空间距离和像素值差异进行滤波。既考虑像素位置距离,也考虑像素值的相似性,以平滑噪声同时保留边缘。
双边滤波采用了两个高斯滤波的结合,一个负责计算空间邻近度的权值(也就是空域信息),也就是上面的高斯滤波器,另一个负责计算像素值相似度的权值(也就是值域信息),也是一个高斯滤波器。其公式如下所示:
-
效果:在去噪的同时能够较好地保留图像的边缘细节。
import cv2 img = cv2.imread('./src/lvbo2.png') img1 = cv2.blur(img, (3, 3)) # 均值滤波 img2 = cv2.boxFilter(img, -1,(3, 3),normalize=True) # 方框滤波 img3 = cv2.GaussianBlur(img, (3, 3),1) # 高斯滤波 img4 = cv2.medianBlur(img,3) #中值滤波 img5 = cv2.bilateralFilter(img,10,80,75) #双边滤波 cv2.imshow("img", img) cv2.imshow("img1", img1) cv2.imshow("img2", img2) cv2.imshow("img3", img3) cv2.imshow("img4", img4) cv2.imshow("img5", img5) cv2.waitKey(0) cv2.destroyAllWindows()
图像梯度处理
1.图像梯度
在高等数学中,我们利用一阶导数来求函数的极值。同样地,可以将图像视为一个连续的二维函数。在图像中,边缘部分的像素值与周围像素值存在明显差异,因此,通过局部求极值的方法,我们可以提取出图像的边缘信息。然而,由于图像是离散的二维函数,我们采用差分的方法来近似导数,这种差分被称为图像的梯度。
2.垂直边缘提取
cv2.filter2D
函数用于对图像进行二维卷积操作,允许使用自定义的卷积核来实现各种图像处理效果,如平滑、锐化和边缘检测。以下是参数的简要说明:
-
src
: 输入图像,通常为numpy
数组。 -
ddepth
: 输出图像的深度。如果设为-1
,则输出图像与输入图像具有相同的深度。可以设为其他正值或特定值来控制输出图像的深度。 -
kernel
: 卷积核,是一个二维数组(通常为奇数大小的矩阵),用于计算每个像素周围邻域的加权和。
3.Sobel算子
Sobel 算子是一种用于图像边缘检测的经典算子,它通过计算图像梯度来识别边缘。Sobel 算子有两个方向的卷积核,分别用于计算图像在水平方向和垂直方向的梯度。
在使用 cv2.Sobel
函数时,你可以设置以下参数:
-
src
: 输入图像,通常是灰度图像,因为 Sobel 算子是基于像素亮度计算梯度的。如果图像是彩色的,你需要先将其转换为灰度图像。 -
ddepth
: 输出图像的深度,通常设置为-1
,表示输出图像的深度与输入图像相同。 -
dx
和dy
: 分别表示计算图像在 x 方向和 y 方向的梯度。dx=1
和dy=0
表示计算 x 方向的一阶导数,dx=0
和dy=1
表示计算 y 方向的一阶导数。 -
ksize
: Sobel 算子的大小,通常选择 3、5 或 7,默认值是 3。
这些算子提供了不同的边缘检测效果,选择适当的算子可以根据实际应用需求来确定。
4.Laplacian算子
在 OpenCV 中,使用 cv2.Laplacian(src, ddepth)
进行 Laplacian 运算,其中 src
是输入图像,ddepth
表示输出图像的深度,-1
表示输出图像深度与输入图像相同。
import cv2 import numpy as np img=cv2.imread('./src/shudu.png',cv2.IMREAD_GRAYSCALE) kernel=np.array([[-1,0,1],[-2,0,2],[-1,0,1]], dtype=np.float32) img1=cv2.filter2D(img,-1,kernel) #垂直边缘提取 img2=cv2.filter2D(img, -1, kernel.T) #水平边缘提取 #Sobel算子 img3=cv2.Sobel(img,-1,1,0,ksize=3) #水平方向的梯度,垂直边缘提取 img4=cv2.Sobel(img,-1,0,1,ksize=3) #垂直方向的梯度,水平边缘提取 # Laplacian算子 img5=cv2.Laplacian(img,-1) cv2.imshow("img",img) cv2.imshow("img1",img1) cv2.imshow("img2",img2) cv2.imshow("img3",img3) cv2.imshow("img4",img4) cv2.imshow("img5",img5) cv2.waitKey(0) cv2.destroyAllWindows()
图像边缘检测
Canny 边缘检测算法是一种非常流行的边缘检测算法,是 John F. Canny 于 1986年提出的,被认为是最优的边缘检测算法。
操作步骤按照如下进行:
-
读取图像
-
二值化图像。
-
高斯滤波。
-
计算图像的梯度和方向。
-
非极大值抑制。
-
双阈值筛选。
1.高斯滤波
边缘检测是一种锐化操作,对噪声较为敏感。因此,在进行边缘检测之前,通常需要对图像进行平滑处理,以减少噪声的影响。这里我们使用一个 5x5 的高斯核来实现高斯滤波,消除图像中的噪声。
高斯滤波器的公式可以用来计算每个像素周围的加权平均值,权重由高斯函数决定,越接近中心的像素权重越大,越远离中心的像素权重越小。这有助于保留图像的边缘信息,同时模糊掉较小的噪声。
2. 计算图像的梯度与方向
1. 使用Sobel算子计算梯度
-
水平方向Sobel算子:
-
垂直方向Sobel算子:
应用这两个算子分别得到水平方向的梯度 Gx和垂直方向的梯度 Gy。
2. 计算梯度大小和方向
-
梯度大小:
-
或者简化版本:
G=∣Gx+Gy∣
-
梯度方向:
这个角度值其实是当前边缘的梯度的方向
注意处理当 Gx=0的情况,以避免除以零的错误。
3. 非极大值抑制 (Non-Maximum Suppression)
-
如果梯度方向不是标准的角度(如0°、45°、90°、135°),需要进行插值来确定是否保留该像素作为边缘的一部分。通常使用线性插值来计算邻近像素的梯度值,并检查中心像素是否为局部最大值。
4. 双阈值筛选 (Double Thresholding)
-
选择阈值:
-
选取一个高阈值 Thigh和一个低阈值Tlow,其中 Tlowl<Thigh。常见的比例是 Tlow=0.05×Thigh 到 Tlow=0.2×Thigh。
-
-
边缘分类:
-
强边缘: 如果梯度 G>Thigh,则该像素标记为强边缘。
-
弱边缘: 如果 Tlow<G<G<Thigh,则该像素标记为弱边缘。
-
非边缘: 如果 G≤Tlow,则该像素不被视为边缘。
-
实现步骤
-
计算梯度:
-
应用Sobel算子计算每个像素点的 Gx和 Gy。
-
计算梯度大小 G和方向 θ。
-
-
非极大值抑制:
-
根据梯度方向 θ,使用适当的插值方法计算邻近像素的梯度值。
-
检查中心像素的梯度是否大于其两个邻近像素的梯度值。如果不是,则抑制该像素。
-
-
双阈值筛选:
-
使用 Tlow和 Thigh 标记强边缘和弱边缘。
-
弱边缘只有在其至少有一个相邻像素被标记为强边缘的情况下才保留下来。
-
-
边缘连接:
-
从每个强边缘像素开始,递归地检查其相邻像素中是否有其他强边缘或符合条件的弱边缘。
-
将符合条件的弱边缘连接到强边缘上。
import cv2 img=cv2.imread("./src/e.png") img1=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret,img2=cv2.img1old(img1,127,255,cv2.img1_BINARY) img3=cv2.Canny(img2,30,100) cv2.imshow("img",img) cv2.imshow("img3",img3) cv2.waitKey(0)
-
绘制图像轮廓
-
加载图像:使用 OpenCV 加载图像。
-
转换为灰度图像:将图像转换为灰度,以简化处理。
-
应用边缘检测:使用边缘检测算法,如 Canny 边缘检测。
-
绘制轮廓:利用 OpenCV 的
findContours
和drawContours
函数来找到并绘制轮廓。
import cv2 img=cv2.imread("./src/e.png") img1=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret,img2=cv2.img1old(img1,127,255,cv2.img1_BINARY_INV+cv2.img1_OTSU) # 查找轮廓 # cv2.RETR_EXTERNAL cv2.RETR_CCOMP cv2.RETR_LIST cv2.RETR_TREE c,h=cv2.findContours(img2,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # 绘制轮廓 cv2.drawContours(img,c,-1,(0,0,255),2) cv2.imshow("img",img) cv2.imshow("img2",img2) cv2.waitKey(0)