使用高斯滤波器(3×3 大小,标准差 s=1.3)来对imori_noise.jpg
进行降噪处理吧!
高斯滤波器是一种可以使图像平滑的滤波器,用于去除噪声。可用于去除噪声的滤波器还有中值滤波器,平滑滤波器、LoG 滤波器。
高斯滤波器将中心像素周围的像素按照高斯分布加权平均进行平滑化。这样的(二维)权值通常被称为卷积核或者滤波器。
但是,由于图像的长宽可能不是滤波器大小的整数倍,因此我们需要在图像的边缘补0。这种方法称作 Zero Padding。并且权值(卷积核)要进行归一化操作(\sum\ g = 1)。
权值 g(x,y,s) = 1/ (s*sqrt(2 * pi)) * exp( - (x^2 + y^2) / (2*s^2))
标准差 s = 1.3 的 8 近邻 高斯滤波器如下:
1 2 1
K = 1/16 [ 2 4 2 ]
1 2 1
python实现:
import cv2
import numpy as np
# Read image
img = cv2.imread("imori_noise.jpg")
H, W, C = img.shape
# Gaussian Filter
K_size = 3
sigma = 1.3
## Zero padding
pad = K_size // 2
out = np.zeros((H + pad*2, W + pad*2, C), dtype=np.float)
out[pad:pad+H, pad:pad+W] = img.copy().astype(np.float)
## Kernel
K = np.zeros((K_size, K_size), dtype=np.float)
for x in range(-pad, -pad+K_size):
for y in range(-pad, -pad+K_size):
K[y+pad, x+pad] = np.exp( -(x**2 + y**2) / (2* (sigma**2)))
K /= (sigma * np.sqrt(2 * np.pi))
K /= K.sum()
tmp = out.copy()
for y in range(H):
for x in range(W):
for c in range(C):
out[pad+y, pad+x, c] = np.sum(K * tmp[y:y+K_size, x:x+K_size, c])
out = out[pad:pad+H, pad:pad+W].astype(np.uint8)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++实现:
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>
int main(int argc, const char* argv[]){
cv::Mat img = cv::imread("imori_noise.jpg", cv::IMREAD_COLOR);
int width = img.rows;
int height = img.cols;
cv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);
// prepare kernel
double s = 1.3;
int k_size = 3;
int p = floor(k_size / 2);
int x = 0, y = 0;
double k_sum = 0;
float k[k_size][k_size];
for (int j = 0; j < k_size; j++){
for (int i = 0; i < k_size; i++){
y = j - p;
x = i - p;
k[j][i] = 1 / (s * sqrt(2 * M_PI)) * exp( - (x*x + y*y) / (2*s*s));
k_sum += k[j][i];
}
}
for (int j = 0; j < k_size; j++){
for (int i = 0; i < k_size; i++){
k[j][i] /= k_sum;
}
}
// filtering
double v = 0;
for (int j = 0; j < height; j++){
for (int i = 0; i < width; i++){
for (int c = 0; c < 3; c++){
v = 0;
for (int _j = -p; _j < p+1; _j++){
for (int _i = -p; _i < p+1; _i++){
if (((j+_j) >= 0) && ((i+_i) >= 0)){
v += (double)img.at<cv::Vec3b>(j+_j, i+_i)[c] * k[_j+p][_i+p];
}
}
}
out.at<cv::Vec3b>(j,i)[c] = v;
}
}
}
//cv::imwrite("out.jpg", out);
cv::imshow("answer", out);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
输入:
输出: