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