Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -47,11 +47,11 @@ class ReferenceBoxNotDetectedError(Exception):
|
|
47 |
pass
|
48 |
|
49 |
class BoundaryOverlapError(Exception):
|
50 |
-
"""
|
51 |
pass
|
52 |
|
53 |
class TextOverlapError(Exception):
|
54 |
-
"""Raised when the text overlaps with the inner contours (with a margin of 0.75)."""
|
55 |
pass
|
56 |
|
57 |
# ---------------------
|
@@ -155,7 +155,7 @@ def yolo_detect(image: Union[str, Path, int, Image.Image, list, tuple, np.ndarra
|
|
155 |
|
156 |
def detect_reference_square(img: np.ndarray):
|
157 |
t = time.time()
|
158 |
-
res = reference_detector_global.predict(img, conf=0.
|
159 |
if not res or len(res) == 0 or len(res[0].boxes) == 0:
|
160 |
raise ReferenceBoxNotDetectedError("Reference Coin not detected in the image.")
|
161 |
print("Reference coin detection completed in {:.2f} seconds".format(time.time() - t))
|
@@ -782,16 +782,54 @@ def build_tool_polygon(points_inch):
|
|
782 |
logger.error(f"Error in build_tool_polygon: {e}")
|
783 |
raise
|
784 |
|
785 |
-
def polygon_to_exterior_coords(poly: Polygon):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
786 |
logger.info(f"Starting polygon_to_exterior_coords with polygon type {poly.geom_type}")
|
787 |
|
788 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
789 |
if poly.geom_type == "MultiPolygon":
|
790 |
logger.debug("Converting MultiPolygon to single Polygon")
|
791 |
biggest = max(poly.geoms, key=lambda g: g.area)
|
792 |
poly = biggest
|
793 |
|
794 |
-
if not poly.exterior:
|
795 |
logger.warning("Polygon has no exterior")
|
796 |
return []
|
797 |
|
@@ -800,8 +838,9 @@ def polygon_to_exterior_coords(poly: Polygon):
|
|
800 |
return coords
|
801 |
except Exception as e:
|
802 |
logger.error(f"Error in polygon_to_exterior_coords: {e}")
|
803 |
-
|
804 |
-
|
|
|
805 |
def place_finger_cut_adjusted(
|
806 |
tool_polygon: Polygon,
|
807 |
points_inch: list,
|
@@ -976,7 +1015,7 @@ def save_dxf_spline(offset_value,inflated_contours, scaling_factor, height, fing
|
|
976 |
finger_cut_centers,
|
977 |
final_polygons_inch,
|
978 |
circle_diameter=1.0,
|
979 |
-
min_gap=(0.
|
980 |
max_attempts=100
|
981 |
)
|
982 |
|
@@ -1067,9 +1106,9 @@ def add_rectangular_boundary(doc, polygons_inch, boundary_length, boundary_width
|
|
1067 |
text_top = boundary_polygon.bounds[1] + 1
|
1068 |
too_small = boundary_width_in < inner_width + 2 * clearance_side or boundary_length_in < inner_length + 2 * clearance_tb
|
1069 |
if too_small:
|
1070 |
-
raise BoundaryOverlapError("Error: The specified boundary dimensions are too small and overlap with the inner contours. Please provide larger
|
1071 |
-
if annotation_text.strip() and text_top > min_y -
|
1072 |
-
raise TextOverlapError("Error: The text is too close to the inner contours. Please
|
1073 |
return boundary_polygon
|
1074 |
|
1075 |
def draw_polygons_inch(polygons_inch, image_rgb, scaling_factor, image_height, color=(0,0,255), thickness=2):
|
@@ -1139,7 +1178,7 @@ def predict(
|
|
1139 |
t = time.time()
|
1140 |
if drawer_detected:
|
1141 |
# For detected drawers: shrink and square
|
1142 |
-
shrunked_img = make_square(shrink_bbox(drawer_img, 0.
|
1143 |
else:
|
1144 |
# For non-drawer images: keep original dimensions
|
1145 |
shrunked_img = drawer_img # Already in BGR format from above
|
@@ -1447,10 +1486,10 @@ if __name__ == "__main__":
|
|
1447 |
gr.Image(label="Input Image"),
|
1448 |
gr.Number(label="Offset value for Mask", value=0.075),
|
1449 |
gr.Dropdown(label="Offset Unit", choices=["mm", "inches"], value="inches"),
|
1450 |
-
gr.Dropdown(label="Add Finger Clearance?", choices=["Yes", "No"], value="
|
1451 |
-
gr.Dropdown(label="Add Rectangular Boundary?", choices=["Yes", "No"], value="
|
1452 |
-
gr.Number(label="Boundary Length", value=
|
1453 |
-
gr.Number(label="Boundary Width", value=
|
1454 |
gr.Textbox(label="Annotation (max 20 chars)", max_length=20, placeholder="Type up to 20 characters")
|
1455 |
],
|
1456 |
outputs=[
|
@@ -1461,7 +1500,7 @@ if __name__ == "__main__":
|
|
1461 |
gr.Textbox(label="Scaling Factor (inches/pixel)")
|
1462 |
],
|
1463 |
examples=[
|
1464 |
-
["./Test20.jpg", 0.075, "inches", "
|
1465 |
["./Test21.jpg", 0.075, "inches", "Yes", "Yes", 300.0, 200.0, "Tool2"]
|
1466 |
]
|
1467 |
)
|
|
|
47 |
pass
|
48 |
|
49 |
class BoundaryOverlapError(Exception):
|
50 |
+
"""The specified boundary dimensions are too small and overlap with the inner contours.Please provide larger value for boundary length and width."""
|
51 |
pass
|
52 |
|
53 |
class TextOverlapError(Exception):
|
54 |
+
"""Raised when the text overlaps with the inner contours (with a margin of 0.75).Please provide larger value for boundary length and width."""
|
55 |
pass
|
56 |
|
57 |
# ---------------------
|
|
|
155 |
|
156 |
def detect_reference_square(img: np.ndarray):
|
157 |
t = time.time()
|
158 |
+
res = reference_detector_global.predict(img, conf=0.15)
|
159 |
if not res or len(res) == 0 or len(res[0].boxes) == 0:
|
160 |
raise ReferenceBoxNotDetectedError("Reference Coin not detected in the image.")
|
161 |
print("Reference coin detection completed in {:.2f} seconds".format(time.time() - t))
|
|
|
782 |
logger.error(f"Error in build_tool_polygon: {e}")
|
783 |
raise
|
784 |
|
785 |
+
# def polygon_to_exterior_coords(poly: Polygon):
|
786 |
+
# logger.info(f"Starting polygon_to_exterior_coords with polygon type {poly.geom_type}")
|
787 |
+
|
788 |
+
# try:
|
789 |
+
# if poly.geom_type == "MultiPolygon":
|
790 |
+
# logger.debug("Converting MultiPolygon to single Polygon")
|
791 |
+
# biggest = max(poly.geoms, key=lambda g: g.area)
|
792 |
+
# poly = biggest
|
793 |
+
|
794 |
+
# if not poly.exterior:
|
795 |
+
# logger.warning("Polygon has no exterior")
|
796 |
+
# return []
|
797 |
+
|
798 |
+
# coords = list(poly.exterior.coords)
|
799 |
+
# logger.info(f"Completed polygon_to_exterior_coords with {len(coords)} coordinates")
|
800 |
+
# return coords
|
801 |
+
# except Exception as e:
|
802 |
+
# logger.error(f"Error in polygon_to_exterior_coords: {e}")
|
803 |
+
# raise
|
804 |
+
|
805 |
+
def polygon_to_exterior_coords(poly):
|
806 |
logger.info(f"Starting polygon_to_exterior_coords with polygon type {poly.geom_type}")
|
807 |
|
808 |
try:
|
809 |
+
# Handle GeometryCollection case specifically
|
810 |
+
if poly.geom_type == "GeometryCollection":
|
811 |
+
logger.warning("Converting GeometryCollection to Polygon")
|
812 |
+
# Find the largest geometry in the collection that has an exterior
|
813 |
+
largest_area = 0
|
814 |
+
largest_geom = None
|
815 |
+
for geom in poly.geoms:
|
816 |
+
if hasattr(geom, 'area') and geom.area > largest_area:
|
817 |
+
if hasattr(geom, 'exterior') or geom.geom_type == "MultiPolygon":
|
818 |
+
largest_area = geom.area
|
819 |
+
largest_geom = geom
|
820 |
+
|
821 |
+
if largest_geom is None:
|
822 |
+
logger.warning("No valid geometry found in GeometryCollection")
|
823 |
+
return []
|
824 |
+
|
825 |
+
poly = largest_geom
|
826 |
+
|
827 |
if poly.geom_type == "MultiPolygon":
|
828 |
logger.debug("Converting MultiPolygon to single Polygon")
|
829 |
biggest = max(poly.geoms, key=lambda g: g.area)
|
830 |
poly = biggest
|
831 |
|
832 |
+
if not hasattr(poly, 'exterior') or poly.exterior is None:
|
833 |
logger.warning("Polygon has no exterior")
|
834 |
return []
|
835 |
|
|
|
838 |
return coords
|
839 |
except Exception as e:
|
840 |
logger.error(f"Error in polygon_to_exterior_coords: {e}")
|
841 |
+
# Return empty list as fallback
|
842 |
+
return []
|
843 |
+
|
844 |
def place_finger_cut_adjusted(
|
845 |
tool_polygon: Polygon,
|
846 |
points_inch: list,
|
|
|
1015 |
finger_cut_centers,
|
1016 |
final_polygons_inch,
|
1017 |
circle_diameter=1.0,
|
1018 |
+
min_gap=(0.5+offset_value),
|
1019 |
max_attempts=100
|
1020 |
)
|
1021 |
|
|
|
1106 |
text_top = boundary_polygon.bounds[1] + 1
|
1107 |
too_small = boundary_width_in < inner_width + 2 * clearance_side or boundary_length_in < inner_length + 2 * clearance_tb
|
1108 |
if too_small:
|
1109 |
+
raise BoundaryOverlapError("Error: The specified boundary dimensions are too small and overlap with the inner contours. Please provide larger value for boundary length and width.")
|
1110 |
+
if annotation_text.strip() and text_top > min_y - 1:
|
1111 |
+
raise TextOverlapError("Error: The text is too close to the inner contours. Please provide larger value for boundary length and width.")
|
1112 |
return boundary_polygon
|
1113 |
|
1114 |
def draw_polygons_inch(polygons_inch, image_rgb, scaling_factor, image_height, color=(0,0,255), thickness=2):
|
|
|
1178 |
t = time.time()
|
1179 |
if drawer_detected:
|
1180 |
# For detected drawers: shrink and square
|
1181 |
+
shrunked_img = make_square(shrink_bbox(drawer_img, 0.95))
|
1182 |
else:
|
1183 |
# For non-drawer images: keep original dimensions
|
1184 |
shrunked_img = drawer_img # Already in BGR format from above
|
|
|
1486 |
gr.Image(label="Input Image"),
|
1487 |
gr.Number(label="Offset value for Mask", value=0.075),
|
1488 |
gr.Dropdown(label="Offset Unit", choices=["mm", "inches"], value="inches"),
|
1489 |
+
gr.Dropdown(label="Add Finger Clearance?", choices=["Yes", "No"], value="Yes"),
|
1490 |
+
gr.Dropdown(label="Add Rectangular Boundary?", choices=["Yes", "No"], value="Yes"),
|
1491 |
+
gr.Number(label="Boundary Length", value=50, precision=2),
|
1492 |
+
gr.Number(label="Boundary Width", value=50, precision=2),
|
1493 |
gr.Textbox(label="Annotation (max 20 chars)", max_length=20, placeholder="Type up to 20 characters")
|
1494 |
],
|
1495 |
outputs=[
|
|
|
1500 |
gr.Textbox(label="Scaling Factor (inches/pixel)")
|
1501 |
],
|
1502 |
examples=[
|
1503 |
+
["./Test20.jpg", 0.075, "inches", "Yes", "No", 300.0, 200.0, "MyTool"],
|
1504 |
["./Test21.jpg", 0.075, "inches", "Yes", "Yes", 300.0, 200.0, "Tool2"]
|
1505 |
]
|
1506 |
)
|