autoforge 1.3.1__tar.gz → 1.3.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.3.1 → autoforge-1.3.2}/PKG-INFO +1 -2
- {autoforge-1.3.1 → autoforge-1.3.2}/README.md +0 -1
- {autoforge-1.3.1 → autoforge-1.3.2}/pyproject.toml +1 -1
- {autoforge-1.3.1 → autoforge-1.3.2}/src/AutoForge.egg-info/PKG-INFO +1 -2
- {autoforge-1.3.1 → autoforge-1.3.2}/src/AutoForge.egg-info/SOURCES.txt +2 -1
- autoforge-1.3.2/src/autoforge/Helper/ImageHelper.py +22 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Helper/OptimizerHelper.py +45 -7
- autoforge-1.3.2/src/autoforge/Misc/color_fit_all.py +1877 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Modules/Optimizer.py +0 -6
- autoforge-1.3.2/src/autoforge/__init__.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/auto_forge.py +14 -2
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/auto_forge_gradio.py +1 -1
- autoforge-1.3.1/src/autoforge/Helper/ImageHelper.py +0 -13
- autoforge-1.3.1/src/autoforge/color_fit_bayesian.py +0 -225
- {autoforge-1.3.1 → autoforge-1.3.2}/setup.cfg +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/AutoForge.egg-info/dependency_links.txt +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/AutoForge.egg-info/entry_points.txt +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/AutoForge.egg-info/requires.txt +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/AutoForge.egg-info/top_level.txt +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Helper/FilamentHelper.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Helper/OutputHelper.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Helper/PruningHelper.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Helper/__init__.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Loss/LossFunctions.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Loss/PerceptionLoss.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/Loss/__init__.py +0 -0
- {autoforge-1.3.1/src/autoforge/Modules → autoforge-1.3.2/src/autoforge/Misc}/__init__.py +0 -0
- {autoforge-1.3.1/src/autoforge → autoforge-1.3.2/src/autoforge/Modules}/__init__.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/__main__.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.2}/src/autoforge/filamentcolors_library.py +0 -0
- {autoforge-1.3.1 → autoforge-1.3.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.3.
|
|
3
|
+
Version: 1.3.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
|
|
@@ -162,7 +162,6 @@ Although I would love to be it fully color compatible with hueforge, I don't thi
|
|
|
162
162
|
AutoForge © 2025 by Hendric Voss is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).
|
|
163
163
|
The software is provided as-is and comes with no warranty or guarantee of support.
|
|
164
164
|
|
|
165
|
-
The
|
|
166
165
|
|
|
167
166
|
## Acknowledgements
|
|
168
167
|
|
|
@@ -142,7 +142,6 @@ Although I would love to be it fully color compatible with hueforge, I don't thi
|
|
|
142
142
|
AutoForge © 2025 by Hendric Voss is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).
|
|
143
143
|
The software is provided as-is and comes with no warranty or guarantee of support.
|
|
144
144
|
|
|
145
|
-
The
|
|
146
145
|
|
|
147
146
|
## Acknowledgements
|
|
148
147
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "AutoForge"
|
|
7
|
-
version="1.3.
|
|
7
|
+
version="1.3.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.3.
|
|
3
|
+
Version: 1.3.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
|
|
@@ -162,7 +162,6 @@ Although I would love to be it fully color compatible with hueforge, I don't thi
|
|
|
162
162
|
AutoForge © 2025 by Hendric Voss is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).
|
|
163
163
|
The software is provided as-is and comes with no warranty or guarantee of support.
|
|
164
164
|
|
|
165
|
-
The
|
|
166
165
|
|
|
167
166
|
## Acknowledgements
|
|
168
167
|
|
|
@@ -10,7 +10,6 @@ src/autoforge/__init__.py
|
|
|
10
10
|
src/autoforge/__main__.py
|
|
11
11
|
src/autoforge/auto_forge.py
|
|
12
12
|
src/autoforge/auto_forge_gradio.py
|
|
13
|
-
src/autoforge/color_fit_bayesian.py
|
|
14
13
|
src/autoforge/filamentcolors_library.py
|
|
15
14
|
src/autoforge/old_jax_files.py
|
|
16
15
|
src/autoforge/Helper/FilamentHelper.py
|
|
@@ -22,5 +21,7 @@ src/autoforge/Helper/__init__.py
|
|
|
22
21
|
src/autoforge/Loss/LossFunctions.py
|
|
23
22
|
src/autoforge/Loss/PerceptionLoss.py
|
|
24
23
|
src/autoforge/Loss/__init__.py
|
|
24
|
+
src/autoforge/Misc/__init__.py
|
|
25
|
+
src/autoforge/Misc/color_fit_all.py
|
|
25
26
|
src/autoforge/Modules/Optimizer.py
|
|
26
27
|
src/autoforge/Modules/__init__.py
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def resize_image(img, max_size):
|
|
5
|
+
h_img, w_img, _ = img.shape
|
|
6
|
+
|
|
7
|
+
# Compute the scaling factor based on the larger dimension
|
|
8
|
+
if w_img >= h_img:
|
|
9
|
+
scale = max_size / w_img
|
|
10
|
+
else:
|
|
11
|
+
scale = max_size / h_img
|
|
12
|
+
|
|
13
|
+
# Compute new dimensions and round them
|
|
14
|
+
new_w = int(round(w_img * scale))
|
|
15
|
+
new_h = int(round(h_img * scale))
|
|
16
|
+
|
|
17
|
+
# Resize the image with an appropriate interpolation method
|
|
18
|
+
img_out = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_CUBIC)
|
|
19
|
+
# INTER_CUBIC is actually not a good choice for shrinking images. Except in our case.
|
|
20
|
+
# 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.
|
|
21
|
+
# INTER_AREA actually destroys a lot of the colors of our solver.
|
|
22
|
+
return img_out
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import random
|
|
2
|
+
from itertools import permutations
|
|
2
3
|
|
|
3
4
|
import numpy as np
|
|
4
5
|
import torch
|
|
@@ -7,6 +8,7 @@ from skimage.color import rgb2lab
|
|
|
7
8
|
from sklearn.cluster import KMeans
|
|
8
9
|
from sklearn.exceptions import ConvergenceWarning
|
|
9
10
|
from sklearn.utils._testing import ignore_warnings
|
|
11
|
+
from tqdm import tqdm
|
|
10
12
|
from transformers import pipeline
|
|
11
13
|
from PIL import Image
|
|
12
14
|
from sklearn.metrics import silhouette_score
|
|
@@ -110,9 +112,10 @@ def composite_image(
|
|
|
110
112
|
comp = torch.zeros(H, W, 3, dtype=torch.float32, device=pixel_height.device)
|
|
111
113
|
remaining = torch.ones(H, W, dtype=torch.float32, device=pixel_height.device)
|
|
112
114
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
o = -1.1021105e-02
|
|
116
|
+
A = 1.0786635e00
|
|
117
|
+
k = 3.0878708e01
|
|
118
|
+
b = -5.0812101e00
|
|
116
119
|
|
|
117
120
|
for i in range(max_layers):
|
|
118
121
|
layer_idx = max_layers - 1 - i
|
|
@@ -146,8 +149,11 @@ def composite_image(
|
|
|
146
149
|
color_i = torch.matmul(p_i, material_colors)
|
|
147
150
|
TD_i = torch.matmul(p_i, material_TDs) * 0.1
|
|
148
151
|
TD_i = torch.clamp(TD_i, 1e-8, 1e8)
|
|
149
|
-
|
|
152
|
+
|
|
153
|
+
opac = o + (A * torch.log1p(k * (eff_thick / TD_i)) + b * (eff_thick / TD_i))
|
|
150
154
|
opac = torch.clamp(opac, 0.0, 1.0)
|
|
155
|
+
# Setting opac to 1.0 for the layers where the thickness is less than 2*h to avoid single layer artifacts
|
|
156
|
+
opac = torch.where(TD_i <= h * 2, torch.tensor(1.0), opac)
|
|
151
157
|
|
|
152
158
|
comp = comp + ((remaining * opac).unsqueeze(-1) * color_i)
|
|
153
159
|
remaining = remaining * (1 - opac)
|
|
@@ -610,7 +616,7 @@ def init_height_map(target, max_layers, h, eps=1e-6, random_seed=None):
|
|
|
610
616
|
|
|
611
617
|
# --- Step 2: Second clustering of centroids into bands ---
|
|
612
618
|
num_bands = choose_optimal_num_bands(
|
|
613
|
-
centroids, min_bands=5, max_bands=
|
|
619
|
+
centroids, min_bands=5, max_bands=10, random_seed=random_seed
|
|
614
620
|
)
|
|
615
621
|
band_kmeans = KMeans(n_clusters=num_bands, random_state=random_seed).fit(centroids)
|
|
616
622
|
band_labels = band_kmeans.labels_
|
|
@@ -643,7 +649,39 @@ def init_height_map(target, max_layers, h, eps=1e-6, random_seed=None):
|
|
|
643
649
|
L_values = [lab[0] for lab in band_reps]
|
|
644
650
|
start_band = np.argmin(L_values) # darkest band index
|
|
645
651
|
end_band = np.argmax(L_values) # brightest band index
|
|
646
|
-
|
|
652
|
+
|
|
653
|
+
# --- Step 5: Find the best ordering for the middle bands ---
|
|
654
|
+
# We want to order the bands so that the total perceptual difference (Euclidean distance in Lab)
|
|
655
|
+
# between consecutive bands is minimized, while forcing the darkest band first and brightest band last.
|
|
656
|
+
all_indices = list(range(len(bands)))
|
|
657
|
+
middle_indices = [i for i in all_indices if i not in (start_band, end_band)]
|
|
658
|
+
|
|
659
|
+
min_total_distance = np.inf
|
|
660
|
+
best_order = None
|
|
661
|
+
total = len(middle_indices) * len(middle_indices)
|
|
662
|
+
# Try all permutations of the middle bands
|
|
663
|
+
ie = 0
|
|
664
|
+
tbar = tqdm(
|
|
665
|
+
permutations(middle_indices),
|
|
666
|
+
total=total,
|
|
667
|
+
desc="Finding best ordering for color bands:",
|
|
668
|
+
)
|
|
669
|
+
for perm in tbar:
|
|
670
|
+
candidate = [start_band] + list(perm) + [end_band]
|
|
671
|
+
total_distance = 0
|
|
672
|
+
for i in range(len(candidate) - 1):
|
|
673
|
+
total_distance += np.linalg.norm(
|
|
674
|
+
band_reps[candidate[i]] - band_reps[candidate[i + 1]]
|
|
675
|
+
)
|
|
676
|
+
if total_distance < min_total_distance:
|
|
677
|
+
min_total_distance = total_distance
|
|
678
|
+
best_order = candidate
|
|
679
|
+
tbar.set_description(
|
|
680
|
+
f"Finding best ordering for color bands: Total distance = {min_total_distance:.2f}"
|
|
681
|
+
)
|
|
682
|
+
ie += 1
|
|
683
|
+
if ie > 500000:
|
|
684
|
+
break
|
|
647
685
|
|
|
648
686
|
new_order = []
|
|
649
687
|
for band_idx in best_order:
|
|
@@ -656,7 +694,7 @@ def init_height_map(target, max_layers, h, eps=1e-6, random_seed=None):
|
|
|
656
694
|
|
|
657
695
|
new_labels = new_labels.astype(np.float32) / new_labels.max()
|
|
658
696
|
|
|
659
|
-
normalized_lum = np.array(new_labels, dtype=np.
|
|
697
|
+
normalized_lum = np.array(new_labels, dtype=np.float32)
|
|
660
698
|
# convert out to inverse sigmoid logit function
|
|
661
699
|
pixel_height_logits = np.log((normalized_lum + eps) / (1 - normalized_lum + eps))
|
|
662
700
|
|