OpenCV滤波算法

三种滤波的优缺点对比

高斯滤波

高斯滤波适合有高斯噪声的图片。能够很好的抑制图像输入时随机引入的噪声,将像素点跟邻域像素看作是一种高斯分布的关系,它的操作是将图像和一个高斯核进行卷积操作。但是不能很好地抑制椒盐噪声。

中值滤波

中值滤波适合有椒盐噪声的图片。将窗口函数里面的所有像素进行排序取得中位数来代表该窗口中心的像素值,对椒盐噪声和脉冲噪声的抑制效果特别好,同时又能保留边缘细节。但是不能很好地抑制高斯噪声。

均值滤波

把每个像素都用周围的8个像素来做均值操作,幅值近似相等且随机分布在不同位置上,这样可以平滑图像,速度较快,算法简单。但是无法去掉噪声,只能微弱的减弱它。对于椒盐噪声,中值滤波是选择适当的点来替代污染点的值,所以处理效果好,由于椒盐噪声的均值不为0,所以均值滤波不能很好地去除噪声点。

三种滤波算法对不同噪声的处理

给经过灰度处理的图像分别加入椒盐噪声、高斯噪声和椒盐高斯噪声,分别使用高斯滤波、中值滤波和均值滤波对图像进行滤波,下面为运行后的效果图:

添加椒盐噪声

image-20220308132251591

添加高斯噪声

image-20220308132404182

添加椒盐噪声和高斯噪声

image-20220308132459737

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#include <iostream>
#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

class Flitter
{
private:

public:
//生成高斯噪声
double generate_gause_noise(double mu, double sigma)
{
//定义小值
const double epsilon = numeric_limits<double>::min();
static double z0, z1;
static bool flag = false;
flag = !flag;
//flag为假构造高斯随机变量X
if (!flag)
return z1 * sigma + mu;
double u1, u2;
//构造随机变量
do
{
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
} while (u1 <= epsilon);
//flag为真构造高斯随机变量
z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI*u2);
z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI*u2);
return z0*sigma + mu;
}

//为图像加入高斯噪声
void add_gause_noise(Mat& image)
{
int channels = image.channels();
int rowsNumber = image.rows;
int colsNumber = image.cols*channels;
//推断图像的连续性
if (image.isContinuous())
{
colsNumber *= rowsNumber;
rowsNumber = 1;
}
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
//加入高斯噪声
int val = image.ptr<uchar>(i)[j] + generate_gause_noise(3, 0.8) * 32;
if (val < 0)
val = 0;
if (val>255)
val = 255;
image.ptr<uchar>(i)[j] = (uchar)val;
}
}
}
//添加椒盐噪声
void add_salt_noise(Mat& image, int n)
{
for (int k = 0; k < n; k++)
{
int i = rand() % image.cols;
int j = rand() % image.rows;
// 灰度图像
if (image.type() == CV_8UC1)
{
image.at<uchar>(j, i) = 255;
}
// 彩色图像
else if (image.type() == CV_8UC3)
{
image.at<cv::Vec3b>(j, i)[0] = 255;
image.at<cv::Vec3b>(j, i)[1] = 255;
image.at<cv::Vec3b>(j, i)[2] = 255;
}
}
for (int k = 0; k < n; k++)
{
int i = rand() % image.cols;
int j = rand() % image.rows;
// 灰度图像
if (image.type() == CV_8UC1)
{
image.at<uchar>(j, i) = 0;
}
// 彩色图像
else if (image.type() == CV_8UC3)
{
image.at<cv::Vec3b>(j, i)[0] = 0;
image.at<cv::Vec3b>(j, i)[1] = 0;
image.at<cv::Vec3b>(j, i)[2] = 0;
}
}
}

//中值滤波
void median_flitter(Mat& src, int win_size) {
int rows = src.rows, cols = src.cols;
int start = win_size/2;
for (int m = start; m <rows - start; m++) {
for (int n = start; n < cols - start; n++) {
vector<uchar> model;
for (int i = -start + m; i <= start + m; i++) {
for (int j = -start + n; j <= start + n; j++) {
//cout << int(src.at<uchar>(i, j)) << endl;
model.push_back(src.at<uchar>(i, j));
}
}
sort(model.begin(), model.end()); //采用快速排序进行
src.at<uchar>(m, n) = model[win_size*win_size/2];
}
}
}
//均值滤波
void mean_flitter(Mat& src, int win_size) {
int rows = src.rows, cols = src.cols;
int start = win_size / 2;
for (int m = start; m <rows - start; m++) {
for (int n = start; n < cols - start; n++) {
int sum = 0;
for (int i = -start + m; i <= start + m; i++) {
for (int j = -start + n; j <= start + n; j++) {
sum += src.at<uchar>(i, j);
}
}
src.at<uchar>(m, n) = uchar(sum / win_size / win_size);
}
}
}

//生成高斯模板
vector<vector<float>> gause_template(float sigma, int size)
{
int xcore = size / 2, ycore = size / 2;
vector<vector<float>> res;
float base = 1.0 / 2 / CV_PI / sigma / sigma;
for (int x = 0; x < size; x++) {
vector<float>v;
for (int y = 0; y < size; y++) {
float t1 = (pow(x - xcore, 2) + pow(y - ycore, 2)) / 2.0 / sigma / sigma;
float temp = base*exp(-t1);
v.push_back(temp);
}
res.push_back(v);
}
return res;
}

