Siromanec commited on
Commit
1ffdc4a
1 Parent(s): 0d51758

added line-component separation using vertex masks

Browse files
Files changed (1) hide show
  1. handcrafted_solution.py +91 -74
handcrafted_solution.py CHANGED
@@ -1,15 +1,15 @@
1
  # Description: This file contains the handcrafted solution for the task of wireframe reconstruction
2
 
3
  import io
4
- from PIL import Image as PImage
5
- import numpy as np
6
  from collections import defaultdict
7
- import cv2
8
  from typing import Tuple, List
9
- from scipy.spatial.distance import cdist
10
 
 
 
 
 
11
  from hoho.read_write_colmap import read_cameras_binary, read_images_binary, read_points3D_binary
12
- from hoho.color_mappings import gestalt_color_mapping, ade20k_color_mapping
13
 
14
  apex_color = gestalt_color_mapping["apex"]
15
  eave_end_point = gestalt_color_mapping["eave_end_point"]
@@ -19,10 +19,10 @@ apex_color, eave_end_point, flashing_end_point = [np.array(i) for i in [apex_col
19
  unclassified = np.array([(215, 62, 138)])
20
  line_classes = ['eave', 'ridge', 'rake', 'valley']
21
 
 
22
  def empty_solution():
23
  '''Return a minimal valid solution, i.e. 2 vertices and 1 edge.'''
24
- return np.zeros((2,3)), [(0, 1)]
25
-
26
 
27
 
28
  def undesired_objects(image):
@@ -40,6 +40,7 @@ def undesired_objects(image):
40
  img2[output == max_label] = 1
41
  return img2
42
 
 
43
  def clean_image(image_gestalt) -> np.ndarray:
44
  # clears image in from of unclassified and disconected components
45
  image_gestalt = np.array(image_gestalt)
@@ -55,10 +56,10 @@ def clean_image(image_gestalt) -> np.ndarray:
55
 
56
 
57
  def get_vertices(image_gestalt, *, color_range=4., dialations=3, erosions=1, kernel_size=13):
58
-
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, flashing_end_point + color_range)
 
62
  eave_end_point_mask = cv2.bitwise_or(eave_end_point_mask, flashing_end_point_mask)
63
 
64
  kernel = np.ones((kernel_size, kernel_size), np.uint8)
@@ -69,14 +70,16 @@ def get_vertices(image_gestalt, *, color_range=4., dialations=3, erosions=1, ker
69
  eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_DILATE, kernel, iterations=dialations)
70
  eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_ERODE, kernel, iterations=erosions)
71
 
72
- *_, apex_centroids = cv2.connectedComponentsWithStats(apex_mask, connectivity=8)
73
- *_, other_centroids = cv2.connectedComponentsWithStats(eave_end_point_mask, connectivity=8)
 
 
74
 
75
- return [apex_centroids[1:], other_centroids[1:]]
76
 
77
  def convert_entry_to_human_readable(entry):
78
  out = {}
79
- already_good = ['__key__', 'wf_vertices', 'wf_edges', 'edge_semantics', 'mesh_vertices', 'mesh_faces', 'face_semantics', 'K', 'R', 't']
 
80
  for k, v in entry.items():
81
  if k in already_good:
82
  out[k] = v
@@ -88,35 +91,47 @@ def convert_entry_to_human_readable(entry):
88
  if k == 'images':
89
  out[k] = read_images_binary(fid=io.BytesIO(v))
90
  if k in ['ade20k', 'gestalt']:
91
- out[k] = [PImage.open(io.BytesIO(x)).convert('RGB') for x in v]
92
  if k == 'depthcm':
93
  out[k] = [PImage.open(io.BytesIO(x)) for x in entry['depthcm']]
94
  return out
95
 
96
 
97
- def get_vertices_and_edges_from_segmentation(gest_seg_np, edge_th = 50.0):
98
  '''Get the vertices and edges from the gestalt segmentation mask of the house'''
99
- connections = []
100
  # Apex
 
 
 
101
  gest_seg_np = clean_image(gest_seg_np)
