Skip to content

Commit 84352d8

Browse files
committed
Fixing quad so it extends to the edges of the mask
Ignoring rectangles that lie outside of the image
1 parent 1eb51ae commit 84352d8

File tree

2 files changed

+73
-18
lines changed

2 files changed

+73
-18
lines changed

Image_based/LeaderDetector.py

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,25 @@
1919

2020
class LeaderDetector:
2121
image_type = {"Mask", "Flow", "RGB1", "RGB2", "Edge", "RGB_Stats", "Mask_Stats", "Edge_debug"}
22+
23+
_width = 0
24+
_height = 0
25+
26+
_x_grid = None
27+
_y_grid = None
28+
29+
@staticmethod
30+
def _init_grid_(in_im):
31+
""" INitialize width, height, xgrid, etc so we don't have to keep re-making it
32+
:param in_im: Input image
33+
"""
34+
if LeaderDetector._width == in_im.shape[1] and LeaderDetector._height == in_im.shape[0]:
35+
return
36+
LeaderDetector._width = in_im.shape[1]
37+
LeaderDetector._height = in_im.shape[0]
38+
39+
LeaderDetector._x_grid, LeaderDetector._y_grid = np.meshgrid(np.linspace(0.5, LeaderDetector._width - 0.5, LeaderDetector._width), np.linspace(0.5, LeaderDetector._height - 0.5, LeaderDetector._height))
40+
2241
def __init__(self, path, image_name, b_output_debug=True, b_recalc=False):
2342
""" Read in the image, mask image, flow image, 2 rgb images
2443
@param path: Directory where files are located
@@ -32,7 +51,7 @@ def __init__(self, path, image_name, b_output_debug=True, b_recalc=False):
3251
# Read in all images that have name_ and are not debugging images
3352
self.images = self.read_images(path, image_name)
3453
# Split the mask into connected components, each of which might be a vertical leader
35-
self.vertical_leader_masks = self.split_mask(self.images["Mask"], b_debug=b_output_debug)
54+
self.vertical_leader_masks = self.split_mask(self.images["Mask"], b_one_mask=True, b_debug=b_output_debug)
3655
self.vertical_leader_stats = []
3756
self.vertical_leader_quads = []
3857

@@ -85,7 +104,7 @@ def __init__(self, path, image_name, b_output_debug=True, b_recalc=False):
85104
pass
86105

87106
cv2.imwrite(self.path_debug + image_name + "_" + f"{i}_mask_points.png", self.images["Mask_Stats"])
88-
cv2.imwrite(self.path_debug + image_name + "_" + "rgb_points.png", self.images["RGB_Stats"])
107+
# cv2.imwrite(self.path_debug + image_name + "_" + "rgb_points.png", self.images["RGB_Stats"])
89108

90109
# Fit a quad to each vertical leader
91110
print("Fitting quads")
@@ -164,16 +183,18 @@ def read_images(self, path, image_name):
164183

165184
return images
166185

167-
def split_mask(self, in_im_mask, b_debug=False):
186+
def split_mask(self, in_im_mask, b_one_mask=True, b_debug=False):
168187
"""Split the mask image up into connected components, discarding anything really small
169188
@param in_im_mask - the mask image
170189
@param b_debug - print out mask labeled image
171-
@return a list of boolean indices for each componet"""
190+
@return a list of boolean indices for each component"""
172191
output = cv2.connectedComponentsWithStats(in_im_mask)
173192
labels = output[1]
174193
stats = output[2]
175194

176195
ret_masks = []
196+
i_widest = 0
197+
i_area = 0
177198
for i, stat in enumerate(stats):
178199
if np.sum(in_im_mask[labels == i]) == 0:
179200
continue
@@ -182,11 +203,20 @@ def split_mask(self, in_im_mask, b_debug=False):
182203
continue
183204
if stat[cv2.CC_STAT_HEIGHT] < 0.5 * in_im_mask.shape[1]:
184205
continue
206+
if i_area < stat[cv2.CC_STAT_AREA]:
207+
i_widest = len(ret_masks)
208+
i_area = stat[cv2.CC_STAT_AREA]
185209
ret_masks.append(labels == i)
186210

