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 |
|