Siromanec commited on
Commit
94daf11
1 Parent(s): c65c7a4

a lot of changes, I want to see how it performs (rewrote evaluation to load data in batches)

Browse files
Files changed (2) hide show
  1. handcrafted_solution.py +188 -90
  2. script.py +36 -23
handcrafted_solution.py CHANGED
@@ -14,6 +14,12 @@ from hoho.read_write_colmap import read_cameras_binary, read_images_binary, read
14
  from scipy.spatial import KDTree
15
  from scipy.spatial.distance import cdist
16
  from sklearn.cluster import DBSCAN
 
 
 
 
 
 
17
 
18
  apex_color = gestalt_color_mapping["apex"]
19
  eave_end_point = gestalt_color_mapping["eave_end_point"]
@@ -23,7 +29,24 @@ apex_color, eave_end_point, flashing_end_point = [np.array(i) for i in [apex_col
23
  unclassified = np.array([(215, 62, 138)])
24
  line_classes = ['eave', 'ridge', 'rake', 'valley']
25
 
26
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  def empty_solution():
28
  '''Return a minimal valid solution, i.e. 2 vertices and 1 edge.'''
29
  return np.zeros((2, 3)), [(0, 1)]
@@ -70,15 +93,15 @@ def remove_undesired_objects(image):
70
  def clean_image(image_gestalt) -> np.ndarray:
71
  # clears image in from of unclassified and disconected components
72
  image_gestalt = np.array(image_gestalt)
73
- unclassified_mask = cv2.inRange(image_gestalt, unclassified + 0.0, unclassified + 0.8)
74
- unclassified_mask = cv2.bitwise_not(unclassified_mask)
75
- mask = remove_undesired_objects(unclassified_mask).astype(np.uint8)
76
- mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((11, 11), np.uint8), iterations=11)
77
- mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, np.ones((11, 11), np.uint8), iterations=2)
78
-
79
- image_gestalt[:, :, 0] *= mask
80
- image_gestalt[:, :, 1] *= mask
81
- image_gestalt[:, :, 2] *= mask
82
  return image_gestalt
83
 
84
 
@@ -98,10 +121,10 @@ def get_vertices(image_gestalt, *, color_range=4., dialations=3, erosions=1, ker
98
  eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_DILATE, kernel, iterations=dialations)
99
  eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_ERODE, kernel, iterations=erosions)
100
 
101
- *_, apex_centroids = cv2.connectedComponentsWithStats(apex_mask, connectivity=4, stats=cv2.CV_32S)
102
- *_, other_centroids = cv2.connectedComponentsWithStats(eave_end_point_mask, connectivity=4, stats=cv2.CV_32S)
103
 
104
- return apex_centroids[1:], other_centroids[1:], apex_mask, eave_end_point_mask
105
 
106
 
107
  def infer_vertices(image_gestalt, *, color_range=4.):
