-
Notifications
You must be signed in to change notification settings - Fork 1
/
depth_estimation.py
143 lines (125 loc) · 5.55 KB
/
depth_estimation.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
import numpy as np
from scipy.ndimage.interpolation import shift
from tqdm import trange
import matplotlib.pyplot as plt
from config import output_folder
class DepthEstimator:
"""
Uses Stero matching and guided image filtering to estimate depth
"""
def __init__(self, im1, im2, imname):
self.im1 = im1 / 255
self.im2 = im2 / 255
self.imname = imname
self.shifted_im2 = None
self.depth_map = None
self.d = 26
self.shift_amount = 1
self.Tc = 0.028
self.Tg = 0.008
self.alpha = 0.9
self.r = 9
self.epsilon = 100
self.abs_diffs = np.zeros(im1.shape[:3] + (self.d,))
self.gradients = np.zeros(im1.shape[:3] + (self.d,))
self.costs = np.zeros(im1.shape[:3] + (self.d,))
self.c_prime = np.zeros(im1.shape[:2] + (self.d,))
def compute_depth(self):
"""
Core of the objects, runs through the member functions in order
:return:
"""
for d in trange(self.d, desc=f"Computing depth maps for {self.imname} "):
self.shifted_im2 = shift(self.im2, shift=(0, -d * self.shift_amount, 0), order=0)
self.abs_diffs[:, :, :, d] = self.absolute_difference()
self.gradients[:, :, :, d] = self.compute_gradients()
self.costs[:, :, :, d] = self.compute_costs(d)
self.c_prime[:, :, d] = self.compute_cprime(d)
self.depth_map = np.min(self.c_prime, axis=2)
print("Done!")
self.show()
return self.depth_map
def absolute_difference(self):
"""
Computes the absolute difference between im1 and shifted_im2, summing across colors
"""
return np.repeat(
np.expand_dims(
np.sum(
np.abs(self.im1 - self.shifted_im2), axis=2),
axis=2),
3, 2)
def compute_gradients(self):
"""
Computes the gradients for im1 and shifted_im2
:return: the absolute value of the pairwise difference of the gradients
"""
gradients_im1 = np.gradient(self.im1, axis=1)
gradients_im2 = np.gradient(self.shifted_im2, axis=1)
return np.abs(gradients_im1 - gradients_im2)
def compute_costs(self, d):
"""
Computes the cost of a certain depth map
:param d: depth map index
:return: the cost matrix associated with the depth map
"""
return self.alpha * np.minimum(np.full(self.im1.shape[:3], self.Tc), self.abs_diffs[:, :, :, d]) + \
(1 - self.alpha) * np.minimum(np.full(self.im1.shape[:3], self.Tg), self.gradients[:, :, :, d])
def compute_cprime(self, d):
"""
Computes the filtered cost value
:param d: depth map index
:return: filtered cost map
"""
def filter(img, radius):
rows, cols = img.shape
image_distance = np.zeros(img.shape)
image_sum = np.cumsum(img, 0)
image_distance[0: radius + 1, :] = image_sum[radius: 2 * radius + 1, :]
image_distance[radius + 1: rows - radius, :] = image_sum[2 * radius + 1: rows, :] - \
image_sum[0: rows - 2 * radius - 1, :]
image_distance[rows - radius: rows, :] = np.tile(image_sum[rows - 1, :], [radius, 1]) - \
image_sum[rows - 2 * radius - 1: rows - radius - 1, :]
image_sum = np.cumsum(image_distance, 1)
image_distance[:, 0: radius + 1] = image_sum[:, radius: 2 * radius + 1]
image_distance[:, radius + 1: cols - radius] = image_sum[:, 2 * radius + 1: cols] - \
image_sum[:, 0: cols - 2 * radius - 1]
image_distance[:, cols - radius: cols] = np.tile(image_sum[:, cols - 1], [radius, 1]).T - \
image_sum[:, cols - 2 * radius - 1: cols - radius - 1]
return image_distance
cost = self.costs[:, :, :, d].mean(axis=2)
guide = self.im1.mean(axis=2)
N = filter(np.ones([guide.shape[0], guide.shape[1]]), self.r)
mean_guide = filter(guide, self.r) / N
mean_cost = filter(cost, self.r) / N
mean_both = filter(guide * cost, self.r) / N
varI = filter(guide * guide, self.r) / N - mean_guide * mean_guide
a = mean_both - mean_guide * mean_cost / (varI + self.epsilon)
b = mean_cost - a * mean_guide
meanA = filter(a, self.r) / N
meanB = filter(b, self.r) / N
return meanA * guide + meanB
def show_arr(self, arr, title):
"""
Helper function to avoid duplicated code
:param arr: numpy 2d or 3d array
:param title: title for saving and displaying
"""
plt.imshow((arr / arr.max())-arr.min())
plt.title(title)
fname = str(output_folder / title.replace(" ", "_"))
plt.savefig(fname)
plt.show()
def show(self):
"""
Displays insternal states
"""
# for im in [self.im1, self.im2]:
# image = Image.fromarray(im)
# image.show()
for d in [0]:
self.show_arr(self.abs_diffs[:, :, :, d], f"{self.imname} Absolute difference {d}")
self.show_arr(self.gradients[:, :, :, d], f"{self.imname} Gradient {d}")
self.show_arr(self.costs[:, :, :, d], f"{self.imname} Cost {d}")
self.show_arr(self.c_prime[:, :, d], f"{self.imname} C' {d}")
self.show_arr(self.depth_map, f"{self.imname} Depth map")