crabbly commited on
Commit
a1ced6f
·
verified ·
1 Parent(s): d09b2d7

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +34 -25
main.py CHANGED
@@ -167,39 +167,47 @@ class WatermelonProcessor:
167
 
168
  @staticmethod
169
  def calculate_axis_metrics(cx, cy, phi, rind_mask, flesh_mask):
170
- """Casts rays along the major/minor axes to find height, width, and rind thickness."""
171
  h, w = rind_mask.shape
172
 
173
- def ray_cast(theta):
174
- max_r = int(np.hypot(h, w))
175
- r_steps = np.arange(0, max_r, 0.5)
176
- xs = np.clip(np.round(cx + r_steps * np.cos(theta)), 0, w - 1).astype(int)
177
- ys = np.clip(np.round(cy - r_steps * np.sin(theta)), 0, h - 1).astype(int)
 
 
178
 
179
- rind_vals = rind_mask[ys, xs]
180
- inside_rind = np.where(rind_vals > 0)[0]
181
- r_rind = r_steps[inside_rind[-1]] if len(inside_rind) > 0 else 0
182
 
183
- flesh_vals = flesh_mask[ys, xs]
184
- inside_flesh = np.where(flesh_vals > 0)[0]
185
- r_flesh = r_steps[inside_flesh[-1]] if len(inside_flesh) > 0 else 0
186
 
187
- pt_rind = (int(np.round(cx + r_rind * np.cos(theta))), int(np.round(cy - r_rind * np.sin(theta))))
188
- return r_rind, r_flesh, pt_rind
189
-
190
- # phi is the rotation of the fruit. Top/Bot are perpendicular to Left/Right
191
- r_top, _, pt_top = ray_cast(phi + np.pi/2)
192
- r_bot, _, pt_bot = ray_cast(phi - np.pi/2)
193
- r_right, f_right, pt_right = ray_cast(phi)
194
- r_left, f_left, pt_left = ray_cast(phi + np.pi)
 
 
195
 
196
- height_px = float(r_top + r_bot)
197
- width_px = float(r_left + r_right)
 
 
 
 
 
 
198
 
199
  rind_thick_px = None
200
- if f_left > 0 and f_right > 0:
201
- # Average the rind thickness of the left and right sides
202
- rind_thick_px = float((max(0, r_left - f_left) + max(0, r_right - f_right)) / 2.0)
203
 
204
  return height_px, width_px, rind_thick_px, (pt_top, pt_bot), (pt_left, pt_right)
205
 
@@ -578,6 +586,7 @@ class WatermelonProcessor:
578
  _, _, angle = cv2.fitEllipse(rind_cnt)
579
  phi = np.deg2rad(180 - angle) if angle > 90 else np.deg2rad(-angle)
580
 
 
581
  height_px, width_px, rind_thick_px, h_line, w_line = self.calculate_axis_metrics(
582
  cx, cy, phi, target_rind_mask, flesh_combined
583
  )
 
167
 
168
  @staticmethod
169
  def calculate_axis_metrics(cx, cy, phi, rind_mask, flesh_mask):
170
+ """Instantly finds axes and rind thickness using fast OpenCV bitwise operations."""
171
  h, w = rind_mask.shape
172
 
173
+ def get_intersections(theta, mask):
174
+ temp = np.zeros((h, w), dtype=np.uint8)
175
+ L = max(h, w)
176
+ # Draw a line spanning across the entire image
177
+ p1 = (int(cx + L * np.cos(theta)), int(cy - L * np.sin(theta)))
178
+ p2 = (int(cx - L * np.cos(theta)), int(cy + L * np.sin(theta)))
179
+ cv2.line(temp, p1, p2, 255, 1)
180
 
181
+ # Find where the line overlaps the mask
182
+ overlap = cv2.bitwise_and(mask, temp)
183
+ y_pts, x_pts = np.where(overlap > 0)
184
 
185
+ if len(x_pts) == 0:
186
+ return (int(cx), int(cy)), (int(cx), int(cy)), 0.0
 
187
 
188
+ # Project points to find the two extreme ends of the line segment
189
+ dx, dy = x_pts - cx, y_pts - cy
190
+ proj = dx * np.cos(theta) - dy * np.sin(theta)
191
+
192
+ idx_max, idx_min = np.argmax(proj), np.argmin(proj)
193
+ pt1 = (int(x_pts[idx_max]), int(y_pts[idx_max]))
194
+ pt2 = (int(x_pts[idx_min]), int(y_pts[idx_min]))
195
+ dist = float(np.hypot(pt1[0] - pt2[0], pt1[1] - pt2[1]))
196
+
197
+ return pt1, pt2, dist
198
 
199
+ # Height line (perpendicular to phi)
200
+ pt_top, pt_bot, height_px = get_intersections(phi + np.pi/2, rind_mask)
201
+
202
+ # Width line (parallel to phi)
203
+ pt_right, pt_left, width_px = get_intersections(phi, rind_mask)
204
+
205
+ # Flesh width along the exact same width line
206
+ _, _, flesh_width_px = get_intersections(phi, flesh_mask)
207
 
208
  rind_thick_px = None
209
+ if width_px > 0 and flesh_width_px > 0:
210
+ rind_thick_px = float(max(0.0, (width_px - flesh_width_px) / 2.0))
 
211
 
212
  return height_px, width_px, rind_thick_px, (pt_top, pt_bot), (pt_left, pt_right)
213
 
 
586
  _, _, angle = cv2.fitEllipse(rind_cnt)
587
  phi = np.deg2rad(180 - angle) if angle > 90 else np.deg2rad(-angle)
588
 
589
+ # Call the new, faster axis calculator
590
  height_px, width_px, rind_thick_px, h_line, w_line = self.calculate_axis_metrics(
591
  cx, cy, phi, target_rind_mask, flesh_combined
592
  )