@@ -168,8 +191,8 @@ def get_lines_and_directions(gest_seg_np, edge_class, *, color_range=4., rho, th
168
 
169
  direction = extend * direction
170
 
171
- x1, y1 = (-direction + (x1, y1)).astype(np.int32)
172
- x2, y2 = (+ direction + (x2, y2)).astype(np.int32)
173
 
174
  edges.append((x1, y1, x2, y2))
175
  return edges, line_directions
@@ -189,14 +212,19 @@ def infer_missing_vertices(ridge_edges, rake_edges):
189
  return ridge_ends.data[missing_candidates]
190
 
191
 
192
- def get_vertices_and_edges_from_segmentation(gest_seg_np, *, point_radius=30, max_angle=5.,
 
 
 
193
  **kwargs):
194
  '''Get the vertices and edges from the gestalt segmentation mask of the house'''
195
  # Apex
196
  connections = []
197
  deviation_threshold = np.cos(np.deg2rad(max_angle))
198
 
199
- apex_centroids, eave_end_point_centroids, apex_mask, eave_end_point_mask = get_vertices(gest_seg_np)
 
 
200
 
201
  vertices = np.concatenate([apex_centroids, eave_end_point_centroids])
202
  # inferred_vertices, inferred_mask = infer_vertices(gest_seg_np)
@@ -206,12 +234,6 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, point_radius=30, ma
206
  if len(vertices) < 2:
207
  return [], []
208
 
209
- # scale = 1
210
- # vertex_size = np.zeros(vertices.shape[0])
211
- # for i, coords in enumerate(vertices):
212
- # # coords = np.round(coords).astype(np.uint32)
213
- # radius = point_radius # np.clip(int(max_depth//2 + depth_np[coords[1], coords[0]]), 10, 30)#int(np.clip(max_depth - depth_np[coords[1], coords[0]], 10, 20))
214
- # vertex_size[i] = (scale * radius) ** 2 # because we are using squared distances
215
 
216
  edges = []
217
  line_directions = []
@@ -251,6 +273,19 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, point_radius=30, ma
251
  missed_vertices = get_missed_vertices(vertices, inferred_vertices, **kwargs)
252
  vertices = np.concatenate([vertices, missed_vertices])
253
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  vertices = KDTree(vertices)
255
 
256
  for edge_class in ['eave',
@@ -291,12 +326,29 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, point_radius=30, ma
291
  end_vertex_list = []
292
  line_idx_list = []
293
  for line_idx in line_indices:
294
- begin_vertex, end_vertex = begin_indices[line_idx], end_indices[line_idx]
295
- begin_vertex, end_vertex = np.meshgrid(begin_vertex, end_vertex)
296
- begin_vertex_list.extend(begin_vertex.flatten())
297
- end_vertex_list.extend(end_vertex.flatten())
 
 
 
 
 
 
 
 
 
 
 
 
 
298
 
299
- line_idx_list.extend([line_idx] * len(begin_vertex.flatten()))
 
 
 
 
300
 
301
  line_idx_list = np.array(line_idx_list)
302
  all_connections = np.array([begin_vertex_list, end_vertex_list])
@@ -334,9 +386,9 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, point_radius=30, ma
334
  if np.any(line_deviations > deviation_threshold):
335
  connections.append(possible_connections[:, fitted_line_idx])
336
 
337
- vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
338
- vertices += [{"xy": v, "type": "apex"} for v in missed_vertices]
339
- vertices += [{"xy": v, "type": "eave_end_point"} for v in eave_end_point_centroids]
340
  return vertices, connections
341
 
342
 
@@ -376,7 +428,7 @@ def merge_vertices_3d(vert_edge_per_image, merge_th=0.1, **kwargs):
376
  new_vertex_mapping = dict(zip(left_vertex_indices, new_indices))
377
 
378
  vertices = [v for i, v in enumerate(vertices) if i in new_vertex_mapping]
379
- types += [int(v['type'] == 'apex') for v in vertices]
380
  vertices_3d = vertices_3d[left_vertex_indices]
381
  connections = [[new_vertex_mapping[a] + cur_start, new_vertex_mapping[b] + cur_start] for a, b in connections]
382
 
@@ -454,8 +506,13 @@ def prune_not_connected(all_3d_vertices, connections_3d):
454
  return np.array(new_verts), connected_out
455
 
456
 
457
- def predict(entry, visualize=False, scale_estimation_coefficient=2.5, clustering_eps=100, dist_coeff=0, pointcloud_depth_coeff = 1, **kwargs) -> Tuple[
458
- np.ndarray, List[int]]:
 
 
 
 
 
459
  if 'gestalt' not in entry or 'depthcm' not in entry or 'K' not in entry or 'R' not in entry or 't' not in entry:
460
  print('Missing required fields in the entry')
461
  return (entry['__key__'], *empty_solution())
@@ -486,10 +543,13 @@ def predict(entry, visualize=False, scale_estimation_coefficient=2.5, clustering
486
  clustered_keys = np.split(point_keys, cluster_indices[1:])
487
 
488
  biggest_cluster_index = np.argmax([len(i) for i in clustered_points])
489
- # biggest_cluster = clustered_points[biggest_cluster_index]
490
  biggest_cluster_keys = clustered_keys[biggest_cluster_index]
491
  biggest_cluster_keys = set(biggest_cluster_keys)
492
 
 
 
 
493
  for i, (gest, depthcm, K, R, t, imagekey) in enumerate(zip(entry['gestalt'],
494
  entry['depthcm'],
495
  entry['K'],
@@ -498,89 +558,127 @@ def predict(entry, visualize=False, scale_estimation_coefficient=2.5, clustering
498
  entry['__imagekey__']
499
  )):
500
 
 
 
 
 
 
 
 
 
 
 
501
  try:
502
- # gest_seg = gest.resize(depthcm.size)
503
- gest_seg_np = np.array(gest).astype(np.uint8)
504
- vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, **kwargs)
505
- if (len(vertices) < 2) or (len(connections) < 1):
506
- print(f'Not enough vertices or connections in image {i}')
507
- vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
508
- continue
509
- belonging_points = []
510
- for point_id in image_dict[imagekey].point3D_ids[np.where(image_dict[imagekey].point3D_ids != -1)]:
511
  if point_id in biggest_cluster_keys:
512
- belonging_points.append(entry["points3d"][point_id])
 
513
 
514
- if len(belonging_points) < 1:
515
  print(f'No 3D points in image {i}')
516
  vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
517
  raise KeyError
518
- projected2d, _ = cv2.projectPoints(np.array([i.xyz for i in belonging_points]), R, t, K, dist_coeff)
519
- important = np.where(np.all(projected2d >= 0, axis=2))
 
 
520
  # Normalize the uv to the camera intrinsics
521
  world_to_cam = np.eye(4)
522
  world_to_cam[:3, :3] = R
523
  world_to_cam[:3, 3] = t
524
 
525
- homo_belonging_points = cv2.convertPointsToHomogeneous(np.array([i.xyz for i in belonging_points]))
526
  depth = cv2.convertPointsFromHomogeneous(cv2.transform(homo_belonging_points, world_to_cam))
527
  depth = depth[:, 0, 2]
528
- depth = depth[important[0]] * pointcloud_depth_coeff
529
- projected2d = projected2d[important]
 
 
 
 
 
530
  if len(depth) < 1:
531
  print(f'No 3D points in image {i}')
532
  vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
533
  raise KeyError
534
  # print(projected2d.shape, depth.shape)
535
 
536
- interpolator = si.NearestNDInterpolator(projected2d, depth, rescale=True)
537
- # interpolator = si.CloughTocher2DInterpolator(projected2d, depth, np.nan)
 
538
 
539
- vertex_coordinates = np.array([v['xy'] for v in vertices])
540
- xi, yi = vertex_coordinates[:, 0], vertex_coordinates[:, 1]
541
- depth_vert = interpolator(xi, yi)
542
- xy_local = np.ones((len(vertex_coordinates), 3))
543
- xy_local[:, 0] = (vertex_coordinates[:, 0] - K[0, 2]) / K[0, 0]
544
- xy_local[:, 1] = (vertex_coordinates[:, 1] - K[1, 2]) / K[1, 1]
545
- # Get the 3D vertices
546
- vertices_3d_local = depth_vert[..., None] * (xy_local / np.linalg.norm(xy_local, axis=1)[..., None])
547
- world_to_cam = np.eye(4)
548
- world_to_cam[:3, :3] = R
549
- world_to_cam[:3, 3] = t.reshape(-1)
550
- cam_to_world = np.linalg.inv(world_to_cam)
551
- vertices_3d = cv2.transform(cv2.convertPointsToHomogeneous(vertices_3d_local), cam_to_world)
552
- vertices_3d = cv2.convertPointsFromHomogeneous(vertices_3d).reshape(-1, 3)
553
 
 
554
  except KeyError:
555
- gest_seg = gest.resize(depthcm.size)
556
- gest_seg_np = np.array(gest_seg).astype(np.uint8)
557
  # Metric3D
558
- depth_np = np.array(depthcm) / scale_estimation_coefficient
559
- cv2.GaussianBlur(depth_np, (21, 21), 1, depth_np)
560
- # cv2.medianBlur(depth_np, 5)
561
- # depth_np = np.zeros_like(depth_np)
562
- vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, **kwargs)
563
- if (len(vertices) < 2) or (len(connections) < 1):
564
- print(f'Not enough vertices or connections in image {i}')
565
- vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
566
- continue
567
- uv, depth_vert = get_uv_depth(vertices, depth_np)
568
  # Normalize the uv to the camera intrinsics
569
- xy_local = np.ones((len(uv), 3))
570
- xy_local[:, 0] = (uv[:, 0] - K[0, 2]) / K[0, 0]
571
- xy_local[:, 1] = (uv[:, 1] - K[1, 2]) / K[1, 1]
572
- # Get the 3D vertices
573
- vertices_3d_local = depth_vert[..., None] * (xy_local / np.linalg.norm(xy_local, axis=1)[..., None])
574
- world_to_cam = np.eye(4)
575
- world_to_cam[:3, :3] = R
576
- world_to_cam[:3, 3] = t.reshape(-1)
577
- cam_to_world = np.linalg.inv(world_to_cam)
578
- vertices_3d = cv2.transform(cv2.convertPointsToHomogeneous(vertices_3d_local), cam_to_world)
579
- vertices_3d = cv2.convertPointsFromHomogeneous(vertices_3d).reshape(-1, 3)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
580
 
581
  vert_edge_per_image[i] = vertices, connections, vertices_3d
582
  all_3d_vertices, connections_3d = merge_vertices_3d(vert_edge_per_image, **kwargs)
583
  all_3d_vertices_clean, connections_3d_clean = all_3d_vertices, connections_3d
 
 
 
 
584
  # all_3d_vertices_clean, connections_3d_clean = prune_not_connected(all_3d_vertices, connections_3d)
585
  if (len(all_3d_vertices_clean) < 2) or len(connections_3d_clean) < 1:
586
  print(f'Not enough vertices or connections in the 3D vertices')
 
14
  from scipy.spatial import KDTree
15
  from scipy.spatial.distance import cdist
16
  from sklearn.cluster import DBSCAN
17
+ from scipy.spatial import cKDTree
18
+
19
+ from enum import Enum
20
+
21
+
22
+
23
 
24
  apex_color = gestalt_color_mapping["apex"]
25
  eave_end_point = gestalt_color_mapping["eave_end_point"]
 
29
  unclassified = np.array([(215, 62, 138)])
30
  line_classes = ['eave', 'ridge', 'rake', 'valley']
31
 
32
+ class VertexType(Enum):
33
+ APEX = 0
34
+ EAVE_END_POINT = 1
35
+
36
+ class NearestNDInterpolatorWithThreshold(si.NearestNDInterpolator):
37
+ def __init__(self, points, values, max_distance):
38
+ super().__init__(points, values)
39
+ self.max_distance = max_distance
40
+ self.tree = cKDTree(points)
41
+
42
+ def __call__(self, *args):
43
+ # Convert the input to a 2D array of query points
44
+ query_points = np.array(args).T
45
+ distances, indices = self.tree.query(query_points)
46
+ values = np.full(query_points.shape[:-1], np.nan)
47
+ valid_mask = distances <= self.max_distance
48
+ values[valid_mask] = self.values[indices[valid_mask]]
49
+ return values.T
50
  def empty_solution():
51
  '''Return a minimal valid solution, i.e. 2 vertices and 1 edge.'''
52
  return np.zeros((2, 3)), [(0, 1)]
 
93
  def clean_image(image_gestalt) -> np.ndarray:
94
  # clears image in from of unclassified and disconected components
95
  image_gestalt = np.array(image_gestalt)
96
+ # unclassified_mask = cv2.inRange(image_gestalt, unclassified - 1, unclassified + 1)
97
+ # unclassified_mask = cv2.bitwise_not(unclassified_mask)
98
+ # mask = remove_undesired_objects(unclassified_mask).astype(np.uint8)
99
+ # mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((11, 11), np.uint8), iterations=11)
100
+ # mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, np.ones((11, 11), np.uint8), iterations=2)
101
+
102
+ # image_gestalt[:, :, 0] *= mask
103
+ # image_gestalt[:, :, 1] *= mask
104
+ # image_gestalt[:, :, 2] *= mask
105
  return image_gestalt
106
 
107
 
 
121
  eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_DILATE, kernel, iterations=dialations)
122
  eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_ERODE, kernel, iterations=erosions)
