fixed bad logic in line selection, vectorized the calculations, added hough lines, changed distance to sqeuclidean, rewrote convert_entry_to_human_readable to use match case
Browse files- handcrafted_solution.py +67 -46
handcrafted_solution.py
CHANGED
@@ -78,44 +78,44 @@ def get_vertices(image_gestalt, *, color_range=4., dialations=3, erosions=1, ker
|
|
78 |
|
79 |
def convert_entry_to_human_readable(entry):
|
80 |
out = {}
|
81 |
-
already_good =
|
82 |
-
'face_semantics', 'K', 'R', 't'
|
83 |
for k, v in entry.items():
|
84 |
if k in already_good:
|
85 |
out[k] = v
|
86 |
continue
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
|
|
97 |
return out
|
98 |
|
99 |
|
100 |
def get_vertices_and_edges_from_segmentation(gest_seg_np, edge_th=50.0):
|
101 |
'''Get the vertices and edges from the gestalt segmentation mask of the house'''
|
102 |
# Apex
|
103 |
-
color_range =
|
104 |
connections = []
|
|
|
105 |
|
106 |
-
gest_seg_np = clean_image(gest_seg_np)
|
107 |
apex_centroids, eave_end_point_centroids, apex_mask, eave_end_point_mask = get_vertices(gest_seg_np)
|
108 |
|
|
|
|
|
109 |
vertex_mask = np.zeros_like(apex_mask)
|
110 |
for i in apex_centroids:
|
111 |
-
cv2.circle(vertex_mask, np.round(i).astype(np.uint32), 20, (255,
|
112 |
for i in eave_end_point_centroids:
|
113 |
-
cv2.circle(vertex_mask, np.round(i).astype(np.uint32), 15, (255,
|
114 |
vertex_mask = np.bitwise_not(vertex_mask)
|
115 |
|
116 |
-
apex_pts = np.concatenate([apex_centroids, eave_end_point_centroids])
|
117 |
-
|
118 |
-
|
119 |
for edge_class in ['eave', 'ridge', 'rake', 'valley', 'flashing']:
|
120 |
if (len(apex_pts) < 2):
|
121 |
break
|
@@ -124,39 +124,60 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, edge_th=50.0):
|
|
124 |
mask = cv2.inRange(gest_seg_np,
|
125 |
edge_color - color_range,
|
126 |
edge_color + color_range)
|
|
|
127 |
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
mask = cv2.morphologyEx(mask,
|
132 |
-
cv2.MORPH_DILATE, np.ones((11, 11)), iterations=
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
edges = []
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
xright_idx = np.argmax(x)
|
144 |
-
x_right = x[xright_idx]
|
145 |
-
y_right = y[xright_idx]
|
146 |
-
edges.append((x_left, y_left, x_right, y_right))
|
147 |
-
# cv2.line(line_img, (x_left, y_left), (x_right, y_right), (255, 255, 255), 2)
|
148 |
edges = np.array(edges)
|
149 |
if len(edges) < 1:
|
150 |
continue
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
|
161 |
vertices += [{"xy": v, "type": "eave_end_point"} for v in eave_end_point_centroids]
|
162 |
return vertices, connections
|
|
|
78 |
|
79 |
def convert_entry_to_human_readable(entry):
|
80 |
out = {}
|
81 |
+
already_good = {'__key__', 'wf_vertices', 'wf_edges', 'edge_semantics', 'mesh_vertices', 'mesh_faces',
|
82 |
+
'face_semantics', 'K', 'R', 't'}
|
83 |
for k, v in entry.items():
|
84 |
if k in already_good:
|
85 |
out[k] = v
|
86 |
continue
|
87 |
+
match k:
|
88 |
+
case 'points3d':
|
89 |
+
out[k] = read_points3D_binary(fid=io.BytesIO(v))
|
90 |
+
case 'cameras':
|
91 |
+
out[k] = read_cameras_binary(fid=io.BytesIO(v))
|
92 |
+
case 'images':
|
93 |
+
out[k] = read_images_binary(fid=io.BytesIO(v))
|
94 |
+
case 'ade20k' | 'gestalt':
|
95 |
+
out[k] = [PImage.open(io.BytesIO(x)).convert('RGB') for x in v]
|
96 |
+
case 'depthcm':
|
97 |
+
out[k] = [PImage.open(io.BytesIO(x)) for x in entry['depthcm']]
|
98 |
return out
|
99 |
|
100 |
|
101 |
def get_vertices_and_edges_from_segmentation(gest_seg_np, edge_th=50.0):
|
102 |
'''Get the vertices and edges from the gestalt segmentation mask of the house'''
|
103 |
# Apex
|
104 |
+
color_range = 8.
|
105 |
connections = []
|
106 |
+
edge_th = edge_th ** 2
|
107 |
|
|
|
108 |
apex_centroids, eave_end_point_centroids, apex_mask, eave_end_point_mask = get_vertices(gest_seg_np)
|
109 |
|
110 |
+
apex_pts = np.concatenate([apex_centroids, eave_end_point_centroids])
|
111 |
+
|
112 |
vertex_mask = np.zeros_like(apex_mask)
|
113 |
for i in apex_centroids:
|
114 |
+
cv2.circle(vertex_mask, np.round(i).astype(np.uint32), 20, (255,), 40, -1)
|
115 |
for i in eave_end_point_centroids:
|
116 |
+
cv2.circle(vertex_mask, np.round(i).astype(np.uint32), 15, (255,), 30, -1)
|
117 |
vertex_mask = np.bitwise_not(vertex_mask)
|
118 |
|
|
|
|
|
|
|
119 |
for edge_class in ['eave', 'ridge', 'rake', 'valley', 'flashing']:
|
120 |
if (len(apex_pts) < 2):
|
121 |
break
|
|
|
124 |
mask = cv2.inRange(gest_seg_np,
|
125 |
edge_color - color_range,
|
126 |
edge_color + color_range)
|
127 |
+
mask = cv2.bitwise_and(mask, vertex_mask)
|
128 |
|
129 |
+
mask = cv2.morphologyEx(mask,
|
130 |
+
cv2.MORPH_DILATE, np.ones((11, 11)), iterations=2)
|
131 |
+
if edge_class == "ridge":
|
132 |
mask = cv2.morphologyEx(mask,
|
133 |
+
cv2.MORPH_DILATE, np.ones((11, 11)), iterations=1)
|
134 |
+
|
135 |
+
if np.any(mask):
|
136 |
+
|
137 |
+
rho = 1 # distance resolution in pixels of the Hough grid
|
138 |
+
theta = np.pi / 180 # angular resolution in radians of the Hough grid
|
139 |
+
threshold = 15 # minimum number of votes (intersections in Hough grid cell)
|
140 |
+
min_line_length = 40 # minimum number of pixels making up a line
|
141 |
+
max_line_gap = 30 # maximum gap in pixels between connectable line segments
|
142 |
+
|
143 |
+
# Run Hough on edge detected image
|
144 |
+
# Output "lines" is an array containing endpoints of detected line segments
|
145 |
+
lines = cv2.HoughLinesP(mask, rho, theta, threshold, np.array([]),
|
146 |
+
min_line_length, max_line_gap)
|
147 |
+
|
148 |
edges = []
|
149 |
+
|
150 |
+
for line in lines if lines is not None else []:
|
151 |
+
for x1, y1, x2, y2 in line:
|
152 |
+
edges.append((x1, y1, x2, y2))
|
153 |
+
|
|
|
|
|
|
|
|
|
|
|
154 |
edges = np.array(edges)
|
155 |
if len(edges) < 1:
|
156 |
continue
|
157 |
+
|
158 |
+
begin_distances = cdist(apex_pts, edges[:, :2], metric="sqeuclidean")
|
159 |
+
end_distances = cdist(apex_pts, edges[:, 2:], metric="sqeuclidean")
|
160 |
+
|
161 |
+
begin_closest_points = np.argmin(begin_distances,
|
162 |
+
axis=0) # index of the closest point for each edge end point
|
163 |
+
end_closest_points = np.argmin(end_distances, axis=0)
|
164 |
+
|
165 |
+
begin_closest_point_distances = begin_distances[begin_closest_points, np.arange(len(begin_closest_points))]
|
166 |
+
end_closest_point_distances = end_distances[end_closest_points, np.arange(len(end_closest_points))]
|
167 |
+
|
168 |
+
begin_in_range_mask = begin_closest_point_distances < edge_th
|
169 |
+
end_in_range_mask = end_closest_point_distances < edge_th
|
170 |
+
|
171 |
+
# where both ends are in range
|
172 |
+
in_range_connected_mask = np.logical_and(begin_in_range_mask, end_in_range_mask)
|
173 |
+
|
174 |
+
edge_idxs = np.where(in_range_connected_mask)[0]
|
175 |
+
|
176 |
+
unique_edges = np.unique(np.array([begin_closest_points[edge_idxs], end_closest_points[edge_idxs]]).T,
|
177 |
+
axis=0)
|
178 |
+
|
179 |
+
connections.extend(unique_edges)
|
180 |
+
|
181 |
vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
|
182 |
vertices += [{"xy": v, "type": "eave_end_point"} for v in eave_end_point_centroids]
|
183 |
return vertices, connections
|