autoforge 1.4.0__tar.gz → 1.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {autoforge-1.4.0 → autoforge-1.4.2}/PKG-INFO +2 -1
  2. {autoforge-1.4.0 → autoforge-1.4.2}/README.md +1 -0
  3. {autoforge-1.4.0 → autoforge-1.4.2}/pyproject.toml +1 -1
  4. {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/PKG-INFO +2 -1
  5. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/ImageHelper.py +8 -0
  6. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/OutputHelper.py +103 -64
  7. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/auto_forge.py +55 -18
  8. {autoforge-1.4.0 → autoforge-1.4.2}/setup.cfg +0 -0
  9. {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/SOURCES.txt +0 -0
  10. {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/dependency_links.txt +0 -0
  11. {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/entry_points.txt +0 -0
  12. {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/requires.txt +0 -0
  13. {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/top_level.txt +0 -0
  14. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/Views/__init__.py +0 -0
  15. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/Views/backend_database.py +0 -0
  16. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/Views/filament_editor.py +0 -0
  17. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/__init__.py +0 -0
  18. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/app.py +0 -0
  19. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/main.py +0 -0
  20. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/FilamentHelper.py +0 -0
  21. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/OptimizerHelper.py +0 -0
  22. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/PruningHelper.py +0 -0
  23. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/__init__.py +0 -0
  24. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/filamentcolors_library.py +0 -0
  25. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Loss/LossFunctions.py +0 -0
  26. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Loss/PerceptionLoss.py +0 -0
  27. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Loss/__init__.py +0 -0
  28. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Misc/__init__.py +0 -0
  29. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Misc/color_fit_all.py +0 -0
  30. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Modules/Optimizer.py +0 -0
  31. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Modules/__init__.py +0 -0
  32. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/__init__.py +0 -0
  33. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/__main__.py +0 -0
  34. {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/old_jax_files.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: AutoForge
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: AutoForge is a Python tool for generating 3D printed layered models from an input image.
5
5
  Author-email: Hendric Voss <hvoss@techfak.uni-bielefeld.de>
6
6
  License: CC BY-NC-SA 4.0
@@ -114,6 +114,7 @@ autoforge --input_image path/to/input_image.jpg --csv_file path/to/materials.csv
114
114
  **Note:** We solve on a smaller size as this is many times faster, but also a bit less accurate. Increase if you need more accuracy.
115
115
  - `--init_tau`: Initial tau value for Gumbel-Softmax (default: 1.0).
116
116
  - `--final_tau`: Final tau value for the Gumbel-Softmax formulation (default: 0.01).
117
+ - `--stl_output_size`: Size of the output stl file in mm (default: 200) (20cm).
117
118
  - `--visualize`: Flag to enable live visualization of the composite image during optimization.
118
119
  - `--tensorboard`: Enable TensorBoard logging
119
120
  - `--run-name`: Name of the run used for TensorBoard logging (optional).
@@ -93,6 +93,7 @@ autoforge --input_image path/to/input_image.jpg --csv_file path/to/materials.csv
93
93
  **Note:** We solve on a smaller size as this is many times faster, but also a bit less accurate. Increase if you need more accuracy.
94
94
  - `--init_tau`: Initial tau value for Gumbel-Softmax (default: 1.0).
95
95
  - `--final_tau`: Final tau value for the Gumbel-Softmax formulation (default: 0.01).
96
+ - `--stl_output_size`: Size of the output stl file in mm (default: 200) (20cm).
96
97
  - `--visualize`: Flag to enable live visualization of the composite image during optimization.
97
98
  - `--tensorboard`: Enable TensorBoard logging
98
99
  - `--run-name`: Name of the run used for TensorBoard logging (optional).
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "AutoForge"
7
- version="1.4.0"
7
+ version="1.4.2"
8
8
  description = "AutoForge is a Python tool for generating 3D printed layered models from an input image."
9
9
  authors = [{ name = "Hendric Voss", email = "hvoss@techfak.uni-bielefeld.de" }]
10
10
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: AutoForge
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: AutoForge is a Python tool for generating 3D printed layered models from an input image.
5
5
  Author-email: Hendric Voss <hvoss@techfak.uni-bielefeld.de>
6
6
  License: CC BY-NC-SA 4.0
@@ -114,6 +114,7 @@ autoforge --input_image path/to/input_image.jpg --csv_file path/to/materials.csv
114
114
  **Note:** We solve on a smaller size as this is many times faster, but also a bit less accurate. Increase if you need more accuracy.
115
115
  - `--init_tau`: Initial tau value for Gumbel-Softmax (default: 1.0).
116
116
  - `--final_tau`: Final tau value for the Gumbel-Softmax formulation (default: 0.01).
117
+ - `--stl_output_size`: Size of the output stl file in mm (default: 200) (20cm).
117
118
  - `--visualize`: Flag to enable live visualization of the composite image during optimization.
118
119
  - `--tensorboard`: Enable TensorBoard logging
119
120
  - `--run-name`: Name of the run used for TensorBoard logging (optional).
@@ -23,6 +23,14 @@ def resize_image(img, max_size):
23
23
  return img_out
24
24
 
25
25
 
26
+ def resize_image_exact(img, new_w, new_h):
27
+ img_out = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_CUBIC)
28
+ # INTER_CUBIC is actually not a good choice for shrinking images. Except in our case.
29
+ # As we shrink the image, we lose information and the image becomes blurry with INTER_AREA. This is detrimental for the solver. If you want to try it out be my guest.
30
+ # INTER_AREA actually destroys a lot of the colors of our solver.
31
+ return img_out
32
+
33
+
26
34
  def srgb_to_lab(srgb, eps=1e-6):
27
35
  """
28
36
  Converts an sRGB image (values in [0, 255]) to the CIELAB color space.
@@ -186,108 +186,147 @@ def generate_project_file(
186
186
  json.dump(project_data, f, indent=4)
187
187
 
188
188
 
189
- def generate_stl(height_map, filename, background_height, scale=1.0):
189
+ import numpy as np
190
+ import struct
191
+
192
+
193
+ def generate_stl(height_map, filename, background_height, maximum_x_y_size, alpha_mask=None):
190
194
  """
191
- Generate a binary STL file from a height map with shared boundary vertices
192
- to fix non-manifold edge warnings.
195
+ Generate a binary STL file from a height map with an optional alpha mask.
196
+ If alpha_mask is provided, vertices where alpha < 128 are omitted.
197
+ This function builds a manifold mesh consisting of:
198
+ - a top surface (only quads whose four vertices are valid),
199
+ - side walls along the boundary edges of the top surface, and
200
+ - a bottom face covering the valid region.
193
201
 
194
202
  Args:
195
203
  height_map (np.ndarray): 2D array representing the height map.
196
204
  filename (str): The name of the output STL file.
197
205
  background_height (float): The height of the background in the STL model.
198
- scale (float, optional): Scale factor for the x dimension (and optionally y). Defaults to 1.0.
206
+ maximum_x_y_size (float): Maximum size (in millimeters) for the x and y dimensions.
207
+ alpha_mask (np.ndarray): Optional alpha mask (same shape as height_map).
208
+ A pixel is “valid” only if its alpha is ≥ 128.
199
209
  """
200
210
  H, W = height_map.shape
201
211
 
202
- # Create the top vertices grid.
203
- # Note: y is computed as H-1-i. (Apply scale to y if desired.)
212
+ # Compute valid mask: True if no alpha mask or alpha >= 128.
213
+ if alpha_mask is None:
214
+ valid_mask = np.ones((H, W), dtype=bool)
215
+ else:
216
+ valid_mask = (alpha_mask >= 128)
217
+
218
+ # --- Create vertices for the top surface ---
219
+ # We compute a grid of vertices (even for masked-out regions) but later only use those that are valid.
204
220
  top_vertices = np.zeros((H, W, 3), dtype=np.float32)
205
221
  for i in range(H):
206
222
  for j in range(W):
207
- top_vertices[i, j, 0] = j * scale
208
- top_vertices[i, j, 1] = H - 1 - i # or (H - 1 - i) * scale if you want uniform scaling
223
+ top_vertices[i, j, 0] = j
224
+ # Note: y coordinate is set so that row 0 is at the top.
225
+ top_vertices[i, j, 1] = H - 1 - i
209
226
  top_vertices[i, j, 2] = height_map[i, j] + background_height
210
227
 
211
- # Create the bottom vertices for the boundary by copying the x and y coordinates,
212
- # but setting z to 0. Using these ensures that adjacent triangles share the same vertices.
228
+ # Create corresponding bottom vertices (same x,y but z = 0)
213
229
  bottom_vertices = top_vertices.copy()
214
230
  bottom_vertices[:, :, 2] = 0
215
231
 
216
- triangles = []
232
+ # --- Scale vertices so that the maximum x or y dimension equals maximum_x_y_size ---
233
+ original_max = max(W - 1, H - 1)
234
+ scale = maximum_x_y_size / original_max
235
+ top_vertices[:, :, 0] *= scale
236
+ top_vertices[:, :, 1] *= scale
237
+ bottom_vertices[:, :, 0] *= scale
238
+ bottom_vertices[:, :, 1] *= scale
239
+
240
+ triangles = [] # List to collect all triangles (each as a tuple of three vertices)
217
241
 
218
242
  def add_triangle(v1, v2, v3):
219
- """Add a triangle defined by vertices v1, v2, and v3."""
243
+ """Append a triangle (defined by 3 vertices) to the triangle list."""
220
244
  triangles.append((v1, v2, v3))
221
245
 
222
246
  # --- Top Surface ---
247
+ # For the top surface, we iterate over each cell (quad) in the grid.
248
+ # Only if all 4 corners of the quad are valid do we add two triangles.
249
+ # We also store the grid indices (i,j) of the vertices used so we can later extract the boundary edges.
250
+ top_triangles_indices = [] # Each element is a tuple of 3 (i,j) indices.
223
251
  for i in range(H - 1):
224
252
  for j in range(W - 1):
225
- v0 = top_vertices[i, j]
226
- v1 = top_vertices[i, j + 1]
227
- v2 = top_vertices[i + 1, j + 1]
228
- v3 = top_vertices[i + 1, j]
229
- # Using reversed order so that normals face upward.
230
- add_triangle(v2, v1, v0)
231
- add_triangle(v3, v2, v0)
253
+ if valid_mask[i, j] and valid_mask[i, j + 1] and valid_mask[i + 1, j + 1] and valid_mask[i + 1, j]:
254
+ # Define the four corners of the quad.
255
+ v0 = top_vertices[i, j]
256
+ v1 = top_vertices[i, j + 1]
257
+ v2 = top_vertices[i + 1, j + 1]
258
+ v3 = top_vertices[i + 1, j]
259
+ # For the top surface, use a reversed order so that the computed normal (via cross product) faces upward.
260
+ add_triangle(v2, v1, v0)
261
+ add_triangle(v3, v2, v0)
262
+ # Save the corresponding grid indices (for later boundary detection)
263
+ top_triangles_indices.append(((i, j), (i, j + 1), (i + 1, j + 1)))
264
+ top_triangles_indices.append(((i + 1, j), (i + 1, j + 1), (i, j)))
232
265
 
233
266
  # --- Side Walls ---
234
- # Top edge (i = 0)
235
- for j in range(W - 1):
236
- vt0 = top_vertices[0, j]
237
- vt1 = top_vertices[0, j + 1]
238
- vb0 = bottom_vertices[0, j]
239
- vb1 = bottom_vertices[0, j + 1]
240
- add_triangle(vt0, vt1, vb1)
241
- add_triangle(vt0, vb1, vb0)
242
-
243
- # Bottom edge (i = H - 1)
244
- for j in range(W - 1):
245
- vt0 = top_vertices[H - 1, j]
246
- vt1 = top_vertices[H - 1, j + 1]
247
- vb0 = bottom_vertices[H - 1, j]
248
- vb1 = bottom_vertices[H - 1, j + 1]
249
- add_triangle(vt1, vt0, vb0)
250
- add_triangle(vt1, vb0, vb1)
251
-
252
- # Left edge (j = 0)
253
- for i in range(H - 1):
254
- vt0 = top_vertices[i, 0]
255
- vt1 = top_vertices[i + 1, 0]
256
- vb0 = bottom_vertices[i, 0]
257
- vb1 = bottom_vertices[i + 1, 0]
258
- add_triangle(vt1, vt0, vb0)
259
- add_triangle(vt1, vb0, vb1)
260
-
261
- # Right edge (j = W - 1)
262
- for i in range(H - 1):
263
- vt0 = top_vertices[i, W - 1]
264
- vt1 = top_vertices[i + 1, W - 1]
265
- vb0 = bottom_vertices[i, W - 1]
266
- vb1 = bottom_vertices[i + 1, W - 1]
267
- add_triangle(vt0, vt1, vb1)
268
- add_triangle(vt0, vb1, vb0)
267
+ # Instead of simply using the rectangular border, we compute the boundary of the top surface.
268
+ # We count each undirected edge from the top surface triangles and select those that appear only once.
269
+ edge_count = {}
270
+
271
+ def add_edge(idx1, idx2):
272
+ # Store an undirected edge as a sorted tuple of the grid indices.
273
+ key = tuple(sorted((idx1, idx2)))
274
+ edge_count[key] = edge_count.get(key, 0) + 1
275
+
276
+ for tri in top_triangles_indices:
277
+ add_edge(tri[0], tri[1])
278
+ add_edge(tri[1], tri[2])
279
+ add_edge(tri[2], tri[0])
280
+
281
+ # A boundary edge appears only once.
282
+ boundary_edges = [edge for edge, count in edge_count.items() if count == 1]
283
+
284
+ # Helper functions to get the coordinate for a given grid index.
285
+ def get_top_vertex(idx):
286
+ i, j = idx
287
+ return top_vertices[i, j]
288
+
289
+ def get_bottom_vertex(idx):
290
+ i, j = idx
291
+ return bottom_vertices[i, j]
292
+
293
+ # For each boundary edge, create a vertical wall.
294
+ for edge in boundary_edges:
295
+ idx1, idx2 = edge
296
+ v_top1 = get_top_vertex(idx1)
297
+ v_top2 = get_top_vertex(idx2)
298
+ v_bottom1 = get_bottom_vertex(idx1)
299
+ v_bottom2 = get_bottom_vertex(idx2)
300
+ # Create a quad (two triangles) connecting the top edge to the bottom.
301
+ add_triangle(v_top1, v_top2, v_bottom2)
302
+ add_triangle(v_top1, v_bottom2, v_bottom1)
269
303
 
270
304
  # --- Bottom Face ---
271
- # Use the four corner vertices from the bottom_vertices grid.
272
- b_top_left = bottom_vertices[0, 0]
273
- b_top_right = bottom_vertices[0, W - 1]
274
- b_bottom_right = bottom_vertices[H - 1, W - 1]
275
- b_bottom_left = bottom_vertices[H - 1, 0]
276
- # Triangulate the bottom face (ensure the normal faces downward).
277
- add_triangle(b_bottom_right, b_top_right, b_top_left)
278
- add_triangle(b_bottom_left, b_bottom_right, b_top_left)
305
+ # For the bottom face, we mimic the top-surface logic but using the bottom vertices.
306
+ # The ordering is reversed (relative to the top face) so that the normals face downward.
307
+ for i in range(H - 1):
308
+ for j in range(W - 1):
309
+ if valid_mask[i, j] and valid_mask[i, j + 1] and valid_mask[i + 1, j + 1] and valid_mask[i + 1, j]:
310
+ v0 = bottom_vertices[i, j]
311
+ v1 = bottom_vertices[i, j + 1]
312
+ v2 = bottom_vertices[i + 1, j + 1]
313
+ v3 = bottom_vertices[i + 1, j]
314
+ # Order so that the normal will point downward.
315
+ add_triangle(v0, v1, v2)
316
+ add_triangle(v0, v2, v3)
279
317
 
280
318
  num_triangles = len(triangles)
281
319
 
282
- # --- Write Binary STL ---
320
+ # --- Write Binary STL File ---
283
321
  with open(filename, "wb") as f:
284
- header_str = "Binary STL generated from heightmap"
322
+ header_str = "Binary STL generated from heightmap with alpha mask"
285
323
  header = header_str.encode("utf-8")
286
324
  header = header.ljust(80, b" ")
287
325
  f.write(header)
288
326
  f.write(struct.pack("<I", num_triangles))
289
327
  for tri in triangles:
290
328
  v1, v2, v3 = tri
329
+ # Compute the normal as the normalized cross product of (v2-v1) and (v3-v1).
291
330
  normal = np.cross(v2 - v1, v3 - v1)
292
331
  norm = np.linalg.norm(normal)
293
332
  if norm == 0:
@@ -7,7 +7,7 @@ import numpy as np
7
7
  from tqdm import tqdm
8
8
 
9
9
  from autoforge.Helper.FilamentHelper import hex_to_rgb, load_materials
10
- from autoforge.Helper.ImageHelper import resize_image
10
+ from autoforge.Helper.ImageHelper import resize_image, resize_image_exact
11
11
  from autoforge.Helper.OptimizerHelper import (
12
12
  init_height_map,
13
13
  composite_image,
@@ -86,10 +86,16 @@ def main():
86
86
  help="Maximum dimension for solver (fast) image",
87
87
  )
88
88
  parser.add_argument(
89
- "--init_tau", type=float, default=1.0, help="Initial tau value for Gumbel-Softmax"
89
+ "--init_tau",
90
+ type=float,
91
+ default=1.0,
92
+ help="Initial tau value for Gumbel-Softmax",
90
93
  )
91
94
  parser.add_argument(
92
- "--final_tau", type=float, default=0.01, help="Final tau value for Gumbel-Softmax"
95
+ "--final_tau",
96
+ type=float,
97
+ default=0.01,
98
+ help="Final tau value for Gumbel-Softmax",
93
99
  )
94
100
 
95
101
  parser.add_argument(
@@ -98,6 +104,13 @@ def main():
98
104
  help="Enable visualization during optimization",
99
105
  )
100
106
 
107
+ parser.add_argument(
108
+ "--stl_output_size",
109
+ type=int,
110
+ default=200,
111
+ help="Size of the longest dimension of the output STL file",
112
+ )
113
+
101
114
  parser.add_argument(
102
115
  "--perform_pruning",
103
116
  type=bool,
@@ -171,14 +184,10 @@ def main():
171
184
  help="Use the Metal Performance Shaders (MPS) backend, if available.",
172
185
  )
173
186
  parser.add_argument(
174
- "--run-name",
175
- type=str,
176
- help="Name of the run used for TensorBoard logging"
187
+ "--run-name", type=str, help="Name of the run used for TensorBoard logging"
177
188
  )
178
189
  parser.add_argument(
179
- "--tensorboard",
180
- action="store_true",
181
- help="Enable TensorBoard logging"
190
+ "--tensorboard", action="store_true", help="Enable TensorBoard logging"
182
191
  )
183
192
 
184
193
  args = parser.parse_args()
@@ -218,7 +227,18 @@ def main():
218
227
  material_TDs = torch.tensor(material_TDs_np, dtype=torch.float32, device=device)
219
228
 
220
229
  # Read input image
221
- img = cv2.imread(args.input_image)
230
+ img = cv2.imread(args.input_image, cv2.IMREAD_UNCHANGED)
231
+
232
+ alpha = None
233
+ # check for alpha mask
234
+ if img.shape[2] == 4:
235
+ # Extract the alpha channel
236
+ alpha = img[:, :, 3]
237
+ alpha = alpha[..., None]
238
+ alpha = resize_image(alpha, args.output_size)
239
+ # Convert the image from BGRA to BGR
240
+ img = img[:, :, :3]
241
+
222
242
  img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
223
243
 
224
244
  # This smaller 'target' is the solver resolution
@@ -247,11 +267,15 @@ def main():
247
267
  output_img_np, args.max_layers, args.layer_height, random_seed=random_seed
248
268
  )
249
269
 
270
+ # if we have an alpha mask we set the height for thos pixels to -13.815512 (the lowest init sigmoid value)
271
+ if alpha is not None:
272
+ pixel_height_logits_init[alpha < 128] = -13.815512
273
+
250
274
  # But we will solve at the smaller resolution => resize that init to solver size
251
275
  # Add a dummy channel so that cv2.resize can handle it
252
276
  tmp_3d = pixel_height_logits_init[..., None] # shape (H, W, 1)
253
- phl_solver_np = resize_image(
254
- tmp_3d, args.solver_size
277
+ phl_solver_np = resize_image_exact(
278
+ tmp_3d, target_solver.shape[1], target_solver.shape[0]
255
279
  ) # shape (H', W') cause of weird opencv quirk
256
280
 
257
281
  # VGG Perceptual Loss
@@ -298,7 +322,9 @@ def main():
298
322
  optimizer.best_discrete_loss = new_loss
299
323
  print(f"New best seed found: {new_rng_seed} with loss: {new_loss}")
300
324
 
301
- optimizer.log_to_tensorboard(interval=1, namespace="post_opt", step=(post_opt_step := post_opt_step + 1))
325
+ optimizer.log_to_tensorboard(
326
+ interval=1, namespace="post_opt", step=(post_opt_step := post_opt_step + 1)
327
+ )
302
328
 
303
329
  # Optionally prune
304
330
  if args.perform_pruning:
@@ -310,14 +336,18 @@ def main():
310
336
  tau_g=optimizer.best_tau,
311
337
  )
312
338
 
313
- optimizer.log_to_tensorboard(interval=1, namespace="post_opt", step=(post_opt_step := post_opt_step + 1))
339
+ optimizer.log_to_tensorboard(
340
+ interval=1, namespace="post_opt", step=(post_opt_step := post_opt_step + 1)
341
+ )
314
342
 
315
343
  # Do a quick search for a better rng seed
316
344
  new_rng_seed, new_loss = optimizer.rng_seed_search(
317
345
  optimizer.best_discrete_loss, 500
318
346
  )
319
347
 
320
- optimizer.log_to_tensorboard(interval=1, namespace="post_opt", step=(post_opt_step := post_opt_step + 1))
348
+ optimizer.log_to_tensorboard(
349
+ interval=1, namespace="post_opt", step=(post_opt_step := post_opt_step + 1)
350
+ )
321
351
 
322
352
  if new_loss < optimizer.best_discrete_loss:
323
353
  optimizer.best_seed = new_rng_seed
@@ -371,8 +401,9 @@ def main():
371
401
  rng_seed=optimizer.best_seed,
372
402
  )
373
403
 
374
- optimizer.log_to_tensorboard(interval=1, namespace="post_opt", step=(post_opt_step := post_opt_step + 1))
375
-
404
+ optimizer.log_to_tensorboard(
405
+ interval=1, namespace="post_opt", step=(post_opt_step := post_opt_step + 1)
406
+ )
376
407
 
377
408
  comp_disc_np = comp_disc.cpu().numpy().astype(np.uint8)
378
409
  comp_disc_np = cv2.cvtColor(comp_disc_np, cv2.COLOR_RGB2BGR)
@@ -382,7 +413,13 @@ def main():
382
413
  height_map_mm = (
383
414
  disc_height_image.cpu().numpy().astype(np.float32)
384
415
  ) * args.layer_height
385
- generate_stl(height_map_mm, stl_filename, args.background_height, scale=1.0)
416
+ generate_stl(
417
+ height_map_mm,
418
+ stl_filename,
419
+ args.background_height,
420
+ maximum_x_y_size=args.stl_output_size,
421
+ alpha_mask=alpha,
422
+ )
386
423
 
387
424
  # Swap instructions
388
425
  background_layers = int(args.background_height // args.layer_height)
File without changes