123
 
124
+ *_, apex_stats, apex_centroids = cv2.connectedComponentsWithStats(apex_mask, connectivity=4, stats=cv2.CV_32S)
125
+ *_, other_stats, other_centroids = cv2.connectedComponentsWithStats(eave_end_point_mask, connectivity=4, stats=cv2.CV_32S)
126
 
127
+ return apex_centroids[1:], other_centroids[1:], apex_mask, eave_end_point_mask, apex_stats[1:, cv2.CC_STAT_WIDTH]/2, other_stats[1:, cv2.CC_STAT_WIDTH]/2
128
 
129
 
130
  def infer_vertices(image_gestalt, *, color_range=4.):
 
191
 
192
  direction = extend * direction
193
 
194
+ x1, y1 = -direction + (x1, y1)
195
+ x2, y2 = + direction + (x2, y2)
196
 
197
  edges.append((x1, y1, x2, y2))
198
  return edges, line_directions
 
212
  return ridge_ends.data[missing_candidates]
213
 
214
 
215
+ def get_vertices_and_edges_from_segmentation(gest_seg_np, *,
216
+ point_radius=30,
217
+ max_angle=5.,
218
+ point_radius_scale=1,
219
  **kwargs):
220
  '''Get the vertices and edges from the gestalt segmentation mask of the house'''
