OpenCV Python smooth denoising
【Target】
- Smooth and denoise images with different low-pass filters (average, Gaussian, median, bilateral)
- Use your own custom filters
- 5x5 averaging filter
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 average filter
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
【Code】
- custom smoothing filter
Like one-dimensional signals, images can also be filtered by low-pass filters and high-pass filters; low-pass filters can blur images and remove noise, and high-pass filters can be used to find image edges.
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()
- Vague
Take a pixel as the center, and take the average value of the surrounding pixels as the pixel value of the pixel.
If you don’t want to use a normalized filter, use cv2.boxFilter and pass innormalize=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()
- Gaussian blur
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()
- median filter
The median filter is different from other filters. The pixel value of the median filter is the pixel value inside the image, and other filters are obtained by calculation. The kernel width of the median filter is a positive odd number. Great for handling salt and pepper noise.
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()
- bilateral filtering
It can effectively remove noise while retaining edge information, but it is very time-consuming.
NOTE: Bilateral filtering is very unfriendly to salt and pepper noise. Please refer to Reference 2 for specific principles.
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()
【interface】
- 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
Convolve an image with a convolution kernel
- src : input image
- dst : output image
- ddepth : the depth of the output image
- kernel : convolution kernel
- anchor : the default is (-1, -1) at the center of the convolution kernel
- delta : added to the filtered pixel value before storing
- borderType : padding type, not supported
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
Blur the image with
- src : input image
- dst : output image
- ksize : the size of the blur kernel
- anchor : the default is (-1, -1) at the center of the convolution kernel
- borderType : padding type, not supported
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 : input image
- dst : output image
- ddepth : the depth of the output image
- ksize : the size of the blur kernel
- anchor : the default is (-1, -1) at the center of the convolution kernel
- normalize : normalization flag
- borderType : padding type, not supported
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
Gaussian blur
- src : input image
- dst : output image
- ksize : the size of the blur kernel
- sigmaX : the variance of the Gaussian kernel in the X direction
- sigmaY : The variance of the Gaussian kernel in the Y direction, if set to 0, it is set to
sigmaX
, if both are set to 0, it is calculated through the window. It is best to set both.- borderType : padding type, not supported
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
Apply bilateral filtering to an image
- src : input image
- dst : output image
- d : The diameter of the pixel neighborhood used for filtering, if it is a negative number, it will
sigmaSpace
be calculated .- sigmaColor : The variance of the color space, if the setting is large, the pixel with a large pixel difference is considered to be a neighboring pixel;
- sigmaSpace : The variance of the coordinate space. If it is set to be large, it means that the pixels far away are neighbor pixels. If it is
d > 0
, it is determined by the coordinates whether it is a neighbor.- borderType : padding type, not supported
BORDER_WRAP