OpenCV-Python系列六:图像滤波

图像滤波是一种十分常见的图像处理手段。通常,你可以认为相邻位置像素是紧密联系的,它们共同来显示对某个物体,图像滤波则通过运算来排除图像中和周围相差大的像素。当然,这并不是绝对的,有时候你为了评估图像的质量,也会将这些“特立独行”的像素作为选取的目标。无论你采用什么方法,记住你要的目标就行,有时候你的目标可能是别人的背景。
滤波常常会使得图像变得模糊(非绝对),那么,为什么你需要将一幅清晰的图像变得模糊呢?下面的例子应该可以解释。

1.无滤波模糊的边缘特征(左上),2.无滤波模糊的特征提取(右上)3.模糊化的边缘特征(左下),4.模糊化边缘后特征提取
区别在哪?放大图像你就能发现问题了,对近处的车道线提取的效果不太理想,模糊处理后对车道线的提取效果较好,也存在环境干扰大的问题需要处理,对于这些,你可以通过设定直线特征阈值等操作来滤除。这是由于在提取线特征时(霍夫变换),未经模糊化的边缘锯齿严重,即便在邻近区域拟合的直线也不同,即便整体上它们落在一条直线上,累加器很难达到阈值。

相关博客:使用OpenCV进行实时车道检测:https://www.jianshu.com/p/c6b7a8a601f2

1.高斯滤波

高斯滤波采用满足正态分布的核模板,其参数的主要参数是标准差σ,代表核的离散程度,σ值越小,模板中心系数与边缘系数差越大,平滑的程度越小。
高斯滤波对图像采集过程中由于不良照明/高温引起的传感器噪声信号有较好的效果,消除了图像中的高频信号。

cv2,GaussianBlur(img, ksize, sigma_x, sigma_y,border_type)
只给定sigma_x时,sigma_y会取相同的值,如果两个都是0,会依据核函数的大小计算。
cv2.getGaussianKernel(kszie, sigma, ktype)
ksize为核大小(奇数),得到一个一维的垂向kernel

由于得到的是一维的Gaussian Kernel,你可以采用下面的方式转为二维的

import cv2
import numpy as np

kernel_x = cv2.getGaussianKernel(5, 2, cv2.CV_32F)
kernel_y = cv2.getGaussianKernel(5, 2, cv2.CV_32F)
# 转为2维的kernel
kernel_gaussian = np.multiply(kernel_x, np.transpose(kernel_y))

print(kernel_gaussian)

参考博客:二维高斯核函数https://blog.csdn.net/qq_16013649/article/details/78784791
对于kernel保留不同的小数位数对计算会产生一定的差距,请留意

灰度图,灰度图+Canny, 灰度图+GaussianBlur+Canny

为了便于直观感受高斯滤波的效果,使用Canny算子来提取轮廓对比,你可以试试在特征提取前加高斯滤波对比。

# 高斯滤波
import cv2
import numpy as np

img=cv2.imread('scraths.jpg')

gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 高斯平滑,为了消除图像中的噪声
gaussian_img = cv2.GaussianBlur(gray_img,(5, 5),0)
# Canny算子
gaussian_canny_edges_img = cv2.Canny(gaussian_img, 100, 200, 5)
canny_edges_img = cv2.Canny(gray_img, 100, 200, 5)



cv2.imshow('canny_img',canny_edges_img)
cv2.imshow('gaussian_canny_img',gaussian_canny_edges_img)
cv2.imshow('gray_img', gray_img)

cv2.waitKey(0)
cv2.destroyAllWindows()
2.均值滤波

均值滤波,中心点的像素为kernel区域像素的均值,使得像素间的差距变小,达到平滑的效果,对脉冲型(椒盐等)噪声的效果不理想,不过在你需要提取轮廓特征时,让图像平滑些会更有利。
kernel为3和5的均值滤波效果
blur_img_3 = cv2.blur(gray_img, (3, 3))

cv2.blur(img, ksize, anchor, bordertype)
anchor通常取-1,将锚点(被平滑的点)设置为kernel的中心

补充说明:对于均值滤波,你也可以使用cv2.boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]])来实现,需要将normalize设置为True,当设置normalize为False时,实现的是将kernel内像素相加,官方文档做出的描述为:

Unnormalized box filter is useful for computing various integral characteristics over each pixel neighborhood, such as covariance matrices of image derivatives (used in dense optical flow algorithms, and so on). If you need to compute pixel sums over variable-size windows.) 链接:https://docs.opencv.org/3.0-beta/modules/imgproc/doc/filtering.html?highlight=cv2.bilateralfilter#boxfilter
在后期的光流处理算法中可能会涉及到

3.中值滤波

中值滤波对图像中的脉冲型(椒盐等)噪声信号处理效果好,当你的应用场景存在这种颗粒感的噪声信号时,中值滤波会是一种很好的选择。它,选取kernel区域内像素点集的中值最为锚点的像素值,对类似投票机制中的最高分(高灰阶点)和最低分(过低灰阶点)影响有很好的抑制作用。

kernel size为5和9的中值滤波效果

cv2.medianBlur(img, ksize)
ksize须为奇数

4.双边滤波

如果你的应用涉及到图像美化,双边滤波可以初步达到你的期望,关于双边滤波,这里不做展开,由你来探索,其函数参数信息如下。

cv2.bilateralFilter(img, d, sigma_color, sigma_space, bordertype)
d:表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数,则函数会从参数sigmaSpace计算该值。
sigmaColor: 颜色空间过滤器的sigma值,这个参数的值月大,表明该像素邻域内有月宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
sigmaSpace: 坐标空间中滤波器的sigma值,如果该值较大,则意味着颜色相近的较远的像素将相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当d>0时,d指定了邻域大小且与sigmaSpace无关,否则d正比于sigmaSpace
参考博客:opencv学习(二十二)之双边滤波bilateralFilter:https://blog.csdn.net/keith_bb/java/article/details/54427779

5.filter2D自定义的kernel进行卷积

cv2.filter2D(src, ddepth, kernel[, anchor[, delta[, borderType]]])
ddepth:图像的深度
kernel:自定义的核
anchor:锚点,默认(-1,-1)即核中心
delta:将像素存于dst之前会加上delta,类似偏置
参考博客:Python-OpenCV中的filter2D()函数https://www.cnblogs.com/lfri/p/10599420.html
自定义kernel的方式如下:

# 根据自己kernel数据来选择类型:https://www.runoob.com/numpy/numpy-dtype.html
kernel = np.array((
        [0.0625, 0.125, 0.0625],
        [0.125, 0.25, 0.125],
        [0.0625, 0.125, 0.0625]), dtype = np.float32)

对于opencv-python的图像滤波部分有问题欢迎留言, Have Fun With OpenCV-Python, 下期见。

你可能感兴趣的:(OpenCV-Python系列六:图像滤波)