102
- apex_centroids, eave_end_point_centroids = get_vertices(gest_seg_np)
 
 
 
 
 
 
103
  apex_pts = np.concatenate([apex_centroids, eave_end_point_centroids])
104
-
105
- # Ridge connects two apex points
106
- for edge_class in ['eave', 'ridge', 'rake', 'valley']:
107
  edge_color = np.array(gestalt_color_mapping[edge_class])
108
- mask = cv2.morphologyEx(cv2.inRange(gest_seg_np,
109
- edge_color-0.5,
110
- edge_color+0.5),
111
- cv2.MORPH_DILATE, np.ones((11, 11)))
112
- line_img = np.copy(gest_seg_np) * 0
113
- if mask.sum() > 0:
 
 
 
 
 
114
  output = cv2.connectedComponentsWithStats(mask, 8, cv2.CV_32S)
115
  (numLabels, labels, stats, centroids) = output
116
  stats, centroids = stats[1:], centroids[1:]
117
  edges = []
118
  for i in range(1, numLabels):
119
- y,x = np.where(labels == i)
120
  xleft_idx = np.argmin(x)
121
  x_left = x[xleft_idx]
122
  y_left = y[xleft_idx]
@@ -126,21 +141,22 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, edge_th = 50.0):
126
  edges.append((x_left, y_left, x_right, y_right))
127
  cv2.line(line_img, (x_left, y_left), (x_right, y_right), (255, 255, 255), 2)
128
  edges = np.array(edges)
129
- if (len(apex_pts) < 2) or len(edges) <1:
130
  continue
131
- pts_to_edges_dist = np.minimum(cdist(apex_pts, edges[:,:2]), cdist(apex_pts, edges[:,2:]))
132
  connectivity_mask = pts_to_edges_dist <= edge_th
133
  edge_connects = connectivity_mask.sum(axis=0)
134
  for edge_idx, edgesum in enumerate(edge_connects):
135
- if edgesum>=2:
136
- connected_verts = np.where(connectivity_mask[:,edge_idx])[0]
137
  for a_i, a in enumerate(connected_verts):
138
- for b in connected_verts[a_i+1:]:
139
  connections.append((a, b))
140
  vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
141
  vertices += [{"xy": v, "type": "eave_end_point"} for v in eave_end_point_centroids]
142
  return vertices, connections
143
 
 
144
  def get_uv_depth(vertices, depth):
145
  '''Get the depth of the vertices from the depth image'''
146
  uv = []
@@ -149,9 +165,9 @@ def get_uv_depth(vertices, depth):
149
  uv = np.array(uv)
150
  uv_int = uv.astype(np.int32)
151
  H, W = depth.shape[:2]
152
- uv_int[:, 0] = np.clip( uv_int[:, 0], 0, W-1)
153
- uv_int[:, 1] = np.clip( uv_int[:, 1], 0, H-1)
154
- vertex_depth = depth[(uv_int[:, 1] , uv_int[:, 0])]
155
  return uv, vertex_depth
156
 
157
 
@@ -163,16 +179,16 @@ def merge_vertices_3d(vert_edge_per_image, th=0.1):
163
  cur_start = 0
164
  types = []
165
  for cimg_idx, (vertices, connections, vertices_3d) in vert_edge_per_image.items():
166
- types += [int(v['type']=='apex') for v in vertices]
167
  all_3d_vertices.append(vertices_3d)
168
- connections_3d+=[(x+cur_start,y+cur_start) for (x,y) in connections]
169
- cur_start+=len(vertices_3d)
170
  all_3d_vertices = np.concatenate(all_3d_vertices, axis=0)
171
- #print (connections_3d)
172
  distmat = cdist(all_3d_vertices, all_3d_vertices)
173
- types = np.array(types).reshape(-1,1)
174
  same_types = cdist(types, types)
175
- mask_to_merge = (distmat <= th) & (same_types==0)
176
  new_vertices = []
177
  new_connections = []
178
  to_merge = sorted(list(set([tuple(a.nonzero()[0].tolist()) for a in mask_to_merge])))
@@ -180,10 +196,10 @@ def merge_vertices_3d(vert_edge_per_image, th=0.1):
180
  for i in range(len(all_3d_vertices)):
