OpenCV Python 平滑去噪
【目标】
- 利用不同的低通滤波器对图像进行平滑去噪(平均、高斯、中值、双边)
- 使用自己定制的滤波器
- 5x5 平均滤波器
K = 1 25 [ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ] K= \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1\\ 1 & 1 & 1 & 1 & 1\\ 1 & 1 & 1 & 1 & 1\\ 1 & 1 & 1 & 1 & 1\\ 1 & 1 & 1 & 1 & 1 \end{bmatrix} K=251⎣⎢⎢⎢⎢⎡1111111111111111111111111⎦⎥⎥⎥⎥⎤
- 3x3 平均滤波器
K = 1 9 [ 1 1 1 1 1 1 1 1 1 ] K= \frac{1}{9} \begin{bmatrix} 1 & 1 & 1\\ 1 & 1 & 1\\ 1 & 1 & 1 \end{bmatrix} K=91⎣⎡111111111⎦⎤
【代码】
- 自定义平滑滤波器
和一维信号一样,图像也可以通过低通滤波器和高通滤波器进行滤波;低通滤波器可以模糊图像和去除噪声,高通滤波器可以用于找图像边缘。
import numpy as np
import cv2
img = cv2.imread('opencv-logo-white.png')
kernel = np.ones((5, 5), np.float32)/25
dst = cv2.filter2D(img, -1, kernel)
cv2.imshow("src", img)
cv2.imshow("filter2D", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 模糊
以一个像素为中心,取周边的像素平均值作为该像素的像素值
如果不想用归一化的滤波器,那就用 cv2.boxFilter, 并且传入normalize=False
import cv2
import numpy as np
img = cv2.imread('opencv-logo-white.png')
blur = cv2.blur(img,(5,5))
cv2.imshow("src", img)
cv2.imshow("blur", blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 高斯模糊
import cv2
import numpy as np
img = cv2.imread('opencv-logo-white.png')
blur = cv2.GaussianBlur(img, (5, 5), 0)
cv2.imshow("src", img)
cv2.imshow("GaussianBlur", blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 中值滤波
中值滤波和其他滤波器不一样,中值滤波取的像素值为图像内部的像素值,其他滤波是通过计算得到的。中值滤波器的核宽为正奇数。非常适合处理椒盐噪声。
import numpy as np
import cv2
def addPepperSalt(src: cv2.Mat, snr: float = 0.99) -> cv2.Mat:
"""
addPepperSalt 给彩色图像添加黑白椒盐噪声
_extended_summary_
Args:
src (cv2.Mat): 输入图像
snr (float): 信噪比
"""
if src is None:
return None
dst = src.copy()
h, w, _ = src.shape
imgsz = h * w
pepperSaltNum = int(imgsz * (1.0 - snr))
for i in range(pepperSaltNum):
randx = np.random.randint(1, w-1)
randy = np.random.randint(1, h-1)
if np.random.random() <= 0.5:
dst[randy, randx] = 0
else:
dst[randy, randx] = 255
return dst
img = cv2.imread('sheets.png')
cv2.imshow("src", img)
pepperSaltIm = addPepperSalt(img, 0.99)
cv2.imshow("peppersalt", pepperSaltIm)
median = cv2.medianBlur(pepperSaltIm, 5)
blur = cv2.bilateralFilter(pepperSaltIm, 15, 180, 180)
cv2.imshow("median", median)
cv2.imshow("blur", blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 双边滤波
可以非常有效的去除噪声的同时保留边缘信息,但是非常耗时。
NOTE: 双边滤波对椒盐噪声效果非常不友好,具体原理请看 参考2
import cv2
import numpy as np
img = cv2.imread('bilateral.png')
blur = cv2.bilateralFilter(img,9,75,75)
cv2.imshow("src", img)
cv2.imshow("bilateralFilter", blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
【接口】
- cv2.filter2D
void cv::filter2D ( InputArray src,
OutputArray dst,
int ddepth,
InputArray kernel,
Point anchor = Point(-1,-1),
double delta = 0,
int borderType = BORDER_DEFAULT
);
cv2.filter2D( src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]] ) -> dst
通过卷积核对图像进行卷积
- src: 输入图像
- dst: 输出图像
- ddepth: 输出图像的深度
- kernel: 卷积核
- anchor: 默认为(-1, -1) 是在卷积核的中心
- delta: 在存储前加到滤波后的像素值上
- borderType: 填充类型,不支持
BORDER_WRAP
ddepth:
borderType:
- cv2.blur
void cv::blur ( InputArray src,
OutputArray dst,
Size ksize,
Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT
);
cv2.blur( src, ksize[, dst[, anchor[, borderType]]] ) -> dst
利用
boxFilter
对图像进行模糊处理
- src: 输入图像
- dst: 输出图像
- ksize: 模糊核的大小
- anchor: 默认为(-1, -1) 是在卷积核的中心
- borderType: 填充类型,不支持
BORDER_WRAP
- cv2.boxFilter
void cv::boxFilter ( InputArray src,
OutputArray dst,
int ddepth,
Size ksize,
Point anchor = Point(-1,-1),
bool normalize = true,
int borderType = BORDER_DEFAULT
);
cv2.boxFilter( src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]] ) -> dst
- src: 输入图像
- dst: 输出图像
- ddepth: 输出图像的深度
- ksize: 模糊核的大小
- anchor: 默认为(-1, -1) 是在卷积核的中心
- normalize: 归一化标志
- borderType: 填充类型,不支持
BORDER_WRAP
- cv2.GaussianBlur
void cv::GaussianBlur ( InputArray src,
OutputArray dst,
Size ksize,
double sigmaX,
double sigmaY = 0,
int borderType = BORDER_DEFAULT
);
cv2.GaussianBlur( src, ksize, sigmaX[, dst[, sigmaY[, borderType]]] ) -> dst
高斯模糊
- src: 输入图像
- dst: 输出图像
- ksize: 模糊核的大小
- sigmaX: 高斯核X方向的方差
- sigmaY: 高斯核Y方向的方差,如果设置为0,则被设置为
sigmaX
, 如果都设置为0,则通过窗口计算。最好是都设置。- borderType: 填充类型,不支持
BORDER_WRAP
- cv2.bilateralFilter
void cv::bilateralFilter ( InputArray src,
OutputArray dst,
int d,
double sigmaColor,
double sigmaSpace,
int borderType = BORDER_DEFAULT
);
cv2.bilateralFilter( src, d, sigmaColor, sigmaSpace[, dst[, borderType]] ) -> dst
对图像应用双边滤波
- src: 输入图像
- dst: 输出图像
- d: 滤波使用的像素邻域直径,如果是负数,则通过
sigmaSpace
计算。- sigmaColor: 颜色空间的方差,如果设置很大,则认定像素差很大的像素为邻域像素;
- sigmaSpace: 坐标空间的方差,如果设置很大,意味着很远的像素为邻域像素,如果
d > 0
, 由坐标决定是否为邻域。- borderType: 填充类型,不支持
BORDER_WRAP