autoforge 1.5.3__tar.gz → 1.5.4__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.5.3 → autoforge-1.5.4}/PKG-INFO +3 -2
- {autoforge-1.5.3 → autoforge-1.5.4}/README.md +1 -1
- {autoforge-1.5.3 → autoforge-1.5.4}/pyproject.toml +3 -2
- {autoforge-1.5.3 → autoforge-1.5.4}/src/AutoForge.egg-info/PKG-INFO +3 -2
- {autoforge-1.5.3 → autoforge-1.5.4}/src/AutoForge.egg-info/requires.txt +1 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/Heightmaps/ChristofidesHeightMap.py +47 -45
- autoforge-1.5.4/src/autoforge/Helper/OptimizerHelper.py +475 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Modules/Optimizer.py +1 -1
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/auto_forge.py +8 -4
- autoforge-1.5.3/src/autoforge/Helper/OptimizerHelper.py +0 -985
- {autoforge-1.5.3 → autoforge-1.5.4}/setup.cfg +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/AutoForge.egg-info/SOURCES.txt +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/AutoForge.egg-info/dependency_links.txt +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/AutoForge.egg-info/entry_points.txt +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/AutoForge.egg-info/top_level.txt +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Gui/Views/__init__.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Gui/Views/backend_database.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Gui/Views/filament_editor.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Gui/__init__.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Gui/app.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Gui/main.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/CAdamW.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/FilamentHelper.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/Heightmaps/DepthEstimateHeightMap.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/Heightmaps/OldHeightmap.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/Heightmaps/__init__.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/ImageHelper.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/OutputHelper.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/PruningHelper.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/__init__.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/filamentcolors_library.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Loss/LossFunctions.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Loss/PerceptionLoss.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Loss/__init__.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Misc/__init__.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Misc/color_fit_all.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Modules/__init__.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/__init__.py +0 -0
- {autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/__main__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: AutoForge
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.4
|
|
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
|
|
@@ -18,6 +18,7 @@ Requires-Dist: pandas>=1.1.0
|
|
|
18
18
|
Requires-Dist: scikit-image
|
|
19
19
|
Requires-Dist: scikit-learn
|
|
20
20
|
Requires-Dist: tensorboard
|
|
21
|
+
Requires-Dist: pillow>=11.1.0
|
|
21
22
|
|
|
22
23
|
# AutoForge
|
|
23
24
|
|
|
@@ -104,7 +105,7 @@ autoforge --input_image path/to/input_image.jpg --csv_file path/to/materials.csv
|
|
|
104
105
|
- `--background_color`: Background color in hexadecimal format (default: `#000000` aka Black). \
|
|
105
106
|
**Note:** The solver currently assumes that you have a solid color in the background, which means a color with a TD value of 4 or less (if you have a background height of 0.4)
|
|
106
107
|
- `--output_size`: Maximum dimension for target image (default: 1024).
|
|
107
|
-
- `--solver_size`: Maximum dimension for solver (fast) image (default:
|
|
108
|
+
- `--solver_size`: Maximum dimension for solver (fast) image (default: 256). \
|
|
108
109
|
**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.
|
|
109
110
|
- `--init_tau`: Initial tau value for Gumbel-Softmax (default: 1.0).
|
|
110
111
|
- `--final_tau`: Final tau value for the Gumbel-Softmax formulation (default: 0.01).
|
|
@@ -83,7 +83,7 @@ autoforge --input_image path/to/input_image.jpg --csv_file path/to/materials.csv
|
|
|
83
83
|
- `--background_color`: Background color in hexadecimal format (default: `#000000` aka Black). \
|
|
84
84
|
**Note:** The solver currently assumes that you have a solid color in the background, which means a color with a TD value of 4 or less (if you have a background height of 0.4)
|
|
85
85
|
- `--output_size`: Maximum dimension for target image (default: 1024).
|
|
86
|
-
- `--solver_size`: Maximum dimension for solver (fast) image (default:
|
|
86
|
+
- `--solver_size`: Maximum dimension for solver (fast) image (default: 256). \
|
|
87
87
|
**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.
|
|
88
88
|
- `--init_tau`: Initial tau value for Gumbel-Softmax (default: 1.0).
|
|
89
89
|
- `--final_tau`: Final tau value for the Gumbel-Softmax formulation (default: 0.01).
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "AutoForge"
|
|
7
|
-
version="1.5.
|
|
7
|
+
version="1.5.4"
|
|
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"
|
|
@@ -22,7 +22,8 @@ dependencies = [
|
|
|
22
22
|
"pandas>=1.1.0",
|
|
23
23
|
"scikit-image",
|
|
24
24
|
"scikit-learn",
|
|
25
|
-
"tensorboard"
|
|
25
|
+
"tensorboard",
|
|
26
|
+
"pillow>=11.1.0"
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
[tool.setuptools]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: AutoForge
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.4
|
|
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
|
|
@@ -18,6 +18,7 @@ Requires-Dist: pandas>=1.1.0
|
|
|
18
18
|
Requires-Dist: scikit-image
|
|
19
19
|
Requires-Dist: scikit-learn
|
|
20
20
|
Requires-Dist: tensorboard
|
|
21
|
+
Requires-Dist: pillow>=11.1.0
|
|
21
22
|
|
|
22
23
|
# AutoForge
|
|
23
24
|
|
|
@@ -104,7 +105,7 @@ autoforge --input_image path/to/input_image.jpg --csv_file path/to/materials.csv
|
|
|
104
105
|
- `--background_color`: Background color in hexadecimal format (default: `#000000` aka Black). \
|
|
105
106
|
**Note:** The solver currently assumes that you have a solid color in the background, which means a color with a TD value of 4 or less (if you have a background height of 0.4)
|
|
106
107
|
- `--output_size`: Maximum dimension for target image (default: 1024).
|
|
107
|
-
- `--solver_size`: Maximum dimension for solver (fast) image (default:
|
|
108
|
+
- `--solver_size`: Maximum dimension for solver (fast) image (default: 256). \
|
|
108
109
|
**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.
|
|
109
110
|
- `--init_tau`: Initial tau value for Gumbel-Softmax (default: 1.0).
|
|
110
111
|
- `--final_tau`: Final tau value for the Gumbel-Softmax formulation (default: 0.01).
|
{autoforge-1.5.3 → autoforge-1.5.4}/src/autoforge/Helper/Heightmaps/ChristofidesHeightMap.py
RENAMED
|
@@ -3,9 +3,9 @@ import random
|
|
|
3
3
|
from concurrent.futures import ThreadPoolExecutor
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
|
+
from PIL import Image
|
|
6
7
|
from scipy.spatial.distance import cdist
|
|
7
8
|
from skimage.color import rgb2lab
|
|
8
|
-
from sklearn.cluster import MiniBatchKMeans
|
|
9
9
|
from tqdm import tqdm
|
|
10
10
|
|
|
11
11
|
|
|
@@ -244,7 +244,6 @@ def tsp_order_christofides_path(nodes, labs, bg, fg):
|
|
|
244
244
|
Returns an ordering (list of cluster indices) that contains all nodes,
|
|
245
245
|
starts with bg and ends with fg.
|
|
246
246
|
"""
|
|
247
|
-
# Use an artificial node to force a Hamiltonian path.
|
|
248
247
|
artificial = -1
|
|
249
248
|
augmented_nodes = nodes + [artificial]
|
|
250
249
|
LARGE = 1e6
|
|
@@ -255,9 +254,8 @@ def tsp_order_christofides_path(nodes, labs, bg, fg):
|
|
|
255
254
|
|
|
256
255
|
# Build an augmented matrix of size (n+1)x(n+1).
|
|
257
256
|
aug_mat = np.zeros((n + 1, n + 1))
|
|
258
|
-
# Fill the top-left block with D.
|
|
259
257
|
aug_mat[:n, :n] = D
|
|
260
|
-
# For the artificial node
|
|
258
|
+
# For the artificial node, set cost = 0 for bg/fg, LARGE otherwise.
|
|
261
259
|
for i, u in enumerate(nodes):
|
|
262
260
|
if u in {bg, fg}:
|
|
263
261
|
aug_mat[i, n] = 0.0
|
|
@@ -265,7 +263,6 @@ def tsp_order_christofides_path(nodes, labs, bg, fg):
|
|
|
265
263
|
else:
|
|
266
264
|
aug_mat[i, n] = LARGE
|
|
267
265
|
aug_mat[n, i] = LARGE
|
|
268
|
-
# Set artificial-to-artificial cost to 0.
|
|
269
266
|
aug_mat[n, n] = 0.0
|
|
270
267
|
|
|
271
268
|
# Convert the augmented matrix into a graph dictionary.
|
|
@@ -291,6 +288,15 @@ def tsp_order_christofides_path(nodes, labs, bg, fg):
|
|
|
291
288
|
cycle.remove(fg)
|
|
292
289
|
cycle.append(fg)
|
|
293
290
|
|
|
291
|
+
# --- NEW: Check if reversing the internal order yields a lower ordering metric ---
|
|
292
|
+
if len(cycle) > 2:
|
|
293
|
+
# Reverse the ordering of the nodes between bg and fg.
|
|
294
|
+
reversed_cycle = [cycle[0]] + cycle[1:-1][::-1] + [cycle[-1]]
|
|
295
|
+
if compute_ordering_metric(reversed_cycle, labs) < compute_ordering_metric(
|
|
296
|
+
cycle, labs
|
|
297
|
+
):
|
|
298
|
+
cycle = reversed_cycle
|
|
299
|
+
|
|
294
300
|
return cycle
|
|
295
301
|
|
|
296
302
|
|
|
@@ -338,55 +344,55 @@ def init_height_map(
|
|
|
338
344
|
random.seed(random_seed)
|
|
339
345
|
|
|
340
346
|
H, W, _ = target.shape
|
|
341
|
-
target_np = np.asarray(target).reshape(H, W, 3).astype(np.float32) / 255.0
|
|
342
|
-
|
|
343
|
-
# Convert the image to Lab space and apply weights.
|
|
344
|
-
target_lab = rgb2lab(target_np)
|
|
345
|
-
# Apply weights: scale L channel by lab_weights[0], a by lab_weights[1], b by lab_weights[2]
|
|
346
|
-
target_lab[..., 0] *= lab_weights[0]
|
|
347
|
-
target_lab[..., 1] *= lab_weights[1]
|
|
348
|
-
target_lab[..., 2] *= lab_weights[2]
|
|
349
347
|
|
|
350
|
-
#
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
#
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
348
|
+
# Convert target (assumed in [0,255]) to a PIL Image.
|
|
349
|
+
pil_im = Image.fromarray(target.astype(np.uint8))
|
|
350
|
+
# Quantize image into max_layers colors.
|
|
351
|
+
quantized_im = pil_im.quantize(colors=max_layers)
|
|
352
|
+
# Retrieve per-pixel labels (indices into the palette).
|
|
353
|
+
labels = np.array(quantized_im)
|
|
354
|
+
|
|
355
|
+
# Get the full palette and reshape it into (-1, 3)
|
|
356
|
+
full_palette = quantized_im.getpalette()
|
|
357
|
+
palette_arr = np.array(full_palette, dtype=np.uint8).reshape(-1, 3)
|
|
358
|
+
|
|
359
|
+
# Get only the palette indices actually used in the quantized image.
|
|
360
|
+
unique_palette_indices = sorted(np.unique(labels))
|
|
361
|
+
# Create the labs array from the used palette colors.
|
|
362
|
+
labs_rgb = palette_arr[unique_palette_indices].astype(np.float32)
|
|
363
|
+
|
|
364
|
+
# Convert RGB values (0-255) to Lab space.
|
|
365
|
+
labs = rgb2lab(labs_rgb / 255.0)
|
|
366
|
+
# Apply the weighting to each Lab channel.
|
|
367
|
+
labs[:, 0] *= lab_weights[0]
|
|
368
|
+
labs[:, 1] *= lab_weights[1]
|
|
369
|
+
labs[:, 2] *= lab_weights[2]
|
|
370
|
+
|
|
371
|
+
# Remap the labels in the image to a compact index range.
|
|
372
|
+
palette_map = {old: new for new, old in enumerate(unique_palette_indices)}
|
|
373
|
+
labels = np.vectorize(lambda x: palette_map[x])(labels)
|
|
374
|
+
|
|
375
|
+
# Convert the background color to Lab (with same weighting).
|
|
365
376
|
bg_rgb = np.array(background_tuple).astype(np.float32) / 255.0
|
|
366
377
|
bg_lab = rgb2lab(np.array([[bg_rgb]]))[0, 0, :]
|
|
367
378
|
bg_lab[0] *= lab_weights[0]
|
|
368
379
|
bg_lab[1] *= lab_weights[1]
|
|
369
380
|
bg_lab[2] *= lab_weights[2]
|
|
370
381
|
|
|
371
|
-
# Identify the
|
|
382
|
+
# Identify the best background and foreground clusters.
|
|
372
383
|
distances = np.linalg.norm(labs - bg_lab, axis=1)
|
|
373
384
|
bg_cluster = int(np.argmin(distances))
|
|
374
385
|
fg_cluster = int(np.argmax(distances))
|
|
375
386
|
|
|
376
|
-
#
|
|
377
|
-
unique_clusters =
|
|
387
|
+
# Use all the new compact cluster indices.
|
|
388
|
+
unique_clusters = list(range(len(unique_palette_indices)))
|
|
378
389
|
nodes = unique_clusters
|
|
379
390
|
|
|
380
|
-
# Get the ordering
|
|
391
|
+
# Get the ordering via TSP ordering function.
|
|
381
392
|
final_ordering = tsp_order_christofides_path(nodes, labs, bg_cluster, fg_cluster)
|
|
382
|
-
# Optionally
|
|
393
|
+
# Optionally prune out outliers.
|
|
383
394
|
final_ordering = prune_ordering(
|
|
384
|
-
final_ordering,
|
|
385
|
-
labs,
|
|
386
|
-
bg_cluster,
|
|
387
|
-
fg_cluster,
|
|
388
|
-
min_length=3,
|
|
389
|
-
improvement_factor=3,
|
|
395
|
+
final_ordering, labs, bg_cluster, fg_cluster, min_length=3, improvement_factor=3
|
|
390
396
|
)
|
|
391
397
|
|
|
392
398
|
# Create a mapping that covers all clusters.
|
|
@@ -395,11 +401,6 @@ def init_height_map(
|
|
|
395
401
|
pixel_height_logits = np.log((new_labels + eps) / (1 - new_labels + eps))
|
|
396
402
|
|
|
397
403
|
ordering_metric = compute_ordering_metric(final_ordering, labs)
|
|
398
|
-
# print(
|
|
399
|
-
# "Ordering metric (total weighted Lab-space distance):",
|
|
400
|
-
# ordering_metric / max_layers,
|
|
401
|
-
# )
|
|
402
|
-
|
|
403
404
|
return pixel_height_logits, ordering_metric
|
|
404
405
|
|
|
405
406
|
|
|
@@ -410,7 +411,7 @@ def run_init_threads(
|
|
|
410
411
|
background_tuple,
|
|
411
412
|
eps=1e-6,
|
|
412
413
|
random_seed=None,
|
|
413
|
-
num_threads=
|
|
414
|
+
num_threads=64,
|
|
414
415
|
):
|
|
415
416
|
"""
|
|
416
417
|
Initializes pixel height logits using multiple threads.
|
|
@@ -447,6 +448,7 @@ def run_init_threads(
|
|
|
447
448
|
total=num_threads,
|
|
448
449
|
)
|
|
449
450
|
]
|
|
451
|
+
# print(f"metric values: {[r[1] for r in results]}")
|
|
450
452
|
# get lowest ordering metric
|
|
451
453
|
best_result = min(results, key=lambda x: x[1])
|
|
452
454
|
|