181
  for j in to_merge:
182
  if i in j:
183
- to_merge_final[i]+=j
184
  for k, v in to_merge_final.items():
185
  to_merge_final[k] = list(set(v))
186
- already_there = set()
187
  merged = []
188
  for k, v in to_merge_final.items():
189
  if k in already_there:
@@ -192,24 +208,25 @@ def merge_vertices_3d(vert_edge_per_image, th=0.1):
192
  for vv in v:
193
  already_there.add(vv)
194
  old_idx_to_new = {}
195
- count=0
196
  for idxs in merged:
197
  new_vertices.append(all_3d_vertices[idxs].mean(axis=0))
198
  for idx in idxs:
199
  old_idx_to_new[idx] = count
200
- count +=1
201
- #print (connections_3d)
202
- new_vertices=np.array(new_vertices)
203
- #print (connections_3d)
204
  for conn in connections_3d:
205
  new_con = sorted((old_idx_to_new[conn[0]], old_idx_to_new[conn[1]]))
206
  if new_con[0] == new_con[1]:
207
  continue
208
  if new_con not in new_connections:
209
  new_connections.append(new_con)
210
- #print (f'{len(new_vertices)} left after merging {len(all_3d_vertices)} with {th=}')
211
  return new_vertices, new_connections
212
 
 
213
  def prune_not_connected(all_3d_vertices, connections_3d):
214
  '''Prune vertices that are not connected to any other vertex'''
215
  connected = defaultdict(list)
@@ -219,16 +236,16 @@ def prune_not_connected(all_3d_vertices, connections_3d):
219
  new_indexes = {}
220
  new_verts = []
221
  connected_out = []
222
- for k,v in connected.items():
223
  vert = all_3d_vertices[k]
224
  if tuple(vert) not in new_verts:
225
  new_verts.append(tuple(vert))
226
- new_indexes[k]=len(new_verts) -1
227
- for k,v in connected.items():
228
  for vv in v:
229
- connected_out.append((new_indexes[vv[0]],new_indexes[vv[1]]))
230
- connected_out=list(set(connected_out))
231
-
232
  return np.array(new_verts), connected_out
233
 
234
 
@@ -236,43 +253,43 @@ def predict(entry, visualize=False) -> Tuple[np.ndarray, List[int]]:
236
  good_entry = convert_entry_to_human_readable(entry)
237
  vert_edge_per_image = {}
238
  for i, (gest, depth, K, R, t) in enumerate(zip(good_entry['gestalt'],
239
- good_entry['depthcm'],
240
- good_entry['K'],
241
- good_entry['R'],
242
- good_entry['t']
243
- )):
244
  gest_seg = gest.resize(depth.size)
245
  gest_seg_np = np.array(gest_seg).astype(np.uint8)
246
  # Metric3D
247
- depth_np = np.array(depth) / 2.5 # 2.5 is the scale estimation coefficient
248
- vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, edge_th = 20.)
249
  if (len(vertices) < 2) or (len(connections) < 1):
250
- print (f'Not enough vertices or connections in image {i}')
251
  vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
252
  continue
253
  uv, depth_vert = get_uv_depth(vertices, depth_np)
254
  # Normalize the uv to the camera intrinsics
255
  xy_local = np.ones((len(uv), 3))
256
- xy_local[:, 0] = (uv[:, 0] - K[0,2]) / K[0,0]
257
- xy_local[:, 1] = (uv[:, 1] - K[1,2]) / K[1,1]
258
  # Get the 3D vertices
259
- vertices_3d_local = depth_vert[...,None] * (xy_local/np.linalg.norm(xy_local, axis=1)[...,None])
260
  world_to_cam = np.eye(4)
261
  world_to_cam[:3, :3] = R
262
  world_to_cam[:3, 3] = t.reshape(-1)
263
- cam_to_world = np.linalg.inv(world_to_cam)
264
  vertices_3d = cv2.transform(cv2.convertPointsToHomogeneous(vertices_3d_local), cam_to_world)
265
  vertices_3d = cv2.convertPointsFromHomogeneous(vertices_3d).reshape(-1, 3)