221
  # Apex
222
  connections = []
223
  deviation_threshold = np.cos(np.deg2rad(max_angle))
224
 
225
+ (apex_centroids, eave_end_point_centroids,
226
+ apex_mask, eave_end_point_mask,
227
+ apex_radii, eave_radii) = get_vertices(gest_seg_np)
228
 
229
  vertices = np.concatenate([apex_centroids, eave_end_point_centroids])
230
  # inferred_vertices, inferred_mask = infer_vertices(gest_seg_np)
 
234
  if len(vertices) < 2:
235
  return [], []
236
 
 
 
 
 
 
 
237
 
238
  edges = []
239
  line_directions = []
 
273
  missed_vertices = get_missed_vertices(vertices, inferred_vertices, **kwargs)
274
  vertices = np.concatenate([vertices, missed_vertices])
275
 
276
+ vertex_size = np.full(len(vertices), point_radius/2)
277
+ apex_radii *= point_radius_scale
278
+ eave_radii *= point_radius_scale
279
+ apex_radii = np.clip(apex_radii, 10, point_radius)
280
+ eave_radii = np.clip(eave_radii, 10, point_radius)
281
+ vertex_size[:len(apex_radii)] = apex_radii
282
+ vertex_size[len(apex_radii):len(apex_radii) + len(eave_radii)] = eave_radii
283
+
284
+ # for i, coords in enumerate(vertices):
285
+ # coords = np.round(coords).astype(np.uint32)
286
+ # radius = point_radius # np.clip(int(max_depth//2 + depth_np[coords[1], coords[0]]), 10, 30)#int(np.clip(max_depth - depth_np[coords[1], coords[0]], 10, 20))
287
+ # vertex_size[i] = scale * radius
288
+
289
  vertices = KDTree(vertices)
