OpenCV学习 day3
一、灰度实验
将彩色图像转换为灰度图像的过程称为灰度化,这种做法在图像处理中和计算机视觉领域非常常见
1、灰度图
灰度图是一种 单通道图像,每个像素仅存储 亮度信息(0=纯黑,255=纯白),没有颜色信息(RGB)。在计算机视觉(OpenCV)和图像处理中广泛使用。
灰度图 vs RGB 图的区别
特性 | 灰度图 | RGB 彩色图 |
---|---|---|
通道数 | 1(单通道) | 3(红、绿、蓝三通道) |
像素值范围 | 0(黑)~255(白) | 每个通道 0~255 |
存储大小 | 较小(节省内存) | 较大(3倍于灰度图) |
适用场景 | 边缘检测、人脸识别等 | 彩色图像分析、显示 |
2、图像灰度化方法
灰度图与彩色图最大的不同就是:彩色图是由R、G、B三个通道组成,而灰度图只有一个通道,也称为单通道图像,所以彩色图转成灰度图的过程本质上就是将R、G、B三通道合并成一个通道的过程。本实验中一共介绍了三种合并方法,分别是最大值法、平均值法以及加权均值法。
(1)最大值法
对于彩色图像的每个像素,它会从R、G、B三个通道的值中选出最大的一个,并将其作为灰度图像中对应位置的像素值。
OpenCV代码实现
import cv2 as cv
import numpy as np#读图
cat = cv.imread("../../images/cat1.png")
cv.imshow("cat", cat)
#提取高度和宽度
h,w = cat.shape[:2]
#创建单通道全0矩阵(黑色),用于存放灰度图 (h,w)
black = np.zeros((h,w), np.uint8)for i in range(h):#遍历每一行for j in range(w):#遍历每一列black[i,j] = max(cat[i,j,0],cat[i,j,1],cat[i,j,2]) # 提取RGB的最大值cv.imshow("black", black)
cv.waitKey(0)
cv.destroyAllWindows()
(2)平均值法
对于彩色图像的每个像素,它会将R、G、B三个通道的像素值全部加起来,然后再除以三,得到的平均值就是灰度图像中对应位置的像素值。
OpenCV代码实现:
import cv2 as cv
import numpy as np
#读图
cat = cv.imread("../../images/cat1.png")
cv.imshow("cat", cat)
#提取高度和宽度
h,w = cat.shape[:2]
#创建单通道全0矩阵(黑色),用于存放灰度图 (h,w)
black = np.zeros((h,w), np.uint8)
#遍历每一行
for i in range(h):#遍历每一列for j in range(w):#数据类型为unint8,为了防止数值溢出,需要转为更大的数值类型(int),处理完后将数据类型转回来(np.uint8)black[i,j] = np.uint8((int(cat[i,j,0])+int(cat[i,j,1])+int(cat[i,j,2]))//3)cv.imshow("black", black)
cv.waitKey(0)
cv.destroyAllWindows()
(3)加权平均值法
对于彩色图像的每个像素,它会按照一定的权重去乘以每个通道的像素值,并将其相加,得到最后的值就是灰度图像中对应位置的像素值。本实验中,权重的比例为: R乘以0.299,G乘以0.587,B乘以0.114,这是经过大量实验得到的一个权重比例,也是一个比较常用的权重比例。
所使用的权重之和应该等于1。这是为了确保生成的灰度图像素值保持在合理的亮度范围内,并且不会因为权重的比例不当导致整体过亮或过暗
OpenCV代码实现:
import cv2 as cv
import numpy as np
#读图
cat = cv.imread("../../images/cat1.png")
cv.imshow("cat", cat)
h,w = cat.shape[:2]
#创建单通道全0矩阵(黑色),用于存放灰度图 (h,w)
black = np.zeros((h,w), np.uint8)
#定义每个通道上的权重
wb,wg,wr = 0.114,0.587,0.299
#遍历每一行
for i in range(h):#遍历每一列for j in range(w): # round取整black[i,j] = round(wb * cat[i,j,0] + wg * cat[i,j,1] + wr * cat[i,j,2])cv.imshow("black", black)
cv.waitKey(0)
cv.destroyAllWindows()
3、 两个极端的灰度值
在灰度图像中,“极端”的灰度值指的是亮度的两个极端:最暗和最亮的值。
- 最暗的灰度值:0。这代表完全黑色,在灰度图像中没有任何亮度。
- 最亮的灰度值:255。这代表完全白色,在灰度图像中具有最大亮度。
二、图像二值化处理
图像二值化是将灰度图像转换为仅包含黑白两种像素值(通常0和255)的图像处理技术,是计算机视觉预处理的关键步骤。
通俗的说就是将某张图像的所有像素改成只有两种值
1、二值图像
一幅二值图像的二维矩阵仅由0、1两个值构成,“0”代表黑色,“1”代白色。由于每一像素(矩阵中每一元素)取值仅有0、1两种可能,所以计算机中二值图像的数据类型通常为1个二进制位。二值图像通常用于文字、线条图的扫描识别(OCR)和掩膜图像的存储。
灰度图:
二值图像(举例):
其操作的图像也必须是灰度图。也就是说,二值化的过程,就是将一张灰度图上的像素根据某种规则修改为0和maxval(maxval表示最大值,一般为255,显示白色)两种像素值,使图像呈现黑白的效果,能够帮助我们更好地分析图像中的形状、边缘和轮廓等特征。
特点:
- 简便:降低计算量和计算需求,加快处理速度。
- 节约资源:二值图像占用空间远小于彩色图。
- 边缘检测:二值化常作为边缘检测的预处理步骤,因为简化后的图易于识别出轮廓和边界。
全局阈值法代码以及参数
_,binary = cv2.threshold(img,thresh,maxval,type)
- img:输入图像,要进行二值化处理的灰度图像。
- thresh:设定的阈值。
- type:阈值处理的类型
返回值:
- 第一个值(通常用下划线表示):计算出的阈值,若使用自适应阈值法,会根据算法自动计算出这个值。
- 第二个值(binary):二值化后的图像矩阵。与输入图像(需进行处理的灰度图)尺寸相同。
2、基本阈值方法
(1)阈值法
阈值法就是通过设置一个阈值,将灰度图中的每一个像素值与该阈值进行比较,小于等于阈值的像素就被设置为0(通常代表背景),大于阈值的像素就被设置为maxval(通常代表前景)。对于我们的8位图像(0~255)来说,通常是设置为255。
使用场景:
- 文档扫描
- 高对比度图像分割
- 工业零件检测
特点:
-
计算速度快
-
对光照变化敏感
举例处理前文灰度图(后面记录的方法同样,可以作为比较):
OpenCV代码实现:
import cv2 as cv
#读图
flower = cv.imread("./images/flower.png")
#重新设定图像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化处理,二值化处理的对象是灰度图
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#阈值法:小于阈值的像素设置为0,大于阈值的像素设置为maxval
_,binary=cv.threshold(gray,127,255,cv.THRESH_BINARY)
cv.imshow("binary",binary)cv.waitKey(0)
cv.destroyAllWindows()
处理结果
(2)反阈值法
顾名思义,就是与阈值法相反。反阈值法是当灰度图的像素值大于阈值时,该像素值将会变成0(黑),当灰度图的像素值小于等于阈值时,该像素值将会变成maxval。
应用场景:
-
深色背景上的浅色物体检测
-
医学图像处理(如X光片)
OpenCV代码实现:
import cv2 as cv
#读图
flower = cv.imread("../../images/flower.png")
#重新设定图像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化处理,二值化处理的对象是灰度图
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#反阈值法:大于阈值的像素值设置为0,小于阈值的像素值设置为maxval
_,binary_inv=cv.threshold(gray,127,255,cv.THRESH_BINARY_INV)
cv.imshow("binary_inv",binary_inv)cv.waitKey(0)
cv.destroyAllWindows()
处理结果
(3)截断阈值法
截断阈值法,指将灰度图中的所有像素与阈值进行比较,像素值大于阈值的部分将会被修改为阈值,小于等于阈值的部分不变。
换句话说,经过截断阈值法处理过的二值化图中的最大像素值就是阈值
特点:
-
保留部分灰度信息
-
用于图像压缩
OpenCV代码实现:
import cv2 as cv
#读图
flower = cv.imread("../../images/flower.png")
#重新设定图像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化处理,二值化处理的对象是灰度图
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#截断阈值法,大于阈值的像素值修改为阈值,小于等于阈值的部分不变,像素的最大值就是阈值
_,trunc = cv.threshold(gray,170,255,cv.THRESH_TRUNC)
cv.imshow("trunc",trunc)cv.waitKey(0)
cv.destroyAllWindows()
处理结果
(4)低阈值零处理
低阈值零处理,字面意思,就是像素值小于等于阈值的部分设置为0(也就是黑色),大于阈值的部分不变。
应用场景:
-
弱边缘增强
-
噪声抑制
OpenCV代码实现:
import cv2 as cv
#读图
flower = cv.imread("../../images/flower.png")
#重新设定图像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化处理,二值化处理的对象是灰度图
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#低阈值零处理,小于阈值的像素值修设置为0,大于阈值的部分不变,像素值的最小值就是阈值
_,zeros = cv.threshold(gray,127,255,cv.THRESH_TOZERO)
cv.imshow("zeros",zeros)cv.waitKey(0)
cv.destroyAllWindows()
处理结果
(5)超阈值零处理
超阈值零处理就是将灰度图中的每个像素与阈值进行比较,像素值大于阈值的部分置为0(也就是黑色),像素值小于等于阈值的部分不变。
特殊应用:
- 高光区域抑制
- 阴影分析
OpenCV代码实现:
import cv2 as cv
#读图
flower = cv.imread("../../images/flower.png")
#重新设定图像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化处理,二值化处理的对象是灰度图
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#超阈值零处理,大于阈值的像素值设置为0,小于阈值的像素值不变
_,tozero_inv = cv.threshold(gray,170,255,cv.THRESH_TOZERO_INV)
cv.imshow("tozero_inv",tozero_inv)cv.waitKey(0)
cv.destroyAllWindows()
处理结果
2、高级阈值方法
(1)OTSU阈值法
cv2.THRESH_OTSU 并不是一个有效的阈值类型或标。THRESH_OTSU 本身并不是一个独立的阈值化方法,而是与 OpenCV 中的二值化方法结合使用的一个标志。具体来说,THRESH_OTSU 通常与 THRESH_BINARY 或 THRESH_BINARY_INV 结合使用。在实际应用中,如果你使用 THRESH_OTSU 标志但没有指定其他二值化类型,默认情况下它会与 THRESH_BINARY 结合使用。也就是说,当你仅指定了 cv2.THRESH_OTSU,实际上等同于同时指定了 cv2.THRESH_BINARY + cv2.THRESH_OTSU。
原理简答
OTSU算法像是一个"自动找最佳分界线"的方法——它遍历所有可能的黑白分界值(阈值),计算按该值分成两类像素时,两类之间的差异最大(比如前景和背景颜色差别最明显)的那个阈值,最终选择这个"让黑白对比最强烈"的值作为最佳分界点。(算法自动生成阈值)
也就是说OTSU方法只是计算出了处理灰度图时最佳阈值,处理时需再加上基本阈值方法(默认阈值法)才能对灰度图进行处理
适用条件:
-
直方图呈双峰分布
-
前景背景对比度明显
优点:
-
自动确定最佳阈值
-
无需人工干预
OpenCV代码实现:
import cv2 as cv
#读图
flower = cv.imread("../../images/flower.png")
#重新设定图像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化处理,二值化处理的对象是灰度图
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#OTSU阈值法,默认结合阈值法,最大类间方差 cv.THRESH_OTSU = cv.THRESH_OTSU+CV.THRESH_BINARY
thresh,otsu = cv.threshold(gray,0,255,cv.THRESH_OTSU)
print(f"OTSU自动计算的阈值:{thresh}")cv.imshow("otsu",otsu)
cv.waitKey(0)
cv.destroyAllWindows()
处理结果
(2)自适应二值化
与二值化算法相比,自适应二值化更加适合用在明暗分布不均的图片,因为图片的明暗不均,导致图片上的每一小部分都要使用不同的阈值进行二值化处理,这时候传统的二值化算法就无法满足我们的需求了,于是就出现了自适应二值化。
自适应二值化方法会对图像中的所有像素点计算其各自的阈值,这样能够更好的保留图片里的一些信息。
两种自适应求和的方法:
1、取均值(ADAPTIVE_THRESH_MEAN_C)::计算邻域均值作为局部阈值
2、加权求和(高斯法) (ADAPTIVE_THRESH_GAUSSIAN_C):使用高斯加权计算局部阈值
应用场景:
-
光照不均匀的图像
-
文档图像阴影处理
-
自然场景文本识别
cv2.adaptiveThreshold(img, maxval, cv2.ADAPTIVE_THRESH_MEAN_C, thresholdType, blockSize, C)
其中各个参数的含义如下:
-
maxval:最大阈值,一般为255
-
ADAPTIVE_THRESH_MEAN_C:小区域内取均值
-
ADAPTIVE_THRESH_GAUSSIAN_C:小区域内加权求和,权重是个高斯核
-
thresholdType:二值化方法,只能使用THRESH_BINARY、THRESH_BINARY_INV,也就是阈值法和反阈值法
-
blockSize:选取的小区域的面积,如7就是7*7的小块。
-
c:最终阈值等于小区域计算出的阈值再减去此值
OpenCV代码实现:
import cv2 as cv
#读图
flower = cv.imread("../../images/flower.png")
#重新设定图像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化处理,二值化处理的对象是灰度图
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)# 自适应二值化 必须结合阈值法或者反阈值法 返回值只有一个
#取均值 (ADAPTIVE_THRESH_MEAN_C)
binary=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,7,10)
cv.imshow("binary",binary)
#加权求和(高斯法) (ADAPTIVE_THRESH_GAUSSIAN_C)
binary_gauss=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,7,10)
cv.imshow("gauss",binary_gauss)cv.waitKey(0)
cv.destroyAllWindows()
处理结果
取均值:
加权求和(高斯法):
3、方法对比
方法 | 计算复杂度 | 适用场景 | 参数敏感性 | 抗噪性 | 保留细节 |
---|---|---|---|---|---|
标准阈值 | O(1) | 均匀光照 | 高 | 差 | 一般 |
反阈值 | O(1) | 反色场景 | 高 | 差 | 一般 |
截断阈值 | O(1) | 压缩处理 | 中 | 一般 | 好 |
OTSU | O(L) L=256 | 双峰图像 | 无 | 一般 | 好 |
自适应 | O(N×M) | 非均匀光 | 中 | 较好 | 优秀 |
(L为灰度级数,N×M为图像尺寸)
三、图像掩膜
1、制作掩膜
掩膜(Mask)是一种在图像处理中常见的操作,它用于选择性地遮挡图像的某些部分,以实现特定任务的目标。掩膜通常是一个二值化图像,并且与原图像的大小相同,其中目标区域被设置为1(或白色),而其他区域被设置为0(或黑色),并且目标区域可以根据HSV的颜色范围进行修改。
创建掩膜代码
mask = cv2.inRange(src, lowerb, upperb)
**作用:**检查图像 src 的每个像素,如果像素值在 [lowerb, upperb] 范围内,则 mask 中对应位置置为 255(白色),否则置为 0(黑色)。
2、与运算
通过掩膜与原图的与运算,我们就可以提取出图像中被掩膜覆盖的区域(扣图)。
cv2.bitwise_and(src1,src2[,mask])
参数
- src1:第一个输入数组。通常是输入的原始图像。
- src2:第二个输入数组。它可以是另一个图像、一个常数值或者与 src1 相同的图像。
- 当应用掩膜时,这个参数经常就是src1本身;即对同一个图像进行操作。
- 如果对两个不同的图像执行按位与操作(例如,将两张图片的某些部分组合在一起),可以分别将它们作为 src1 和 src2 输入到 cv2.bitwise_and() 函数中,创建复杂的图像效果或进行图像合成。
- mask:掩膜(可选)。输入数组元素只有在该掩膜非零时才被处理。是一个8位单通道的数组,尺寸必须与src1和src2相同。
- 返回值:输出数组,应用掩膜后的图像,与输入数组大小和类型相同。
3、颜色替换
前一个实验中,我们已经能够识别到图像中的某一种颜色,那么我们就可以对识别到的颜色进行一个操作,比如将其替换成别的颜色,其原理就是在得到原图的掩膜之后,对掩膜中的白色区域所对应的原图中的区域进行一个像素值的修改即可。
由于掩膜与原图的大小相同,并且像素位置一一对应,那么我们就可以得到掩膜中白色(也就是像素值为255)区域的坐标,并将其带入到原图像中,即可得到原图中的红色区域的坐标,然后就可以修改像素值了,这样就完成了颜色的替换
在替换过程中,实际上对数组做布尔索引
掩膜部分OpenCV代码实现:
import cv2 as cv
import numpy as np#读图
demo = cv.imread("../../images/demo.png")
demo = cv.resize(demo, (480, 380))
#转hsv
hsv = cv.cvtColor(demo, cv.COLOR_BGR2HSV)
#创建掩膜(红色为例)
mask = cv.inRange(hsv, (0,43,46),(10,255,255))
cv.imshow("demo", demo)
cv.imshow("hsv", hsv)
cv.imshow("mask", mask)#颜色提取 与运算
dst = cv.bitwise_and(demo, demo, mask=mask)
cv.imshow("dst", dst)#颜色替换 布尔索引
demo[mask==255]=(177,177,0)
cv.imshow("demo", demo)cv.waitKey(0)
cv.destroyAllWindows()
掩膜
颜色提取,掩膜与原图进行与运算
颜色替换,在原图的基础上,按照掩膜的位置进行颜色的替换
四、ROI切割
ROI(感兴趣区域)切割是图像处理中常用的技术,用于提取图像中的特定区域进行分析或处理
1. 基础ROI切割(矩形区域)
(1)方法一:NumPy数组切片
import cv2
import numpy as np# 读取图像
img = cv2.imread("image.jpg")# 定义ROI坐标 (x1,y1)为左上角,(x2,y2)为右下角
x1, y1, x2, y2 = 100, 50, 300, 200 # 矩形区域:宽=x2-x1,高=y2-y1# 切割ROI (注意OpenCV是height-first: img[y1:y2, x1:x2])
roi = img[y1:y2, x1:x2]# 显示结果
cv2.imshow("ROI", roi)
cv2.waitKey(0)
参数说明:
-
y1:y2:垂直方向范围(行)
-
x1:x2:水平方向范围(列)
注意事项:
-
OpenCV的图像数组是(height, width, channels)顺序
-
确保坐标不越界(可用img.shape检查图像尺寸)
(2)方法二:cv2.rectangle + 掩膜(Mask)
# 创建与原图同尺寸的黑色掩膜
mask = np.zeros_like(img)# 在掩膜上绘制白色矩形(定义ROI区域)
cv2.rectangle(mask, (x1, y1), (x2, y2), (255,255,255), -1) # -1表示填充# 通过按位与运算提取ROI
roi = cv2.bitwise_and(img, mask)# 显示结果
cv2.imshow("Masked ROI", roi)
cv2.waitKey(0)
适用场景:
-
需要非矩形ROI时(结合下文多边形方法)
-
保留ROI外区域为黑色背景
2、 非矩形ROI切割
(1)方法一:多边形ROI(cv2.fillPoly)
# 定义多边形顶点(顺时针或逆时针顺序)
points = np.array([[100,50], [300,50], [350,200], [150,200]]) # 四边形# 创建掩膜
mask = np.zeros_like(img)
cv2.fillPoly(mask, [points], (255,255,255)) # 填充多边形# 提取ROI
roi = cv2.bitwise_and(img, mask)# 裁剪多边形外区域(可选)
rect = cv2.boundingRect(points) # 获取外接矩形
roi_cropped = roi[rect[1]:rect[1]+rect[3], rect[0]:rect[0]+rect[2]] # y, x
关键函数:
-
cv2.fillPoly():填充多边形区域
-
cv2.boundingRect():获取多边形的最小外接矩形
(2)方法二:圆形ROI
# 定义圆心和半径
center = (200, 150)
radius = 100# 创建圆形掩膜
mask = np.zeros_like(img)
cv2.circle(mask, center, radius, (255,255,255), -1)# 提取ROI
roi = cv2.bitwise_and(img, mask)
五、图像添加水印
整个图像添加水印的操作实质是灰度化处理、二值化处理、图像掩膜、ROI切割结合的实验操作
OpenCV代码实现:,每一步都写了注释
import cv2 as cv#读图
bg = cv.imread("../images/bg.png")
logo = cv.imread("../images/logohq.png")
#对logo图进行灰度化
gray = cv.cvtColor(logo, cv.COLOR_BGR2GRAY)#生成两种掩膜
#提取白色Logo,生成黑底白字掩膜。进行反阈值二值化处理,提取出白色的logo
_,mask1 = cv.threshold(gray,170,255,cv.THRESH_BINARY_INV)
cv.imshow("mask1", mask1)
#提取黑色Logo,生成白底黑字掩膜。进行阈值二值化处理,提取出黑色的logo
_,mask2 = cv.threshold(gray,170,255,cv.THRESH_BINARY)
cv.imshow("mask2", mask2)#提取logo图的尺寸
shape = logo.shape
#从背景里面截取出与logo图尺寸相同的子区域
roi = bg[:shape[0],:shape[1]]#与运算
#拿logo,只有logo,使用白色logo与logo图进行与运算,mask1 屏蔽了白色背景,保留原logo颜色,提取出logo图中的logo标
dst1 = cv.bitwise_and(logo, logo, mask=mask1)
cv.imshow("dst1", dst1)#拿背景,只有背景,使用黑logo与背景图进行与运算,抠出背景图中与logo标相同的位置
dst2 = cv.bitwise_and(roi, roi, mask=mask2)
cv.imshow("dst2", dst2)#图像融合
dst = cv.add(dst1, dst2)
cv.imshow("dst", dst)#将融合后的图像dst写回背景图bg的ROI区域
roi[:] = dst
cv.imshow("bg", bg)cv.waitKey(0)
cv.destroyAllWindows()
六、图像早点消除
首先介绍一些概念:
噪声:指图像中的一些干扰因素,通常是由图像采集设备、传输信道等因素造成的,表现为图像中随机的亮度,也可以理解为有那么一些点的像素值与周围的像素值格格不入。常见的噪声类型包括高斯噪声和椒盐噪声。高斯噪声是一种分布符合正态分布的噪声,会使图像变得模糊或有噪点。椒盐噪声则是一些黑白色的像素值分布在原图像中。
滤波器:也可以叫做卷积核,与自适应二值化中的核一样,本身是一个小的区域,有着特定的核值,并且工作原理也是在原图上进行滑动并计算中心像素点的像素值。滤波器可分为线性滤波和非线性滤波,线性滤波对邻域中的像素进行线性运算,如在核的范围内进行加权求和,常见的线性滤波器有均值滤波、高斯滤波等。非线性滤波则是利用原始图像与模板之间的一种逻辑关系得到结果,常见的非线性滤波器中有中值滤波器、双边滤波器等。
滤波与模糊联系与区别:
- 它们都属于卷积,不同滤波方法之间只是卷积核不同(对线性滤波而言)
- 低通滤波器是模糊,高通滤波器是锐化
- 低通滤波器就是允许低频信号通过,在图像中边缘和噪点都相当于高频部分,所以低通滤波器用于去除噪点、平滑和模糊图像。高通滤波器则反之,用来增强图像边缘,进行锐化处理。
**注意:**椒盐噪声可以理解为斑点,随机出现在图像中的黑点或白点;高斯噪声可以理解为拍摄图片时由于光照等原因造成的噪声。
本实验中共提供了五种滤波的方式,下面进行一一介绍。
1、均值滤波
原理:用邻域像素的平均值替换中心像素值
特点:
-
优点:实现简单,计算速度快
-
缺点:导致图像模糊,边缘信息丢失
-
适用场景:高斯噪声或均匀噪声
2、方框滤波
原理:
-
均值滤波的推广形式,可控制是否归一化:
-
归一化时等同于均值滤波
-
未归一化时直接求和
特点:
-
优点:比均值滤波更灵活
-
缺点:非归一化时可能导致像素值溢出
-
适用场景:需要快速平滑时
3、高斯滤波
原理:根据高斯函数权重计算邻域像素的加权平均值,中心像素权重最大
特点
-
优点:保留边缘效果优于均值滤波
-
缺点:计算量较大
适用场景:高斯噪声,需要保边平滑
4、中值滤波
原理:取邻域像素的中值作为中心像素值:
特点
-
优点:有效去除椒盐噪声,保留边缘
-
缺点:计算排序耗时
适用场景:椒盐噪声
5. 双边滤波
原理:同时考虑空间距离和像素值相似性的加权平均:
特点
-
优点:极好的边缘保留特性
-
缺点:计算复杂度高
适用场景:需要保边的去噪,如人像美化
6、各个滤波方法对比
滤波方法 | 原理 | 保留边缘 | 计算速度 | 适用噪声类型 | 典型应用场景 |
---|---|---|---|---|---|
均值滤波 | 邻域平均 | 差 | 快 | 高斯噪声 | 实时系统预处理 |
方框滤波 | 可调归一化求和 | 差 | 快 | 均匀噪声 | 快速平滑 |
高斯滤波 | 高斯加权平均 | 中 | 中 | 高斯噪声 | 一般图像去噪 |
中值滤波 | 取邻域中值 | 好 | 慢 | 椒盐噪声 | 医学图像处理 |
双边滤波 | 空间+值域加权 | 极好 | 极慢 | 所有噪声 | 人像美化、HDR |
关键知识点
-
噪声类型决定滤波选择
高斯噪声:高斯滤波或均值滤波
椒盐噪声:中值滤波
混合噪声:可尝试双边滤波 -
边缘保留的重要性
需要锐利边缘的场景(如OCR):优先中值或双边滤波
允许适度模糊的场景:可使用高斯滤波 -
计算效率权衡
实时系统:均值/方框滤波
离线处理:可考虑双边滤波 -
参数选择经验
核大小:通常3×3到9×9,过大导致过度模糊
高斯滤波σ:越大越模糊
双边滤波:σ_color和σ_space需平衡
7、OpenCV代码实现
import cv2 as cv# 读图
lvbo2 = cv.imread("../images/lvbo2.png")
lvbo3 = cv.imread("../images/lvbo3.png")
cv.imshow("lvbo2", lvbo2)
cv.imshow("lvbo3", lvbo3)#均值滤波
mean = cv.blur(lvbo2,(7,7))
cv.imshow("mean", mean)#方框滤波 normalize:ture-均值滤波 False邻域内求和
box = cv.boxFilter(lvbo2,-1,(3,3),normalize=False)
cv.imshow("box", box)#高斯滤波
gauss = cv.GaussianBlur(lvbo2,(3,3),10000)
cv.imshow("gauss", gauss)#中值滤波,适合去除椒盐噪声
middle = cv.medianBlur(lvbo3,3)
cv.imshow("middle", middle)#双边滤波 使用了两个高斯核 同时考虑空域和值域
double = cv.bilateralFilter(lvbo2,9,20,20)
cv.imshow("double", double)cv.waitKey(0)
cv.destroyAllWindows()