Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -185,14 +185,14 @@ def detect_paper_contour(image: np.ndarray) -> Tuple[np.ndarray, float]:
|
|
| 185 |
# Filter contours by area and aspect ratio to find paper-like rectangles
|
| 186 |
paper_contours = []
|
| 187 |
image_area = image.shape[0] * image.shape[1]
|
| 188 |
-
min_area = image_area * 0.
|
| 189 |
-
max_area = image_area * 0.
|
| 190 |
|
| 191 |
for contour in contours:
|
| 192 |
area = cv2.contourArea(contour)
|
| 193 |
if min_area < area < max_area:
|
| 194 |
# Approximate contour to polygon
|
| 195 |
-
epsilon = 0.
|
| 196 |
approx = cv2.approxPolyDP(contour, epsilon, True)
|
| 197 |
|
| 198 |
# Check if it's roughly rectangular (4 corners) or close to it
|
|
@@ -204,12 +204,12 @@ def detect_paper_contour(image: np.ndarray) -> Tuple[np.ndarray, float]:
|
|
| 204 |
|
| 205 |
# Check if aspect ratio matches common paper ratios
|
| 206 |
# A4: 1.414, A3: 1.414, US Letter: 1.294
|
| 207 |
-
if
|
| 208 |
# Check if contour area is close to bounding rect area (rectangularity)
|
| 209 |
rect_area = w * h
|
| 210 |
if rect_area > 0:
|
| 211 |
extent = area / rect_area
|
| 212 |
-
if extent > 0.
|
| 213 |
paper_contours.append((contour, area, aspect_ratio, extent))
|
| 214 |
|
| 215 |
if not paper_contours:
|
|
@@ -467,27 +467,31 @@ def exclude_paper_area(mask: np.ndarray, paper_contour: np.ndarray, expansion_fa
|
|
| 467 |
"""
|
| 468 |
Remove paper area from the mask to focus only on objects
|
| 469 |
"""
|
| 470 |
-
#
|
| 471 |
-
paper_mask = np.zeros(mask.shape[:2], dtype=np.uint8)
|
| 472 |
-
|
| 473 |
-
# Create a more aggressive inward shrinking of paper bounds
|
| 474 |
rect = cv2.boundingRect(paper_contour)
|
| 475 |
-
shrink_pixels = int(min(rect[2], rect[3]) * 0.05) # Shrink by 5% of smaller dimension
|
| 476 |
-
|
| 477 |
-
# Create shrunken rectangle (area INSIDE paper bounds)
|
| 478 |
x, y, w, h = rect
|
| 479 |
-
inner_contour = np.array([
|
| 480 |
-
[[x + shrink_pixels, y + shrink_pixels]],
|
| 481 |
-
[[x + w - shrink_pixels, y + shrink_pixels]],
|
| 482 |
-
[[x + w - shrink_pixels, y + h - shrink_pixels]],
|
| 483 |
-
[[x + shrink_pixels, y + h - shrink_pixels]]
|
| 484 |
-
])
|
| 485 |
|
| 486 |
-
#
|
| 487 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
|
| 489 |
-
#
|
| 490 |
-
|
|
|
|
|
|
|
| 491 |
|
| 492 |
return result_mask
|
| 493 |
|
|
@@ -893,10 +897,9 @@ def predict_with_paper(image, paper_size, offset,offset_unit, finger_clearance=F
|
|
| 893 |
# Mask paper area in input image first
|
| 894 |
masked_input_image = mask_paper_area_in_image(image, paper_contour)
|
| 895 |
|
| 896 |
-
# Remove background from main objects
|
| 897 |
orig_size = image.shape[:2]
|
| 898 |
-
objects_mask = remove_bg(
|
| 899 |
-
|
| 900 |
processed_size = objects_mask.shape[:2]
|
| 901 |
|
| 902 |
# Resize mask to match original image
|
|
@@ -905,6 +908,11 @@ def predict_with_paper(image, paper_size, offset,offset_unit, finger_clearance=F
|
|
| 905 |
# Remove paper area from mask to focus only on objects
|
| 906 |
objects_mask = exclude_paper_area(objects_mask, paper_contour)
|
| 907 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 908 |
# Validate single object
|
| 909 |
validate_single_object(objects_mask, paper_contour)
|
| 910 |
|
|
|
|
| 185 |
# Filter contours by area and aspect ratio to find paper-like rectangles
|
| 186 |
paper_contours = []
|
| 187 |
image_area = image.shape[0] * image.shape[1]
|
| 188 |
+
min_area = image_area * 0.20 # At least 15% of image
|
| 189 |
+
max_area = image_area * 0.85 # At most 95% of image
|
| 190 |
|
| 191 |
for contour in contours:
|
| 192 |
area = cv2.contourArea(contour)
|
| 193 |
if min_area < area < max_area:
|
| 194 |
# Approximate contour to polygon
|
| 195 |
+
epsilon = 0.015 * cv2.arcLength(contour, True)
|
| 196 |
approx = cv2.approxPolyDP(contour, epsilon, True)
|
| 197 |
|
| 198 |
# Check if it's roughly rectangular (4 corners) or close to it
|
|
|
|
| 204 |
|
| 205 |
# Check if aspect ratio matches common paper ratios
|
| 206 |
# A4: 1.414, A3: 1.414, US Letter: 1.294
|
| 207 |
+
if 1.3 < aspect_ratio < 1.5: # More lenient tolerance
|
| 208 |
# Check if contour area is close to bounding rect area (rectangularity)
|
| 209 |
rect_area = w * h
|
| 210 |
if rect_area > 0:
|
| 211 |
extent = area / rect_area
|
| 212 |
+
if extent > 0.85: # At least 70% rectangular
|
| 213 |
paper_contours.append((contour, area, aspect_ratio, extent))
|
| 214 |
|
| 215 |
if not paper_contours:
|
|
|
|
| 467 |
"""
|
| 468 |
Remove paper area from the mask to focus only on objects
|
| 469 |
"""
|
| 470 |
+
# Get paper bounding rectangle
|
|
|
|
|
|
|
|
|
|
| 471 |
rect = cv2.boundingRect(paper_contour)
|
|
|
|
|
|
|
|
|
|
| 472 |
x, y, w, h = rect
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
|
| 474 |
+
# Create much more aggressive inward shrinking
|
| 475 |
+
shrink_x = int(w * 0.15) # Shrink 15% from each side
|
| 476 |
+
shrink_y = int(h * 0.15) # Shrink 15% from top/bottom
|
| 477 |
+
|
| 478 |
+
# Create inner object area (much smaller than paper)
|
| 479 |
+
inner_x = x + shrink_x
|
| 480 |
+
inner_y = y + shrink_y
|
| 481 |
+
inner_w = w - (2 * shrink_x)
|
| 482 |
+
inner_h = h - (2 * shrink_y)
|
| 483 |
+
|
| 484 |
+
# Create mask for object area only
|
| 485 |
+
object_area_mask = np.zeros(mask.shape[:2], dtype=np.uint8)
|
| 486 |
+
cv2.rectangle(object_area_mask, (inner_x, inner_y), (inner_x + inner_w, inner_y + inner_h), 255, -1)
|
| 487 |
+
|
| 488 |
+
# Apply mask: keep only pixels in the inner object area
|
| 489 |
+
result_mask = cv2.bitwise_and(mask, object_area_mask)
|
| 490 |
|
| 491 |
+
# Additional cleanup: remove small noise and fill gaps
|
| 492 |
+
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
|
| 493 |
+
result_mask = cv2.morphologyEx(result_mask, cv2.MORPH_OPEN, kernel, iterations=1)
|
| 494 |
+
result_mask = cv2.morphologyEx(result_mask, cv2.MORPH_CLOSE, kernel, iterations=2)
|
| 495 |
|
| 496 |
return result_mask
|
| 497 |
|
|
|
|
| 897 |
# Mask paper area in input image first
|
| 898 |
masked_input_image = mask_paper_area_in_image(image, paper_contour)
|
| 899 |
|
| 900 |
+
# Remove background from main objects
|
| 901 |
orig_size = image.shape[:2]
|
| 902 |
+
objects_mask = remove_bg(image)
|
|
|
|
| 903 |
processed_size = objects_mask.shape[:2]
|
| 904 |
|
| 905 |
# Resize mask to match original image
|
|
|
|
| 908 |
# Remove paper area from mask to focus only on objects
|
| 909 |
objects_mask = exclude_paper_area(objects_mask, paper_contour)
|
| 910 |
|
| 911 |
+
# Check if we actually have object pixels after paper exclusion
|
| 912 |
+
object_pixels = np.count_nonzero(objects_mask)
|
| 913 |
+
if object_pixels < 1000: # Minimum threshold
|
| 914 |
+
raise NoObjectDetectedError("No significant object detected after excluding paper area")
|
| 915 |
+
|
| 916 |
# Validate single object
|
| 917 |
validate_single_object(objects_mask, paper_contour)
|
| 918 |
|