OpenCV的imgproc 模块:图像平滑处理函数cv2.filter2D、cv2.blur、cv2.GaussianBlur、cv2.medianBlur、cv2.bilateralFilter——OpenCV官方教程翻译(最全最详细)
一、目标
本教程教您怎样使用各种线性滤波器对图像进行平滑处理。
· 用各种低通滤波器模糊图像
· 对图像应用自定义的过滤器(2D卷积)
二、二维卷积(图像滤波)
与一维信号一样,图像也可以用各种低通滤波器(LPF)、高通滤波器(HPF)等进行滤波。LPF有助于去除噪声,模糊图像等。HPF滤波器帮助寻找图像的边缘。
OpenCV提供了一个函数cv.filter2D()
来将内核与图像进行卷积。
cv2.filter2D()函数
dst = cv2.filter2D ( InputArray src,
int ddepth,
InputArray kernel,
Point anchor = Point(-1,-1),
double delta = 0,
int borderType = BORDER_DEFAULT
)
将图像与核进行卷积。
该函数对图像应用任意线性滤波器。支持就地操作。当光圈部分位于图像外部时,函数根据指定的边界模式插值离群像素值。
这个函数实际上计算的是相关性,而不是卷积:
也就是说,内核不是围绕锚点镜像的。如果你需要一个真正的卷积,使用flip翻转内核,并设置新的锚 (kernel.cols - anchor.x - 1, kernel.rows - anchor.y - 1)
。
该函数在足够大的核(~11 x 11或更大)的情况下使用基于dft的算法,对于小的核使用直接算法。
参数 | 说明 |
---|---|
src | 输入图像。 |
dst | 输出与src相同大小和通道数的图像。 |
ddepth | 目标图像所需的深度(等于-1时默认和输入图像相同深度) |
kernel | 卷积核(或者说是相关核),一个单通道浮点矩阵;如果你想应用不同的内核到不同的通道,分割图像到单独的颜色平面使用split和处理他们单独。 |
anchor | 内核的锚点,指示过滤点在内核中的相对位置;锚应该位于内核内;默认值(-1,-1)表示锚位于内核中心。 |
delta | 可选值,添加到过滤后的像素,然后存储到dst中。 |
borderType | 像素外推方法,参见BorderTypes。 |
BorderTypes
BordeeTypes参数 | 说明 |
---|---|
cv2.BORDER_CONSTANT | iiiiii-abcdefgh-iiiiiii with some specified i |
cv2.BORDER_REPLICATE | aaaaaa-abcdefgh-hhhhhhh |
cv2.BORDER_REFLECT | fedcba-abcdefgh-hgfedcb |
cv2.BORDER_WRAP | cdefgh-abcdefgh-abcdefg |
cv2.BORDER_REFLECT_101 | gfedcb-abcdefgh-gfedcba |
cv2.BORDER_TRANSPARENT | uvwxyz-abcdefgh-ijklmno |
cv2.BORDER_REFLECT101 | same as BORDER_REFLECT_101 |
cv2.BORDER_DEFAULT | same as BORDER_REFLECT_101 |
cv2.BORDER_ISOLATED | do not look outside of ROI |
cv2.filter2D()举例
作为一个例子,我们将在一个图像上尝试一个平均滤波器。一个5x5平均滤波器内核如下图所示:
操作是这样的:将内核保持在一个像素以上,将内核以下的所有25个像素相加,取平均值,并用新的平均值替换中心像素。对图像中的所有像素继续执行此操作。
尝试以下代码并检查结果:
# 二维卷积(图像滤波)
img = cv2.imread('lenaNoise.png')
kernel = np.ones((5,5),np.float32)/25 #5x5的卷积核,均值处理
dst1 = cv2.filter2D(img,-1,kernel)
cv2.imshow('Original',img)
cv2.imshow('filter2D',dst1)
# 等待时间,毫秒级,0表示任意键终止
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
三、图像模糊(图像平滑)
图像模糊是通过卷积图像与低通滤波核来实现的。它对去除噪声很有用。它实际上从图像中删除了高频内容(如:噪声,边缘)。所以在这个操作中,边缘会变得模糊一点(也有一些模糊技术不会模糊边缘)。OpenCV提供了四种主要的模糊技术,分别是:
·归一化块滤波器 (Normalized Box Filter)
·高斯滤波器 (Gaussian Filter)
·中值滤波器 (Median Filter)
·双边滤波 (Bilateral Filter)
3.1 归一化块滤波器 (Normalized Box Filter)
这是通过将图像与归一化块滤波器进行卷积来实现的。它只是取内核区域下所有像素的平均值,并替换中心元素。这是由函数cv2.blur()
或cv2.boxFilter()
完成的。
dst = cv2.blur ( InputArray src,
Size ksize,
Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT
)
使用归一化块滤波器 模糊图像。
该函数使用卷积内核平滑图像:
cv2.blur(src, dst, ksize, anchor, borderType)
和 cv2.boxFilter(src, dst, src.type(), anchor, true, borderType)
是等效的。
参数 | 说明 |
---|---|
src | 输入图像;它可以有任意数量的通道,这些通道是独立处理的,但是深度应该是CV_8U、CV_16U、CV_16S、CV_32F或CV_64F。 |
dst | 输出与src相同大小和类型的图像。 |
ksize | 模糊内核大小。 |
anchor | 锚点;默认值Point(-1,-1)表示锚位于内核中心。 |
borderType | 用于外推图像像素的边框模式,参见BorderTypes |
cv2.blur()举例
查看下面5x5内核大小的示例演示:
# 归一化块滤波器 (Normalized Box Filter)
img = cv2.imread('lenaNoise.png')
blur = cv2.blur(img,(5,5)) #5x5卷积核,与cv2.filter2D()效果一样
cv2.imshow('Original',img)
cv2.imshow('Normalized Box Filter',blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
3.2 高斯滤波器 (Gaussian Filter)
在这种方法中,不使用盒形滤波器,而是使用高斯核。这是通过函数cv2.GaussianBlur()
完成的。我们应该指定内核的宽度和高度,它们应该是正的和奇数的。我们还应该指定X和Y方向的标准差,分别为sigmaX和sigmaY。如果只指定sigmaX,则sigmaY与sigmaX相同。如果两者都是0,则根据内核大小计算。高斯模糊是去除图像高斯噪声的一种有效方法。
dst = cv2.GaussianBlur ( InputArray src,
Size ksize,
double sigmaX,
double sigmaY = 0,
int borderType = BORDER_DEFAULT
)
使用高斯滤波器模糊图像。
该函数将源图像与指定的高斯核进行卷积。支持直接滤波。
参数 | 说明 |
---|---|
src | 输入图像;图像可以有任意数量的通道,这些通道是独立处理的,但是深度应该是CV_8U, CV_16U, CV_16S, CV_32F或CV_64F。 |
dst | 输出与src相同大小和类型的图像。 |
ksize | 高斯核大小。ksize。宽度和ksize。高度可以不同,但它们都必须是正的和奇数的。或者,它们可以是0,然后用来计算。 |
sigmaX | X方向的sigmax高斯核标准差。 |
sigmaY | Y方向sigmay高斯核标准差;如果sigmaY为0,则设置为sigmaX,如果两个sigma都为零,则从ksize计算。宽度和ksize。高度,分别(详见getGaussianKernel);为了完全控制结果,而不考虑将来可能对所有这些语义进行的修改,建议指定所有的ksize、sigmaX和sigmaY。 |
bordertype | 像素外推方法,参见BorderTypes |
cv2.GaussianBlur()举例
# 高斯滤波器 (Gaussian Filter)
img = cv2.imread('lenaNoise.png')
blur1 = cv2.GaussianBlur(img,(5,5),0)
cv2.imshow('Original',img)
cv2.imshow('Gaussian Filter',blur1)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
3.3 中值滤波器 (Median Filter)
这里,函数cv2.medianBlur()
取内核区域下所有像素的中值,中心元素被替换为这个中值。这是非常有效的对抗盐和胡椒噪声的图像。有趣的是,在上面的滤镜中,中心元素是一个新计算的值,可能是图像中的像素值,也可能是一个新值。但在中值模糊中,中心元素总是被图像中的某个像素值所代替。它能有效地降低噪音。它的核大小应该是一个正奇数。
dst = cv2.medianBlur ( InputArray src,
int ksize
)
使用中值滤波器模糊图像。
该函数使用孔径为ksize×ksize的中值滤波器对图像进行平滑处理。对多通道图像的每个通道进行独立处理。支持就地操作。
注意:中值滤波器在内部使用BORDER_REPLICATE
来处理边框像素,参见BorderTypes。
参数 | 说明 |
---|---|
src | 输入1-、3-或4通道图像;当ksize为3或5时,图像深度应为CV_8U, CV_16U,或CV_32F,对于较大的光圈尺寸,只能为CV_8U。 |
dst | 与src大小和类型相同的dst目标阵列。 |
ksize | 孔径线性尺寸;必须为奇数且大于1,例如:3,5,7… |
cv2.medianBlur()举例
# 中值滤波器 (Median Filter)
img = cv2.imread('lenaNoise.png')
median = cv2.medianBlur(img,5)
cv2.imshow('Original',img)
cv2.imshow('Median Filter',median)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
3.4 双边滤波 (Bilateral Filter)
cv2.bilateralFilter()
在去除噪声的同时保持边缘锐利。但与其他滤波器相比,它的操作要慢一些。我们已经看到高斯滤波器取像素周围的邻域并求其高斯加权平均。该高斯滤波器仅是空间的函数,即在滤波时考虑到附近的像素。它没有考虑像素是否具有几乎相同的强度。它不考虑一个像素是否是边缘像素。所以它也模糊了边缘,这是我们不想做的。
双边滤波也采用空间高斯滤波器,但更多的高斯滤波器是像素差的函数。空间的高斯函数保证了只考虑邻近像素进行模糊,而强度差的高斯函数保证了只考虑与中心像素强度相近的像素进行模糊。所以它保留了边缘,因为边缘上的像素有很大的强度变化。
dst = cv2.bilateralFilter ( InputArray src,
int d,
double sigmaColor,
double sigmaSpace,
int borderType = BORDER_DEFAULT
)
对图像应用双边滤波器。
该函数对输入图像应用双边滤波,如http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html bilateralFilter所述,可以很好地减少不必要的噪声,同时保持边缘相当锐利。然而,与大多数滤波器相比,它是非常慢的。
Sigma values:为简单起见,你可以设置两个Sigma values相同。如果它们很小(< 10),滤镜不会有太大的效果,然而如果它们很大(> 150),它们将有一个非常强的效果,使图像看起来“卡通化”。
Filter size:大的滤波器(d > 5)非常慢,因此建议使用d=5用于实时应用,可能d=9用于离线应用,需要强噪声滤波。
这个滤波器不能就地工作。
参数 | 说明 |
---|---|
src | 源8位或浮点,1通道或3通道图像 |
dst | 与src相同大小和类型的目标图像 |
d | 滤波过程中使用的每个像素邻域的直径。如果它是非正数,则从sigmasspace计算 |
sigmaColor | 在颜色空间中过滤sigma。该参数的值越大,意味着像素邻域内更远的颜色(参见sigmaSpace)将混合在一起,从而产生更大的半相等颜色区域 |
sigmaSpace | 在坐标空间中过滤。参数值越大,越远的像素将相互影响,只要它们的颜色足够接近(请参阅sigmaColor)。当d>0时,它指定邻域大小,而不考虑sigmspace。否则,d与空间成比例 |
borderType | 边框模式用于外推图像外的像素,参见BorderTypes |
cv2.bilateralFilter()举例
下面的示例显示了双边过滤器的使用:
# 双边滤波 (Bilateral Filter)
img = cv2.imread('lenaNoise.png')
blur2 = cv2.bilateralFilter(img,9,75,75)
cv2.imshow('Original',img)
cv2.imshow('Bilateral Filter',blur2)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
表面的纹理消失了,但边缘还保留着。
<后续还会继续翻译和整理【OpenCV-图像处理】相关内容,如果需要,可持续关注我哦~> |
<翻译和整理不易,留个赞或评论支持一下我吧^^>
如有疑问,欢迎批评指正^^