Nighty3912 commited on
Commit
052acac
·
verified ·
1 Parent(s): d0c7712

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -96
app.py CHANGED
@@ -13,7 +13,7 @@ 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
@@ -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.25)
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))
@@ -286,35 +286,39 @@ def polygon_to_exterior_coords(poly: Polygon):
286
  return []
287
  return list(poly.exterior.coords)
288
 
289
- def place_finger_cut_randomly(tool_polygon, points_inch, existing_centers, all_polygons, circle_diameter=1.0, min_gap=0.25, max_attempts=30):
290
  import random
291
  needed_center_distance = circle_diameter + min_gap
292
  radius = circle_diameter / 2.0
293
- for _ in range(max_attempts):
294
- idx = random.randint(0, len(points_inch) - 1)
295
- cx, cy = points_inch[idx]
296
- too_close = False
297
- for (ex_x, ex_y) in existing_centers:
298
- if np.hypot(cx - ex_x, cy - ex_y) < needed_center_distance:
299
- too_close = True
300
- break
301
- if too_close:
302
- continue
303
- circle_poly = Point((cx, cy)).buffer(radius, resolution=64)
304
- union_poly = tool_polygon.union(circle_poly)
305
- overlap_with_others = False
306
- too_close_to_others = False
307
- for poly in all_polygons:
308
- if union_poly.intersects(poly):
309
- overlap_with_others = True
310
- break
311
- if circle_poly.buffer(min_gap).intersects(poly):
312
- too_close_to_others = True
313
- break
314
- if overlap_with_others or too_close_to_others:
315
- continue
316
- existing_centers.append((cx, cy))
317
- return union_poly, (cx, cy)
 
 
 
 
318
  print("Warning: Could not place a finger cut circle meeting all spacing requirements.")
319
  return None, None
320
 
