autoforge 1.7.1__tar.gz → 1.7.3__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.7.1 → autoforge-1.7.3}/PKG-INFO +5 -2
- {autoforge-1.7.1 → autoforge-1.7.3}/README.md +4 -1
- {autoforge-1.7.1 → autoforge-1.7.3}/pyproject.toml +1 -1
- {autoforge-1.7.1 → autoforge-1.7.3}/src/AutoForge.egg-info/PKG-INFO +5 -2
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/Heightmaps/ChristofidesHeightMap.py +2 -1
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/PruningHelper.py +6 -3
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Modules/Optimizer.py +51 -63
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/auto_forge.py +1 -1
- {autoforge-1.7.1 → autoforge-1.7.3}/setup.cfg +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/AutoForge.egg-info/SOURCES.txt +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/AutoForge.egg-info/dependency_links.txt +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/AutoForge.egg-info/entry_points.txt +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/AutoForge.egg-info/requires.txt +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/AutoForge.egg-info/top_level.txt +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Gui/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Gui/browser_gui/Views/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Gui/browser_gui/Views/backend_database.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Gui/browser_gui/Views/filament_editor.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Gui/browser_gui/app.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Gui/browser_gui/main.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/CAdamW.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/FilamentHelper.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/Heightmaps/DepthEstimateHeightMap.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/Heightmaps/OldHeightmap.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/Heightmaps/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/ImageHelper.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/OptimizerHelper.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/OutputHelper.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/filamentcolors_library.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Init_comparer/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Init_comparer/auto_forge_init_check.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Init_comparer/plot_results.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Loss/LossFunctions.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Loss/PerceptionLoss.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Loss/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Misc/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Misc/color_fit_all.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Modules/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/__init__.py +0 -0
- {autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/__main__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AutoForge
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.3
|
|
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
|
|
@@ -30,8 +30,11 @@ AutoForge is a Python tool for generating 3D printed layered models from an inpu
|
|
|
30
30
|
|
|
31
31
|
**TLDR:** It uses a picture to generate a 3D layer image that you can print with a 3d printer. Similar to [Hueforge](https://shop.thehueforge.com/), but without the manual work (and without the artistic control).
|
|
32
32
|
|
|
33
|
+
|
|
34
|
+
## You can now run Autoforge for free in your browser thanks to [Huggingface space support](https://huggingface.co/spaces/hvoss-techfak/Autoforge).
|
|
35
|
+
|
|
33
36
|
## Example
|
|
34
|
-
All examples use only the 13 BambuLab Basic filaments, currently available in Hueforge, the background color is set to black.
|
|
37
|
+
All examples use only the 13 BambuLab Basic filaments, currently available in Hueforge 0.8.9, the background color is set to black.
|
|
35
38
|
The pruning is set to a maximum of 8 color and 20 swaps, so each image uses at most 8 different colors and swaps the filament at most 20 times.
|
|
36
39
|
<div style="display: flex; justify-content: center; gap: 20px;">
|
|
37
40
|
<div style="text-align: center;">
|
|
@@ -4,8 +4,11 @@ AutoForge is a Python tool for generating 3D printed layered models from an inpu
|
|
|
4
4
|
|
|
5
5
|
**TLDR:** It uses a picture to generate a 3D layer image that you can print with a 3d printer. Similar to [Hueforge](https://shop.thehueforge.com/), but without the manual work (and without the artistic control).
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
## You can now run Autoforge for free in your browser thanks to [Huggingface space support](https://huggingface.co/spaces/hvoss-techfak/Autoforge).
|
|
9
|
+
|
|
7
10
|
## Example
|
|
8
|
-
All examples use only the 13 BambuLab Basic filaments, currently available in Hueforge, the background color is set to black.
|
|
11
|
+
All examples use only the 13 BambuLab Basic filaments, currently available in Hueforge 0.8.9, the background color is set to black.
|
|
9
12
|
The pruning is set to a maximum of 8 color and 20 swaps, so each image uses at most 8 different colors and swaps the filament at most 20 times.
|
|
10
13
|
<div style="display: flex; justify-content: center; gap: 20px;">
|
|
11
14
|
<div style="text-align: center;">
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "AutoForge"
|
|
7
|
-
version="1.7.
|
|
7
|
+
version="1.7.3"
|
|
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.4
|
|
2
2
|
Name: AutoForge
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.3
|
|
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
|
|
@@ -30,8 +30,11 @@ AutoForge is a Python tool for generating 3D printed layered models from an inpu
|
|
|
30
30
|
|
|
31
31
|
**TLDR:** It uses a picture to generate a 3D layer image that you can print with a 3d printer. Similar to [Hueforge](https://shop.thehueforge.com/), but without the manual work (and without the artistic control).
|
|
32
32
|
|
|
33
|
+
|
|
34
|
+
## You can now run Autoforge for free in your browser thanks to [Huggingface space support](https://huggingface.co/spaces/hvoss-techfak/Autoforge).
|
|
35
|
+
|
|
33
36
|
## Example
|
|
34
|
-
All examples use only the 13 BambuLab Basic filaments, currently available in Hueforge, the background color is set to black.
|
|
37
|
+
All examples use only the 13 BambuLab Basic filaments, currently available in Hueforge 0.8.9, the background color is set to black.
|
|
35
38
|
The pruning is set to a maximum of 8 color and 20 swaps, so each image uses at most 8 different colors and swaps the filament at most 20 times.
|
|
36
39
|
<div style="display: flex; justify-content: center; gap: 20px;">
|
|
37
40
|
<div style="text-align: center;">
|
{autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/Heightmaps/ChristofidesHeightMap.py
RENAMED
|
@@ -532,9 +532,10 @@ def run_init_threads(
|
|
|
532
532
|
cluster_layers=None,
|
|
533
533
|
material_colors=None,
|
|
534
534
|
):
|
|
535
|
+
background_tuple = (np.asarray(background_tuple) * 255).tolist()
|
|
535
536
|
if random_seed is None:
|
|
536
537
|
random_seed = np.random.randint(1e6)
|
|
537
|
-
lab_space =
|
|
538
|
+
lab_space = True
|
|
538
539
|
tasks = [
|
|
539
540
|
delayed(init_height_map)(
|
|
540
541
|
target,
|
|
@@ -51,6 +51,7 @@ def prune_num_colors(
|
|
|
51
51
|
*,
|
|
52
52
|
fast: bool = True, # enable incremental search
|
|
53
53
|
chunking_percent=0.05, # percentage of layers to process at once
|
|
54
|
+
allowed_loss_increase_percent=0.005, # percentage of loss increase allowed over best loss
|
|
54
55
|
) -> torch.Tensor:
|
|
55
56
|
"""Iteratively merge materials until the number of distinct colors is
|
|
56
57
|
<= max_colors_allowed or until merging would worsen the loss.
|
|
@@ -116,7 +117,7 @@ def prune_num_colors(
|
|
|
116
117
|
n_jobs=n_jobs, backend="threading", prefer="threads"
|
|
117
118
|
)(delayed(score_color)(best_dg, *pair) for pair in chunk)
|
|
118
119
|
merge_loss, merge_dg = min(cand_results, key=lambda x: x[0])
|
|
119
|
-
if merge_loss < best_loss:
|
|
120
|
+
if merge_loss < best_loss * (1 + allowed_loss_increase_percent):
|
|
120
121
|
best_dg, best_loss = merge_dg, merge_loss
|
|
121
122
|
improved = True
|
|
122
123
|
break # move on to next outer iteration
|
|
@@ -164,6 +165,7 @@ def prune_num_swaps(
|
|
|
164
165
|
*,
|
|
165
166
|
fast: bool = True, # enable incremental search
|
|
166
167
|
chunking_percent=0.05, # percentage of layers to process at once
|
|
168
|
+
allowed_loss_increase_percent=0.005, # percentage of loss increase allowed over best loss
|
|
167
169
|
) -> torch.Tensor:
|
|
168
170
|
"""Reduce the number of color boundaries until it is below or equal to
|
|
169
171
|
*max_swaps_allowed*, stopping earlier if any further merge would worsen the
|
|
@@ -231,7 +233,7 @@ def prune_num_swaps(
|
|
|
231
233
|
for band_a, band_b, direction in chunk
|
|
232
234
|
)
|
|
233
235
|
merge_loss, merge_dg = min(cand_results, key=lambda x: x[0])
|
|
234
|
-
if merge_loss < best_loss:
|
|
236
|
+
if merge_loss < best_loss * (1 + allowed_loss_increase_percent):
|
|
235
237
|
best_dg, best_loss = merge_dg, merge_loss
|
|
236
238
|
improved = True
|
|
237
239
|
break
|
|
@@ -389,6 +391,7 @@ def prune_redundant_layers(
|
|
|
389
391
|
*,
|
|
390
392
|
fast: bool = True, # NEW: enable 10 percent incremental search
|
|
391
393
|
chunking_percent=0.05, # percentage of layers to process at once
|
|
394
|
+
allowed_loss_increase_percent=0.005, # percentage of loss increase allowed over best loss
|
|
392
395
|
):
|
|
393
396
|
"""Iteratively drop layers until the loss cannot be improved.
|
|
394
397
|
|
|
@@ -466,7 +469,7 @@ def prune_redundant_layers(
|
|
|
466
469
|
cand_loss, cand_params, cand_max_layers = min(
|
|
467
470
|
cand_results, key=lambda x: x[0]
|
|
468
471
|
)
|
|
469
|
-
if cand_loss <= best_loss:
|
|
472
|
+
if cand_loss <= best_loss * (1 + allowed_loss_increase_percent):
|
|
470
473
|
removed_layers += 1
|
|
471
474
|
best_loss = cand_loss
|
|
472
475
|
current_max_layers = cand_max_layers
|
|
@@ -5,12 +5,6 @@ import matplotlib.pyplot as plt
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import torch
|
|
7
7
|
from torch.utils.tensorboard import SummaryWriter
|
|
8
|
-
from torchcam.methods import SmoothGradCAMpp
|
|
9
|
-
from torchcam.utils import overlay_mask
|
|
10
|
-
from torchvision import models
|
|
11
|
-
from torchvision.models import ResNet18_Weights
|
|
12
|
-
from torchvision.transforms._functional_tensor import resize, normalize
|
|
13
|
-
from torchvision.transforms.functional import to_pil_image
|
|
14
8
|
from tqdm import tqdm
|
|
15
9
|
|
|
16
10
|
from autoforge.Helper.CAdamW import CAdamW
|
|
@@ -119,48 +113,48 @@ class FilamentOptimizer:
|
|
|
119
113
|
lr=self.learning_rate,
|
|
120
114
|
)
|
|
121
115
|
|
|
122
|
-
# Setup the focus map component
|
|
123
|
-
# Load a state-of-the-art ResNet50 model with pretrained weights.
|
|
124
|
-
cam_model = models.resnet18(weights=ResNet18_Weights.DEFAULT).to(
|
|
125
|
-
|
|
126
|
-
)
|
|
127
|
-
cam_model.eval()
|
|
128
|
-
# Use ScoreCAM from torchcam on the 'layer4' block.
|
|
129
|
-
cam_extractor = SmoothGradCAMpp(cam_model, target_layer="layer4")
|
|
130
|
-
# Preprocess the target image for ResNet50.
|
|
131
|
-
target_preprocessed = normalize(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
)
|
|
136
|
-
focus_maps = []
|
|
137
|
-
for _ in tqdm(range(1), desc="Creating loss function attention map..."):
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
# get maximum over all maps
|
|
147
|
-
self.focus_map = torch.stack(focus_maps)
|
|
148
|
-
self.focus_map = self.focus_map.max(dim=0)[0]
|
|
149
|
-
# normalize again
|
|
150
|
-
self.focus_map = (self.focus_map - self.focus_map.min()) / (
|
|
151
|
-
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
# resize back to target size, current dim is [1,h,w]
|
|
155
|
-
self.focus_map = (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
)
|
|
116
|
+
# # Setup the focus map component
|
|
117
|
+
# # Load a state-of-the-art ResNet50 model with pretrained weights.
|
|
118
|
+
# cam_model = models.resnet18(weights=ResNet18_Weights.DEFAULT).to(
|
|
119
|
+
# self.target.device
|
|
120
|
+
# )
|
|
121
|
+
# cam_model.eval()
|
|
122
|
+
# # Use ScoreCAM from torchcam on the 'layer4' block.
|
|
123
|
+
# cam_extractor = SmoothGradCAMpp(cam_model, target_layer="layer4")
|
|
124
|
+
# # Preprocess the target image for ResNet50.
|
|
125
|
+
# target_preprocessed = normalize(
|
|
126
|
+
# resize(self.target.permute(2, 0, 1), (224, 224)) / 255.0,
|
|
127
|
+
# [0.485, 0.456, 0.406],
|
|
128
|
+
# [0.229, 0.224, 0.225],
|
|
129
|
+
# )
|
|
130
|
+
# focus_maps = []
|
|
131
|
+
# for _ in tqdm(range(1), desc="Creating loss function attention map..."):
|
|
132
|
+
# out = cam_model(target_preprocessed.unsqueeze(0))
|
|
133
|
+
# # ScoreCAM returns a dict with keys corresponding to layers.
|
|
134
|
+
# focus_map = cam_extractor(out.squeeze(0).argmax().item(), out)[0]
|
|
135
|
+
# # Normalize the focus map to [0, 1]
|
|
136
|
+
# focus_map = (focus_map - focus_map.min()) / (
|
|
137
|
+
# focus_map.max() - focus_map.min() + 1e-8
|
|
138
|
+
# )
|
|
139
|
+
# focus_maps.append(focus_map)
|
|
140
|
+
# # get maximum over all maps
|
|
141
|
+
# self.focus_map = torch.stack(focus_maps)
|
|
142
|
+
# self.focus_map = self.focus_map.max(dim=0)[0]
|
|
143
|
+
# # normalize again
|
|
144
|
+
# self.focus_map = (self.focus_map - self.focus_map.min()) / (
|
|
145
|
+
# self.focus_map.max() - self.focus_map.min() + 1e-8
|
|
146
|
+
# )
|
|
147
|
+
#
|
|
148
|
+
# # resize back to target size, current dim is [1,h,w]
|
|
149
|
+
# self.focus_map = (
|
|
150
|
+
# torch.nn.functional.interpolate(
|
|
151
|
+
# self.focus_map.unsqueeze(0),
|
|
152
|
+
# (self.H, self.W),
|
|
153
|
+
# mode="bilinear",
|
|
154
|
+
# )
|
|
155
|
+
# .squeeze(0)
|
|
156
|
+
# .squeeze(0)
|
|
157
|
+
# )
|
|
164
158
|
|
|
165
159
|
# Setup best discrete solution tracking
|
|
166
160
|
self.best_discrete_loss = float("inf")
|
|
@@ -202,17 +196,14 @@ class FilamentOptimizer:
|
|
|
202
196
|
)
|
|
203
197
|
self.ax[1, 1].set_title("Height Map Changes")
|
|
204
198
|
|
|
205
|
-
target_vis = self.target.cpu().detach().numpy()
|
|
206
|
-
focus_vis = self.focus_map.cpu().detach().numpy()
|
|
207
|
-
|
|
208
|
-
overlay = overlay_mask(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
self.focus_map_ax = self.ax[1, 2].imshow(overlay)
|
|
215
|
-
self.ax[1, 2].set_title("Image Focus Map (currently unused)")
|
|
199
|
+
# target_vis = self.target.cpu().detach().numpy()
|
|
200
|
+
# focus_vis = self.focus_map.cpu().detach().numpy()
|
|
201
|
+
#
|
|
202
|
+
# overlay = overlay_mask(
|
|
203
|
+
# to_pil_image(target_vis),
|
|
204
|
+
# to_pil_image(focus_vis, mode="F"),
|
|
205
|
+
# alpha=0.5,
|
|
206
|
+
# )
|
|
216
207
|
|
|
217
208
|
# Compute and store the initial height map for later difference computation.
|
|
218
209
|
with torch.no_grad():
|
|
@@ -286,7 +277,7 @@ class FilamentOptimizer:
|
|
|
286
277
|
material_TDs=self.material_TDs,
|
|
287
278
|
background=self.background,
|
|
288
279
|
add_penalty_loss=10.0,
|
|
289
|
-
focus_map=
|
|
280
|
+
focus_map=None,
|
|
290
281
|
focus_strength=0.0,
|
|
291
282
|
)
|
|
292
283
|
|
|
@@ -609,9 +600,6 @@ class FilamentOptimizer:
|
|
|
609
600
|
rng_seed=seed,
|
|
610
601
|
)
|
|
611
602
|
|
|
612
|
-
# 3) Compute the "discrete" loss function
|
|
613
|
-
# If you have a separate function for that, just call it.
|
|
614
|
-
# Otherwise, reuse the standard compute_loss with add_penalty_loss=False, etc.
|
|
615
603
|
current_disc_loss = compute_loss(
|
|
616
604
|
comp=comp_disc,
|
|
617
605
|
target=self.target,
|
|
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
|
{autoforge-1.7.1 → autoforge-1.7.3}/src/autoforge/Helper/Heightmaps/DepthEstimateHeightMap.py
RENAMED
|
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
|