290
 
291
  for edge_class in ['eave',
 
326
  end_vertex_list = []
327
  line_idx_list = []
328
  for line_idx in line_indices:
329
+ begin_vertices, end_vertices = begin_indices[line_idx], end_indices[line_idx]
330
+ begin_vertices, end_vertices = np.array(begin_vertices), np.array(end_vertices)
331
+ begin_value = begin_edges.data[line_idx]
332
+ end_value = end_edges.data[line_idx]
333
+ begin_in_range_indices = np.where(
334
+ np.linalg.norm(vertices.data[begin_vertices] - begin_value, axis=1)
335
+ <
336
+ vertex_size[begin_vertices])[0]
337
+ end_in_range_indices = np.where(
338
+ np.linalg.norm(vertices.data[end_vertices] - end_value, axis=1)
339
+ <
340
+ vertex_size[end_vertices])[0]
341
+ begin_vertices = begin_vertices[begin_in_range_indices]
342
+ end_vertices = end_vertices[end_in_range_indices]
343
+ if len(begin_vertices) < 1 or len(end_vertices) < 1:
344
+ continue
345
+
346
 
347
+ begin_vertices, end_vertices = np.meshgrid(begin_vertices, end_vertices)
348
+ begin_vertex_list.extend(begin_vertices.flatten())
349
+ end_vertex_list.extend(end_vertices.flatten())
350
+
351
+ line_idx_list.extend([line_idx] * len(begin_vertices.flatten()))
352
 
353
  line_idx_list = np.array(line_idx_list)
354
  all_connections = np.array([begin_vertex_list, end_vertex_list])
 
386
  if np.any(line_deviations > deviation_threshold):
387
  connections.append(possible_connections[:, fitted_line_idx])
388
 
389
+ vertices = [{"xy": v, "type": VertexType.APEX} for v in apex_centroids]
390
+ vertices += [{"xy": v, "type": VertexType.APEX} for v in missed_vertices]
391
+ vertices += [{"xy": v, "type": VertexType.EAVE_END_POINT} for v in eave_end_point_centroids]
392
  return vertices, connections
393
 
394
 
 
428
  new_vertex_mapping = dict(zip(left_vertex_indices, new_indices))
429
 
430
  vertices = [v for i, v in enumerate(vertices) if i in new_vertex_mapping]
431
+ types += [int(v['type'] == VertexType.APEX) for v in vertices]
432
  vertices_3d = vertices_3d[left_vertex_indices]
433
  connections = [[new_vertex_mapping[a] + cur_start, new_vertex_mapping[b] + cur_start] for a, b in connections]
434
 
 
506
  return np.array(new_verts), connected_out
507
 
508
 
509
+ def predict(entry, visualize=False,
510
+ scale_estimation_coefficient=2.5,
511
+ clustering_eps=100,
512
+ dist_coeff=0,
513
+ pointcloud_depth_coeff = 1,
514
+ interpolation_radius=200,
515
+ **kwargs) -> Tuple[np.ndarray, List[int]]:
516
  if 'gestalt' not in entry or 'depthcm' not in entry or 'K' not in entry or 'R' not in entry or 't' not in entry:
517
  print('Missing required fields in the entry')
518
  return (entry['__key__'], *empty_solution())
 
543
  clustered_keys = np.split(point_keys, cluster_indices[1:])
544
 
545
  biggest_cluster_index = np.argmax([len(i) for i in clustered_points])
546
+ biggest_cluster = clustered_points[biggest_cluster_index]
547
  biggest_cluster_keys = clustered_keys[biggest_cluster_index]
548
  biggest_cluster_keys = set(biggest_cluster_keys)
549
 
550
+ points3d_kdtree = KDTree(biggest_cluster)
551
+
552
+
553
  for i, (gest, depthcm, K, R, t, imagekey) in enumerate(zip(entry['gestalt'],
554
  entry['depthcm'],
555
  entry['K'],
 
558
  entry['__imagekey__']
559
  )):
560
 
561
+ gest_seg = gest.resize(depthcm.size)
562
+ gest_seg_np = np.array(gest_seg).astype(np.uint8)
563
+ vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, **kwargs)
564
+
565
+ if (len(vertices) < 2) or (len(connections) < 1):
566
+ print(f'Not enough vertices or connections in image {i}')
567
+ vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
568
+ continue
569
+ depth_np = np.array(depthcm) / scale_estimation_coefficient
570
+ uv, depth_vert_from_depth_map = get_uv_depth(vertices, depth_np)
571
  try:
