-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdepth_map_utils.py
307 lines (259 loc) · 10.6 KB
/
depth_map_utils.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
import collections
import cv2
import numpy as np
# Full kernels
# FULL_KERNEL_3 = np.ones((3, 3), np.uint8)
# FULL_KERNEL_5 = np.ones((5, 5), np.uint8)
# FULL_KERNEL_7 = np.ones((7, 7), np.uint8)
# FULL_KERNEL_9 = np.ones((9, 9), np.uint8)
# FULL_KERNEL_31 = np.ones((31, 31), np.uint8)
FULL_KERNEL_3 = np.ones((1, 3), np.uint8)
FULL_KERNEL_5 = np.ones((1, 5), np.uint8)
FULL_KERNEL_7 = np.ones((1, 7), np.uint8)
FULL_KERNEL_9 = np.ones((1, 9), np.uint8)
FULL_KERNEL_31 = np.ones((3, 31), np.uint8)
# 3x3 cross kernel
CROSS_KERNEL_3 = np.asarray(
[
[0, 1, 0],
[1, 1, 1],
[0, 1, 0],
], dtype=np.uint8)
# 5x5 cross kernel
CROSS_KERNEL_5 = np.asarray(
[
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
], dtype=np.uint8)
# 5x5 diamond kernel
DIAMOND_KERNEL_5 = np.array(
[
[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0],
], dtype=np.uint8)
# 7x7 cross kernel
CROSS_KERNEL_7 = np.asarray(
[
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
], dtype=np.uint8)
# 7x7 diamond kernel
DIAMOND_KERNEL_7 = np.asarray(
[
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
], dtype=np.uint8)
def fill_in_fast(depth_map, max_depth=100.0, custom_kernel=DIAMOND_KERNEL_5,
extrapolate=False, blur_type='bilateral'):
"""Fast, in-place depth completion.
Args:
depth_map: projected depths
max_depth: max depth value for inversion
custom_kernel: kernel to apply initial dilation
extrapolate: whether to extrapolate by extending depths to top of
the frame, and applying a 31x31 full kernel dilation
blur_type:
'bilateral' - preserves local structure (recommended)
'gaussian' - provides lower RMSE
Returns:
depth_map: dense depth map
"""
# for i in range(0, 100):
# empty_pixels = depth_map < 0.1
# dilated = cv2.dilate(depth_map, np.ones((2, 2), np.uint8))
# depth_map[empty_pixels] = dilated[empty_pixels]
# empty_pixels = depth_map < 0.1
# dilated = cv2.dilate(depth_map, np.ones((2, 2), np.uint8))
# depth_map[empty_pixels] = dilated[empty_pixels]
# Invert
valid_pixels = (depth_map > 0.1)
depth_map[valid_pixels] = max_depth - depth_map[valid_pixels]
for i in range(0, 100):
empty_pixels = depth_map < 0.1
dilated = cv2.dilate(depth_map, np.ones((2, 2), np.uint8))
depth_map[empty_pixels] = dilated[empty_pixels]
# # Dilate
# depth_map = cv2.dilate(depth_map, custom_kernel)
#
# # Hole closing
# depth_map = cv2.morphologyEx(depth_map, cv2.MORPH_CLOSE, FULL_KERNEL_5)
#
# # Fill empty spaces with dilated values
# empty_pixels = (depth_map < 0.1)
# dilated = cv2.dilate(depth_map, FULL_KERNEL_7)
# depth_map[empty_pixels] = dilated[empty_pixels]
# # Extend highest pixel to top of image
# if extrapolate:
# top_row_pixels = np.argmax(depth_map > 0.1, axis=0)
# top_pixel_values = depth_map[top_row_pixels, range(depth_map.shape[1])]
#
# for pixel_col_idx in range(depth_map.shape[1]):
# depth_map[0:top_row_pixels[pixel_col_idx], pixel_col_idx] = \
# top_pixel_values[pixel_col_idx]
#
# # Large Fill
# empty_pixels = depth_map < 0.1
# dilated = cv2.dilate(depth_map, FULL_KERNEL_31)
# depth_map[empty_pixels] = dilated[empty_pixels]
#
# # Median blur
# # depth_map = cv2.medianBlur(depth_map, )
#
# # # Bilateral or Gaussian blur
# # if blur_type == 'bilateral':
# # # Bilateral blur
# # depth_map = cv2.bilateralFilter(depth_map, 5, 1.5, 2.0)
# # elif blur_type == 'gaussian':
# # # Gaussian blur
# # valid_pixels = (depth_map > 0.1)
# # blurred = cv2.GaussianBlur(depth_map, (5, 5), 0)
# # depth_map[valid_pixels] = blurred[valid_pixels]
#
# Invert
valid_pixels = (depth_map > 0.1)
depth_map[valid_pixels] = max_depth - depth_map[valid_pixels]
return depth_map
def fill_in_multiscale(depth_map, max_depth=100.0,
dilation_kernel_far=CROSS_KERNEL_3,
dilation_kernel_med=CROSS_KERNEL_5,
dilation_kernel_near=CROSS_KERNEL_7,
extrapolate=False,
blur_type='bilateral',
show_process=False):
"""Slower, multi-scale dilation version with additional noise removal that
provides better qualitative results.
Args:
depth_map: projected depths
max_depth: max depth value for inversion
dilation_kernel_far: dilation kernel to use for 30.0 < depths < 80.0 m
dilation_kernel_med: dilation kernel to use for 15.0 < depths < 30.0 m
dilation_kernel_near: dilation kernel to use for 0.1 < depths < 15.0 m
extrapolate:whether to extrapolate by extending depths to top of
the frame, and applying a 31x31 full kernel dilation
blur_type:
'gaussian' - provides lower RMSE
'bilateral' - preserves local structure (recommended)
show_process: saves process images into an OrderedDict
Returns:
depth_map: dense depth map
process_dict: OrderedDict of process images
"""
# Convert to float32
depths_in = np.float32(depth_map)
# Calculate bin masks before inversion
valid_pixels_near = (depths_in > 0.1) & (depths_in <= 15.0)
valid_pixels_med = (depths_in > 15.0) & (depths_in <= 30.0)
valid_pixels_far = (depths_in > 30.0)
# Invert (and offset)
s1_inverted_depths = np.copy(depths_in)
valid_pixels = (s1_inverted_depths > 0.1)
s1_inverted_depths[valid_pixels] = \
max_depth - s1_inverted_depths[valid_pixels]
# Multi-scale dilation
dilated_far = cv2.dilate(
np.multiply(s1_inverted_depths, valid_pixels_far),
dilation_kernel_far)
dilated_med = cv2.dilate(
np.multiply(s1_inverted_depths, valid_pixels_med),
dilation_kernel_med)
dilated_near = cv2.dilate(
np.multiply(s1_inverted_depths, valid_pixels_near),
dilation_kernel_near)
# Find valid pixels for each binned dilation
valid_pixels_near = (dilated_near > 0.1)
valid_pixels_med = (dilated_med > 0.1)
valid_pixels_far = (dilated_far > 0.1)
# Combine dilated versions, starting farthest to nearest
s2_dilated_depths = np.copy(s1_inverted_depths)
s2_dilated_depths[valid_pixels_far] = dilated_far[valid_pixels_far]
s2_dilated_depths[valid_pixels_med] = dilated_med[valid_pixels_med]
s2_dilated_depths[valid_pixels_near] = dilated_near[valid_pixels_near]
# Small hole closure
s3_closed_depths = cv2.morphologyEx(
s2_dilated_depths, cv2.MORPH_CLOSE, FULL_KERNEL_5)
# Median blur to remove outliers
s4_blurred_depths = np.copy(s3_closed_depths)
blurred = cv2.medianBlur(s3_closed_depths, 5)
valid_pixels = (s3_closed_depths > 0.1)
s4_blurred_depths[valid_pixels] = blurred[valid_pixels]
# Calculate a top mask
top_mask = np.ones(depths_in.shape, dtype=np.bool)
for pixel_col_idx in range(s4_blurred_depths.shape[1]):
pixel_col = s4_blurred_depths[:, pixel_col_idx]
top_pixel_row = np.argmax(pixel_col > 0.1)
top_mask[0:top_pixel_row, pixel_col_idx] = False
# Get empty mask
valid_pixels = (s4_blurred_depths > 0.1)
empty_pixels = ~valid_pixels & top_mask
# Hole fill
dilated = cv2.dilate(s4_blurred_depths, FULL_KERNEL_9)
s5_dilated_depths = np.copy(s4_blurred_depths)
s5_dilated_depths[empty_pixels] = dilated[empty_pixels]
# Extend highest pixel to top of image or create top mask
s6_extended_depths = np.copy(s5_dilated_depths)
top_mask = np.ones(s5_dilated_depths.shape, dtype=np.bool)
top_row_pixels = np.argmax(s5_dilated_depths > 0.1, axis=0)
top_pixel_values = s5_dilated_depths[top_row_pixels,
range(s5_dilated_depths.shape[1])]
for pixel_col_idx in range(s5_dilated_depths.shape[1]):
if extrapolate:
s6_extended_depths[0:top_row_pixels[pixel_col_idx],
pixel_col_idx] = top_pixel_values[pixel_col_idx]
else:
# Create top mask
top_mask[0:top_row_pixels[pixel_col_idx], pixel_col_idx] = False
# Fill large holes with masked dilations
s7_blurred_depths = np.copy(s6_extended_depths)
for i in range(6):
empty_pixels = (s7_blurred_depths < 0.1) & top_mask
dilated = cv2.dilate(s7_blurred_depths, FULL_KERNEL_5)
s7_blurred_depths[empty_pixels] = dilated[empty_pixels]
# Median blur
blurred = cv2.medianBlur(s7_blurred_depths, 5)
valid_pixels = (s7_blurred_depths > 0.1) & top_mask
s7_blurred_depths[valid_pixels] = blurred[valid_pixels]
if blur_type == 'gaussian':
# Gaussian blur
blurred = cv2.GaussianBlur(s7_blurred_depths, (5, 5), 0)
valid_pixels = (s7_blurred_depths > 0.1) & top_mask
s7_blurred_depths[valid_pixels] = blurred[valid_pixels]
elif blur_type == 'bilateral':
# Bilateral blur
blurred = cv2.bilateralFilter(s7_blurred_depths, 5, 0.5, 2.0)
s7_blurred_depths[valid_pixels] = blurred[valid_pixels]
# Invert (and offset)
s8_inverted_depths = np.copy(s7_blurred_depths)
valid_pixels = np.where(s8_inverted_depths > 0.1)
s8_inverted_depths[valid_pixels] = \
max_depth - s8_inverted_depths[valid_pixels]
depths_out = s8_inverted_depths
process_dict = None
if show_process:
process_dict = collections.OrderedDict()
process_dict['s0_depths_in'] = depths_in
process_dict['s1_inverted_depths'] = s1_inverted_depths
process_dict['s2_dilated_depths'] = s2_dilated_depths
process_dict['s3_closed_depths'] = s3_closed_depths
process_dict['s4_blurred_depths'] = s4_blurred_depths
process_dict['s5_combined_depths'] = s5_dilated_depths
process_dict['s6_extended_depths'] = s6_extended_depths
process_dict['s7_blurred_depths'] = s7_blurred_depths
process_dict['s8_inverted_depths'] = s8_inverted_depths
process_dict['s9_depths_out'] = depths_out
return depths_out, process_dict