Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -9,6 +9,11 @@ import numpy as np
|
|
9 |
import torch
|
10 |
import cv2
|
11 |
import ezdxf
|
|
|
|
|
|
|
|
|
|
|
12 |
import gradio as gr
|
13 |
from PIL import Image, ImageEnhance
|
14 |
from pathlib import Path
|
@@ -45,6 +50,10 @@ class BoundaryOverlapError(Exception):
|
|
45 |
"""Raised when the optional boundary dimensions are too small and overlap with the inner contours."""
|
46 |
pass
|
47 |
|
|
|
|
|
|
|
|
|
48 |
# ---------------------
|
49 |
# Global Model Initialization with caching and print statements
|
50 |
# ---------------------
|
@@ -146,7 +155,7 @@ def yolo_detect(image: Union[str, Path, int, Image.Image, list, tuple, np.ndarra
|
|
146 |
|
147 |
def detect_reference_square(img: np.ndarray):
|
148 |
t = time.time()
|
149 |
-
res = reference_detector_global.predict(img, conf=0.
|
150 |
if not res or len(res) == 0 or len(res[0].boxes) == 0:
|
151 |
raise ReferenceBoxNotDetectedError("Reference box not detected in the image.")
|
152 |
print("Reference detection completed in {:.2f} seconds".format(time.time() - t))
|
@@ -383,8 +392,9 @@ def add_rectangular_boundary(doc, polygons_inch, boundary_length, boundary_width
|
|
383 |
clearance_tb = 0.75
|
384 |
|
385 |
# Check if boundary dimensions are at least larger than inner box plus clearance
|
386 |
-
if boundary_width_in <= inner_width + 2 * clearance_side or boundary_length_in <= inner_length + 2 * clearance_tb:
|
387 |
-
|
|
|
388 |
|
389 |
# Calculate center of inner contours
|
390 |
center_x = (min_x + max_x) / 2
|
@@ -400,6 +410,11 @@ def add_rectangular_boundary(doc, polygons_inch, boundary_length, boundary_width
|
|
400 |
from shapely.geometry import Polygon as ShapelyPolygon
|
401 |
boundary_polygon = ShapelyPolygon(rect_coords)
|
402 |
msp.add_lwpolyline(rect_coords, close=True, dxfattribs={"layer": "BOUNDARY"})
|
|
|
|
|
|
|
|
|
|
|
403 |
return boundary_polygon
|
404 |
|
405 |
def draw_polygons_inch(polygons_inch, image_rgb, scaling_factor, image_height, color=(0,0,255), thickness=2):
|
@@ -618,19 +633,40 @@ def predict(
|
|
618 |
# 8) Add annotation text (if provided) in the DXF
|
619 |
# ---------------------
|
620 |
msp = doc.modelspace()
|
|
|
621 |
if annotation_text.strip():
|
|
|
622 |
text_x = ((inner_min_x + inner_max_x) / 2.0) - (int(len(annotation_text.strip()) / 2.0))
|
623 |
-
text_height_dxf = 0.
|
624 |
-
text_y_dxf = inner_min_y - 0.125 - text_height_dxf
|
625 |
-
text_entity = msp.add_text(
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
632 |
)
|
633 |
-
text_entity.dxf.insert = (text_x, text_y_dxf)
|
634 |
|
635 |
# Save the DXF
|
636 |
dxf_filepath = os.path.join("./outputs", "out.dxf")
|
@@ -643,31 +679,109 @@ def predict(
|
|
643 |
new_outlines = np.ones_like(output_img) * 255
|
644 |
draw_polygons_inch(final_polygons_inch, new_outlines, scaling_factor, processed_size[0], color=(0, 0, 255), thickness=2)
|
645 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
646 |
if annotation_text.strip():
|
647 |
-
text_height_cv = 0.
|
648 |
text_x_img = int(((inner_min_x + inner_max_x) / 2.0) / scaling_factor)
|
649 |
-
text_y_in =
|
650 |
text_y_img = int(processed_size[0] - (text_y_in / scaling_factor))
|
651 |
org = (text_x_img - int(len(annotation_text.strip()) * 6), text_y_img)
|
652 |
|
|
|
|
|
|
|
|
|
|
|
|
|
653 |
cv2.putText(
|
654 |
-
|
655 |
-
annotation_text.strip(),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
656 |
org,
|
657 |
cv2.FONT_HERSHEY_SIMPLEX,
|
658 |
-
1.2,
|
659 |
-
(0, 0, 255),
|
660 |
2,
|
|
|
|
|
661 |
cv2.LINE_AA
|
662 |
)
|
|
|
663 |
cv2.putText(
|
664 |
new_outlines,
|
665 |
-
annotation_text.strip(),
|
666 |
org,
|
667 |
cv2.FONT_HERSHEY_SIMPLEX,
|
668 |
-
1.2,
|
669 |
-
(0, 0, 255),
|
670 |
2,
|
|
|
|
|
671 |
cv2.LINE_AA
|
672 |
)
|
673 |
|
@@ -716,5 +830,4 @@ if __name__ == "__main__":
|
|
716 |
["./Test21.jpg", 0.075, "inches", "Yes", "Yes", 300.0, 200.0, "Tool2"]
|
717 |
]
|
718 |
)
|
719 |
-
iface.launch(share=True)
|
720 |
-
|
|
|
9 |
import torch
|
10 |
import cv2
|
11 |
import ezdxf
|
12 |
+
from ezdxf.addons.text2path import make_paths_from_str
|
13 |
+
from ezdxf import path
|
14 |
+
from ezdxf.addons import text2path
|
15 |
+
from ezdxf.enums import TextEntityAlignment
|
16 |
+
from ezdxf.fonts.fonts import FontFace,get_font_face
|
17 |
import gradio as gr
|
18 |
from PIL import Image, ImageEnhance
|
19 |
from pathlib import Path
|
|
|
50 |
"""Raised when the optional boundary dimensions are too small and overlap with the inner contours."""
|
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 |
# ---------------------
|
58 |
# Global Model Initialization with caching and print statements
|
59 |
# ---------------------
|
|
|
155 |
|
156 |
def detect_reference_square(img: np.ndarray):
|
157 |
t = time.time()
|
158 |
+
res = reference_detector_global.predict(img, conf=0.05)
|
159 |
if not res or len(res) == 0 or len(res[0].boxes) == 0:
|
160 |
raise ReferenceBoxNotDetectedError("Reference box not detected in the image.")
|
161 |
print("Reference detection completed in {:.2f} seconds".format(time.time() - t))
|
|
|
392 |
clearance_tb = 0.75
|
393 |
|
394 |
# Check if boundary dimensions are at least larger than inner box plus clearance
|
395 |
+
# if boundary_width_in <= inner_width + 2 * clearance_side or boundary_length_in <= inner_length + 2 * clearance_tb:
|
396 |
+
# raise BoundaryOverlapError("Error: The specified boundary dimensions are too small and overlap with the inner contours. Please provide larger values.")
|
397 |
+
|
398 |
|
399 |
# Calculate center of inner contours
|
400 |
center_x = (min_x + max_x) / 2
|
|
|
410 |
from shapely.geometry import Polygon as ShapelyPolygon
|
411 |
boundary_polygon = ShapelyPolygon(rect_coords)
|
412 |
msp.add_lwpolyline(rect_coords, close=True, dxfattribs={"layer": "BOUNDARY"})
|
413 |
+
|
414 |
+
text_top=boundary_polygon.bounds[1] + 1
|
415 |
+
if text_top > (min_y-0.75):
|
416 |
+
raise TextOverlapError("Error: The Text is overlapping the inner contours of the object.")
|
417 |
+
|
418 |
return boundary_polygon
|
419 |
|
420 |
def draw_polygons_inch(polygons_inch, image_rgb, scaling_factor, image_height, color=(0,0,255), thickness=2):
|
|
|
633 |
# 8) Add annotation text (if provided) in the DXF
|
634 |
# ---------------------
|
635 |
msp = doc.modelspace()
|
636 |
+
|
637 |
if annotation_text.strip():
|
638 |
+
|
639 |
text_x = ((inner_min_x + inner_max_x) / 2.0) - (int(len(annotation_text.strip()) / 2.0))
|
640 |
+
text_height_dxf = 0.75
|
641 |
+
text_y_dxf = boundary_polygon.bounds[1] + 0.25 #+ text_height_dxf#inner_min_y - 0.125 - text_height_dxf
|
642 |
+
# text_entity = msp.add_text(
|
643 |
+
# annotation_text.strip().upper(),
|
644 |
+
# dxfattribs={
|
645 |
+
# "height": text_height_dxf,
|
646 |
+
# "layer": "ANNOTATION",
|
647 |
+
# "style": "Simplex",
|
648 |
+
# }
|
649 |
+
# )
|
650 |
+
# text_entity.dxf.insert = (text_x, text_y_dxf)
|
651 |
+
font = get_font_face("Arial")
|
652 |
+
paths = text2path.make_paths_from_str(
|
653 |
+
annotation_text.strip().upper(),
|
654 |
+
font=font, # Use default font
|
655 |
+
size=text_height_dxf,
|
656 |
+
align=TextEntityAlignment.LEFT
|
657 |
+
)
|
658 |
+
|
659 |
+
# Create a translation matrix
|
660 |
+
translation = ezdxf.math.Matrix44.translate(text_x, text_y_dxf, 0)
|
661 |
+
# Apply the translation to each path
|
662 |
+
translated_paths = [p.transform(translation) for p in paths]
|
663 |
+
|
664 |
+
# Render the paths as splines and polylines
|
665 |
+
path.render_splines_and_polylines(
|
666 |
+
msp,
|
667 |
+
translated_paths,
|
668 |
+
dxfattribs={"layer": "ANNOTATION", "color": 7}
|
669 |
)
|
|
|
670 |
|
671 |
# Save the DXF
|
672 |
dxf_filepath = os.path.join("./outputs", "out.dxf")
|
|
|
679 |
new_outlines = np.ones_like(output_img) * 255
|
680 |
draw_polygons_inch(final_polygons_inch, new_outlines, scaling_factor, processed_size[0], color=(0, 0, 255), thickness=2)
|
681 |
|
682 |
+
# if annotation_text.strip():
|
683 |
+
# text_height_cv = 0.75
|
684 |
+
# text_x_img = int(((inner_min_x + inner_max_x) / 2.0) / scaling_factor)
|
685 |
+
# text_y_in = boundary_polygon.bounds[1] + 0.25 #+ text_height_cv#inner_min_y - 0.125 - text_height_cv
|
686 |
+
# text_y_img = int(processed_size[0] - (text_y_in / scaling_factor))
|
687 |
+
# org = (text_x_img - int(len(annotation_text.strip()) * 6), text_y_img)
|
688 |
+
|
689 |
+
# cv2.putText(
|
690 |
+
# output_img,
|
691 |
+
# annotation_text.strip().upper(),
|
692 |
+
# org,
|
693 |
+
# cv2.FONT_HERSHEY_SIMPLEX,
|
694 |
+
# 1.2,
|
695 |
+
# (0, 0, 255),
|
696 |
+
# 2,
|
697 |
+
# cv2.LINE_AA
|
698 |
+
# )
|
699 |
+
# cv2.putText(
|
700 |
+
# new_outlines,
|
701 |
+
# annotation_text.strip().upper(),
|
702 |
+
# org,
|
703 |
+
# cv2.FONT_HERSHEY_SIMPLEX,
|
704 |
+
# 1.2,
|
705 |
+
# (0, 0, 255),
|
706 |
+
# 2,
|
707 |
+
# cv2.LINE_AA
|
708 |
+
# )
|
709 |
if annotation_text.strip():
|
710 |
+
text_height_cv = 0.75
|
711 |
text_x_img = int(((inner_min_x + inner_max_x) / 2.0) / scaling_factor)
|
712 |
+
text_y_in = boundary_polygon.bounds[1] + 0.25
|
713 |
text_y_img = int(processed_size[0] - (text_y_in / scaling_factor))
|
714 |
org = (text_x_img - int(len(annotation_text.strip()) * 6), text_y_img)
|
715 |
|
716 |
+
# Method 2: Use two different thicknesses
|
717 |
+
# Draw thicker outline
|
718 |
+
# Create a clean temporary image for drawing the text outline
|
719 |
+
temp_img = np.zeros_like(output_img)
|
720 |
+
|
721 |
+
# Draw thick text on temp image
|
722 |
cv2.putText(
|
723 |
+
temp_img,
|
724 |
+
annotation_text.strip().upper(),
|
725 |
+
org,
|
726 |
+
cv2.FONT_HERSHEY_SIMPLEX,
|
727 |
+
2,
|
728 |
+
(0, 0, 255), # Red color
|
729 |
+
4, # Thicker outline
|
730 |
+
cv2.LINE_AA
|
731 |
+
)
|
732 |
+
|
733 |
+
# Draw inner text in black on temp image
|
734 |
+
cv2.putText(
|
735 |
+
temp_img,
|
736 |
+
annotation_text.strip().upper(),
|
737 |
+
org,
|
738 |
+
cv2.FONT_HERSHEY_SIMPLEX,
|
739 |
+
2,
|
740 |
+
(0, 0, 0), # Black to create hole
|
741 |
+
2, # Thinner inner part
|
742 |
+
cv2.LINE_AA
|
743 |
+
)
|
744 |
+
|
745 |
+
# Create a mask from the temp image
|
746 |
+
outline_mask = cv2.cvtColor(temp_img, cv2.COLOR_BGR2GRAY)
|
747 |
+
_, outline_mask = cv2.threshold(outline_mask, 1, 255, cv2.THRESH_BINARY)
|
748 |
+
|
749 |
+
# Apply only the red channel from the temp image to the output image
|
750 |
+
# This preserves the original background where the outline isn't
|
751 |
+
output_img[outline_mask > 0] = temp_img[outline_mask > 0]
|
752 |
+
|
753 |
+
# Draw inner part with background color
|
754 |
+
# cv2.putText(
|
755 |
+
# output_img,
|
756 |
+
# annotation_text.strip().upper(),
|
757 |
+
# org,
|
758 |
+
# cv2.FONT_HERSHEY_SIMPLEX,
|
759 |
+
# 2,
|
760 |
+
# (255, 255, 255), # Assuming black background, adjust as needed
|
761 |
+
# 2, # Thinner inner part
|
762 |
+
# cv2.LINE_AA
|
763 |
+
# )
|
764 |
+
|
765 |
+
# Do the same for new_outlines
|
766 |
+
cv2.putText(
|
767 |
+
new_outlines,
|
768 |
+
annotation_text.strip().upper(),
|
769 |
org,
|
770 |
cv2.FONT_HERSHEY_SIMPLEX,
|
|
|
|
|
771 |
2,
|
772 |
+
(0, 0, 255), # Red color
|
773 |
+
4, # Thicker outline
|
774 |
cv2.LINE_AA
|
775 |
)
|
776 |
+
|
777 |
cv2.putText(
|
778 |
new_outlines,
|
779 |
+
annotation_text.strip().upper(),
|
780 |
org,
|
781 |
cv2.FONT_HERSHEY_SIMPLEX,
|
|
|
|
|
782 |
2,
|
783 |
+
(255, 255, 255), # Assuming black background, adjust as needed
|
784 |
+
2, # Thinner inner part
|
785 |
cv2.LINE_AA
|
786 |
)
|
787 |
|
|
|
830 |
["./Test21.jpg", 0.075, "inches", "Yes", "Yes", 300.0, 200.0, "Tool2"]
|
831 |
]
|
832 |
)
|
833 |
+
iface.launch(share=True)
|
|