572
+ belonging_points3d = []
573
+ belonging_points2d = []
574
+ point_indices = np.where(image_dict[imagekey].point3D_ids != -1)[0]
575
+ for idx, point_id in zip(point_indices, image_dict[imagekey].point3D_ids[point_indices]):
 
 
 
 
 
576
  if point_id in biggest_cluster_keys:
577
+ belonging_points3d.append(entry["points3d"][point_id].xyz)
578
+ belonging_points2d.append(image_dict[imagekey].xys[idx])
579
 
580
+ if len(belonging_points3d) < 1:
581
  print(f'No 3D points in image {i}')
582
  vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
583
  raise KeyError
584
+ belonging_points3d = np.array(belonging_points3d)
585
+ belonging_points2d = np.array(belonging_points2d)
586
+ # projected2d, _ = cv2.projectPoints(belonging_points3d, R, t, K, dist_coeff)
587
+ important = np.where(np.all(belonging_points2d >= 0, axis=1))
588
  # Normalize the uv to the camera intrinsics
589
  world_to_cam = np.eye(4)
590
  world_to_cam[:3, :3] = R
591
  world_to_cam[:3, 3] = t
592
 
593
+ homo_belonging_points = cv2.convertPointsToHomogeneous(belonging_points3d)
594
  depth = cv2.convertPointsFromHomogeneous(cv2.transform(homo_belonging_points, world_to_cam))
595
  depth = depth[:, 0, 2]
596
+ # projected2d = projected2d[:, 0, :]
597
+ depth = depth[important[0]]
598
+ # projected2d = projected2d[important[0]]
599
+ projected2d = belonging_points2d[important[0]]
600
+ # print(projected2d.shape)
601
+ # print(depth.shape)
602
+ depth *= pointcloud_depth_coeff
603
  if len(depth) < 1:
