-
Notifications
You must be signed in to change notification settings - Fork 6
/
bilateralfilter.py
94 lines (90 loc) · 4.31 KB
/
bilateralfilter.py
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
import numpy as np
import cv2
import time
# image: input image
# texture: guidance image
# sigma_s: spatial parameter (pixels)
# sigma_r: range parameter (not normalized)
def bilateralfilter(image, texture, sigma_s, sigma_r):
r = int(np.ceil(3 * sigma_s))
# Image padding
if image.ndim == 3:
h, w, ch = image.shape
I = np.pad(image, ((r, r), (r, r), (0, 0)), 'symmetric').astype(np.float32)
elif image.ndim == 2:
h, w = image.shape
I = np.pad(image, ((r, r), (r, r)), 'symmetric').astype(np.float32)
else:
print('Input image is not valid!')
return image
# Check texture size and do padding
if texture.ndim == 3:
ht, wt, cht = texture.shape
if ht != h or wt != w:
print('The guidance image is not aligned with input image!')
return image
T = np.pad(texture, ((r, r), (r, r), (0, 0)), 'symmetric').astype(np.int32)
elif texture.ndim == 2:
ht, wt = texture.shape
if ht != h or wt != w:
print('The guidance image is not aligned with input image!')
return image
T = np.pad(texture, ((r, r), (r, r)), 'symmetric').astype(np.int32)
# Pre-compute
output = np.zeros_like(image)
scaleFactor_s = 1 / (2 * sigma_s * sigma_s)
scaleFactor_r = 1 / (2 * sigma_r * sigma_r)
# A lookup table for range kernel
LUT = np.exp(-np.arange(256) * np.arange(256) * scaleFactor_r)
# Generate a spatial Gaussian function
x, y = np.meshgrid(np.arange(2 * r + 1) - r, np.arange(2 * r + 1) - r)
kernel_s = np.exp(-(x * x + y * y) * scaleFactor_s)
# Main body
if I.ndim == 2 and T.ndim == 2: # I1T1 filter
for y in range(r, r + h):
for x in range(r, r + w):
wgt = LUT[np.abs(T[y - r:y + r + 1, x - r:x + r + 1] - T[y, x])] * kernel_s
output[y - r, x - r] = np.sum(wgt * I[y - r:y + r + 1, x - r:x + r + 1]) / np.sum(wgt)
elif I.ndim == 3 and T.ndim == 2: # I3T1 filter
for y in range(r, r + h):
for x in range(r, r + w):
wgt = LUT[abs(T[y - r:y + r + 1, x - r:x + r + 1] - T[y, x])] * kernel_s
wacc = np.sum(wgt)
output[y - r, x - r, 0] = np.sum(wgt * I[y - r:y + r + 1, x - r:x + r + 1, 0]) / wacc
output[y - r, x - r, 1] = np.sum(wgt * I[y - r:y + r + 1, x - r:x + r + 1, 1]) / wacc
output[y - r, x - r, 2] = np.sum(wgt * I[y - r:y + r + 1, x - r:x + r + 1, 2]) / wacc
elif I.ndim == 3 and T.ndim == 3: # I3T3 filter
for y in range(r, r + h):
for x in range(r, r + w):
wgt = LUT[abs(T[y - r:y + r + 1, x - r:x + r + 1, 0] - T[y, x, 0])] * \
LUT[abs(T[y - r:y + r + 1, x - r:x + r + 1, 1] - T[y, x, 1])] * \
LUT[abs(T[y - r:y + r + 1, x - r:x + r + 1, 2] - T[y, x, 2])] * \
kernel_s
wacc = np.sum(wgt)
output[y - r, x - r, 0] = np.sum(wgt * I[y - r:y + r + 1, x - r:x + r + 1, 0]) / wacc
output[y - r, x - r, 1] = np.sum(wgt * I[y - r:y + r + 1, x - r:x + r + 1, 1]) / wacc
output[y - r, x - r, 2] = np.sum(wgt * I[y - r:y + r + 1, x - r:x + r + 1, 2]) / wacc
elif I.ndim == 2 and T.ndim == 3: # I1T3 filter
for y in range(r, r + h):
for x in range(r, r + w):
wgt = LUT[abs(T[y - r:y + r + 1, x - r:x + r + 1, 0] - T[y, x, 0])] * \
LUT[abs(T[y - r:y + r + 1, x - r:x + r + 1, 1] - T[y, x, 1])] * \
LUT[abs(T[y - r:y + r + 1, x - r:x + r + 1, 2] - T[y, x, 2])] * \
kernel_s
output[y - r, x - r] = np.sum(wgt * I[y - r:y + r + 1, x - r:x + r + 1]) / np.sum(wgt)
else:
print('Something wrong!')
return image
# return np.clip(output, 0, 255)
return output
if __name__ == '__main__':
sigma_s = 1
sigma_r = 0.1*255
img = cv2.imread('2c.png')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
tic = time.time()
img_bf = bilateralfilter(img, img_gray, sigma_s, sigma_r)
toc = time.time()
print('Elapsed time: %f sec.' % (toc - tic))
cv2.imwrite('2c_y.png', img_gray)
cv2.imwrite('output.png', img_bf)