Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -551,14 +551,48 @@ class WatermelonProcessor:
|
|
| 551 |
target_rind_mask, rind_source, rind_overlap_ratio, r_warn = self.choose_target_rind_mask(rind_mask, flesh_combined)
|
| 552 |
warnings.extend(r_warn)
|
| 553 |
|
| 554 |
-
# Bridge the gap for the unified flesh boundary (visuals and smoothed fit)
|
| 555 |
-
bridge_k = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (45, 45))
|
| 556 |
-
flesh_closed = cv2.morphologyEx(flesh_combined, cv2.MORPH_CLOSE, bridge_k)
|
| 557 |
mark("mask_parse")
|
| 558 |
|
| 559 |
-
# 3. EXTRACTION
|
| 560 |
rind_data = self.get_polar_data(target_rind_mask)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 561 |
flesh_data = self.get_polar_data(flesh_closed)
|
|
|
|
| 562 |
if rind_data is None:
|
| 563 |
return fail("No stable perimeter.", measurement_unit="cm" if cm_per_px else "px", scale_source="color_checker" if cm_per_px else "original_pixels", color_checker_found=checker_corners is not None, rind_source=rind_source, rind_overlap_ratio=rind_overlap_ratio)
|
| 564 |
|
|
@@ -683,46 +717,49 @@ class WatermelonProcessor:
|
|
| 683 |
|
| 684 |
def draw_base(r_m, f_m):
|
| 685 |
out = image.copy().astype(np.float32)
|
| 686 |
-
alpha = 0.
|
| 687 |
-
#
|
| 688 |
out[..., 0] = np.where(r_m > 0, out[..., 0]*(1-alpha) + 0, out[..., 0])
|
| 689 |
out[..., 1] = np.where(r_m > 0, out[..., 1]*(1-alpha) + 170, out[..., 1])
|
| 690 |
out[..., 2] = np.where(r_m > 0, out[..., 2]*(1-alpha) + 0, out[..., 2])
|
| 691 |
|
| 692 |
-
#
|
| 693 |
-
out[..., 0] = np.where(f_m > 0, out[..., 0]*(1-alpha) +
|
| 694 |
-
out[..., 1] = np.where(f_m > 0, out[..., 1]*(1-alpha) +
|
| 695 |
out[..., 2] = np.where(f_m > 0, out[..., 2]*(1-alpha) + 255, out[..., 2])
|
| 696 |
|
| 697 |
out = np.clip(out, 0, 255).astype(np.uint8)
|
| 698 |
-
if checker_corners is not None:
|
|
|
|
| 699 |
if len(midline) > 1:
|
| 700 |
cv2.polylines(out, [midline.astype(np.int32)], False, (0, 255, 255), 3)
|
| 701 |
pt1, pt2 = tuple(midline[0].astype(int)), tuple(midline[-1].astype(int))
|
| 702 |
for pt in (pt1, pt2):
|
| 703 |
-
cv2.circle(out, pt, 8, (0,0,0), 2)
|
|
|
|
| 704 |
return out
|
| 705 |
|
| 706 |
# RAW
|
| 707 |
out_raw = draw_base(target_rind_mask, flesh_closed)
|
| 708 |
cv2.line(out_raw, raw_h_line[0], raw_h_line[1], (255, 100, 255), 2)
|
| 709 |
cv2.line(out_raw, raw_w_line[0], raw_w_line[1], (255, 255, 100), 2)
|
| 710 |
-
|
| 711 |
f_cnts_raw, _ = cv2.findContours(flesh_closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
| 712 |
-
if f_cnts_raw:
|
| 713 |
-
|
| 714 |
-
cv2.polylines(out_raw, [raw_rind_cnt], True, (0, 200, 0),
|
| 715 |
res.image_raw_base64 = encode_img(out_raw)
|
| 716 |
|
| 717 |
# SMOOTH
|
| 718 |
if sm_rind_cnt is not None:
|
| 719 |
-
|
|
|
|
| 720 |
cv2.line(out_sm, sm_h_line[0], sm_h_line[1], (255, 100, 255), 2)
|
| 721 |
cv2.line(out_sm, sm_w_line[0], sm_w_line[1], (255, 255, 100), 2)
|
| 722 |
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
cv2.polylines(out_sm, [sm_rind_cnt], True, (0,
|
| 726 |
res.image_sm_base64 = encode_img(out_sm)
|
| 727 |
|
| 728 |
mark("render")
|
|
|
|
| 551 |
target_rind_mask, rind_source, rind_overlap_ratio, r_warn = self.choose_target_rind_mask(rind_mask, flesh_combined)
|
| 552 |
warnings.extend(r_warn)
|
| 553 |
|
|
|
|
|
|
|
|
|
|
| 554 |
mark("mask_parse")
|
| 555 |
|
| 556 |
+
# 3. EXTRACTION (Rind First)
|
| 557 |
rind_data = self.get_polar_data(target_rind_mask)
|
| 558 |
+
if rind_data is None:
|
| 559 |
+
return fail("No stable perimeter.", measurement_unit="cm" if cm_per_px else "px", scale_source="color_checker" if cm_per_px else "original_pixels", color_checker_found=checker_corners is not None, rind_source=rind_source, rind_overlap_ratio=rind_overlap_ratio)
|
| 560 |
+
|
| 561 |
+
t_r, raw_r_r, (cx, cy), raw_rind_cnt = rind_data
|
| 562 |
+
pts_r_raw = raw_rind_cnt.reshape(-1, 2).astype(np.float32)
|
| 563 |
+
|
| 564 |
+
# --- NEW SCAN-LINE FLESH GAP FILLING (Preserves V-shape) ---
|
| 565 |
+
_, (ma, Ma), angle = cv2.fitEllipse(raw_rind_cnt) if len(raw_rind_cnt) > 5 else (None, (0,0), 0)
|
| 566 |
+
rot_angle = angle if ma < Ma else angle + 90
|
| 567 |
+
M_rot = cv2.getRotationMatrix2D((cx, cy), rot_angle, 1.0)
|
| 568 |
+
M_inv = cv2.getRotationMatrix2D((cx, cy), -rot_angle, 1.0)
|
| 569 |
+
|
| 570 |
+
l_rot = cv2.warpAffine(flesh_l_m, M_rot, (w, h))
|
| 571 |
+
r_rot = cv2.warpAffine(flesh_r_m, M_rot, (w, h))
|
| 572 |
+
|
| 573 |
+
l_idx = np.where(l_rot > 0)[1]
|
| 574 |
+
r_idx = np.where(r_rot > 0)[1]
|
| 575 |
+
if len(l_idx) > 0 and len(r_idx) > 0 and np.mean(l_idx) > np.mean(r_idx):
|
| 576 |
+
l_rot, r_rot = r_rot, l_rot
|
| 577 |
+
|
| 578 |
+
flesh_closed_rot = cv2.bitwise_or(l_rot, r_rot)
|
| 579 |
+
y_l, y_r = np.where(l_rot > 0)[0], np.where(r_rot > 0)[0]
|
| 580 |
+
if len(y_l) > 0 and len(y_r) > 0:
|
| 581 |
+
for y in range(max(np.min(y_l), np.min(y_r)), min(np.max(y_l), np.max(y_r))):
|
| 582 |
+
row_l = np.where(l_rot[y, :] > 0)[0]
|
| 583 |
+
row_r = np.where(r_rot[y, :] > 0)[0]
|
| 584 |
+
if len(row_l) > 0 and len(row_r) > 0:
|
| 585 |
+
x_start = row_l[-1]
|
| 586 |
+
x_end = row_r[0]
|
| 587 |
+
if x_start < x_end:
|
| 588 |
+
flesh_closed_rot[y, x_start:x_end] = 255
|
| 589 |
+
|
| 590 |
+
flesh_closed = cv2.warpAffine(flesh_closed_rot, M_inv, (w, h))
|
| 591 |
+
_, flesh_closed = cv2.threshold(flesh_closed, 127, 255, cv2.THRESH_BINARY)
|
| 592 |
+
|
| 593 |
+
# Now extract the unified flesh data
|
| 594 |
flesh_data = self.get_polar_data(flesh_closed)
|
| 595 |
+
# -----------------------------------------------------------
|
| 596 |
if rind_data is None:
|
| 597 |
return fail("No stable perimeter.", measurement_unit="cm" if cm_per_px else "px", scale_source="color_checker" if cm_per_px else "original_pixels", color_checker_found=checker_corners is not None, rind_source=rind_source, rind_overlap_ratio=rind_overlap_ratio)
|
| 598 |
|
|
|
|
| 717 |
|
| 718 |
def draw_base(r_m, f_m):
|
| 719 |
out = image.copy().astype(np.float32)
|
| 720 |
+
alpha = 0.21 # Half transparency
|
| 721 |
+
# Rind fill: Green
|
| 722 |
out[..., 0] = np.where(r_m > 0, out[..., 0]*(1-alpha) + 0, out[..., 0])
|
| 723 |
out[..., 1] = np.where(r_m > 0, out[..., 1]*(1-alpha) + 170, out[..., 1])
|
| 724 |
out[..., 2] = np.where(r_m > 0, out[..., 2]*(1-alpha) + 0, out[..., 2])
|
| 725 |
|
| 726 |
+
# Flesh fill: Red
|
| 727 |
+
out[..., 0] = np.where(f_m > 0, out[..., 0]*(1-alpha) + 0, out[..., 0])
|
| 728 |
+
out[..., 1] = np.where(f_m > 0, out[..., 1]*(1-alpha) + 0, out[..., 1])
|
| 729 |
out[..., 2] = np.where(f_m > 0, out[..., 2]*(1-alpha) + 255, out[..., 2])
|
| 730 |
|
| 731 |
out = np.clip(out, 0, 255).astype(np.uint8)
|
| 732 |
+
if checker_corners is not None:
|
| 733 |
+
cv2.polylines(out, [np.int32(checker_corners)], True, (0, 165, 255), 4)
|
| 734 |
if len(midline) > 1:
|
| 735 |
cv2.polylines(out, [midline.astype(np.int32)], False, (0, 255, 255), 3)
|
| 736 |
pt1, pt2 = tuple(midline[0].astype(int)), tuple(midline[-1].astype(int))
|
| 737 |
for pt in (pt1, pt2):
|
| 738 |
+
cv2.circle(out, pt, 8, (0,0,0), 2)
|
| 739 |
+
cv2.circle(out, pt, 6, (255,255,255), -1)
|
| 740 |
return out
|
| 741 |
|
| 742 |
# RAW
|
| 743 |
out_raw = draw_base(target_rind_mask, flesh_closed)
|
| 744 |
cv2.line(out_raw, raw_h_line[0], raw_h_line[1], (255, 100, 255), 2)
|
| 745 |
cv2.line(out_raw, raw_w_line[0], raw_w_line[1], (255, 255, 100), 2)
|
| 746 |
+
|
| 747 |
f_cnts_raw, _ = cv2.findContours(flesh_closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
| 748 |
+
if f_cnts_raw:
|
| 749 |
+
cv2.polylines(out_raw, [max(f_cnts_raw, key=cv2.contourArea)], True, (0, 0, 255), 2) # Red, 2px
|
| 750 |
+
cv2.polylines(out_raw, [raw_rind_cnt], True, (0, 200, 0), 2) # Dark Green, 2px
|
| 751 |
res.image_raw_base64 = encode_img(out_raw)
|
| 752 |
|
| 753 |
# SMOOTH
|
| 754 |
if sm_rind_cnt is not None:
|
| 755 |
+
# Use raw fills for the smoothed preview (decoupled visual)
|
| 756 |
+
out_sm = draw_base(target_rind_mask, flesh_closed)
|
| 757 |
cv2.line(out_sm, sm_h_line[0], sm_h_line[1], (255, 100, 255), 2)
|
| 758 |
cv2.line(out_sm, sm_w_line[0], sm_w_line[1], (255, 255, 100), 2)
|
| 759 |
|
| 760 |
+
if sm_flesh_cnt is not None:
|
| 761 |
+
cv2.polylines(out_sm, [sm_flesh_cnt], True, (0, 0, 255), 2) # Red, 2px
|
| 762 |
+
cv2.polylines(out_sm, [sm_rind_cnt], True, (0, 200, 0), 2) # Dark Green, 2px
|
| 763 |
res.image_sm_base64 = encode_img(out_sm)
|
| 764 |
|
| 765 |
mark("render")
|