Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -368,6 +368,20 @@ def detect_paper_bounds(image: np.ndarray, paper_size: str, output_unit: str = "
|
|
368 |
# Use fallback contour detection
|
369 |
logger.info("Using fallback contour detection for paper")
|
370 |
paper_contour, _ = detect_paper_contour(image, output_unit)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
|
372 |
# Calculate scaling factor based on paper size with proper units
|
373 |
scaling_factor = calculate_paper_scaling_factor(paper_contour, paper_size, output_unit)
|
@@ -529,24 +543,20 @@ def mask_paper_area_in_image(image: np.ndarray, paper_contour: np.ndarray) -> np
|
|
529 |
return masked_image
|
530 |
|
531 |
def exclude_paper_area(mask: np.ndarray, paper_contour: np.ndarray, expansion_factor: float = 1.2) -> np.ndarray:
|
532 |
-
"""
|
533 |
-
Remove paper area from the mask to focus only on objects using soft boundaries
|
534 |
-
"""
|
535 |
# Create paper mask
|
536 |
paper_mask = np.zeros(mask.shape[:2], dtype=np.uint8)
|
537 |
cv2.fillPoly(paper_mask, [paper_contour], 255)
|
538 |
|
539 |
-
#
|
540 |
-
|
541 |
-
|
542 |
-
eroded_paper_mask = cv2.erode(paper_mask, kernel, iterations=2)
|
543 |
|
544 |
-
|
545 |
-
|
546 |
|
547 |
-
#
|
548 |
-
|
549 |
-
result_mask = cv2.morphologyEx(result_mask, cv2.MORPH_CLOSE, small_kernel, iterations=1)
|
550 |
|
551 |
return result_mask
|
552 |
|
@@ -964,51 +974,31 @@ def predict_with_paper(image, paper_size, offset, offset_unit, finger_clearance=
|
|
964 |
raise gr.Error(f"Error processing image: {str(e)}")
|
965 |
|
966 |
try:
|
967 |
-
#
|
968 |
-
|
|
|
969 |
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
if not results or len(results) == 0 or not hasattr(results[0], 'boxes') or len(results[0].boxes) == 0:
|
981 |
-
logger.warning("No objects detected by YOLOv8, proceeding with full image")
|
982 |
-
cropped_image = image
|
983 |
-
crop_offset = (0, 0)
|
984 |
-
else:
|
985 |
-
boxes = results[0].boxes.xyxy.cpu().numpy()
|
986 |
-
confidences = results[0].boxes.conf.cpu().numpy()
|
987 |
-
|
988 |
-
# Filter out very large boxes (likely paper/background)
|
989 |
-
image_area = image.shape[0] * image.shape[1]
|
990 |
-
valid_boxes = []
|
991 |
-
|
992 |
-
for i, box in enumerate(boxes):
|
993 |
-
x_min, y_min, x_max, y_max = box
|
994 |
-
box_area = (x_max - x_min) * (y_max - y_min)
|
995 |
-
# Keep boxes that are 5% to 40% of image area
|
996 |
-
if 0.001 * image_area < box_area < 0.6 * image_area:
|
997 |
-
valid_boxes.append((i, confidences[i]))
|
998 |
-
|
999 |
-
if not valid_boxes:
|
1000 |
-
logger.warning("No valid objects detected, proceeding with full image")
|
1001 |
-
cropped_image = image
|
1002 |
-
crop_offset = (0, 0)
|
1003 |
-
else:
|
1004 |
-
# Get highest confidence valid box
|
1005 |
-
best_idx = max(valid_boxes, key=lambda x: x[1])[0]
|
1006 |
-
x_min, y_min, x_max, y_max = map(int, boxes[best_idx])
|
1007 |
|
1008 |
-
# Remove background
|
1009 |
-
orig_size = image.shape[:2]
|
1010 |
objects_mask = remove_bg(cropped_image)
|
1011 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1012 |
|
1013 |
# Resize mask to match cropped region and place back in original image space
|
1014 |
full_mask = np.zeros((orig_size[0], orig_size[1]), dtype=np.uint8)
|
|
|
368 |
# Use fallback contour detection
|
369 |
logger.info("Using fallback contour detection for paper")
|
370 |
paper_contour, _ = detect_paper_contour(image, output_unit)
|
371 |
+
|
372 |
+
# After getting paper_contour, expand it
|
373 |
+
rect = cv2.boundingRect(paper_contour)
|
374 |
+
expansion = int(min(rect[2], rect[3]) * 0.1) # Expand by 10%
|
375 |
+
|
376 |
+
x, y, w, h = rect
|
377 |
+
expanded_contour = np.array([
|
378 |
+
[[max(0, x - expansion), max(0, y - expansion)]],
|
379 |
+
[[min(image.shape[1], x + w + expansion), max(0, y - expansion)]],
|
380 |
+
[[min(image.shape[1], x + w + expansion), min(image.shape[0], y + h + expansion)]],
|
381 |
+
[[max(0, x - expansion), min(image.shape[0], y + h + expansion)]]
|
382 |
+
])
|
383 |
+
|
384 |
+
paper_contour = expanded_contour
|
385 |
|
386 |
# Calculate scaling factor based on paper size with proper units
|
387 |
scaling_factor = calculate_paper_scaling_factor(paper_contour, paper_size, output_unit)
|
|
|
543 |
return masked_image
|
544 |
|
545 |
def exclude_paper_area(mask: np.ndarray, paper_contour: np.ndarray, expansion_factor: float = 1.2) -> np.ndarray:
|
546 |
+
"""Less aggressive paper area exclusion"""
|
|
|
|
|
547 |
# Create paper mask
|
548 |
paper_mask = np.zeros(mask.shape[:2], dtype=np.uint8)
|
549 |
cv2.fillPoly(paper_mask, [paper_contour], 255)
|
550 |
|
551 |
+
# Instead of eroding, slightly expand the paper mask
|
552 |
+
rect = cv2.boundingRect(paper_contour)
|
553 |
+
expansion = max(10, int(min(rect[2], rect[3]) * 0.02)) # 2% expansion
|
|
|
554 |
|
555 |
+
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (expansion, expansion))
|
556 |
+
expanded_paper_mask = cv2.dilate(paper_mask, kernel, iterations=1)
|
557 |
|
558 |
+
# Keep objects within expanded paper area
|
559 |
+
result_mask = cv2.bitwise_and(mask, expanded_paper_mask)
|
|
|
560 |
|
561 |
return result_mask
|
562 |
|
|
|
974 |
raise gr.Error(f"Error processing image: {str(e)}")
|
975 |
|
976 |
try:
|
977 |
+
# Get paper bounds with expansion
|
978 |
+
rect = cv2.boundingRect(paper_contour)
|
979 |
+
expansion = max(20, int(min(rect[2], rect[3]) * 0.05)) # 5% expansion
|
980 |
|
981 |
+
x, y, w, h = rect
|
982 |
+
x_min = max(0, x - expansion)
|
983 |
+
y_min = max(0, y - expansion)
|
984 |
+
x_max = min(image.shape[1], x + w + expansion)
|
985 |
+
y_max = min(image.shape[0], y + h + expansion)
|
986 |
+
|
987 |
+
# Process the expanded paper area
|
988 |
+
cropped_image = image[y_min:y_max, x_min:x_max]
|
989 |
+
crop_offset = (x_min, y_min)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
990 |
|
991 |
+
# Remove background
|
|
|
992 |
objects_mask = remove_bg(cropped_image)
|
993 |
+
|
994 |
+
# Place back in full image space
|
995 |
+
full_mask = np.zeros((image.shape[0], image.shape[1]), dtype=np.uint8)
|
996 |
+
full_mask[y_min:y_max, x_min:x_max] = objects_mask
|
997 |
+
|
998 |
+
# Light filtering only - don't exclude paper area aggressively
|
999 |
+
# Just remove small noise
|
1000 |
+
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
|
1001 |
+
objects_mask = cv2.morphologyEx(full_mask, cv2.MORPH_OPEN, kernel)
|
1002 |
|
1003 |
# Resize mask to match cropped region and place back in original image space
|
1004 |
full_mask = np.zeros((orig_size[0], orig_size[1]), dtype=np.uint8)
|