Nighty3912 commited on
Commit
178b9c4
·
verified ·
1 Parent(s): f38b75d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -73
app.py CHANGED
@@ -823,78 +823,146 @@ def draw_single_polygon(poly, image_rgb, scaling_factor, image_height, color=(0,
823
  import numpy as np
824
  import cv2
825
 
826
- def draw_and_pad(polygons_inch, scaling_factor, boundary_polygon, padding=50,
827
- color=(0, 0, 255), thickness=2):
828
- """
829
- Draws Shapely Polygons (in inch units) on a white canvas.
830
 
831
- When boundary_polygon is None, the computed bounds are expanded by the padding value
832
- so that the drawn contours are not clipped at the edges after adding the final padding.
833
 
834
- Arguments:
835
- polygons_inch: list of Shapely Polygons in inch units (already including boundary).
836
- scaling_factor: inches per pixel.
837
- boundary_polygon: the Shapely boundary polygon, or None.
838
- padding: padding in pixels.
839
- color: color of the drawn polylines (in BGR format).
840
- thickness: line thickness.
841
-
842
- Returns:
843
- padded: an image (numpy array) of the drawn polygons with an external white border.
844
- """
845
- all_x = []
846
- all_y = []
847
- pixel_polys = []
848
 
849
- # 1) Convert each polygon to pixel coordinates and compute overall bounds.
850
- for poly in polygons_inch:
851
- coords = list(poly.exterior.coords)
852
- pts = []
853
- for x_in, y_in in coords:
854
- px = int(round(x_in / scaling_factor))
855
- py = int(round(y_in / scaling_factor))
856
- pts.append([px, py])
857
- all_x.append(px)
858
- all_y.append(py)
859
- pixel_polys.append(np.array(pts, dtype=np.int8))
860
 
861
- # 2) Compute the basic canvas size from the polygon bounds.
862
- min_x, max_x = min(all_x), max(all_x)
863
- min_y, max_y = min(all_y), max(all_y)
864
 
865
- # If no boundary polygon is provided, expand the bounds to add margin
866
- # so that later when we pad externally, the contours do not get clipped.
867
- if boundary_polygon is None:
868
- min_x -= padding
869
- max_x += padding
870
- min_y -= padding
871
- max_y += padding
872
-
873
- width = max_x - min_x + 1
874
- height = max_y - min_y + 1
875
 
876
- # 3) Create a blank white canvas.
877
- canvas = 255 * np.ones((height, width, 3), dtype=np.uint8)
878
 
879
- # 4) Draw each polygon, flipping the y-coordinates to match image coordinates.
880
- for pts in pixel_polys:
881
- # Offset so the minimum corner becomes (0,0) on canvas.
882
- pts_off = pts - np.array([[min_x, min_y]])
883
- # Flip y: image coordinates have (0,0) at the top-left.
884
- pts_off[:, 1] = (height - 1) - pts_off[:, 1]
885
- cv2.polylines(canvas, [pts_off], isClosed=True,
886
- color=color, thickness=thickness, lineType=cv2.LINE_AA)
887
 
888
- # 5) Finally, add external padding on all sides.
889
- padded = cv2.copyMakeBorder(
890
- canvas,
891
- top=padding, bottom=padding,
892
- left=padding, right=padding,
893
- borderType=cv2.BORDER_CONSTANT,
894
- value=[255, 255, 255]
895
- )
896
 
897
- return padded
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898
 
899
  # ---------------------
900
  # Main Predict Function with Finger Cut Clearance, Boundary Box, Annotation and Sharpness Enhancement
@@ -1149,7 +1217,7 @@ def predict(
1149
  if boundary_polygon is not None and poly == boundary_polygon:
1150
  continue
1151
  draw_single_polygon(poly, output_img, scaling_factor, processed_size[0], color=(0, 0, 255), thickness=2)
1152
- new_outlines= draw_and_pad(final_polygons_inch, scaling_factor,boundary_polygon, padding=50)
1153
 
1154
  #draw_polygons_inch(final_polygons_inch, new_outlines, scaling_factor, processed_size[0], color=(0, 0, 255), thickness=2)
1155
  import math
@@ -1175,27 +1243,29 @@ def predict(
1175
  output_img[outline_mask > 0] = temp_img[outline_mask > 0]
1176
 
1177
  # For new_outlines - simple, centered text
1178
- font_scale = 1
1179
- def optimal_font_dims(img, font_scale = 2e-3, thickness_scale = 5e-3):
1180
  h, w, _ = img.shape
1181
  font_scale = min(w, h) * font_scale
1182
  thickness = math.ceil(min(w, h) * thickness_scale)
1183
  return font_scale, thickness
1184
  font_scale,thickness = optimal_font_dims(new_outlines)
1185
- (text_width, text_height) = cv2.getTextSize(text, font, font_scale, thickness)[0]
1186
  text_x = (canvas_width - text_width) // 2
 
 
 
 
1187
  # bottom_margin_px = int(0.25 / scaling_factor)
1188
  # font_scale,_ = optimal_font_dims(new_outlines)
1189
- text_y_outlines = int(canvas_height - (text_y_in + (0.75) / scaling_factor))
1190
 
1191
  # First outline, then inner text
1192
- cv2.putText(new_outlines, text, (text_x, text_y_outlines), font, font_scale, (0, 0, 255), thickness+(2), cv2.LINE_AA)
1193
- cv2.putText(new_outlines, text, (text_x, text_y_outlines), font, font_scale, (255, 255, 255), thickness-(1), cv2.LINE_AA)
1194
 
1195
 
1196
  outlines_color = cv2.cvtColor(new_outlines, cv2.COLOR_BGR2RGB)
1197
  print("Total prediction time: {:.2f} seconds".format(time.time() - overall_start))
1198
-
1199
  return (
1200
  cv2.cvtColor(output_img, cv2.COLOR_BGR2RGB),
1201
  outlines_color,
@@ -1227,8 +1297,8 @@ if __name__ == "__main__":
1227
  gr.Textbox(label="Annotation (max 20 chars)", max_length=20, placeholder="Type up to 20 characters")
1228
  ],
1229
  outputs=[
1230
- gr.Image(label="Output Image"),
1231
- gr.Image(label="Outlines of Objects"),
1232
  gr.File(label="DXF file"),
1233
  gr.Image(label="Mask"),
1234
  gr.Textbox(label="Scaling Factor (inches/pixel)")
 
823
  import numpy as np
824
  import cv2
825
 
826
+ # def draw_and_pad(polygons_inch, scaling_factor, boundary_polygon, padding=50,
827
+ # color=(0, 0, 255), thickness=2):
828
+ # """
829
+ # Draws Shapely Polygons (in inch units) on a white canvas.
830
 
831
+ # When boundary_polygon is None, the computed bounds are expanded by the padding value
832
+ # so that the drawn contours are not clipped at the edges after adding the final padding.
833
 
834
+ # Arguments:
835
+ # polygons_inch: list of Shapely Polygons in inch units (already including boundary).
836
+ # scaling_factor: inches per pixel.
837
+ # boundary_polygon: the Shapely boundary polygon, or None.
838
+ # padding: padding in pixels.
839
+ # color: color of the drawn polylines (in BGR format).
840
+ # thickness: line thickness.
841
+
842
+ # Returns:
843
+ # padded: an image (numpy array) of the drawn polygons with an external white border.
844
+ # """
845
+ # all_x = []
846
+ # all_y = []
847
+ # pixel_polys = []
848
 
849
+ # # 1) Convert each polygon to pixel coordinates and compute overall bounds.
850
+ # for poly in polygons_inch:
851
+ # coords = list(poly.exterior.coords)
852
+ # pts = []
853
+ # for x_in, y_in in coords:
854
+ # px = int(round(x_in / scaling_factor))
855
+ # py = int(round(y_in / scaling_factor))
856
+ # pts.append([px, py])
857
+ # all_x.append(px)
858
+ # all_y.append(py)
859
+ # pixel_polys.append(np.array(pts, dtype=np.int32))
860
 
861
+ # # 2) Compute the basic canvas size from the polygon bounds.
862
+ # min_x, max_x = min(all_x), max(all_x)
863
+ # min_y, max_y = min(all_y), max(all_y)
864
 
865
+ # # If no boundary polygon is provided, expand the bounds to add margin
866
+ # # so that later when we pad externally, the contours do not get clipped.
867
+ # if boundary_polygon is None:
868
+ # min_x -= padding
869
+ # max_x += padding
870
+ # min_y -= padding
871
+ # max_y += padding
872
+
873
+ # width = max_x - min_x + 1
874
+ # height = max_y - min_y + 1
875
 
876
+ # # 3) Create a blank white canvas.
877
+ # canvas = 255 * np.ones((height, width, 3), dtype=np.uint8)
878
 
879
+ # # 4) Draw each polygon, flipping the y-coordinates to match image coordinates.
880
+ # for pts in pixel_polys:
881
+ # # Offset so the minimum corner becomes (0,0) on canvas.
882
+ # pts_off = pts - np.array([[min_x, min_y]])
883
+ # # Flip y: image coordinates have (0,0) at the top-left.
884
+ # pts_off[:, 1] = (height - 1) - pts_off[:, 1]
885
+ # cv2.polylines(canvas, [pts_off], isClosed=True,
886
+ # color=color, thickness=thickness, lineType=cv2.LINE_AA)
887
 
888
+ # # 5) Finally, add external padding on all sides.
889
+ # padded = cv2.copyMakeBorder(
890
+ # canvas,
891
+ # top=padding, bottom=padding,
892
+ # left=padding, right=padding,
893
+ # borderType=cv2.BORDER_CONSTANT,
894
+ # value=[255, 255, 255]
895
+ # )
896
 
897
+ # return padded
898
+
899
+ import numpy as np
900
+ import cv2
901
+ from shapely.geometry import Polygon
902
+
903
+ import numpy as np
904
+ import cv2
905
+ from shapely.geometry import Polygon
906
+
907
+ def draw_and_pad(polygons_inch,
908
+ scaling_factor, # inches per pixel
909
+ boundary_polygon=None,
910
+ max_res=1024,
911
+ simplify_tol_px=1.0,
912
+ padding_px=20,
913
+ color=(0,0,255),
914
+ thickness=2):
915
+ # 1) Simplify & collect raw coords in inches
916
+ all_x, all_y = [], []
917
+ simple_polys = []
918
+ for poly in polygons_inch:
919
+ tol_in = simplify_tol_px * scaling_factor / max_res
920
+ simp = poly.simplify(tolerance=tol_in, preserve_topology=True)
921
+ coords = np.array(simp.exterior.coords) # (N,2) in inches
922
+ all_x.extend(coords[:,0])
923
+ all_y.extend(coords[:,1])
924
+ simple_polys.append(coords)
925
+
926
+ # 2) Compute full‑res pixel extents
927
+ min_x_in, max_x_in = min(all_x), max(all_x)
928
+ min_y_in, max_y_in = min(all_y), max(all_y)
929
+ w_in = (max_x_in - min_x_in) if boundary_polygon is None else (max_x_in - min_x_in)
930
+ h_in = (max_y_in - min_y_in) if boundary_polygon is None else (max_y_in - min_y_in)
931
+ full_w_px = np.ceil(w_in / scaling_factor)
932
+ full_h_px = np.ceil(h_in / scaling_factor)
933
+
934
+ # 3) Compute preview scale ≤1 so dims ≤ max_res
935
+ scale = min(max_res / full_w_px, max_res / full_h_px, 1.0)
936
+
937
+ # 4) Compute preview dims & allocate _fully‐padded_ canvas
938
+ W = int(np.ceil(full_w_px * scale))
939
+ H = int(np.ceil(full_h_px * scale))
940
+ PW, PH = W + 2*padding_px, H + 2*padding_px
941
+ canvas = 255 * np.ones((PH, PW, 3), dtype=np.uint8)
942
+
943
+ # Precompute offsets (in preview px) of the “world origin”
944
+ off_x = int(np.floor(min_x_in / scaling_factor * scale))
945
+ off_y = int(np.floor(min_y_in / scaling_factor * scale))
946
+
947
+ # 5) Draw each polygon, now fully inside the padded canvas
948
+ for coords in simple_polys:
949
+ # inch→preview‐px transform
950
+ pts = ((coords / scaling_factor) * scale).round().astype(int)
951
+ # shift by both the minimum and the padding:
952
+ pts[:,0] = pts[:,0] - off_x + padding_px
953
+ pts[:,1] = pts[:,1] - off_y + padding_px
954
+ # flip Y into image coords
955
+ pts[:,1] = PH - 1 - pts[:,1]
956
+ cv2.polylines(canvas,
957
+ [pts],
958
+ isClosed=True,
959
+ color=color,
960
+ thickness=thickness,
961
+ lineType=cv2.LINE_AA)
962
+
963
+ return canvas, scale, off_y, padding_px, PH
964
+
965
+
966
 
967
  # ---------------------
968
  # Main Predict Function with Finger Cut Clearance, Boundary Box, Annotation and Sharpness Enhancement
 
1217
  if boundary_polygon is not None and poly == boundary_polygon:
1218
  continue
1219
  draw_single_polygon(poly, output_img, scaling_factor, processed_size[0], color=(0, 0, 255), thickness=2)
1220
+ new_outlines,preview_scale, off_y, padding_px, PH= draw_and_pad(final_polygons_inch, scaling_factor,boundary_polygon)
1221
 
1222
  #draw_polygons_inch(final_polygons_inch, new_outlines, scaling_factor, processed_size[0], color=(0, 0, 255), thickness=2)
1223
  import math
 
1243
  output_img[outline_mask > 0] = temp_img[outline_mask > 0]
1244
 
1245
  # For new_outlines - simple, centered text
1246
+ def optimal_font_dims(img, font_scale = 1e-3, thickness_scale = 2e-3):
 
1247
  h, w, _ = img.shape
1248
  font_scale = min(w, h) * font_scale
1249
  thickness = math.ceil(min(w, h) * thickness_scale)
1250
  return font_scale, thickness
1251
  font_scale,thickness = optimal_font_dims(new_outlines)
1252
+ (text_width, text_height), baseline = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, font_scale, thickness)
1253
  text_x = (canvas_width - text_width) // 2
1254
+ raw_y = (text_y_in / scaling_factor) * preview_scale
1255
+ y1 = raw_y - off_y + padding_px
1256
+ text_y_px = int(round(PH - 1 - y1))
1257
+ text_y_px_adjusted = text_y_px - baseline
1258
  # bottom_margin_px = int(0.25 / scaling_factor)
1259
  # font_scale,_ = optimal_font_dims(new_outlines)
1260
+ #text_y_outlines = int(canvas_height - (text_y_in + (0.75) / scaling_factor))
1261
 
1262
  # First outline, then inner text
1263
+ cv2.putText(new_outlines, text, (text_x, text_y_px_adjusted), font, font_scale, (0, 0, 255), thickness+2, cv2.LINE_AA)
1264
+ cv2.putText(new_outlines, text, (text_x, text_y_px_adjusted), font, font_scale, (255, 255, 255), thickness-1, cv2.LINE_AA)
1265
 
1266
 
1267
  outlines_color = cv2.cvtColor(new_outlines, cv2.COLOR_BGR2RGB)
1268
  print("Total prediction time: {:.2f} seconds".format(time.time() - overall_start))
 
1269
  return (
1270
  cv2.cvtColor(output_img, cv2.COLOR_BGR2RGB),
1271
  outlines_color,
 
1297
  gr.Textbox(label="Annotation (max 20 chars)", max_length=20, placeholder="Type up to 20 characters")
1298
  ],
1299
  outputs=[
1300
+ gr.Image(format="png",label="Output Image"),
1301
+ gr.Image(format="png",label="Outlines of Objects"),
1302
  gr.File(label="DXF file"),
1303
  gr.Image(label="Mask"),
1304
  gr.Textbox(label="Scaling Factor (inches/pixel)")