@@ -340,7 +344,7 @@ def save_dxf_spline(inflated_contours, scaling_factor, height, finger_clearance=
340
  points_inch.append(points_inch[0])
341
  tool_polygon = build_tool_polygon(points_inch)
342
  if finger_clearance:
343
- union_poly, center = place_finger_cut_randomly(tool_polygon, points_inch, finger_cut_centers, final_polygons_inch, circle_diameter=1.0, min_gap=0.25, max_attempts=30)
344
  if union_poly is not None:
345
  tool_polygon = union_poly
346
  exterior_coords = polygon_to_exterior_coords(tool_polygon)
@@ -391,11 +395,6 @@ def add_rectangular_boundary(doc, polygons_inch, boundary_length, boundary_width
391
  if annotation_text.strip():
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
401
  center_y = (min_y + max_y) / 2
@@ -411,8 +410,8 @@ def add_rectangular_boundary(doc, polygons_inch, boundary_length, boundary_width
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
@@ -561,7 +560,7 @@ def predict(
561
  objects_mask = remove_bg(shrunked_img)
562
  processed_size = objects_mask.shape[:2]
563
 
564
- objects_mask = exclude_scaling_box(objects_mask, scaling_box_coords, orig_size, processed_size, expansion_factor=1.7)
565
  objects_mask = resize_img(objects_mask, (shrunked_img.shape[1], shrunked_img.shape[0]))
566
  del scaling_box_coords
567
  gc.collect()
@@ -635,19 +634,9 @@ def predict(
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(),
@@ -658,7 +647,7 @@ def predict(
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
@@ -679,33 +668,6 @@ def predict(
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)
@@ -715,10 +677,8 @@ def predict(
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(),
@@ -730,7 +690,6 @@ def predict(
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(),
@@ -742,27 +701,11 @@ def predict(
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(),
@@ -780,7 +723,7 @@ def predict(
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
  )
 
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
 
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 box not detected in the image.")
161
  print("Reference detection completed in {:.2f} seconds".format(time.time() - t))
 
286
  return []
287
  return list(poly.exterior.coords)
288
 
289
+ def place_finger_cut_adjusted(tool_polygon, points_inch, existing_centers, all_polygons, circle_diameter=1.0, min_gap=0.25, max_attempts=30):
290
  import random
291
  needed_center_distance = circle_diameter + min_gap
292
  radius = circle_diameter / 2.0
293
+ attempts = 0
294
+ indices = list(range(len(points_inch)))
295
+ random.shuffle(indices) # Shuffle indices for randomness
296
+
297
+ for i in indices:
298
+ if attempts >= max_attempts:
299
+ break
300
+ cx, cy = points_inch[i]
301
+ # Try small adjustments around the chosen candidate
302
+ for dx in np.linspace(-0.1, 0.1, 5):
303
+ for dy in np.linspace(-0.1, 0.1, 5):
304
+ candidate_center = (cx + dx, cy + dy)
305
+ # Check distance from already placed centers
306
+ if any(np.hypot(candidate_center[0] - ex, candidate_center[1] - ey) < needed_center_distance for ex, ey in existing_centers):
307
+ continue
308
+ circle_poly = Point(candidate_center).buffer(radius, resolution=64)
309
+ union_poly = tool_polygon.union(circle_poly)
310
+ overlap = False
311
+ # Check against other tool polygons for overlap or proximity issues
312
+ for poly in all_polygons:
313
+ if union_poly.intersects(poly) or circle_poly.buffer(min_gap).intersects(poly):
314
+ overlap = True
315
+ break
316
+ if overlap:
317
+ continue
318
+ # If candidate passes, accept it
319
+ existing_centers.append(candidate_center)
320
+ return union_poly, candidate_center
321
+ attempts += 1
322
  print("Warning: Could not place a finger cut circle meeting all spacing requirements.")
323
  return None, None
324
 
 
344
  points_inch.append(points_inch[0])
345
  tool_polygon = build_tool_polygon(points_inch)
346
  if finger_clearance:
347
+ union_poly, center = place_finger_cut_adjusted(tool_polygon, points_inch, finger_cut_centers, final_polygons_inch, circle_diameter=1.0, min_gap=0.25, max_attempts=30)
348
  if union_poly is not None:
349
  tool_polygon = union_poly
350
  exterior_coords = polygon_to_exterior_coords(tool_polygon)
 
395
  if annotation_text.strip():
396
  clearance_tb = 0.75
397
 
 
 
 
 
 
398
  # Calculate center of inner contours
399
  center_x = (min_x + max_x) / 2
400
  center_y = (min_y + max_y) / 2
 
410
  boundary_polygon = ShapelyPolygon(rect_coords)
411
  msp.add_lwpolyline(rect_coords, close=True, dxfattribs={"layer": "BOUNDARY"})
412
 
413
+ text_top = boundary_polygon.bounds[1] + 1
414
+ if text_top > (min_y - 0.75):
415
  raise TextOverlapError("Error: The Text is overlapping the inner contours of the object.")
416
 
417
  return boundary_polygon
 
560
  objects_mask = remove_bg(shrunked_img)
561
  processed_size = objects_mask.shape[:2]
562
 
563
+ objects_mask = exclude_scaling_box(objects_mask, scaling_box_coords, orig_size, processed_size, expansion_factor=2)
564
  objects_mask = resize_img(objects_mask, (shrunked_img.shape[1], shrunked_img.shape[0]))
565
  del scaling_box_coords
566
  gc.collect()
 
634
  msp = doc.modelspace()
635
 
636
  if annotation_text.strip():
 
637
  text_x = ((inner_min_x + inner_max_x) / 2.0) - (int(len(annotation_text.strip()) / 2.0))
638
  text_height_dxf = 0.75
639
+ text_y_dxf = boundary_polygon.bounds[1] + 0.25
 
 
 
 
 
 
 
 
 
640
  font = get_font_face("Arial")
641
  paths = text2path.make_paths_from_str(
642
  annotation_text.strip().upper(),
 
647
 
648
  # Create a translation matrix
649
  translation = ezdxf.math.Matrix44.translate(text_x, text_y_dxf, 0)
650
+ # Apply the translation to each path
651
  translated_paths = [p.transform(translation) for p in paths]
652
 
653
  # Render the paths as splines and polylines
 
668
  new_outlines = np.ones_like(output_img) * 255
669
  draw_polygons_inch(final_polygons_inch, new_outlines, scaling_factor, processed_size[0], color=(0, 0, 255), thickness=2)
670
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
671
  if annotation_text.strip():
672
  text_height_cv = 0.75
673
  text_x_img = int(((inner_min_x + inner_max_x) / 2.0) / scaling_factor)
 
677
 
678
  # Method 2: Use two different thicknesses
679
  # Draw thicker outline
 
680
  temp_img = np.zeros_like(output_img)
681
 
 
682
  cv2.putText(
683
  temp_img,
684
  annotation_text.strip().upper(),
 
690
  cv2.LINE_AA
691
  )
692
 
 
693
  cv2.putText(
694
  temp_img,
695
  annotation_text.strip().upper(),
 
701
  cv2.LINE_AA
702
  )
703
 
 
704
  outline_mask = cv2.cvtColor(temp_img, cv2.COLOR_BGR2GRAY)
705
  _, outline_mask = cv2.threshold(outline_mask, 1, 255, cv2.THRESH_BINARY)
706
 
 
 
707
  output_img[outline_mask > 0] = temp_img[outline_mask > 0]
708
 
 
 
 
 
 
 
 
 
 
 
 
 
 
709
  cv2.putText(
710
  new_outlines,
711
  annotation_text.strip().upper(),
 
723
  org,
724
  cv2.FONT_HERSHEY_SIMPLEX,
725
  2,
726
+ (255, 255, 255), # Inner text in white
727
  2, # Thinner inner part
728
  cv2.LINE_AA
729
  )