Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -331,10 +331,13 @@ def validate_single_object(mask: np.ndarray, paper_contour: np.ndarray) -> None:
|
|
331 |
# Find contours of objects within paper bounds
|
332 |
contours, _ = cv2.findContours(masked_objects, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
333 |
|
334 |
-
|
|
|
|
|
335 |
min_area = 1000 # Minimum area threshold
|
336 |
-
|
337 |
-
|
|
|
338 |
if len(significant_contours) == 0:
|
339 |
raise NoObjectDetectedError()
|
340 |
elif len(significant_contours) > 1:
|
@@ -398,7 +401,7 @@ def remove_bg(image: np.ndarray) -> np.ndarray:
|
|
398 |
logger.error(f"Error in BiRefNet background removal: {e}")
|
399 |
raise
|
400 |
|
401 |
-
def exclude_paper_area(mask: np.ndarray, paper_contour: np.ndarray, expansion_factor: float = 1.
|
402 |
"""
|
403 |
Remove paper area from the mask to focus only on objects
|
404 |
"""
|
@@ -777,7 +780,7 @@ def make_square(img: np.ndarray):
|
|
777 |
|
778 |
return padded
|
779 |
|
780 |
-
def predict_with_paper(image, paper_size, offset,
|
781 |
"""Main prediction function using paper as reference"""
|
782 |
|
783 |
logger.info(f"Starting prediction with image shape: {image.shape}")
|
@@ -832,10 +835,7 @@ def predict_with_paper(image, paper_size, offset, offset_unit, edge_radius, fing
|
|
832 |
raise gr.Error(f"Error in object detection: {str(e)}")
|
833 |
|
834 |
# Apply edge rounding if specified
|
835 |
-
|
836 |
-
rounded_mask = round_edges(objects_mask, edge_radius, scaling_factor)
|
837 |
-
else:
|
838 |
-
rounded_mask = objects_mask.copy()
|
839 |
|
840 |
# Apply dilation for offset
|
841 |
if offset > 0:
|
@@ -902,21 +902,14 @@ def predict_with_paper(image, paper_size, offset, offset_unit, edge_radius, fing
|
|
902 |
f"Scale: {scaling_factor:.4f} mm/px | Paper: {paper_size}"
|
903 |
)
|
904 |
|
905 |
-
def predict_full_paper(image, paper_size,
|
906 |
-
"""
|
907 |
-
Full prediction function with paper reference and flexible outputs
|
908 |
-
Returns DXF + conditionally selected additional outputs
|
909 |
-
"""
|
910 |
-
radius = fillet_value_mm if enable_fillet == "On" else 0
|
911 |
finger_flag = "On" if enable_finger_cut == "On" else "Off"
|
912 |
|
913 |
# Always get all outputs from predict_with_paper
|
914 |
ann, outlines, dxf_path, mask, scale_info = predict_with_paper(
|
915 |
image,
|
916 |
paper_size,
|
917 |
-
offset=
|
918 |
-
offset_unit="mm",
|
919 |
-
edge_radius=radius,
|
920 |
finger_clearance=finger_flag,
|
921 |
)
|
922 |
|
@@ -963,22 +956,14 @@ if __name__ == "__main__":
|
|
963 |
)
|
964 |
|
965 |
with gr.Group():
|
966 |
-
gr.Markdown("###
|
967 |
-
|
968 |
-
choices=["On", "Off"],
|
969 |
-
value="Off",
|
970 |
-
label="Enable Edge Rounding",
|
971 |
-
interactive=True
|
972 |
-
)
|
973 |
-
|
974 |
-
fillet_value_mm = gr.Slider(
|
975 |
minimum=0,
|
976 |
-
maximum=
|
977 |
step=1,
|
978 |
-
value=
|
979 |
-
label="
|
980 |
-
|
981 |
-
interactive=True
|
982 |
)
|
983 |
|
984 |
with gr.Group():
|
@@ -1011,10 +996,6 @@ if __name__ == "__main__":
|
|
1011 |
outlines_image = gr.Image(label="Outlines", visible=False)
|
1012 |
mask_image = gr.Image(label="Mask", visible=False)
|
1013 |
|
1014 |
-
# Dynamic visibility updates
|
1015 |
-
def toggle_fillet(choice):
|
1016 |
-
return gr.update(visible=(choice == "On"))
|
1017 |
-
|
1018 |
def update_outputs_visibility(selected):
|
1019 |
return [
|
1020 |
gr.update(visible="Annotated Image" in selected),
|
@@ -1022,12 +1003,6 @@ if __name__ == "__main__":
|
|
1022 |
gr.update(visible="Mask" in selected)
|
1023 |
]
|
1024 |
|
1025 |
-
# Event handlers
|
1026 |
-
enable_fillet.change(
|
1027 |
-
fn=toggle_fillet,
|
1028 |
-
inputs=enable_fillet,
|
1029 |
-
outputs=fillet_value_mm
|
1030 |
-
)
|
1031 |
|
1032 |
output_options.change(
|
1033 |
fn=update_outputs_visibility,
|
@@ -1040,8 +1015,7 @@ if __name__ == "__main__":
|
|
1040 |
inputs=[
|
1041 |
input_image,
|
1042 |
paper_size,
|
1043 |
-
|
1044 |
-
fillet_value_mm,
|
1045 |
enable_finger_cut,
|
1046 |
output_options
|
1047 |
],
|
|
|
331 |
# Find contours of objects within paper bounds
|
332 |
contours, _ = cv2.findContours(masked_objects, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
333 |
|
334 |
+
|
335 |
+
# Filter out very small contours (noise) and paper-sized contours
|
336 |
+
image_area = mask.shape[0] * mask.shape[1]
|
337 |
min_area = 1000 # Minimum area threshold
|
338 |
+
max_area = image_area * 0.5 # Maximum 50% of image area (to exclude paper detection)
|
339 |
+
significant_contours = [c for c in contours if min_area < cv2.contourArea(c) < max_area]
|
340 |
+
|
341 |
if len(significant_contours) == 0:
|
342 |
raise NoObjectDetectedError()
|
343 |
elif len(significant_contours) > 1:
|
|
|
401 |
logger.error(f"Error in BiRefNet background removal: {e}")
|
402 |
raise
|
403 |
|
404 |
+
def exclude_paper_area(mask: np.ndarray, paper_contour: np.ndarray, expansion_factor: float = 1.2) -> np.ndarray:
|
405 |
"""
|
406 |
Remove paper area from the mask to focus only on objects
|
407 |
"""
|
|
|
780 |
|
781 |
return padded
|
782 |
|
783 |
+
def predict_with_paper(image, paper_size, offset, finger_clearance=False):
|
784 |
"""Main prediction function using paper as reference"""
|
785 |
|
786 |
logger.info(f"Starting prediction with image shape: {image.shape}")
|
|
|
835 |
raise gr.Error(f"Error in object detection: {str(e)}")
|
836 |
|
837 |
# Apply edge rounding if specified
|
838 |
+
rounded_mask = objects_mask.copy()
|
|
|
|
|
|
|
839 |
|
840 |
# Apply dilation for offset
|
841 |
if offset > 0:
|
|
|
902 |
f"Scale: {scaling_factor:.4f} mm/px | Paper: {paper_size}"
|
903 |
)
|
904 |
|
905 |
+
def predict_full_paper(image, paper_size, offset_value_mm, enable_finger_cut, selected_outputs):
|
|
|
|
|
|
|
|
|
|
|
906 |
finger_flag = "On" if enable_finger_cut == "On" else "Off"
|
907 |
|
908 |
# Always get all outputs from predict_with_paper
|
909 |
ann, outlines, dxf_path, mask, scale_info = predict_with_paper(
|
910 |
image,
|
911 |
paper_size,
|
912 |
+
offset=offset_value_mm,
|
|
|
|
|
913 |
finger_clearance=finger_flag,
|
914 |
)
|
915 |
|
|
|
956 |
)
|
957 |
|
958 |
with gr.Group():
|
959 |
+
gr.Markdown("### Contour Offset")
|
960 |
+
offset_value_mm = gr.Slider(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
961 |
minimum=0,
|
962 |
+
maximum=50,
|
963 |
step=1,
|
964 |
+
value=0,
|
965 |
+
label="Offset (mm)",
|
966 |
+
info="Expand contours outward by this amount"
|
|
|
967 |
)
|
968 |
|
969 |
with gr.Group():
|
|
|
996 |
outlines_image = gr.Image(label="Outlines", visible=False)
|
997 |
mask_image = gr.Image(label="Mask", visible=False)
|
998 |
|
|
|
|
|
|
|
|
|
999 |
def update_outputs_visibility(selected):
|
1000 |
return [
|
1001 |
gr.update(visible="Annotated Image" in selected),
|
|
|
1003 |
gr.update(visible="Mask" in selected)
|
1004 |
]
|
1005 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1006 |
|
1007 |
output_options.change(
|
1008 |
fn=update_outputs_visibility,
|
|
|
1015 |
inputs=[
|
1016 |
input_image,
|
1017 |
paper_size,
|
1018 |
+
offset_value_mm,
|
|
|
1019 |
enable_finger_cut,
|
1020 |
output_options
|
1021 |
],
|