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.
- {autoforge-1.4.0 → autoforge-1.4.2}/PKG-INFO +2 -1
- {autoforge-1.4.0 → autoforge-1.4.2}/README.md +1 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/pyproject.toml +1 -1
- {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/PKG-INFO +2 -1
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/ImageHelper.py +8 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/OutputHelper.py +103 -64
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/auto_forge.py +55 -18
- {autoforge-1.4.0 → autoforge-1.4.2}/setup.cfg +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/SOURCES.txt +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/dependency_links.txt +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/entry_points.txt +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/requires.txt +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/AutoForge.egg-info/top_level.txt +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/Views/__init__.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/Views/backend_database.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/Views/filament_editor.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/__init__.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/app.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Gui/main.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/FilamentHelper.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/OptimizerHelper.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/PruningHelper.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/__init__.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Helper/filamentcolors_library.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Loss/LossFunctions.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Loss/PerceptionLoss.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Loss/__init__.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Misc/__init__.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Misc/color_fit_all.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Modules/Optimizer.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/Modules/__init__.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/__init__.py +0 -0
- {autoforge-1.4.0 → autoforge-1.4.2}/src/autoforge/__main__.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
192
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
203
|
-
|
|
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
|
|
208
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
"""
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
#
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
add_triangle(
|
|
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
|
-
#
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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",
|
|
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",
|
|
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 =
|
|
254
|
-
tmp_3d,
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|