187211
if b_debug:
188212
labels = 128 + labels * (120 // output[0])
189213
cv2.imwrite(self.path_debug + self.name + "_" + "labels.png", labels)
214+
215+
try:
216+
if b_one_mask:
217+
return [ret_masks[i_widest]]
218+
except:
219+
pass
190220
return ret_masks
191221

192222
def stats_image(self, in_im, pixs_in_mask):
@@ -195,13 +225,10 @@ def stats_image(self, in_im, pixs_in_mask):
195225
@param im image
196226
@returns stats as a dictionary of values"""
197227

198-
width = in_im.shape[1]
199-
height = in_im.shape[0]
200-
201-
x_grid, y_grid = np.meshgrid(np.linspace(0.5, width - 0.5, width), np.linspace(0.5, height - 0.5, height))
228+
LeaderDetector._init_grid_(in_im)
202229

203-
xs = x_grid[pixs_in_mask]
204-
ys = y_grid[pixs_in_mask]
230+
xs = LeaderDetector._x_grid[pixs_in_mask]
231+
ys = LeaderDetector._y_grid[pixs_in_mask]
205232

206233
stats = {}
207234
stats["x_min"] = np.min(xs)
@@ -216,14 +243,14 @@ def stats_image(self, in_im, pixs_in_mask):
216243
if stats["x_span"] > stats["y_span"]:
217244
stats["Direction"] = "left_right"
218245
stats["Length"] = stats["x_span"]
219-
for r in range(0, width):
246+
for r in range(0, LeaderDetector._width):
220247
if sum(pixs_in_mask[:, r]) > 0:
221248
avg_width += sum(pixs_in_mask[:, r] > 0)
222249
count_width += 1
223250
else:
224251
stats["Direction"] = "up_down"
225252
stats["Length"] = stats["y_span"]
226-
for c in range(0, height):
253+
for c in range(0, LeaderDetector._height):
227254
if sum(pixs_in_mask[c, :]) > 0:
228255
avg_width += sum(pixs_in_mask[c, :] > 0)
229256
count_width += 1
@@ -258,10 +285,22 @@ def fit_quad(self, im_mask, pts, b_output_debug=True, quad_name=0):
258285
@returns fitted quad"""
259286

260287
# Fit a quad to the trunk
261-
quad = Quad(pts['lower_left'], pts['upper_right'], 0.5 * pts['width'])
288+
pt_lower_left = pts['center']
289+
vec_len = pts["Length"] * 0.4
290+
while pt_lower_left[0] > 2 + pts['x_min'] and pt_lower_left[1] > 2 + pts['y_min']:
291+
pt_lower_left = pts["center"] - pts["EigenVector"] * vec_len
292+
vec_len = vec_len * 1.1
293+
294+
pt_upper_right = pts['center']
295+
vec_len = pts["Length"] * 0.4
296+
while pt_upper_right[0] < -2 + pts['x_max'] and pt_upper_right[1] < -2 + pts['y_max']:
297+
pt_upper_right = pts["center"] + pts["EigenVector"] * vec_len
298+
vec_len = vec_len * 1.1
299+
300+
quad = Quad(pt_lower_left, pt_upper_right, 0.5 * pts['width'])
262301

263302
# Current parameters for the vertical leader
264-
params = {"step_size": int(quad.radius_2d * 1.5), "width_mask": 1.4, "width": 0.3}
303+
params = {"step_size": int(quad.radius_2d * 1.5), "width_mask": 1.4, "width": 0.25}
265304

266305
# Iteratively move the quad to the center of the mask
267306
for i in range(0, 5):

Image_based/cyl_fit_2d.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def find_edges_hough_transform(self, im_edge, step_size=40, perc_width=0.3, axs=
213213

214214
if axs is not None:
215215
im_debug = cv2.cvtColor(im_edge, cv2.COLOR_GRAY2RGB)
216-
quad.draw_edge_rects(im_debug, step_size=step_size, perc_width=perc_width)
216+
self.draw_edge_rects(im_debug, step_size=step_size, perc_width=perc_width)
217217
axs.imshow(im_debug)
218218

219219
ret_segs = []
@@ -222,6 +222,14 @@ def find_edges_hough_transform(self, im_edge, step_size=40, perc_width=0.3, axs=
222222
line_b = np.zeros((3, 1))
223223
line_b[2, 0] = 1.0
224224
for i_rect, r in enumerate(rects):
225+
b_rect_inside = True
226+
if np.min(r) < -2:
227+
b_rect_inside = False
228+
if np.max(r[:, 0]) > im_edge.shape[1]:
229+
b_rect_inside = False
230+
if np.max(r[:, 1]) > im_edge.shape[0]:
231+
b_rect_inside = False
232+
225233
im_warp, tform3_back = self._image_cutout(im_edge, r, step_size=step_size, height=height)
226234
i_seg = i_rect // 2
227235
i_side = i_rect % 2
@@ -249,7 +257,7 @@ def find_edges_hough_transform(self, im_edge, step_size=40, perc_width=0.3, axs=
249257
p1_back = tform3_back @ p1_in
250258
print(f"Orig {p}, transform back {p1_back}")
251259

252-
if lines is not None:
260+
if lines is not None and b_rect_inside:
253261
for rho, theta in lines[0]:
254262
a = np.cos(theta)
255263
b = np.sin(theta)
@@ -383,15 +391,23 @@ def adjust_quad_by_mask(self, im_mask, step_size=40, perc_width=1.2, axs=None):
383391
if axs is not None:
384392
axs.imshow(im_mask, origin='lower')
385393
for i, r in enumerate(rects):
394+
b_rect_inside = True
395+
if np.min(r) < -2:
396+
b_rect_inside = False
397+
if np.max(r[:, 0]) > im_mask.shape[1]:
398+
b_rect_inside = False
399+
if np.max(r[:, 1]) > im_mask.shape[0]:
400+
b_rect_inside = False
401+
386402
im_warp, tform_inv = self._image_cutout(im_mask, r, step_size=step_size, height=height)
387-
if np.sum(im_warp > 0) > 0:
403+
if b_rect_inside and np.sum(im_warp > 0) > 0:
388404
x_mean = np.mean(x_grid[im_warp > 0])
389405
y_mean = np.mean(y_grid[im_warp > 0])
390406
pt_warp_back = tform_inv @ np.transpose(np.array([x_mean, y_mean, 1]))
391407
print(f"{self.pt_axis(ts[i])} ({x_mean}, {y_mean}), {pt_warp_back}")
392408
b_rhs[i, :] = pt_warp_back[0:2]
393409
else:
394-
print("Empty slice")
410+
print(f"Empty slice {r}")
395411

396412
if axs is not None:
397413
axs.clear()

0 commit comments

Comments
 (0)