604
  print(f'No 3D points in image {i}')
605
  vert_edge_per_image[i] = np.empty((0, 2)), [], np.empty((0, 3))
606
  raise KeyError
607
  # print(projected2d.shape, depth.shape)
608
 
609
+ # interpolator = si.NearestNDInterpolator(projected2d, depth, rescale=True)
610
+ interpolator = NearestNDInterpolatorWithThreshold(projected2d, depth, interpolation_radius)
611
+ # interpolator = si.LinearNDInterpolator(projected2d, depth, np.nan)
612
 
613
+ uv = np.array([v['xy'] for v in vertices])
614
+ xi, yi = uv[:, 0], uv[:, 1]
615
+ depth_vert_from_pointcloud = interpolator(xi, yi)
616
+ depthmap_used = False
 
 
 
 
 
 
 
 
 
 
617
 
618
+ # Get the 3D vertices
619
  except KeyError:
620
+ #Revert to the depthmap
 
621
  # Metric3D
622
+ depthmap_used = True
623
+
 
 
 
 
 
 
 
 
624
  # Normalize the uv to the camera intrinsics
625
+
626
+ xy_local = np.ones((len(uv), 3))
627
+ xy_local[:, 0] = (uv[:, 0] - K[0, 2]) / K[0, 0]
628
+ xy_local[:, 1] = (uv[:, 1] - K[1, 2]) / K[1, 1]
629
+ # Get the 3D vertices
630
+
631
+ depth_vert_nan_idxs = None
632
+ if depthmap_used:
633
+ # norm_factor = np.max(np.linalg.norm(xy_local, axis=1)[..., None])
634
+ depth_vert = depth_vert_from_depth_map
635
+ else:
636
+ # 1. query detected vertices in projected2d
637
+ # if the vertex is beyond some radius, use the depthmap
638
+ # isnt uv
639
+ depth_vert_nan_idxs = np.where(np.isnan(depth_vert_from_pointcloud))[0]
640
+ depth_vert_from_pointcloud[depth_vert_nan_idxs] = depth_vert_from_depth_map[depth_vert_nan_idxs]
641
+ depth_vert = depth_vert_from_pointcloud
642
+
643
+ norm_factor = np.linalg.norm(xy_local, axis=1)[..., None]
644
+ if depth_vert_nan_idxs is not None and len(depth_vert_nan_idxs) > 0:
645
+ norm_factor_min = np.min(norm_factor[depth_vert_nan_idxs])
646
+ if len(depth_vert_nan_idxs) != len(norm_factor):
647
+ norm_factor_max = np.max(norm_factor[~np.isin(np.arange(len(norm_factor)), depth_vert_nan_idxs)])
648
+ else:
649
+ norm_factor_max = np.max(norm_factor)
650
+ else:
651
+ norm_factor_min = np.min(norm_factor)
652
+ norm_factor_max = np.max(norm_factor)
653
+
654
+ vertices_3d_local = depth_vert[..., None] * xy_local
655
+ if depthmap_used:
656
+ vertices_3d_local /= norm_factor_max
657
+ else:
658
+ vertices_3d_local[depth_vert_nan_idxs] /= norm_factor_max
659
+ vertices_3d_local[~np.isin(np.arange(len(vertices_3d_local)), depth_vert_nan_idxs)] /= norm_factor_min
660
+
661
+ # vertices_3d_local = depth_vert[..., None] * (xy_local / norm_factor)
662
+ world_to_cam = np.eye(4)
663
+ world_to_cam[:3, :3] = R
664
+ world_to_cam[:3, 3] = t
665
+
666
+ cam_to_world = np.linalg.inv(world_to_cam)
667
+ vertices_3d = cv2.transform(cv2.convertPointsToHomogeneous(vertices_3d_local), cam_to_world)
668
+ vertices_3d = cv2.convertPointsFromHomogeneous(vertices_3d).reshape(-1, 3)
669
+
670
+ # not_nan_items = np.all(~np.isnan(vertices_3d), axis=1)
671
+ # _, closest_fitted = points3d_kdtree.query(vertices_3d[not_nan_items])
672
+
673
+ # vertices_3d[not_nan_items] = points3d_kdtree.data[closest_fitted]
674
 
675
  vert_edge_per_image[i] = vertices, connections, vertices_3d
676
  all_3d_vertices, connections_3d = merge_vertices_3d(vert_edge_per_image, **kwargs)
