Siromanec commited on
Commit
8aa41b5
1 Parent(s): bef6092

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
Files changed (1) hide show
  1. 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 = ['__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
- if k == 'points3d':
88
- out[k] = read_points3D_binary(fid=io.BytesIO(v))
89
- if k == 'cameras':
90
- out[k] = read_cameras_binary(fid=io.BytesIO(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
 
 
 
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, ), 40, -1)
112
  for i in eave_end_point_centroids:
113
- cv2.circle(vertex_mask, np.round(i).astype(np.uint32), 15, (255, ), 30, -1)
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
- if np.any(mask): # does not really make sense to dilate something if it is empty
129
- mask = cv2.bitwise_and(mask, vertex_mask)
130
-
131
  mask = cv2.morphologyEx(mask,
132
- cv2.MORPH_DILATE, np.ones((11, 11)), iterations=3)
133
- # line_img = np.zeros_like(gest_seg_np)
134
- output = cv2.connectedComponentsWithStats(mask, 8, cv2.CV_32S)
135
- (numLabels, labels, stats, centroids) = output
136
- # stats, centroids = stats[1:], centroids[1:]
 
 
 
 
 
 
 
 
 
 
137
  edges = []
138
- for i in range(1, numLabels):
139
- y, x = np.where(labels == i)
140
- xleft_idx = np.argmin(x)
141
- x_left = x[xleft_idx]
142
- y_left = y[xleft_idx]
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
- pts_to_edges_dist = np.minimum(cdist(apex_pts, edges[:, :2]), cdist(apex_pts, edges[:, 2:]))
152
- connectivity_mask = pts_to_edges_dist <= edge_th
153
- edge_connects = connectivity_mask.sum(axis=0)
154
- for edge_idx, edgesum in enumerate(edge_connects):
155
- if edgesum >= 2:
156
- connected_verts = np.where(connectivity_mask[:, edge_idx])[0]
157
- for a_i, a in enumerate(connected_verts):
158
- for b in connected_verts[a_i + 1:]:
159
- connections.append((a, b))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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