//高斯滤波
void gause_filter(Mat& src, float sigma, int size)
{
vector<vector<float>> gaussTem = gause_template(sigma,size);
int rows = src.rows, cols = src.cols;
int start = size / 2;
for (int m = start; m <rows - start; m++) {
for (int n = start; n < cols - start; n++) {
float sum = 0;
for (int i = -start + m; i <= start + m; i++) {
for (int j = -start + n; j <= start + n; j++) {
//cout << gaussTem[i - m + start][j - n + start] << endl;
sum += src.at<uchar>(i, j)*gaussTem[i-m+start][j-n+start]; //重点理解!!!
}
}
src.at<uchar>(m, n) = uchar(sum);
}
}
}
};

int main()
{
Flitter my_flitter;
Mat src = imread("./luna.jpg");
//灰度处理
cvtColor(src, src,COLOR_BGR2GRAY);
imshow("灰度处理过的原始图像", src);

//椒盐噪声
{
//添加椒盐噪声
Mat src_add_salt_noise;
src.convertTo(src_add_salt_noise, CV_8UC1);
my_flitter.add_salt_noise(src_add_salt_noise, 3000);
imshow("添加椒盐噪声", src_add_salt_noise);

//中值滤波
Mat Trans_Median = src_add_salt_noise.clone();
my_flitter.median_flitter(Trans_Median,3);
imshow("椒盐噪声——中值滤波", Trans_Median);

//均值滤波
Mat Trans_Mean = src_add_salt_noise.clone();
my_flitter.mean_flitter(Trans_Mean, 3);
imshow("椒盐噪声——均值滤波", Trans_Mean);

//高斯滤波
float sigma = 0.84089642; int size = 7;
vector<vector<float>> gaussTem = my_flitter.gause_template(1, 3);
for (auto num : gaussTem)
{
for (auto c : num)
{
cout << setprecision(8) << std::fixed << c << setw(11);
}
cout << endl;
cout << endl;
}
Mat Trans_Gause = src_add_salt_noise.clone();
my_flitter.gause_filter(Trans_Gause, 0.8, 3);
imshow("椒盐噪声——高斯滤波 Sigma=1", Trans_Gause);
}

//高斯噪声
{
//添加高斯噪声
Mat src_add_gause_noise;
src.convertTo(src_add_gause_noise, CV_8UC1);
my_flitter.add_gause_noise(src_add_gause_noise);
imshow("添加高斯噪声", src_add_gause_noise);

//中值滤波
Mat Trans_Median = src_add_gause_noise.clone();
my_flitter.median_flitter(Trans_Median,3);
imshow("高斯噪声——中值滤波", Trans_Median);

//均值滤波
Mat Trans_Mean = src_add_gause_noise.clone();
my_flitter.mean_flitter(Trans_Mean, 3);
imshow("高斯噪声——均值滤波", Trans_Mean);

//高斯滤波
float sigma = 0.84089642; int size = 7;
vector<vector<float>> gaussTem = my_flitter.gause_template(1, 3);
for (auto num : gaussTem)
{
for (auto c : num)
{
cout << setprecision(8) << std::fixed << c << setw(11);
}
cout << endl;
cout << endl;
}
Mat Trans_Gause = src_add_gause_noise.clone();
my_flitter.gause_filter(Trans_Gause, 0.8, 3);
imshow("高斯噪声——高斯滤波 Sigma=1", Trans_Gause);
}

//椒盐+高斯噪声
{
Mat src_add_salt_and_gause_noise;
src.convertTo(src_add_salt_and_gause_noise, CV_8UC1);
//添加椒盐噪声
my_flitter.add_salt_noise(src_add_salt_and_gause_noise, 3000);
//添加高斯噪声
my_flitter.add_gause_noise(src_add_salt_and_gause_noise);
imshow("添加椒盐+高斯噪声", src_add_salt_and_gause_noise);

//中值滤波
Mat Trans_Median = src_add_salt_and_gause_noise.clone();
my_flitter.median_flitter(Trans_Median,3);
imshow("椒盐+高斯噪声——中值滤波", Trans_Median);

//均值滤波
Mat Trans_Mean = src_add_salt_and_gause_noise.clone();
my_flitter.mean_flitter(Trans_Mean, 3);
imshow("椒盐+高斯噪声——均值滤波", Trans_Mean);

//高斯滤波
float sigma = 0.84089642; int size = 7;
vector<vector<float>> gaussTem = my_flitter.gause_template(1, 3);
for (auto num : gaussTem)
{
for (auto c : num)
{
cout << setprecision(8) << std::fixed << c << setw(11);
}
cout << endl;
cout << endl;
}
Mat Trans_Gause = src_add_salt_and_gause_noise.clone();
my_flitter.gause_filter(Trans_Gause, 0.8, 3);
imshow("椒盐+高斯噪声——高斯滤波 Sigma=1", Trans_Gause);
}

waitKey();
return 0;
}