C++实现均值滤波器和中值滤波器

C++实现均值滤波器和中值滤波器

代码实现均值滤波器和中值滤波器
在这里插入图片描述
由于中值滤波器是非线性滤波,不是卷积,所以均值和中值滤波分开实现。opencv版本为3.4.5

my_convolution.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef MY_CONVOLUTION
#define MY_CONVOLUTION
#include <opencv2/opencv.hpp>
class My_Convolution {
public:
My_Convolution();
~My_Convolution();
bool load_kernal(const cv::Mat kernal);//加载卷积核
void convolute(const cv::Mat &image, cv::Mat &dst);//卷积操作
private:
bool kernal_loaded;//是否已经加载卷积核
cv::Mat curr_kernal;//当前卷积核
int bios_x, bios_y;//记录偏移量
//计算每一个像素的掩模乘积之和
void compute_sum_of_product(int i, int j, int chan, cv::Mat &complete_image, cv::Mat & dst);
//将原图像转换成边框补全的图像
void complete_image_transform(const cv::Mat &image, cv::Mat &dst);
};
#endif // MY_CONVOLUTION

my_convolution.cpp

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
#include "my_convolution.h"
using namespace std;
using namespace cv;
My_Convolution::My_Convolution() {
kernal_loaded = false;
}
My_Convolution::~My_Convolution() {}
//加载卷积核
bool My_Convolution::load_kernal(const Mat kernal) {
if (kernal.cols % 2 == 1 && kernal.rows % 2 == 1) {
curr_kernal = kernal.clone();
bios_x = (kernal.cols - 1) / 2;
bios_y = (kernal.rows - 1) / 2;
kernal_loaded = true;
return true;
}
else {
cout << "The size of kernal is not suitable!" << endl;
return false;
}
}
//卷积操作
void My_Convolution::convolute(const Mat &image, Mat &dst) {
if (!kernal_loaded) {
cout << "kernal is empty!Please load the kernal first!" << endl;return;
}
Mat complete_image;
complete_image_transform(image, complete_image);
dst = Mat::zeros(image.rows, image.cols, image.type());
int channels = image.channels();//获取图像的通道数
if (channels == 3) {
for (int chan = 0;chan < channels;chan++) {
for (int i = 0;i < dst.rows;i++) {
for (int j = 0;j < dst.cols;j++) {
compute_sum_of_product(i, j, chan, complete_image, dst);
}
}
}
return;
}
if (channels == 1) {
for (int i = 0;i < dst.rows;i++) {
for (int j = 0;j < dst.cols;j++) {
compute_sum_of_product(i, j, 0, complete_image, dst);
}
}
}
}
//计算掩模乘积之和
void My_Convolution::compute_sum_of_product(int i, int j, int chan, Mat &complete_image, Mat &dst) {
if (complete_image.channels() == 3) {
float sum = 0;
int bios_rows = i;
int bios_cols = j;
for (int curr_rows = 0;curr_rows < curr_kernal.rows;curr_rows++) {
for (int curr_cols = 0;curr_cols < curr_kernal.cols;curr_cols++) {
float a = curr_kernal.at<float>(curr_rows, curr_cols)*complete_image.at<Vec3b>(curr_rows + bios_rows, curr_cols + bios_cols)[chan];
sum += a;
}
}
dst.at<Vec3b>(i, j)[chan] = (int)sum;
}
else if (complete_image.channels() == 1) {
float sum = 0;
int bios_rows = i;
int bios_cols = j;
for (int curr_rows = 0;curr_rows < curr_kernal.rows;curr_rows++) {
for (int curr_cols = 0;curr_cols < curr_kernal.cols;curr_cols++) {
float a = curr_kernal.at<float>(curr_rows, curr_cols)*complete_image.at<uchar>(curr_rows + bios_rows, curr_cols + bios_cols);
sum += a;
}
}
dst.at<uchar>(i, j) = (int)sum;
}
else {
cout << "the type of image is not suitable!" << endl;return;
}
}
//边框像素补全
void My_Convolution::complete_image_transform(const Mat &image, Mat &dst) {
if (!kernal_loaded) {
cout << "kernal is empty!" << endl;
return;
}
//Mat的type()成员函数生成CV_<位数>(S/U/F)C<通道数>
//初始化一个补全图像的大小。
dst = Mat::zeros(2 * bios_y + image.rows, 2 * bios_x + image.cols, image.type());
Rect real_roi_of_image = Rect(bios_x, bios_y, image.cols, image.rows);
Mat real_mat_of_image = dst(real_roi_of_image);
image.copyTo(real_mat_of_image);
}

my_nedianfilter.h

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef MY_MEDIANFILTER
#define MY_MEDIANFILTER
#include <vector>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void MedianFilter(Mat& src, Mat& dst, int win_size);
void Complete_Image_Transform(Mat &src, Mat &comp, int size);
void Calc_Median(Mat& comp, Mat& dst, int r, int c, int s);
#endif

my_nedianfilter.cpp

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
#include "my_medianfilter.h"
void MedianFilter(Mat& src, Mat& dst, int win_size) {
Mat comp = src.clone();
Complete_Image_Transform(src, comp, win_size);
int rows = comp.rows, cols = comp.cols;
int start = win_size / 2;
if (comp.channels() > 1)
{
//彩色图片通道分离
vector<Mat> channels_c, channels_d;
split(comp, channels_c);
split(comp, channels_d);
//滤波
for (int i = 0; i < 3; i++)
Calc_Median(channels_c[i], channels_d[i], rows, cols, start);
//合并彩色通道
merge(channels_d, dst);
}
else
Calc_Median(comp, dst, rows, cols, start);
}
//边框像素补全
void Complete_Image_Transform(Mat &src, Mat &comp, int size) {
//初始化一个补全图像的大小
comp = Mat::zeros(2 * (size / 2) + src.rows, 2 * (size / 2) + src.cols, src.type());
Rect real_roi_of_image = Rect((size / 2), (size / 2), src.cols, src.rows);
Mat real_mat_of_image = comp(real_roi_of_image);
src.copyTo(real_mat_of_image);
}
void Calc_Median(Mat& comp, Mat& dst, int r, int c, int s)
{
for (int m = s; m < r - s; m++) {
for (int n = s; n < c - s; n++) {
vector<uchar> model;
for (int i = -s + m; i <= s + m; i++) {
for (int j = -s + n; j <= s + n; j++) {
//cout << int(src.at<uchar>(i, j)) << endl;
model.push_back(comp.at<uchar>(i, j));
}
}
sort(model.begin(), model.end()); //采用快速排序进行
dst.at<uchar>(m - s, n - s) = model[(s * 2 + 1) * (s * 2 + 1) / 2];
}
}
}