xinsir commited on
Commit
8a192aa
·
verified ·
1 Parent(s): 46a61d5

Upload guided_filter.py

Browse files
Files changed (1) hide show
  1. guided_filter.py +281 -0
guided_filter.py ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # -*- coding: utf-8 -*-
3
+ ## @package guided_filter.core.filters
4
+ #
5
+ # Implementation of guided filter.
6
+ # * GuidedFilter: Original guided filter.
7
+ # * FastGuidedFilter: Fast version of the guided filter.
8
+ # @author tody
9
+ # @date 2015/08/26
10
+
11
+ import numpy as np
12
+ import cv2
13
+
14
+ ## Convert image into float32 type.
15
+ def to32F(img):
16
+ if img.dtype == np.float32:
17
+ return img
18
+ return (1.0 / 255.0) * np.float32(img)
19
+
20
+ ## Convert image into uint8 type.
21
+ def to8U(img):
22
+ if img.dtype == np.uint8:
23
+ return img
24
+ return np.clip(np.uint8(255.0 * img), 0, 255)
25
+
26
+ ## Return if the input image is gray or not.
27
+ def _isGray(I):
28
+ return len(I.shape) == 2
29
+
30
+
31
+ ## Return down sampled image.
32
+ # @param scale (w/s, h/s) image will be created.
33
+ # @param shape I.shape[:2]=(h, w). numpy friendly size parameter.
34
+ def _downSample(I, scale=4, shape=None):
35
+ if shape is not None:
36
+ h, w = shape
37
+ return cv2.resize(I, (w, h), interpolation=cv2.INTER_NEAREST)
38
+
39
+ h, w = I.shape[:2]
40
+ return cv2.resize(I, (int(w / scale), int(h / scale)), interpolation=cv2.INTER_NEAREST)
41
+
42
+
43
+ ## Return up sampled image.
44
+ # @param scale (w*s, h*s) image will be created.
45
+ # @param shape I.shape[:2]=(h, w). numpy friendly size parameter.
46
+ def _upSample(I, scale=2, shape=None):
47
+ if shape is not None:
48
+ h, w = shape
49
+ return cv2.resize(I, (w, h), interpolation=cv2.INTER_LINEAR)
50
+
51
+ h, w = I.shape[:2]
52
+ return cv2.resize(I, (int(w * scale), int(h * scale)), interpolation=cv2.INTER_LINEAR)
53
+
54
+ ## Fast guide filter.
55
+ class FastGuidedFilter:
56
+ ## Constructor.
57
+ # @param I Input guidance image. Color or gray.
58
+ # @param radius Radius of Guided Filter.
59
+ # @param epsilon Regularization term of Guided Filter.
60
+ # @param scale Down sampled scale.
61
+ def __init__(self, I, radius=5, epsilon=0.4, scale=4):
62
+ I_32F = to32F(I)
63
+ self._I = I_32F
64
+ h, w = I.shape[:2]
65
+
66
+ I_sub = _downSample(I_32F, scale)
67
+
68
+ self._I_sub = I_sub
69
+ radius = int(radius / scale)
70
+
71
+ if _isGray(I):
72
+ self._guided_filter = GuidedFilterGray(I_sub, radius, epsilon)
73
+ else:
74
+ self._guided_filter = GuidedFilterColor(I_sub, radius, epsilon)
75
+
76
+ ## Apply filter for the input image.
77
+ # @param p Input image for the filtering.
78
+ def filter(self, p):
79
+ p_32F = to32F(p)
80
+ shape_original = p.shape[:2]
81
+
82
+ p_sub = _downSample(p_32F, shape=self._I_sub.shape[:2])
83
+
84
+ if _isGray(p_sub):
85
+ return self._filterGray(p_sub, shape_original)
86
+
87
+ cs = p.shape[2]
88
+ q = np.array(p_32F)
89
+
90
+ for ci in range(cs):
91
+ q[:, :, ci] = self._filterGray(p_sub[:, :, ci], shape_original)
92
+ return to8U(q)
93
+
94
+ def _filterGray(self, p_sub, shape_original):
95
+ ab_sub = self._guided_filter._computeCoefficients(p_sub)
96
+ ab = [_upSample(abi, shape=shape_original) for abi in ab_sub]
97
+ return self._guided_filter._computeOutput(ab, self._I)
98
+
99
+
100
+ ## Guide filter.
101
+ class GuidedFilter:
102
+ ## Constructor.
103
+ # @param I Input guidance image. Color or gray.
104
+ # @param radius Radius of Guided Filter.
105
+ # @param epsilon Regularization term of Guided Filter.
106
+ def __init__(self, I, radius=5, epsilon=0.4):
107
+ I_32F = to32F(I)
108
+
109
+ if _isGray(I):
110
+ self._guided_filter = GuidedFilterGray(I_32F, radius, epsilon)
111
+ else:
112
+ self._guided_filter = GuidedFilterColor(I_32F, radius, epsilon)
113
+
114
+ ## Apply filter for the input image.
115
+ # @param p Input image for the filtering.
116
+ def filter(self, p):
117
+ return to8U(self._guided_filter.filter(p))
118
+
119
+
120
+ ## Common parts of guided filter.
121
+ #
122
+ # This class is used by guided_filter class. GuidedFilterGray and GuidedFilterColor.
123
+ # Based on guided_filter._computeCoefficients, guided_filter._computeOutput,
124
+ # GuidedFilterCommon.filter computes filtered image for color and gray.
125
+ class GuidedFilterCommon:
126
+ def __init__(self, guided_filter):
127
+ self._guided_filter = guided_filter
128
+
129
+ ## Apply filter for the input image.
130
+ # @param p Input image for the filtering.
131
+ def filter(self, p):
132
+ p_32F = to32F(p)
133
+ if _isGray(p_32F):
134
+ return self._filterGray(p_32F)
135
+
136
+ cs = p.shape[2]
137
+ q = np.array(p_32F)
138
+
139
+ for ci in range(cs):
140
+ q[:, :, ci] = self._filterGray(p_32F[:, :, ci])
141
+ return q
142
+
143
+ def _filterGray(self, p):
144
+ ab = self._guided_filter._computeCoefficients(p)
145
+ return self._guided_filter._computeOutput(ab, self._guided_filter._I)
146
+
147
+
148
+ ## Guided filter for gray guidance image.
149
+ class GuidedFilterGray:
150
+ # @param I Input gray guidance image.
151
+ # @param radius Radius of Guided Filter.
152
+ # @param epsilon Regularization term of Guided Filter.
153
+ def __init__(self, I, radius=5, epsilon=0.4):
154
+ self._radius = 2 * radius + 1
155
+ self._epsilon = epsilon
156
+ self._I = to32F(I)
157
+ self._initFilter()
158
+ self._filter_common = GuidedFilterCommon(self)
159
+
160
+ ## Apply filter for the input image.
161
+ # @param p Input image for the filtering.
162
+ def filter(self, p):
163
+ return self._filter_common.filter(p)
164
+
165
+ def _initFilter(self):
166
+ I = self._I
167
+ r = self._radius
168
+ self._I_mean = cv2.blur(I, (r, r))
169
+ I_mean_sq = cv2.blur(I ** 2, (r, r))
170
+ self._I_var = I_mean_sq - self._I_mean ** 2
171
+
172
+ def _computeCoefficients(self, p):
173
+ r = self._radius
174
+ p_mean = cv2.blur(p, (r, r))
175
+ p_cov = p_mean - self._I_mean * p_mean
176
+ a = p_cov / (self._I_var + self._epsilon)
177
+ b = p_mean - a * self._I_mean
178
+ a_mean = cv2.blur(a, (r, r))
179
+ b_mean = cv2.blur(b, (r, r))
180
+ return a_mean, b_mean
181
+
182
+ def _computeOutput(self, ab, I):
183
+ a_mean, b_mean = ab
184
+ return a_mean * I + b_mean
185
+
186
+
187
+ ## Guided filter for color guidance image.
188
+ class GuidedFilterColor:
189
+ # @param I Input color guidance image.
190
+ # @param radius Radius of Guided Filter.
191
+ # @param epsilon Regularization term of Guided Filter.
192
+ def __init__(self, I, radius=5, epsilon=0.2):
193
+ self._radius = 2 * radius + 1
194
+ self._epsilon = epsilon
195
+ self._I = to32F(I)
196
+ self._initFilter()
197
+ self._filter_common = GuidedFilterCommon(self)
198
+
199
+ ## Apply filter for the input image.
200
+ # @param p Input image for the filtering.
201
+ def filter(self, p):
202
+ return self._filter_common.filter(p)
203
+
204
+ def _initFilter(self):
205
+ I = self._I
206
+ r = self._radius
207
+ eps = self._epsilon
208
+
209
+ Ir, Ig, Ib = I[:, :, 0], I[:, :, 1], I[:, :, 2]
210
+
211
+ self._Ir_mean = cv2.blur(Ir, (r, r))
212
+ self._Ig_mean = cv2.blur(Ig, (r, r))
213
+ self._Ib_mean = cv2.blur(Ib, (r, r))
214
+
215
+ Irr_var = cv2.blur(Ir ** 2, (r, r)) - self._Ir_mean ** 2 + eps
216
+ Irg_var = cv2.blur(Ir * Ig, (r, r)) - self._Ir_mean * self._Ig_mean
217
+ Irb_var = cv2.blur(Ir * Ib, (r, r)) - self._Ir_mean * self._Ib_mean
218
+ Igg_var = cv2.blur(Ig * Ig, (r, r)) - self._Ig_mean * self._Ig_mean + eps
219
+ Igb_var = cv2.blur(Ig * Ib, (r, r)) - self._Ig_mean * self._Ib_mean
220
+ Ibb_var = cv2.blur(Ib * Ib, (r, r)) - self._Ib_mean * self._Ib_mean + eps
221
+
222
+ Irr_inv = Igg_var * Ibb_var - Igb_var * Igb_var
223
+ Irg_inv = Igb_var * Irb_var - Irg_var * Ibb_var
224
+ Irb_inv = Irg_var * Igb_var - Igg_var * Irb_var
225
+ Igg_inv = Irr_var * Ibb_var - Irb_var * Irb_var
226
+ Igb_inv = Irb_var * Irg_var - Irr_var * Igb_var
227
+ Ibb_inv = Irr_var * Igg_var - Irg_var * Irg_var
228
+
229
+ I_cov = Irr_inv * Irr_var + Irg_inv * Irg_var + Irb_inv * Irb_var
230
+ Irr_inv /= I_cov
231
+ Irg_inv /= I_cov
232
+ Irb_inv /= I_cov
233
+ Igg_inv /= I_cov
234
+ Igb_inv /= I_cov
235
+ Ibb_inv /= I_cov
236
+
237
+ self._Irr_inv = Irr_inv
238
+ self._Irg_inv = Irg_inv
239
+ self._Irb_inv = Irb_inv
240
+ self._Igg_inv = Igg_inv
241
+ self._Igb_inv = Igb_inv
242
+ self._Ibb_inv = Ibb_inv
243
+
244
+ def _computeCoefficients(self, p):
245
+ r = self._radius
246
+ I = self._I
247
+ Ir, Ig, Ib = I[:, :, 0], I[:, :, 1], I[:, :, 2]
248
+
249
+ p_mean = cv2.blur(p, (r, r))
250
+
251
+ Ipr_mean = cv2.blur(Ir * p, (r, r))
252
+ Ipg_mean = cv2.blur(Ig * p, (r, r))
253
+ Ipb_mean = cv2.blur(Ib * p, (r, r))
254
+
255
+ Ipr_cov = Ipr_mean - self._Ir_mean * p_mean
256
+ Ipg_cov = Ipg_mean - self._Ig_mean * p_mean
257
+ Ipb_cov = Ipb_mean - self._Ib_mean * p_mean
258
+
259
+ ar = self._Irr_inv * Ipr_cov + self._Irg_inv * Ipg_cov + self._Irb_inv * Ipb_cov
260
+ ag = self._Irg_inv * Ipr_cov + self._Igg_inv * Ipg_cov + self._Igb_inv * Ipb_cov
261
+ ab = self._Irb_inv * Ipr_cov + self._Igb_inv * Ipg_cov + self._Ibb_inv * Ipb_cov
262
+ b = p_mean - ar * self._Ir_mean - ag * self._Ig_mean - ab * self._Ib_mean
263
+
264
+ ar_mean = cv2.blur(ar, (r, r))
265
+ ag_mean = cv2.blur(ag, (r, r))
266
+ ab_mean = cv2.blur(ab, (r, r))
267
+ b_mean = cv2.blur(b, (r, r))
268
+
269
+ return ar_mean, ag_mean, ab_mean, b_mean
270
+
271
+ def _computeOutput(self, ab, I):
272
+ ar_mean, ag_mean, ab_mean, b_mean = ab
273
+
274
+ Ir, Ig, Ib = I[:, :, 0], I[:, :, 1], I[:, :, 2]
275
+
276
+ q = (ar_mean * Ir +
277
+ ag_mean * Ig +
278
+ ab_mean * Ib +
279
+ b_mean)
280
+
281
+ return q