1+ // 针对灰度图的中值滤波+CVPR 2019的SideWindowFilter
2+ // 其他种类的滤波直接换核即可
3+
4+ // 记录每一个方向的核的不为0的元素个数
5+ int cnt[8 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
6+ // 记录每一个方向的滤波器
7+ vector <int > filter[8 ];
8+
9+ // 初始化半径为radius的滤波器,原理可以看https://mp.weixin.qq.com/s/vjzZjRoQw7MnkqAfvwBUNA
10+ void InitFilter (int radius) {
11+ int n = radius * 2 + 1 ;
12+ for (int i = 0 ; i < 8 ; i++) {
13+ cnt[i] = 0 ;
14+ filter[i].clear ();
15+ }
16+ for (int i = 0 ; i < 8 ; i++) {
17+ for (int x = 0 ; x < n; x++) {
18+ for (int y = 0 ; y < n; y++) {
19+ if (i == 0 && x <= radius && y <= radius) {
20+ filter[i].push_back (1 );
21+ }
22+ else if (i == 1 && x <= radius && y >= radius) {
23+ filter[i].push_back (1 );
24+ }
25+ else if (i == 2 && x >= radius && y <= radius) {
26+ filter[i].push_back (1 );
27+ }
28+ else if (i == 3 && x >= radius && y >= radius) {
29+ filter[i].push_back (1 );
30+ }
31+ else if (i == 4 && x <= radius) {
32+ filter[i].push_back (1 );
33+ }
34+ else if (i == 5 && x >= radius) {
35+ filter[i].push_back (1 );
36+ }
37+ else if (i == 6 && y >= radius) {
38+ filter[i].push_back (1 );
39+ }
40+ else if (i == 7 && y <= radius) {
41+ filter[i].push_back (1 );
42+ }
43+ else {
44+ filter[i].push_back (0 );
45+ }
46+ }
47+ }
48+ }
49+ for (int i = 0 ; i < 8 ; i++) {
50+ int sum = 0 ;
51+ for (int j = 0 ; j < filter[i].size (); j++) sum += filter[i][j] == 1 ;
52+ cnt[i] = sum;
53+ }
54+ }
55+
56+ // 实现Side Window Filter的中值滤波,强制保边
57+ Mat MedianSideWindowFilter (Mat src, int radius = 1 ) {
58+ int row = src.rows ;
59+ int col = src.cols ;
60+ int channels = src.channels ();
61+ InitFilter (radius);
62+ // 针对灰度图
63+ if (channels == 1 ) {
64+ Mat dst (row, col, CV_8UC1);
65+ for (int i = 0 ; i < row; i++) {
66+ for (int j = 0 ; j < col; j++) {
67+ if (i < radius || i + radius >= row || j < radius || j + radius >= col) {
68+ dst.at <uchar>(i, j) = src.at <uchar>(i, j);
69+ continue ;
70+ }
71+ int minn = 256 ;
72+ int pos = 0 ;
73+ for (int k = 0 ; k < 8 ; k++) {
74+ int val = 0 ;
75+ int id = 0 ;
76+ vector <int > now;
77+ for (int x = -radius; x <= radius; x++) {
78+ for (int y = -radius; y <= radius; y++) {
79+ // if (x == 0 && y == 0) continue;
80+ now.push_back (src.at <uchar>(i + x, j + y) * filter[k][id++]);
81+ // val += src.at<uchar>(i + x, j + y) * filter[k][id++];
82+ }
83+ }
84+ sort (now.begin (), now.end ());
85+ val = now[(2 * radius + 1 )*(2 * radius + 1 ) / 2 ];
86+ if (abs (val - src.at <uchar>(i, j)) < minn) {
87+ minn = abs (val - src.at <uchar>(i, j));
88+ pos = k;
89+ }
90+ }
91+ int val = 0 ;
92+ int id = 0 ;
93+ vector <int > now;
94+ for (int x = -radius; x <= radius; x++) {
95+ for (int y = -radius; y <= radius; y++) {
96+ // if (x == 0 && y == 0) continue;
97+ now.push_back (src.at <uchar>(i + x, j + y) * filter[pos][id++]);
98+ // val += src.at<uchar>(i + x, j + y) * filter[k][id++];
99+ }
100+ }
101+ sort (now.begin (), now.end ());
102+ val = now[(2 * radius + 1 )*(2 * radius + 1 ) / 2 ];
103+ dst.at <uchar>(i, j) = val;
104+ }
105+ }
106+ return dst;
107+ }
108+ // 针对RGB图
109+ Mat dst (row, col, CV_8UC3);
110+ for (int c = 0 ; c < 3 ; c++) {
111+ for (int i = 0 ; i < row; i++) {
112+ for (int j = 0 ; j < col; j++) {
113+ if (i < radius || i + radius >= row || j < radius || j + radius >= col) {
114+ dst.at <Vec3b>(i, j)[c] = src.at <Vec3b>(i, j)[c];
115+ continue ;
116+ }
117+ int minn = 256 ;
118+ int pos = 0 ;
119+ for (int k = 0 ; k < 8 ; k++) {
120+ int val = 0 ;
121+ int id = 0 ;
122+ vector <int > now;
123+ for (int x = -radius; x <= radius; x++) {
124+ for (int y = -radius; y <= radius; y++) {
125+ // if (x == 0 && y == 0) continue;
126+ // val += src.at<Vec3b>(i + x, j + y)[c] * filter[k][id++];
127+ now.push_back (src.at <Vec3b>(i + x, j + y)[c] * filter[k][id++]);
128+ }
129+ }
130+ val = now[(2 * radius + 1 )*(2 * radius + 1 ) / 2 ];
131+ if (abs (val - src.at <Vec3b>(i, j)[c]) < minn) {
132+ minn = abs (val - src.at <Vec3b>(i, j)[c]);
133+ pos = k;
134+ }
135+ }
136+ int val = 0 ;
137+ int id = 0 ;
138+ vector <int > now;
139+ for (int x = -radius; x <= radius; x++) {
140+ for (int y = -radius; y <= radius; y++) {
141+ // if (x == 0 && y == 0) continue;
142+ // val += src.at<Vec3b>(i + x, j + y)[c] * filter[k][id++];
143+ now.push_back (src.at <Vec3b>(i + x, j + y)[c] * filter[pos][id++]);
144+ }
145+ }
146+ val = now[(2 * radius + 1 )*(2 * radius + 1 ) / 2 ];
147+ dst.at <Vec3b>(i, j)[c] = val;
148+ }
149+ }
150+ }
151+ return dst;
152+ }
153+
154+
155+ int main () {
156+ Mat src = imread (" F:\\ 1.jpg" );
157+ for (int i = 0 ; i < 10 ; i++) {
158+ src = MedianSideWindowFilter (src, 3 );
159+ }
160+ imwrite (" F:\\ res.jpg" , src);
161+ return 0 ;
162+ }
0 commit comments