half implemented missing point detection; scale_estimation_coefficient =4
Browse files- handcrafted_solution.py +43 -6
- script.py +1 -1
- test_solution.ipynb +0 -0
handcrafted_solution.py
CHANGED
@@ -9,6 +9,7 @@ import numpy as np
|
|
9 |
from PIL import Image as PImage
|
10 |
from hoho.color_mappings import gestalt_color_mapping
|
11 |
from hoho.read_write_colmap import read_cameras_binary, read_images_binary, read_points3D_binary
|
|
|
12 |
from scipy.spatial.distance import cdist
|
13 |
|
14 |
apex_color = gestalt_color_mapping["apex"]
|
@@ -48,6 +49,7 @@ def clean_image(image_gestalt) -> np.ndarray:
|
|
48 |
unclassified_mask = cv2.bitwise_not(unclassified_mask)
|
49 |
mask = undesired_objects(unclassified_mask).astype(np.uint8)
|
50 |
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((11, 11), np.uint8), iterations=11)
|
|
|
51 |
|
52 |
image_gestalt[:, :, 0] *= mask
|
53 |
image_gestalt[:, :, 1] *= mask
|
@@ -56,6 +58,7 @@ def clean_image(image_gestalt) -> np.ndarray:
|
|
56 |
|
57 |
|
58 |
def get_vertices(image_gestalt, *, color_range=4., dialations=3, erosions=1, kernel_size=13):
|
|
|
59 |
apex_mask = cv2.inRange(image_gestalt, apex_color - color_range, apex_color + color_range)
|
60 |
eave_end_point_mask = cv2.inRange(image_gestalt, eave_end_point - color_range, eave_end_point + color_range)
|
61 |
flashing_end_point_mask = cv2.inRange(image_gestalt, flashing_end_point - color_range,
|
@@ -76,6 +79,35 @@ def get_vertices(image_gestalt, *, color_range=4., dialations=3, erosions=1, ker
|
|
76 |
return apex_centroids[1:], other_centroids[1:], apex_mask, eave_end_point_mask
|
77 |
|
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',
|
@@ -98,7 +130,8 @@ def convert_entry_to_human_readable(entry):
|
|
98 |
return out
|
99 |
|
100 |
|
101 |
-
def get_vertices_and_edges_from_segmentation(gest_seg_np, *, color_range=4., point_radius=30, max_angle=5., extend
|
|
|
102 |
'''Get the vertices and edges from the gestalt segmentation mask of the house'''
|
103 |
# Apex
|
104 |
connections = []
|
@@ -107,6 +140,9 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, color_range=4., poi
|
|
107 |
apex_centroids, eave_end_point_centroids, apex_mask, eave_end_point_mask = get_vertices(gest_seg_np)
|
108 |
|
109 |
vertices = np.concatenate([apex_centroids, eave_end_point_centroids])
|
|
|
|
|
|
|
110 |
|
111 |
scale = 1
|
112 |
vertex_size = np.zeros(vertices.shape[0])
|
@@ -239,6 +275,7 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, color_range=4., poi
|
|
239 |
connections.append(possible_connections[:, fitted_line_idx])
|
240 |
|
241 |
vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
|
|
|
242 |
vertices += [{"xy": v, "type": "eave_end_point"} for v in eave_end_point_centroids]
|
243 |
return vertices, connections
|
244 |
|
@@ -257,7 +294,7 @@ def get_uv_depth(vertices, depth):
|
|
257 |
return uv, vertex_depth
|
258 |
|
259 |
|
260 |
-
def merge_vertices_3d(vert_edge_per_image,
|
261 |
'''Merge vertices that are close to each other in 3D space and are of same types'''
|
262 |
all_3d_vertices = []
|
263 |
connections_3d = []
|
@@ -274,7 +311,7 @@ def merge_vertices_3d(vert_edge_per_image, th=0.1):
|
|
274 |
distmat = cdist(all_3d_vertices, all_3d_vertices)
|
275 |
types = np.array(types).reshape(-1, 1)
|
276 |
same_types = cdist(types, types)
|
277 |
-
mask_to_merge = (distmat <=
|
278 |
new_vertices = []
|
279 |
new_connections = []
|
280 |
to_merge = sorted(list(set([tuple(a.nonzero()[0].tolist()) for a in mask_to_merge])))
|
@@ -335,7 +372,7 @@ def prune_not_connected(all_3d_vertices, connections_3d):
|
|
335 |
return np.array(new_verts), connected_out
|
336 |
|
337 |
|
338 |
-
def predict(entry, visualize=False, **kwargs) -> Tuple[np.ndarray, List[int]]:
|
339 |
good_entry = convert_entry_to_human_readable(entry)
|
340 |
if 'gestalt' not in good_entry or 'depthcm' not in good_entry or 'K' not in good_entry or 'R' not in good_entry or 't' not in good_entry:
|
341 |
print('Missing required fields in the entry')
|
@@ -350,7 +387,7 @@ def predict(entry, visualize=False, **kwargs) -> Tuple[np.ndarray, List[int]]:
|
|
350 |
gest_seg = gest.resize(depth.size)
|
351 |
gest_seg_np = np.array(gest_seg).astype(np.uint8)
|
352 |
# Metric3D
|
353 |
-
depth_np = np.array(depth) /
|
354 |
vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, **kwargs)
|
355 |
if (len(vertices) < 2) or (len(connections) < 1):
|
356 |
print(f'Not enough vertices or connections in image {i}')
|
@@ -370,7 +407,7 @@ def predict(entry, visualize=False, **kwargs) -> Tuple[np.ndarray, List[int]]:
|
|
370 |
vertices_3d = cv2.transform(cv2.convertPointsToHomogeneous(vertices_3d_local), cam_to_world)
|
371 |
vertices_3d = cv2.convertPointsFromHomogeneous(vertices_3d).reshape(-1, 3)
|
372 |
vert_edge_per_image[i] = vertices, connections, vertices_3d
|
373 |
-
all_3d_vertices, connections_3d = merge_vertices_3d(vert_edge_per_image,
|
374 |
all_3d_vertices_clean, connections_3d_clean = prune_not_connected(all_3d_vertices, connections_3d)
|
375 |
if (len(all_3d_vertices_clean) < 2) or len(connections_3d_clean) < 1:
|
376 |
print(f'Not enough vertices or connections in the 3D vertices')
|
|
|
9 |
from PIL import Image as PImage
|
10 |
from hoho.color_mappings import gestalt_color_mapping
|
11 |
from hoho.read_write_colmap import read_cameras_binary, read_images_binary, read_points3D_binary
|
12 |
+
from scipy.spatial import KDTree
|
13 |
from scipy.spatial.distance import cdist
|
14 |
|
15 |
apex_color = gestalt_color_mapping["apex"]
|
|
|
49 |
unclassified_mask = cv2.bitwise_not(unclassified_mask)
|
50 |
mask = undesired_objects(unclassified_mask).astype(np.uint8)
|
51 |
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((11, 11), np.uint8), iterations=11)
|
52 |
+
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, np.ones((11, 11), np.uint8), iterations=2)
|
53 |
|
54 |
image_gestalt[:, :, 0] *= mask
|
55 |
image_gestalt[:, :, 1] *= mask
|
|
|
58 |
|
59 |
|
60 |
def get_vertices(image_gestalt, *, color_range=4., dialations=3, erosions=1, kernel_size=13):
|
61 |
+
### detects the apex and eave end and flashing end points
|
62 |
apex_mask = cv2.inRange(image_gestalt, apex_color - color_range, apex_color + color_range)
|
63 |
eave_end_point_mask = cv2.inRange(image_gestalt, eave_end_point - color_range, eave_end_point + color_range)
|
64 |
flashing_end_point_mask = cv2.inRange(image_gestalt, flashing_end_point - color_range,
|
|
|
79 |
return apex_centroids[1:], other_centroids[1:], apex_mask, eave_end_point_mask
|
80 |
|
81 |
|
82 |
+
def infer_vertices(image_gestalt, *, color_range=4.):
|
83 |
+
ridge_color = np.array(gestalt_color_mapping["ridge"])
|
84 |
+
rake_color = np.array(gestalt_color_mapping["rake"])
|
85 |
+
ridge_mask = cv2.inRange(image_gestalt,
|
86 |
+
ridge_color - color_range,
|
87 |
+
ridge_color + color_range)
|
88 |
+
ridge_mask = cv2.morphologyEx(ridge_mask,
|
89 |
+
cv2.MORPH_DILATE, np.ones((3, 3)), iterations=4)
|
90 |
+
rake_mask = cv2.inRange(image_gestalt,
|
91 |
+
rake_color - color_range,
|
92 |
+
rake_color + color_range)
|
93 |
+
rake_mask = cv2.morphologyEx(rake_mask,
|
94 |
+
cv2.MORPH_DILATE, np.ones((3, 3)), iterations=4)
|
95 |
+
|
96 |
+
intersection_mask = cv2.bitwise_and(ridge_mask, rake_mask)
|
97 |
+
intersection_mask = cv2.morphologyEx(intersection_mask, cv2.MORPH_DILATE, np.ones((11, 11)), iterations=3)
|
98 |
+
|
99 |
+
*_, inferred_centroids = cv2.connectedComponentsWithStats(intersection_mask, connectivity=8, stats=cv2.CV_32S)
|
100 |
+
|
101 |
+
return inferred_centroids[1:], intersection_mask
|
102 |
+
|
103 |
+
|
104 |
+
def get_missed_vertices(vertices, inferred_centroids, *, min_missing_distance=200.0, **kwargs):
|
105 |
+
vertices = KDTree(vertices)
|
106 |
+
closest = vertices.query(inferred_centroids, k=1, distance_upper_bound=min_missing_distance)
|
107 |
+
missed_points = inferred_centroids[closest[1] == len(vertices.data)]
|
108 |
+
return missed_points
|
109 |
+
|
110 |
+
|
111 |
def convert_entry_to_human_readable(entry):
|
112 |
out = {}
|
113 |
already_good = {'__key__', 'wf_vertices', 'wf_edges', 'edge_semantics', 'mesh_vertices', 'mesh_faces',
|
|
|
130 |
return out
|
131 |
|
132 |
|
133 |
+
def get_vertices_and_edges_from_segmentation(gest_seg_np, *, color_range=4., point_radius=30, max_angle=5., extend=35,
|
134 |
+
**kwargs):
|
135 |
'''Get the vertices and edges from the gestalt segmentation mask of the house'''
|
136 |
# Apex
|
137 |
connections = []
|
|
|
140 |
apex_centroids, eave_end_point_centroids, apex_mask, eave_end_point_mask = get_vertices(gest_seg_np)
|
141 |
|
142 |
vertices = np.concatenate([apex_centroids, eave_end_point_centroids])
|
143 |
+
# inferred_vertices, inferred_mask = infer_vertices(gest_seg_np)
|
144 |
+
# missed_vertices = get_missed_vertices(vertices, inferred_vertices, **kwargs)
|
145 |
+
# vertices = np.concatenate([vertices, missed_vertices])
|
146 |
|
147 |
scale = 1
|
148 |
vertex_size = np.zeros(vertices.shape[0])
|
|
|
275 |
connections.append(possible_connections[:, fitted_line_idx])
|
276 |
|
277 |
vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
|
278 |
+
# vertices += [{"xy": v, "type": "apex"} for v in missed_vertices]
|
279 |
vertices += [{"xy": v, "type": "eave_end_point"} for v in eave_end_point_centroids]
|
280 |
return vertices, connections
|
281 |
|
|
|
294 |
return uv, vertex_depth
|
295 |
|
296 |
|
297 |
+
def merge_vertices_3d(vert_edge_per_image, merge_th=0.1, **kwargs):
|
298 |
'''Merge vertices that are close to each other in 3D space and are of same types'''
|
299 |
all_3d_vertices = []
|
300 |
connections_3d = []
|
|
|
311 |
distmat = cdist(all_3d_vertices, all_3d_vertices)
|
312 |
types = np.array(types).reshape(-1, 1)
|
313 |
same_types = cdist(types, types)
|
314 |
+
mask_to_merge = (distmat <= merge_th) & (same_types == 0)
|
315 |
new_vertices = []
|
316 |
new_connections = []
|
317 |
to_merge = sorted(list(set([tuple(a.nonzero()[0].tolist()) for a in mask_to_merge])))
|
|
|
372 |
return np.array(new_verts), connected_out
|
373 |
|
374 |
|
375 |
+
def predict(entry, visualize=False, scale_estimation_coefficient=2.5, **kwargs) -> Tuple[np.ndarray, List[int]]:
|
376 |
good_entry = convert_entry_to_human_readable(entry)
|
377 |
if 'gestalt' not in good_entry or 'depthcm' not in good_entry or 'K' not in good_entry or 'R' not in good_entry or 't' not in good_entry:
|
378 |
print('Missing required fields in the entry')
|
|
|
387 |
gest_seg = gest.resize(depth.size)
|
388 |
gest_seg_np = np.array(gest_seg).astype(np.uint8)
|
389 |
# Metric3D
|
390 |
+
depth_np = np.array(depth) / scale_estimation_coefficient # 2.5 is the scale estimation coefficient
|
391 |
vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, **kwargs)
|
392 |
if (len(vertices) < 2) or (len(connections) < 1):
|
393 |
print(f'Not enough vertices or connections in image {i}')
|
|
|
407 |
vertices_3d = cv2.transform(cv2.convertPointsToHomogeneous(vertices_3d_local), cam_to_world)
|
408 |
vertices_3d = cv2.convertPointsFromHomogeneous(vertices_3d).reshape(-1, 3)
|
409 |
vert_edge_per_image[i] = vertices, connections, vertices_3d
|
410 |
+
all_3d_vertices, connections_3d = merge_vertices_3d(vert_edge_per_image, **kwargs)
|
411 |
all_3d_vertices_clean, connections_3d_clean = prune_not_connected(all_3d_vertices, connections_3d)
|
412 |
if (len(all_3d_vertices_clean) < 2) or len(connections_3d_clean) < 1:
|
413 |
print(f'Not enough vertices or connections in the 3D vertices')
|
script.py
CHANGED
@@ -127,7 +127,7 @@ if __name__ == "__main__":
|
|
127 |
with ProcessPoolExecutor(max_workers=8) as pool:
|
128 |
results = []
|
129 |
for i, sample in enumerate(tqdm(dataset)):
|
130 |
-
results.append(pool.submit(predict, sample, visualize=False, point_radius=25, max_angle=15, extend=30))
|
131 |
|
132 |
for i, result in enumerate(tqdm(results)):
|
133 |
key, pred_vertices, pred_edges = result.result()
|
|
|
127 |
with ProcessPoolExecutor(max_workers=8) as pool:
|
128 |
results = []
|
129 |
for i, sample in enumerate(tqdm(dataset)):
|
130 |
+
results.append(pool.submit(predict, sample, visualize=False, point_radius=25, max_angle=15, extend=30, merge_th=3.0, min_missing_distance=1000000.0, scale_estimation_coefficient=4))
|
131 |
|
132 |
for i, result in enumerate(tqdm(results)):
|
133 |
key, pred_vertices, pred_edges = result.result()
|
test_solution.ipynb
CHANGED
The diff for this file is too large to render.
See raw diff
|
|