677
  all_3d_vertices_clean, connections_3d_clean = all_3d_vertices, connections_3d
678
+ # highest_edges = np.argpartition(all_3d_vertices_clean[:, 1], 4)[:4].tolist()
679
+ #
680
+ # connections_3d_clean.append(highest_edges[:2])
681
+ # connections_3d_clean.append(highest_edges[2:])
682
  # all_3d_vertices_clean, connections_3d_clean = prune_not_connected(all_3d_vertices, connections_3d)
683
  if (len(all_3d_vertices_clean) < 2) or len(connections_3d_clean) < 1:
684
  print(f'Not enough vertices or connections in the 3D vertices')
script.py CHANGED
@@ -116,7 +116,18 @@ def save_submission(submission, path):
116
  sub = pd.DataFrame(submission, columns=["__key__", "wf_vertices", "wf_edges"])
117
  sub.to_parquet(path)
118
  print(f"Submission saved to {path}")
119
-
 
 
 
 
 
 
 
 
 
 
 
120
  if __name__ == "__main__":
121
  from handcrafted_solution import predict
122
  print ("------------ Loading dataset------------ ")
@@ -127,28 +138,30 @@ if __name__ == "__main__":
127
  solution = []
128
  from concurrent.futures import ProcessPoolExecutor
129
  with ProcessPoolExecutor(max_workers=8) as pool:
130
- results = []
131
- for i, sample in enumerate(tqdm(dataset)):
132
- results.append(pool.submit(predict, sample,
133
- visualize=False,
134
- point_radius=15,
135
- max_angle=5,
136
- extend=25,
137
- merge_th=100.0,
138
- min_missing_distance=350.0,
139
- scale_estimation_coefficient=2.54,
140
- clustering_eps=100,
141
- dist_coeff=0.1,
142
- pointcloud_depth_coeff=1.05,
143
- ))
144
-
145
- for i, result in enumerate(tqdm(results)):
146
- key, pred_vertices, pred_edges = result.result()
147
- solution.append({
148
- '__key__': key,
149
- 'wf_vertices': pred_vertices.tolist(),
150
- 'wf_edges': pred_edges
151
- })
 
 
152
  if i % 100 == 0:
153
  # incrementally save the results in case we run out of time
154
  print(f"Processed {i} samples")
 
116
  sub = pd.DataFrame(submission, columns=["__key__", "wf_vertices", "wf_edges"])
117
  sub.to_parquet(path)
118
  print(f"Submission saved to {path}")
119
+ batch_size = 48 # You can adjust this according to your needs
120
+
121
+ # Define a generator function to yield batches of samples
122
+ def batch_generator(dataset, batch_size):
123
+ batch = []
124
+ for i, sample in enumerate(dataset):
125
+ batch.append(sample)
126
+ if len(batch) == batch_size:
127
+ yield batch
128
+ batch = []
129
+ if batch: # Yield the remaining samples
130
+ yield batch
131
  if __name__ == "__main__":
132
  from handcrafted_solution import predict
133
  print ("------------ Loading dataset------------ ")
 
138
  solution = []
139
  from concurrent.futures import ProcessPoolExecutor
140
  with ProcessPoolExecutor(max_workers=8) as pool:
141
+ for batch in tqdm(batch_generator(dataset, batch_size), desc='Batches'):
142
+ results = []
143
+ for i, sample in enumerate(batch):
144
+ results.append(pool.submit(predict, sample,
145
+ point_radius=40,
146
+ max_angle=15,
147
+ extend=25,
148
+ merge_th=80.0,
149
+ min_missing_distance=350.0,
150
+ scale_estimation_coefficient=2.54,
151
+ clustering_eps=120,
152
+ interpolation_radius=200,
153
+ point_radius_scale=0.5,
154
+ # dist_coeff=0,
155
+ # pointcloud_depth_coeff=1,
156
+ ))
157
+
158
+ for result in tqdm(results, desc='Results', total=len(results), position=0):
159
+ key, pred_vertices, pred_edges = result.result()
160
+ solution.append({
161
+ '__key__': key,
162
+ 'wf_vertices': pred_vertices.tolist(),
163
+ 'wf_edges': pred_edges
164
+ })
165
  if i % 100 == 0:
166
  # incrementally save the results in case we run out of time
167
  print(f"Processed {i} samples")