266
  vert_edge_per_image[i] = vertices, connections, vertices_3d
267
  all_3d_vertices, connections_3d = merge_vertices_3d(vert_edge_per_image, 3.0)
268
- all_3d_vertices_clean, connections_3d_clean = prune_not_connected(all_3d_vertices, connections_3d)
269
  if (len(all_3d_vertices_clean) < 2) or len(connections_3d_clean) < 1:
270
- print (f'Not enough vertices or connections in the 3D vertices')
271
  return (good_entry['__key__'], *empty_solution())
272
  if visualize:
273
  from hoho.viz3d import plot_estimate_and_gt
274
- plot_estimate_and_gt( all_3d_vertices_clean,
275
- connections_3d_clean,
276
- good_entry['wf_vertices'],
277
- good_entry['wf_edges'])
278
- return good_entry['__key__'], all_3d_vertices_clean, connections_3d_clean
 
1
  # Description: This file contains the handcrafted solution for the task of wireframe reconstruction
2
 
3
  import io
 
 
4
  from collections import defaultdict
 
5
  from typing import Tuple, List
 
6
 
7
+ import cv2
8
+ 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"]
15
  eave_end_point = gestalt_color_mapping["eave_end_point"]
 
19
  unclassified = np.array([(215, 62, 138)])
20
  line_classes = ['eave', 'ridge', 'rake', 'valley']
21
 
22
+
23
  def empty_solution():
24
  '''Return a minimal valid solution, i.e. 2 vertices and 1 edge.'''
25
+ return np.zeros((2, 3)), [(0, 1)]
 
26
 
27
 
28
  def undesired_objects(image):
 
40
  img2[output == max_label] = 1
41
  return img2
42
 
43
+
44
  def clean_image(image_gestalt) -> np.ndarray:
45
  # clears image in from of unclassified and disconected components
46
  image_gestalt = np.array(image_gestalt)
 
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,
62
+ flashing_end_point + color_range)
63
  eave_end_point_mask = cv2.bitwise_or(eave_end_point_mask, flashing_end_point_mask)
64
 
65
  kernel = np.ones((kernel_size, kernel_size), np.uint8)
 
70
  eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_DILATE, kernel, iterations=dialations)
71
  eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_ERODE, kernel, iterations=erosions)
72
 
73
+ *_, apex_centroids = cv2.connectedComponentsWithStats(apex_mask, connectivity=8, stats=cv2.CV_32S)
74
+ *_, other_centroids = cv2.connectedComponentsWithStats(eave_end_point_mask, connectivity=8, stats=cv2.CV_32S)
75
+
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',
82
+ 'face_semantics', 'K', 'R', 't']
83
  for k, v in entry.items():
84
  if k in already_good:
85
  out[k] = v
 
91
  if k == 'images':
92
  out[k] = read_images_binary(fid=io.BytesIO(v))
93
  if k in ['ade20k', 'gestalt']:
94
+ out[k] = [PImage.open(io.BytesIO(x)).convert('RGB') for x in v]
95
  if k == 'depthcm':
96
  out[k] = [PImage.open(io.BytesIO(x)) for x in entry['depthcm']]
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 = 4.
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
+ apex_mask = cv2.morphologyEx(apex_mask,
109
+ cv2.MORPH_DILATE, np.ones((11, 11)), iterations=4)
110
+ eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask,
111
+ cv2.MORPH_DILATE, np.ones((5, 5)), iterations=4)
112
+ vertex_mask = cv2.bitwise_not(cv2.bitwise_or(apex_mask, eave_end_point_mask))
113
+
114
  apex_pts = np.concatenate([apex_centroids, eave_end_point_centroids])
115
+
116
+ for edge_class in ['eave', 'ridge', 'rake', 'valley', 'flashing']:
 
117
  edge_color = np.array(gestalt_color_mapping[edge_class])
