1
+ #include < opencv2/opencv.hpp>
2
+ #include < iostream>
3
+ #include < algorithm>
4
+ #include < vector>
5
+ using namespace cv ;
6
+ using namespace std ;
7
+
8
+ cv::Mat guidedFilter (cv::Mat I, cv::Mat p, int r, double eps)
9
+ {
10
+ /*
11
+ % GUIDEDFILTER O(1) time implementation of guided filter.
12
+ %
13
+ % - guidance image: I (should be a gray-scale/single channel image)
14
+ % - filtering input image: p (should be a gray-scale/single channel image)
15
+ % - local window radius: r
16
+ % - regularization parameter: eps
17
+ */
18
+
19
+ cv::Mat _I;
20
+ I.convertTo (_I, CV_64FC1);
21
+ I = _I;
22
+
23
+ cv::Mat _p;
24
+ p.convertTo (_p, CV_64FC1);
25
+ p = _p;
26
+
27
+ // [hei, wid] = size(I);
28
+ int hei = I.rows ;
29
+ int wid = I.cols ;
30
+
31
+ // N = boxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels.
32
+ cv::Mat N;
33
+ cv::boxFilter (cv::Mat::ones (hei, wid, I.type ()), N, CV_64FC1, cv::Size (r, r));
34
+
35
+ // mean_I = boxfilter(I, r) ./ N;
36
+ cv::Mat mean_I;
37
+ cv::boxFilter (I, mean_I, CV_64FC1, cv::Size (r, r));
38
+
39
+ // mean_p = boxfilter(p, r) ./ N;
40
+ cv::Mat mean_p;
41
+ cv::boxFilter (p, mean_p, CV_64FC1, cv::Size (r, r));
42
+
43
+ // mean_Ip = boxfilter(I.*p, r) ./ N;
44
+ cv::Mat mean_Ip;
45
+ cv::boxFilter (I.mul (p), mean_Ip, CV_64FC1, cv::Size (r, r));
46
+
47
+ // cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.
48
+ cv::Mat cov_Ip = mean_Ip - mean_I.mul (mean_p);
49
+
50
+ // mean_II = boxfilter(I.*I, r) ./ N;
51
+ cv::Mat mean_II;
52
+ cv::boxFilter (I.mul (I), mean_II, CV_64FC1, cv::Size (r, r));
53
+
54
+ // var_I = mean_II - mean_I .* mean_I;
55
+ cv::Mat var_I = mean_II - mean_I.mul (mean_I);
56
+
57
+ // a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper;
58
+ cv::Mat a = cov_Ip / (var_I + eps);
59
+
60
+ // b = mean_p - a .* mean_I; % Eqn. (6) in the paper;
61
+ cv::Mat b = mean_p - a.mul (mean_I);
62
+
63
+ // mean_a = boxfilter(a, r) ./ N;
64
+ cv::Mat mean_a;
65
+ cv::boxFilter (a, mean_a, CV_64FC1, cv::Size (r, r));
66
+ mean_a = mean_a / N;
67
+
68
+ // mean_b = boxfilter(b, r) ./ N;
69
+ cv::Mat mean_b;
70
+ cv::boxFilter (b, mean_b, CV_64FC1, cv::Size (r, r));
71
+ mean_b = mean_b / N;
72
+
73
+ // q = mean_a .* I + mean_b; % Eqn. (8) in the paper;
74
+ cv::Mat q = mean_a.mul (I) + mean_b;
75
+
76
+ return q;
77
+ }
78
+
79
+
80
+ int rows, cols;
81
+ // 获取最小值矩阵
82
+ int **getMinChannel (cv::Mat img) {
83
+ rows = img.rows ;
84
+ cols = img.cols ;
85
+ if (img.channels () != 3 ) {
86
+ fprintf (stderr, " Input Error!" );
87
+ exit (-1 );
88
+ }
89
+ int **imgGray;
90
+ imgGray = new int *[rows];
91
+ for (int i = 0 ; i < rows; i++) {
92
+ imgGray[i] = new int [cols];
93
+ }
94
+ for (int i = 0 ; i < rows; i++) {
95
+ for (int j = 0 ; j < cols; j++) {
96
+ int loacalMin = 255 ;
97
+ for (int k = 0 ; k < 3 ; k++) {
98
+ if (img.at <Vec3b>(i, j)[k] < loacalMin) {
99
+ loacalMin = img.at <Vec3b>(i, j)[k];
100
+ }
101
+ }
102
+ imgGray[i][j] = loacalMin;
103
+ }
104
+ }
105
+ return imgGray;
106
+ }
107
+
108
+ // 求暗通道
109
+ int **getDarkChannel (int **img, int blockSize = 3 ) {
110
+ if (blockSize % 2 == 0 || blockSize < 3 ) {
111
+ fprintf (stderr, " blockSize is not odd or too small!" );
112
+ exit (-1 );
113
+ }
114
+ // 计算pool Size
115
+ int poolSize = (blockSize - 1 ) / 2 ;
116
+ int newHeight = rows + poolSize - 1 ;
117
+ int newWidth = cols + poolSize - 1 ;
118
+ int **imgMiddle;
119
+ imgMiddle = new int *[newHeight];
120
+ for (int i = 0 ; i < newHeight; i++) {
121
+ imgMiddle[i] = new int [newWidth];
122
+ }
123
+ for (int i = 0 ; i < newHeight; i++) {
124
+ for (int j = 0 ; j < newWidth; j++) {
125
+ if (i < rows && j < cols) {
126
+ imgMiddle[i][j] = img[i][j];
127
+ }
128
+ else {
129
+ imgMiddle[i][j] = 255 ;
130
+ }
131
+ }
132
+ }
133
+ int **imgDark;
134
+ imgDark = new int *[rows];
135
+ for (int i = 0 ; i < rows; i++) {
136
+ imgDark[i] = new int [cols];
137
+ }
138
+ int localMin = 255 ;
139
+ for (int i = poolSize; i < newHeight - poolSize; i++) {
140
+ for (int j = poolSize; j < newWidth - poolSize; j++) {
141
+ for (int k = i - poolSize; k < i + poolSize + 1 ; k++) {
142
+ for (int l = j - poolSize; l < j + poolSize + 1 ; l++) {
143
+ if (imgMiddle[k][l] < localMin) {
144
+ localMin = imgMiddle[k][l];
145
+ }
146
+ }
147
+ }
148
+ imgDark[i - poolSize][j - poolSize] = localMin;
149
+ }
150
+ }
151
+ return imgDark;
152
+ }
153
+
154
+ struct node {
155
+ int x, y, val;
156
+ node () {}
157
+ node (int _x, int _y, int _val) :x(_x), y(_y), val(_val) {}
158
+ bool operator <(const node &rhs) {
159
+ return val > rhs.val ;
160
+ }
161
+ };
162
+
163
+ // 估算全局大气光值
164
+ int getGlobalAtmosphericLightValue (int **darkChannel, cv::Mat img, bool meanMode = false , float percent = 0.001 ) {
165
+ int size = rows * cols;
166
+ std::vector <node> nodes;
167
+ for (int i = 0 ; i < rows; i++) {
168
+ for (int j = 0 ; j < cols; j++) {
169
+ node tmp;
170
+ tmp.x = i, tmp.y = j, tmp.val = darkChannel[i][j];
171
+ nodes.push_back (tmp);
172
+ }
173
+ }
174
+ sort (nodes.begin (), nodes.end ());
175
+ int atmosphericLight = 0 ;
176
+ if (int (percent*size) == 0 ) {
177
+ for (int i = 0 ; i < 3 ; i++) {
178
+ if (img.at <Vec3b>(nodes[0 ].x , nodes[0 ].y )[i] > atmosphericLight) {
179
+ atmosphericLight = img.at <Vec3b>(nodes[0 ].x , nodes[0 ].y )[i];
180
+ }
181
+ }
182
+ }
183
+ // 开启均值模式
184
+ if (meanMode == true ) {
185
+ int sum = 0 ;
186
+ for (int i = 0 ; i < int (percent*size); i++) {
187
+ for (int j = 0 ; j < 3 ; j++) {
188
+ sum = sum + img.at <Vec3b>(nodes[i].x , nodes[i].y )[j];
189
+ }
190
+ }
191
+ }
192
+ // 获取暗通道在前0.1%的位置的像素点在原图像中的最高亮度值
193
+ for (int i = 0 ; i < int (percent*size); i++) {
194
+ for (int j = 0 ; j < 3 ; j++) {
195
+ if (img.at <Vec3b>(nodes[i].x , nodes[i].y )[j] > atmosphericLight) {
196
+ atmosphericLight = img.at <Vec3b>(nodes[i].x , nodes[i].y )[j];
197
+ }
198
+ }
199
+ }
200
+ return atmosphericLight;
201
+ }
202
+
203
+ // 恢复原图像
204
+ // Omega 去雾比例 参数
205
+ // t0 最小透射率值
206
+ cv::Mat getRecoverScene (cv::Mat img, float omega = 0.95 , float t0 = 0.1 , int blockSize = 15 , bool meanModel = false , float percent = 0.001 ) {
207
+ int ** imgGray = getMinChannel (img);
208
+ int **imgDark = getDarkChannel (imgGray, blockSize = blockSize);
209
+ int atmosphericLight = getGlobalAtmosphericLightValue (imgDark, img, meanModel = meanModel, percent = percent);
210
+ float **imgDark2, **transmission;
211
+ imgDark2 = new float *[rows];
212
+ for (int i = 0 ; i < rows; i++) {
213
+ imgDark2[i] = new float [cols];
214
+ }
215
+ Mat B (rows, cols, CV_8UC1);
216
+ for (int i = 0 ; i < rows; i++) {
217
+ for (int j = 0 ; j < cols; j++) {
218
+ B.at <uchar>(i, j) = img.at <Vec3b>(i, j)[0 ];
219
+ }
220
+ }
221
+ Mat p (rows, cols, CV_64FC1);
222
+ for (int i = 0 ; i < rows; i++) {
223
+ for (int j = 0 ; j < cols; j++) {
224
+ p.at <double >(i, j) = 1 - omega * imgDark[i][j] / atmosphericLight;
225
+ }
226
+ }
227
+ Mat transmission_filter = guidedFilter (B, p, 80 , 1e-3 );
228
+ imshow (" transmission" , transmission_filter);
229
+ imwrite (" F:\\ res3.jpg" , transmission_filter);
230
+ waitKey (0 );
231
+ transmission = new float *[rows];
232
+ for (int i = 0 ; i < rows; i++) {
233
+ transmission[i] = new float [cols];
234
+ }
235
+ for (int i = 0 ; i < rows; i++) {
236
+ for (int j = 0 ; j < cols; j++) {
237
+ imgDark2[i][j] = float (imgDark[i][j]);
238
+ // transmission[i][j] = 1 - omega * imgDark[i][j] / atmosphericLight;
239
+ transmission[i][j] = transmission_filter.at <double >(i, j);
240
+ if (transmission[i][j] < 0.1 ) {
241
+ transmission[i][j] = 0.1 ;
242
+ }
243
+ }
244
+ }
245
+ cv::Mat dst (img.rows , img.cols , CV_8UC3);
246
+ for (int channel = 0 ; channel < 3 ; channel++) {
247
+ for (int i = 0 ; i < rows; i++) {
248
+ for (int j = 0 ; j < cols; j++) {
249
+ int temp = (img.at <Vec3b>(i, j)[channel] - atmosphericLight) / transmission[i][j] + atmosphericLight;
250
+ if (temp > 255 ) {
251
+ temp = 255 ;
252
+ }
253
+ if (temp < 0 ) {
254
+ temp = 0 ;
255
+ }
256
+ dst.at <Vec3b>(i, j)[channel] = temp;
257
+ }
258
+ }
259
+ }
260
+ return dst;
261
+ }
262
+
263
+ int main () {
264
+ Mat src = imread (" F:\\ fog\\ 3.jpg" );
265
+ // cv::Mat src = cv::imread("/home/zxy/CLionProjects/Acmtest/3.jpg");
266
+ rows = src.rows ;
267
+ cols = src.cols ;
268
+ cv::Mat dst = getRecoverScene (src);
269
+ cv::imshow (" origin" , src);
270
+ cv::imshow (" result" , dst);
271
+ cv::imwrite (" F:\\ res2.jpg" , dst);
272
+ waitKey (0 );
273
+ }
0 commit comments