118
+
119
+ mask = cv2.inRange(gest_seg_np,
120
+ edge_color - color_range,
121
+ edge_color + color_range)
122
+
123
+ if np.any(mask): # does not really make sense to dilate something if it is empty
124
+ mask = cv2.bitwise_and(mask, vertex_mask)
125
+
126
+ mask = cv2.morphologyEx(mask,
127
+ cv2.MORPH_DILATE, np.ones((11, 11)), iterations=3)
128
+ line_img = np.zeros_like(gest_seg_np)
129
  output = cv2.connectedComponentsWithStats(mask, 8, cv2.CV_32S)
130
  (numLabels, labels, stats, centroids) = output
131
  stats, centroids = stats[1:], centroids[1:]
132
  edges = []
133
  for i in range(1, numLabels):
134
+ y, x = np.where(labels == i)
135
  xleft_idx = np.argmin(x)
136
  x_left = x[xleft_idx]
137
  y_left = y[xleft_idx]
 
141
  edges.append((x_left, y_left, x_right, y_right))
142
  cv2.line(line_img, (x_left, y_left), (x_right, y_right), (255, 255, 255), 2)
143
  edges = np.array(edges)
144
+ if (len(apex_pts) < 2) or len(edges) < 1:
145
  continue
146
+ pts_to_edges_dist = np.minimum(cdist(apex_pts, edges[:, :2]), cdist(apex_pts, edges[:, 2:]))
147
  connectivity_mask = pts_to_edges_dist <= edge_th
148
  edge_connects = connectivity_mask.sum(axis=0)
149
  for edge_idx, edgesum in enumerate(edge_connects):
150
+ if edgesum >= 2:
151
+ connected_verts = np.where(connectivity_mask[:, edge_idx])[0]
152
  for a_i, a in enumerate(connected_verts):
153
+ for b in connected_verts[a_i + 1:]:
154
  connections.append((a, b))
155
  vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
156
  vertices += [{"xy": v, "type": "eave_end_point"} for v in eave_end_point_centroids]
157
  return vertices, connections
158
 
159
+
160
  def get_uv_depth(vertices, depth):
161
  '''Get the depth of the vertices from the depth image'''
162
  uv = []
 
165
  uv = np.array(uv)
166
  uv_int = uv.astype(np.int32)
167
  H, W = depth.shape[:2]
168
+ uv_int[:, 0] = np.clip(uv_int[:, 0], 0, W - 1)
169
+ uv_int[:, 1] = np.clip(uv_int[:, 1], 0, H - 1)
170
+ vertex_depth = depth[(uv_int[:, 1], uv_int[:, 0])]
171
  return uv, vertex_depth
172
 
173
 
 
179
  cur_start = 0
180
  types = []
181
  for cimg_idx, (vertices, connections, vertices_3d) in vert_edge_per_image.items():
182
+ types += [int(v['type'] == 'apex') for v in vertices]
183
  all_3d_vertices.append(vertices_3d)
184
+ connections_3d += [(x + cur_start, y + cur_start) for (x, y) in connections]
185
+ cur_start += len(vertices_3d)
186
  all_3d_vertices = np.concatenate(all_3d_vertices, axis=0)
187
+ # print (connections_3d)
188
  distmat = cdist(all_3d_vertices, all_3d_vertices)
189
+ types = np.array(types).reshape(-1, 1)
190
  same_types = cdist(types, types)
191
+ mask_to_merge = (distmat <= th) & (same_types == 0)
192
  new_vertices = []
193
  new_connections = []
194
  to_merge = sorted(list(set([tuple(a.nonzero()[0].tolist()) for a in mask_to_merge])))
 
196
  for i in range(len(all_3d_vertices)):
197
  for j in to_merge:
198
  if i in j:
199
+ to_merge_final[i] += j
200
  for k, v in to_merge_final.items():
201
  to_merge_final[k] = list(set(v))
202
+ already_there = set()
203
  merged = []
204
  for k, v in to_merge_final.items():
205
  if k in already_there:
 
208
  for vv in v:
209
  already_there.add(vv)
210
  old_idx_to_new = {}
211
+ count = 0
212
  for idxs in merged:
213
  new_vertices.append(all_3d_vertices[idxs].mean(axis=0))
214
  for idx in idxs:
215
  old_idx_to_new[idx] = count
216
+ count += 1
217
+ # print (connections_3d)
218
+ new_vertices = np.array(new_vertices)
219
+ # print (connections_3d)
220
  for conn in connections_3d:
221
  new_con = sorted((old_idx_to_new[conn[0]], old_idx_to_new[conn[1]]))
222
  if new_con[0] == new_con[1]:
223
  continue
224
  if new_con not in new_connections:
225
  new_connections.append(new_con)
226
+ # print (f'{len(new_vertices)} left after merging {len(all_3d_vertices)} with {th=}')
227
  return new_vertices, new_connections
228
 
229
+
230
  def prune_not_connected(all_3d_vertices, connections_3d):
231
  '''Prune vertices that are not connected to any other vertex'''
232
  connected = defaultdict(list)
 
236
  new_indexes = {}
237
  new_verts = []
238
  connected_out = []
239
+ for k, v in connected.items():
240
  vert = all_3d_vertices[k]
241
  if tuple(vert) not in new_verts:
242
  new_verts.append(tuple(vert))
243
+ new_indexes[k] = len(new_verts) - 1
244
+ for k, v in connected.items():
245
  for vv in v:
246
+ connected_out.append((new_indexes[vv[0]], new_indexes[vv[1]]))
247
+ connected_out = list(set(connected_out))
248
+
249
  return np.array(new_verts), connected_out
250
 
251
 
 
253
  good_entry = convert_entry_to_human_readable(entry)
254
  vert_edge_per_image = {}
255
  for i, (gest, depth, K, R, t) in enumerate(zip(good_entry['gestalt'],
256
+ good_entry['depthcm'],
257
+ good_entry['K'],
258
+ good_entry['R'],
259
+ good_entry['t']
260
+ )):
261
  gest_seg = gest.resize(depth.size)
262
  gest_seg_np = np.array(gest_seg).astype(np.uint8)
263
  # Metric3D
264
+ depth_np = np.array(depth) / 2.5 # 2.5 is the scale estimation coefficient
265
+ vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, edge_th=70.)
266
  if (len(vertices) < 2) or (len(connections) < 1):
267
+ print(f'Not enough vertices or connections in image {i}')
268
  vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
269
  continue
270
  uv, depth_vert = get_uv_depth(vertices, depth_np)
271
  # Normalize the uv to the camera intrinsics
272
  xy_local = np.ones((len(uv), 3))
273
+ xy_local[:, 0] = (uv[:, 0] - K[0, 2]) / K[0, 0]
274
+ xy_local[:, 1] = (uv[:, 1] - K[1, 2]) / K[1, 1]
275
  # Get the 3D vertices
276
+ vertices_3d_local = depth_vert[..., None] * (xy_local / np.linalg.norm(xy_local, axis=1)[..., None])
277
  world_to_cam = np.eye(4)
278
  world_to_cam[:3, :3] = R
279
  world_to_cam[:3, 3] = t.reshape(-1)
280
+ cam_to_world = np.linalg.inv(world_to_cam)
281
  vertices_3d = cv2.transform(cv2.convertPointsToHomogeneous(vertices_3d_local), cam_to_world)
282
  vertices_3d = cv2.convertPointsFromHomogeneous(vertices_3d).reshape(-1, 3)
283
  vert_edge_per_image[i] = vertices, connections, vertices_3d
284
  all_3d_vertices, connections_3d = merge_vertices_3d(vert_edge_per_image, 3.0)
285
+ all_3d_vertices_clean, connections_3d_clean = prune_not_connected(all_3d_vertices, connections_3d)
286
  if (len(all_3d_vertices_clean) < 2) or len(connections_3d_clean) < 1:
287
+ print(f'Not enough vertices or connections in the 3D vertices')
288
  return (good_entry['__key__'], *empty_solution())
289
  if visualize:
290
  from hoho.viz3d import plot_estimate_and_gt
291
+ plot_estimate_and_gt(all_3d_vertices_clean,
292
+ connections_3d_clean,
293
+ good_entry['wf_vertices'],
294
+ good_entry['wf_edges'])
295
+ return good_entry['__key__'], all_3d_vertices_clean, connections_3d_clean