toshas commited on
Commit
68ec468
Β·
1 Parent(s): 1d8cd33

initial commit

Browse files
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: Depth To 3d Print
3
  emoji: πŸ†
4
  colorFrom: blue
5
  colorTo: pink
 
1
  ---
2
+ title: Depth To 3D Print
3
  emoji: πŸ†
4
  colorFrom: blue
5
  colorTo: pink
app.py ADDED
@@ -0,0 +1,410 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2025 Marigold Team, ETH ZΓΌrich. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # --------------------------------------------------------------------------
15
+ # More information about Marigold:
16
+ # https://marigoldmonodepth.github.io
17
+ # https://marigoldcomputervision.github.io
18
+ # Efficient inference pipelines are now part of diffusers:
19
+ # https://huggingface.co/docs/diffusers/using-diffusers/marigold_usage
20
+ # https://huggingface.co/docs/diffusers/api/pipelines/marigold
21
+ # Examples of trained models and live demos:
22
+ # https://huggingface.co/prs-eth
23
+ # Related projects:
24
+ # https://rollingdepth.github.io/
25
+ # https://marigolddepthcompletion.github.io/
26
+ # Citation (BibTeX):
27
+ # https://github.com/prs-eth/Marigold#-citation
28
+ # If you find Marigold useful, we kindly ask you to cite our papers.
29
+ # --------------------------------------------------------------------------
30
+ import os
31
+ import tempfile
32
+
33
+ import gradio as gr
34
+ from PIL import Image
35
+
36
+ from extrude import extrude_depth_3d
37
+ from gradio_patches.examples import Examples
38
+
39
+ default_seed = 2024
40
+ default_batch_size = 4
41
+ default_bas_plane_near = 0.0
42
+ default_bas_plane_far = 1.0
43
+ default_bas_embossing = 20
44
+ default_bas_size_longest_px = 512
45
+ default_bas_size_longest_cm = 10
46
+ default_bas_filter_size = 3
47
+ default_bas_frame_thickness = 5
48
+ default_bas_frame_near = 1
49
+ default_bas_frame_far = 1
50
+
51
+
52
+ def process_bas(
53
+ path_input_depth,
54
+ path_input_rgb=None,
55
+ plane_near=default_bas_plane_near,
56
+ plane_far=default_bas_plane_far,
57
+ embossing=default_bas_embossing,
58
+ size_longest_px=default_bas_size_longest_px,
59
+ size_longest_cm=default_bas_size_longest_cm,
60
+ filter_size=default_bas_filter_size,
61
+ frame_thickness=default_bas_frame_thickness,
62
+ frame_near=default_bas_frame_near,
63
+ frame_far=default_bas_frame_far,
64
+ ):
65
+ if path_input_depth is None:
66
+ raise gr.Error(
67
+ "Missing image in the first pane: upload a file or use one from the gallery below."
68
+ )
69
+
70
+ input_depth = Image.open(path_input_depth)
71
+ if input_depth.mode not in ("I", "I;16"):
72
+ raise gr.Error(
73
+ f"Input depth must be a 16-bit PNG image of a depth map, found {input_depth.mode}"
74
+ )
75
+ depth_longest_px = max(input_depth.size)
76
+
77
+ input_rgb = None
78
+ if path_input_rgb is not None:
79
+ input_rgb = Image.open(path_input_rgb).convert("RGB")
80
+ if (
81
+ input_depth.size[0] * input_rgb.size[1]
82
+ != input_depth.size[0] * input_rgb.size[1]
83
+ ):
84
+ raise gr.Error(
85
+ f"Inputs have incompatible dimensions: {input_depth.size} and {input_rgb.size}"
86
+ )
87
+
88
+ if plane_near >= plane_far:
89
+ raise gr.Error("NEAR plane must have a value smaller than the FAR plane")
90
+
91
+ name_base, name_ext = os.path.splitext(os.path.basename(path_input_depth))
92
+ print(f"Processing bas-relief {name_base}{name_ext}")
93
+
94
+ path_output_dir = tempfile.mkdtemp()
95
+
96
+ def _process_3d(
97
+ size_longest_px,
98
+ filter_size,
99
+ vertex_colors,
100
+ scene_lights,
101
+ output_model_scale=None,
102
+ prepare_for_3d_printing=False,
103
+ zip_outputs=False,
104
+ ):
105
+ image_new_w = size_longest_px * input_depth.width // depth_longest_px
106
+ image_new_h = size_longest_px * input_depth.height // depth_longest_px
107
+ image_new_sz = (image_new_w, image_new_h)
108
+
109
+ path_depth_new = os.path.join(
110
+ path_output_dir, f"{name_base}_depth_{size_longest_px}.png"
111
+ )
112
+ (
113
+ input_depth.convert(mode="F")
114
+ .resize(image_new_sz, Image.BILINEAR)
115
+ .convert("I")
116
+ .save(path_depth_new)
117
+ )
118
+ path_rgb_new = None
119
+ if input_rgb is not None:
120
+ path_rgb_new = os.path.join(
121
+ path_output_dir, f"{name_base}_rgb_{size_longest_px}{name_ext}"
122
+ )
123
+ input_rgb.resize(image_new_sz, Image.LANCZOS).save(path_rgb_new)
124
+
125
+ path_glb, path_stl, path_obj = extrude_depth_3d(
126
+ path_depth_new,
127
+ path_rgb_new,
128
+ output_model_scale=(
129
+ size_longest_cm * 10
130
+ if output_model_scale is None
131
+ else output_model_scale
132
+ ),
133
+ filter_size=filter_size,
134
+ coef_near=plane_near,
135
+ coef_far=plane_far,
136
+ emboss=embossing / 100,
137
+ f_thic=frame_thickness / 100,
138
+ f_near=frame_near / 100,
139
+ f_back=frame_far / 100,
140
+ vertex_colors=vertex_colors,
141
+ scene_lights=scene_lights,
142
+ prepare_for_3d_printing=prepare_for_3d_printing,
143
+ zip_outputs=zip_outputs,
144
+ )
145
+
146
+ return path_glb, path_stl, path_obj
147
+
148
+ path_viewer_glb, _, _ = _process_3d(
149
+ 256, filter_size, vertex_colors=False, scene_lights=True, output_model_scale=1
150
+ )
151
+ path_files_glb, path_files_stl, path_files_obj = _process_3d(
152
+ size_longest_px,
153
+ filter_size,
154
+ vertex_colors=True,
155
+ scene_lights=False,
156
+ prepare_for_3d_printing=True,
157
+ zip_outputs=True,
158
+ )
159
+
160
+ return path_viewer_glb, [path_files_glb, path_files_stl, path_files_obj]
161
+
162
+
163
+ with gr.Blocks(
164
+ title="Depth To 3D Print",
165
+ css="""
166
+ #download {
167
+ height: 118px;
168
+ }
169
+ .viewport {
170
+ aspect-ratio: 4/3;
171
+ }
172
+ h1 {
173
+ text-align: center;
174
+ display: block;
175
+ }
176
+ h2 {
177
+ text-align: center;
178
+ display: block;
179
+ }
180
+ h3 {
181
+ text-align: center;
182
+ display: block;
183
+ }
184
+ .md_feedback li {
185
+ margin-bottom: 0px !important;
186
+ }
187
+ """,
188
+ head="""
189
+ <script async src="https://www.googletagmanager.com/gtag/js?id=G-1FWSVCGZTG"></script>
190
+ <script>
191
+ window.dataLayer = window.dataLayer || [];
192
+ function gtag() {dataLayer.push(arguments);}
193
+ gtag('js', new Date());
194
+ gtag('config', 'G-1FWSVCGZTG');
195
+ </script>
196
+ """,
197
+ ) as demo:
198
+ gr.Markdown(
199
+ """
200
+ # Depth To 3D Print
201
+ <p align="center">
202
+ <a title="Get Depth" href="https://huggingface.co/spaces/prs-eth/marigold" target="_blank" rel="noopener noreferrer" style="display: inline-block;">
203
+ <img src="https://img.shields.io/badge/πŸ€—%20Create%20Your%20-Depth%20from%20Image-blue" alt="Get Depth">
204
+ </a>
205
+ <a title="Website" href="https://marigoldmonodepth.github.io/" target="_blank" rel="noopener noreferrer"
206
+ style="display: inline-block;">
207
+ <img src="https://img.shields.io/badge/%F0%9F%A4%8D%20Project%20-Website-af2928" alt="Website Badge">
208
+ </a>
209
+ <a title="Social" href="https://twitter.com/antonobukhov1" target="_blank" rel="noopener noreferrer"
210
+ style="display: inline-block;">
211
+ <img src="https://www.obukhov.ai/img/badges/badge-social.svg" alt="social">
212
+ </a><br>
213
+ Start exploring the interactive bas-relief examples at the bottom of the page!
214
+ The models are watertight and exported in a variety of formats, which makes them 3D-printable.
215
+ </p>
216
+ """
217
+ )
218
+ with gr.Row():
219
+ with gr.Column():
220
+ bas_depth = gr.Image(
221
+ label="Depth",
222
+ type="filepath",
223
+ format="png",
224
+ image_mode=None,
225
+ sources=["upload", "clipboard"],
226
+ show_fullscreen_button=False,
227
+ )
228
+ bas_rgb = gr.Image(
229
+ label="Image (optional)",
230
+ type="filepath",
231
+ sources=["upload", "clipboard"],
232
+ show_fullscreen_button=False,
233
+ )
234
+ with gr.Row():
235
+ bas_submit_btn = gr.Button(value="Create 3D", variant="primary")
236
+ bas_reset_btn = gr.Button(value="Reset")
237
+ with gr.Accordion("3D printing demo: Main options", open=True):
238
+ bas_plane_near = gr.Slider(
239
+ label="Near plane",
240
+ minimum=0.0,
241
+ maximum=1.0,
242
+ step=0.001,
243
+ value=default_bas_plane_near,
244
+ )
245
+ bas_plane_far = gr.Slider(
246
+ label="Far plane",
247
+ minimum=0.0,
248
+ maximum=1.0,
249
+ step=0.001,
250
+ value=default_bas_plane_far,
251
+ )
252
+ bas_embossing = gr.Slider(
253
+ label="Embossing level",
254
+ minimum=0,
255
+ maximum=100,
256
+ step=1,
257
+ value=default_bas_embossing,
258
+ )
259
+ with gr.Accordion("3D printing demo: Advanced options", open=False):
260
+ bas_size_longest_px = gr.Slider(
261
+ label="Longest side (px)",
262
+ minimum=256,
263
+ maximum=1024,
264
+ step=256,
265
+ value=default_bas_size_longest_px,
266
+ )
267
+ bas_size_longest_cm = gr.Slider(
268
+ label="Longest side (cm)",
269
+ minimum=1,
270
+ maximum=100,
271
+ step=1,
272
+ value=default_bas_size_longest_cm,
273
+ )
274
+ bas_filter_size = gr.Slider(
275
+ label="Smooth radius",
276
+ minimum=1,
277
+ maximum=5,
278
+ step=2,
279
+ value=default_bas_filter_size,
280
+ )
281
+ bas_frame_thickness = gr.Slider(
282
+ label="Frame thickness",
283
+ minimum=0,
284
+ maximum=100,
285
+ step=1,
286
+ value=default_bas_frame_thickness,
287
+ )
288
+ bas_frame_near = gr.Slider(
289
+ label="Near offset",
290
+ minimum=-100,
291
+ maximum=100,
292
+ step=1,
293
+ value=default_bas_frame_near,
294
+ )
295
+ bas_frame_far = gr.Slider(
296
+ label="Far offset",
297
+ minimum=1,
298
+ maximum=10,
299
+ step=1,
300
+ value=default_bas_frame_far,
301
+ )
302
+ with gr.Column():
303
+ bas_output_viewer = gr.Model3D(
304
+ camera_position=(75.0, 90.0, 1.25),
305
+ elem_classes="viewport",
306
+ label="3D preview",
307
+ interactive=False,
308
+ )
309
+ bas_output_files = gr.Files(
310
+ label="3D models",
311
+ elem_id="download",
312
+ interactive=False,
313
+ )
314
+ Examples(
315
+ fn=process_bas,
316
+ examples=[
317
+ [
318
+ "files/einstein_depth_16bit.png", # input_depth
319
+ "files/einstein_rgb.jpg", # input_rgb
320
+ 0.0, # plane_near
321
+ 0.5, # plane_far
322
+ 50, # embossing
323
+ 512, # size_longest_px
324
+ 10, # size_longest_cm
325
+ 3, # filter_size
326
+ 5, # frame_thickness
327
+ -25, # frame_near
328
+ 1, # frame_far
329
+ ],
330
+ ],
331
+ inputs=[
332
+ bas_depth,
333
+ bas_rgb,
334
+ bas_plane_near,
335
+ bas_plane_far,
336
+ bas_embossing,
337
+ bas_size_longest_px,
338
+ bas_size_longest_cm,
339
+ bas_filter_size,
340
+ bas_frame_thickness,
341
+ bas_frame_near,
342
+ bas_frame_far,
343
+ ],
344
+ outputs=[bas_output_viewer, bas_output_files],
345
+ cache_examples=True,
346
+ directory_name="outputs",
347
+ )
348
+
349
+ bas_submit_btn.click(
350
+ fn=process_bas,
351
+ inputs=[
352
+ bas_depth,
353
+ bas_rgb,
354
+ bas_plane_near,
355
+ bas_plane_far,
356
+ bas_embossing,
357
+ bas_size_longest_px,
358
+ bas_size_longest_cm,
359
+ bas_filter_size,
360
+ bas_frame_thickness,
361
+ bas_frame_near,
362
+ bas_frame_far,
363
+ ],
364
+ outputs=[bas_output_viewer, bas_output_files],
365
+ )
366
+
367
+ bas_reset_btn.click(
368
+ fn=lambda: (
369
+ gr.Button(interactive=True),
370
+ None,
371
+ None,
372
+ None,
373
+ None,
374
+ default_bas_plane_near,
375
+ default_bas_plane_far,
376
+ default_bas_embossing,
377
+ default_bas_size_longest_px,
378
+ default_bas_size_longest_cm,
379
+ default_bas_filter_size,
380
+ default_bas_frame_thickness,
381
+ default_bas_frame_near,
382
+ default_bas_frame_far,
383
+ ),
384
+ inputs=[],
385
+ outputs=[
386
+ bas_submit_btn,
387
+ bas_depth,
388
+ bas_rgb,
389
+ bas_output_viewer,
390
+ bas_output_files,
391
+ bas_plane_near,
392
+ bas_plane_far,
393
+ bas_embossing,
394
+ bas_size_longest_px,
395
+ bas_size_longest_cm,
396
+ bas_filter_size,
397
+ bas_frame_thickness,
398
+ bas_frame_near,
399
+ bas_frame_far,
400
+ ],
401
+ )
402
+
403
+
404
+ if __name__ == "__main__":
405
+ demo.queue(
406
+ api_open=False,
407
+ ).launch(
408
+ debug=True,
409
+ server_port=7860,
410
+ )
extrude.py ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2025 Marigold Team, ETH ZΓΌrich. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # --------------------------------------------------------------------------
15
+ # More information about Marigold:
16
+ # https://marigoldmonodepth.github.io
17
+ # https://marigoldcomputervision.github.io
18
+ # Efficient inference pipelines are now part of diffusers:
19
+ # https://huggingface.co/docs/diffusers/using-diffusers/marigold_usage
20
+ # https://huggingface.co/docs/diffusers/api/pipelines/marigold
21
+ # Examples of trained models and live demos:
22
+ # https://huggingface.co/prs-eth
23
+ # Related projects:
24
+ # https://rollingdepth.github.io/
25
+ # https://marigolddepthcompletion.github.io/
26
+ # Citation (BibTeX):
27
+ # https://github.com/prs-eth/Marigold#-citation
28
+ # If you find Marigold useful, we kindly ask you to cite our papers.
29
+ # --------------------------------------------------------------------------
30
+ import math
31
+ import os
32
+ import zipfile
33
+
34
+ import numpy as np
35
+ import pygltflib
36
+ import trimesh
37
+ from PIL import Image
38
+ from scipy.ndimage import median_filter
39
+
40
+
41
+ def quaternion_multiply(q1, q2):
42
+ x1, y1, z1, w1 = q1
43
+ x2, y2, z2, w2 = q2
44
+ return [
45
+ w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2,
46
+ w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2,
47
+ w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2,
48
+ w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2,
49
+ ]
50
+
51
+
52
+ def glb_add_lights(path_input, path_output):
53
+ """
54
+ Adds directional lights in the horizontal plane to the glb file.
55
+ :param path_input: path to input glb
56
+ :param path_output: path to output glb
57
+ :return: None
58
+ """
59
+ glb = pygltflib.GLTF2().load(path_input)
60
+
61
+ N = 3 # default max num lights in Babylon.js is 4
62
+ angle_step = 2 * math.pi / N
63
+ elevation_angle = math.radians(75)
64
+
65
+ light_colors = [
66
+ [1.0, 0.0, 0.0],
67
+ [0.0, 1.0, 0.0],
68
+ [0.0, 0.0, 1.0],
69
+ ]
70
+
71
+ lights_extension = {
72
+ "lights": [
73
+ {"type": "directional", "color": light_colors[i], "intensity": 2.0}
74
+ for i in range(N)
75
+ ]
76
+ }
77
+
78
+ if "KHR_lights_punctual" not in glb.extensionsUsed:
79
+ glb.extensionsUsed.append("KHR_lights_punctual")
80
+ glb.extensions["KHR_lights_punctual"] = lights_extension
81
+
82
+ light_nodes = []
83
+ for i in range(N):
84
+ angle = i * angle_step
85
+
86
+ pos_rot = [0.0, 0.0, math.sin(angle / 2), math.cos(angle / 2)]
87
+ elev_rot = [
88
+ math.sin(elevation_angle / 2),
89
+ 0.0,
90
+ 0.0,
91
+ math.cos(elevation_angle / 2),
92
+ ]
93
+ rotation = quaternion_multiply(pos_rot, elev_rot)
94
+
95
+ node = {
96
+ "rotation": rotation,
97
+ "extensions": {"KHR_lights_punctual": {"light": i}},
98
+ }
99
+ light_nodes.append(node)
100
+
101
+ light_node_indices = list(range(len(glb.nodes), len(glb.nodes) + N))
102
+ glb.nodes.extend(light_nodes)
103
+
104
+ root_node_index = glb.scenes[glb.scene].nodes[0]
105
+ root_node = glb.nodes[root_node_index]
106
+ if hasattr(root_node, "children"):
107
+ root_node.children.extend(light_node_indices)
108
+ else:
109
+ root_node.children = light_node_indices
110
+
111
+ glb.save(path_output)
112
+
113
+
114
+ def extrude_depth_3d(
115
+ path_depth,
116
+ path_rgb=None,
117
+ path_out_base=None,
118
+ output_model_scale=100,
119
+ filter_size=3,
120
+ coef_near=0.0,
121
+ coef_far=1.0,
122
+ emboss=0.3,
123
+ f_thic=0.05,
124
+ f_near=-0.15,
125
+ f_back=0.01,
126
+ vertex_colors=True,
127
+ scene_lights=True,
128
+ prepare_for_3d_printing=False,
129
+ zip_outputs=False,
130
+ ):
131
+ f_far_inner = -emboss
132
+ f_far_outer = f_far_inner - f_back
133
+
134
+ f_near = max(f_near, f_far_inner)
135
+
136
+ depth_image = Image.open(path_depth)
137
+
138
+ w, h = depth_image.size
139
+ d_max = max(w, h)
140
+ depth_image = np.array(depth_image).astype(np.double)
141
+ depth_image = median_filter(depth_image, size=filter_size)
142
+ z_min, z_max = np.min(depth_image), np.max(depth_image)
143
+ depth_image = (depth_image.astype(np.double) - z_min) / (z_max - z_min)
144
+ depth_image[depth_image < coef_near] = coef_near
145
+ depth_image[depth_image > coef_far] = coef_far
146
+ depth_image = emboss * (depth_image - coef_near) / (coef_far - coef_near)
147
+ rgb_image = None
148
+ if path_rgb is not None:
149
+ rgb_image = np.array(
150
+ Image.open(path_rgb).convert("RGB").resize((w, h), Image.Resampling.LANCZOS)
151
+ )
152
+
153
+ w_norm = w / float(d_max - 1)
154
+ h_norm = h / float(d_max - 1)
155
+ w_half = w_norm / 2
156
+ h_half = h_norm / 2
157
+
158
+ x, y = np.meshgrid(np.arange(w), np.arange(h))
159
+ x = x / float(d_max - 1) - w_half # [-w_half, w_half]
160
+ y = -y / float(d_max - 1) + h_half # [-h_half, h_half]
161
+ z = -depth_image # -depth_emboss (far) - 0 (near)
162
+ vertices_2d = np.stack((x, y, z), axis=-1)
163
+ vertices = vertices_2d.reshape(-1, 3)
164
+ if path_rgb is not None:
165
+ colors = rgb_image[:, :, :3].reshape(-1, 3) / 255.0
166
+ else:
167
+ colors = np.array([[0.5, 0.5, 0.5]] * (w * h))
168
+
169
+ faces = []
170
+ for y in range(h - 1):
171
+ for x in range(w - 1):
172
+ idx = y * w + x
173
+ faces.append([idx, idx + w, idx + 1])
174
+ faces.append([idx + 1, idx + w, idx + 1 + w])
175
+
176
+ # OUTER frame
177
+
178
+ nv = len(vertices)
179
+ vertices = np.append(
180
+ vertices,
181
+ [
182
+ [-w_half - f_thic, -h_half - f_thic, f_near], # 00
183
+ [-w_half - f_thic, -h_half - f_thic, f_far_outer], # 01
184
+ [w_half + f_thic, -h_half - f_thic, f_near], # 02
185
+ [w_half + f_thic, -h_half - f_thic, f_far_outer], # 03
186
+ [w_half + f_thic, h_half + f_thic, f_near], # 04
187
+ [w_half + f_thic, h_half + f_thic, f_far_outer], # 05
188
+ [-w_half - f_thic, h_half + f_thic, f_near], # 06
189
+ [-w_half - f_thic, h_half + f_thic, f_far_outer], # 07
190
+ ],
191
+ axis=0,
192
+ )
193
+ faces.extend(
194
+ [
195
+ [nv + 0, nv + 1, nv + 2],
196
+ [nv + 2, nv + 1, nv + 3],
197
+ [nv + 2, nv + 3, nv + 4],
198
+ [nv + 4, nv + 3, nv + 5],
199
+ [nv + 4, nv + 5, nv + 6],
200
+ [nv + 6, nv + 5, nv + 7],
201
+ [nv + 6, nv + 7, nv + 0],
202
+ [nv + 0, nv + 7, nv + 1],
203
+ ]
204
+ )
205
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * 8, axis=0)
206
+
207
+ # INNER frame
208
+
209
+ nv = len(vertices)
210
+ vertices_left_data = vertices_2d[:, 0] # H x 3
211
+ vertices_left_frame = vertices_2d[:, 0].copy() # H x 3
212
+ vertices_left_frame[:, 2] = f_near
213
+ vertices = np.append(vertices, vertices_left_data, axis=0)
214
+ vertices = np.append(vertices, vertices_left_frame, axis=0)
215
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 * h), axis=0)
216
+ for i in range(h - 1):
217
+ nvi_d = nv + i
218
+ nvi_f = nvi_d + h
219
+ faces.append([nvi_d, nvi_f, nvi_d + 1])
220
+ faces.append([nvi_d + 1, nvi_f, nvi_f + 1])
221
+
222
+ nv = len(vertices)
223
+ vertices_right_data = vertices_2d[:, -1] # H x 3
224
+ vertices_right_frame = vertices_2d[:, -1].copy() # H x 3
225
+ vertices_right_frame[:, 2] = f_near
226
+ vertices = np.append(vertices, vertices_right_data, axis=0)
227
+ vertices = np.append(vertices, vertices_right_frame, axis=0)
228
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 * h), axis=0)
229
+ for i in range(h - 1):
230
+ nvi_d = nv + i
231
+ nvi_f = nvi_d + h
232
+ faces.append([nvi_d, nvi_d + 1, nvi_f])
233
+ faces.append([nvi_d + 1, nvi_f + 1, nvi_f])
234
+
235
+ nv = len(vertices)
236
+ vertices_top_data = vertices_2d[0, :] # H x 3
237
+ vertices_top_frame = vertices_2d[0, :].copy() # H x 3
238
+ vertices_top_frame[:, 2] = f_near
239
+ vertices = np.append(vertices, vertices_top_data, axis=0)
240
+ vertices = np.append(vertices, vertices_top_frame, axis=0)
241
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 * w), axis=0)
242
+ for i in range(w - 1):
243
+ nvi_d = nv + i
244
+ nvi_f = nvi_d + w
245
+ faces.append([nvi_d, nvi_d + 1, nvi_f])
246
+ faces.append([nvi_d + 1, nvi_f + 1, nvi_f])
247
+
248
+ nv = len(vertices)
249
+ vertices_bottom_data = vertices_2d[-1, :] # H x 3
250
+ vertices_bottom_frame = vertices_2d[-1, :].copy() # H x 3
251
+ vertices_bottom_frame[:, 2] = f_near
252
+ vertices = np.append(vertices, vertices_bottom_data, axis=0)
253
+ vertices = np.append(vertices, vertices_bottom_frame, axis=0)
254
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 * w), axis=0)
255
+ for i in range(w - 1):
256
+ nvi_d = nv + i
257
+ nvi_f = nvi_d + w
258
+ faces.append([nvi_d, nvi_f, nvi_d + 1])
259
+ faces.append([nvi_d + 1, nvi_f, nvi_f + 1])
260
+
261
+ # FRONT frame
262
+
263
+ nv = len(vertices)
264
+ vertices = np.append(
265
+ vertices,
266
+ [
267
+ [-w_half - f_thic, -h_half - f_thic, f_near],
268
+ [-w_half - f_thic, h_half + f_thic, f_near],
269
+ ],
270
+ axis=0,
271
+ )
272
+ vertices = np.append(vertices, vertices_left_frame, axis=0)
273
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 + h), axis=0)
274
+ for i in range(h - 1):
275
+ faces.append([nv, nv + 2 + i + 1, nv + 2 + i])
276
+ faces.append([nv, nv + 2, nv + 1])
277
+
278
+ nv = len(vertices)
279
+ vertices = np.append(
280
+ vertices,
281
+ [
282
+ [w_half + f_thic, h_half + f_thic, f_near],
283
+ [w_half + f_thic, -h_half - f_thic, f_near],
284
+ ],
285
+ axis=0,
286
+ )
287
+ vertices = np.append(vertices, vertices_right_frame, axis=0)
288
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 + h), axis=0)
289
+ for i in range(h - 1):
290
+ faces.append([nv, nv + 2 + i, nv + 2 + i + 1])
291
+ faces.append([nv, nv + h + 1, nv + 1])
292
+
293
+ nv = len(vertices)
294
+ vertices = np.append(
295
+ vertices,
296
+ [
297
+ [w_half + f_thic, h_half + f_thic, f_near],
298
+ [-w_half - f_thic, h_half + f_thic, f_near],
299
+ ],
300
+ axis=0,
301
+ )
302
+ vertices = np.append(vertices, vertices_top_frame, axis=0)
303
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 + w), axis=0)
304
+ for i in range(w - 1):
305
+ faces.append([nv, nv + 2 + i, nv + 2 + i + 1])
306
+ faces.append([nv, nv + 1, nv + 2])
307
+
308
+ nv = len(vertices)
309
+ vertices = np.append(
310
+ vertices,
311
+ [
312
+ [-w_half - f_thic, -h_half - f_thic, f_near],
313
+ [w_half + f_thic, -h_half - f_thic, f_near],
314
+ ],
315
+ axis=0,
316
+ )
317
+ vertices = np.append(vertices, vertices_bottom_frame, axis=0)
318
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 + w), axis=0)
319
+ for i in range(w - 1):
320
+ faces.append([nv, nv + 2 + i + 1, nv + 2 + i])
321
+ faces.append([nv, nv + 1, nv + w + 1])
322
+
323
+ # BACK frame
324
+
325
+ nv = len(vertices)
326
+ vertices = np.append(
327
+ vertices,
328
+ [
329
+ [-w_half - f_thic, -h_half - f_thic, f_far_outer], # 00
330
+ [w_half + f_thic, -h_half - f_thic, f_far_outer], # 01
331
+ [w_half + f_thic, h_half + f_thic, f_far_outer], # 02
332
+ [-w_half - f_thic, h_half + f_thic, f_far_outer], # 03
333
+ ],
334
+ axis=0,
335
+ )
336
+ faces.extend(
337
+ [
338
+ [nv + 0, nv + 2, nv + 1],
339
+ [nv + 2, nv + 0, nv + 3],
340
+ ]
341
+ )
342
+ colors = np.append(colors, [[0.5, 0.5, 0.5]] * 4, axis=0)
343
+
344
+ trimesh_kwargs = {}
345
+ if vertex_colors:
346
+ trimesh_kwargs["vertex_colors"] = colors
347
+ mesh = trimesh.Trimesh(vertices=vertices, faces=faces, **trimesh_kwargs)
348
+
349
+ mesh.merge_vertices()
350
+
351
+ current_max_dimension = max(mesh.extents)
352
+ scaling_factor = output_model_scale / current_max_dimension
353
+ mesh.apply_scale(scaling_factor)
354
+
355
+ if prepare_for_3d_printing:
356
+ rotation_mat = trimesh.transformations.rotation_matrix(
357
+ np.radians(90), [-1, 0, 0]
358
+ )
359
+ mesh.apply_transform(rotation_mat)
360
+
361
+ if path_out_base is None:
362
+ path_out_base = os.path.splitext(path_depth)[0].replace("_16bit", "")
363
+ path_out_glb = path_out_base + ".glb"
364
+ path_out_stl = path_out_base + ".stl"
365
+ path_out_obj = path_out_base + ".obj"
366
+
367
+ mesh.export(path_out_glb, file_type="glb")
368
+ if scene_lights:
369
+ glb_add_lights(path_out_glb, path_out_glb)
370
+ mesh.export(path_out_stl, file_type="stl")
371
+ mesh.export(path_out_obj, file_type="obj")
372
+
373
+ if zip_outputs:
374
+ with zipfile.ZipFile(path_out_glb + ".zip", "w", zipfile.ZIP_DEFLATED) as zipf:
375
+ arcname = os.path.basename(os.path.splitext(path_out_glb)[0]) + ".glb"
376
+ zipf.write(path_out_glb, arcname=arcname)
377
+ path_out_glb = path_out_glb + ".zip"
378
+ with zipfile.ZipFile(path_out_stl + ".zip", "w", zipfile.ZIP_DEFLATED) as zipf:
379
+ arcname = os.path.basename(os.path.splitext(path_out_stl)[0]) + ".stl"
380
+ zipf.write(path_out_stl, arcname=arcname)
381
+ path_out_stl = path_out_stl + ".zip"
382
+ with zipfile.ZipFile(path_out_obj + ".zip", "w", zipfile.ZIP_DEFLATED) as zipf:
383
+ arcname = os.path.basename(os.path.splitext(path_out_obj)[0]) + ".obj"
384
+ zipf.write(path_out_obj, arcname=arcname)
385
+ path_out_obj = path_out_obj + ".zip"
386
+
387
+ return path_out_glb, path_out_stl, path_out_obj
files/einstein_depth_16bit.png ADDED

Git LFS Details

  • SHA256: 82a94b72c369c3b4b80a5d8912e2cebc16993099ef756cca4abe955ef4c0bec3
  • Pointer size: 132 Bytes
  • Size of remote file: 1.56 MB
files/einstein_rgb.jpg ADDED

Git LFS Details

  • SHA256: d4a4543c0fffb2ca5ea3c17e23e88fcfcf66eae8b487173fbc5c25d0d614bdb6
  • Pointer size: 131 Bytes
  • Size of remote file: 367 kB
gradio_patches/examples.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ import gradio
4
+ from gradio.utils import get_cache_folder
5
+
6
+
7
+ class Examples(gradio.helpers.Examples):
8
+ def __init__(self, *args, directory_name=None, **kwargs):
9
+ super().__init__(*args, **kwargs, _initiated_directly=False)
10
+ if directory_name is not None:
11
+ self.cached_folder = get_cache_folder() / directory_name
12
+ self.cached_file = Path(self.cached_folder) / "log.csv"
13
+ self.cached_indices_file = Path(self.cached_folder) / "indices.csv"
14
+ self.create()
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio==5.13.1
2
+ pygltflib==1.16.1
3
+ trimesh==4.0.5
4
+ imageio==2.34.1
5
+ imageio-ffmpeg==0.5.0
6
+ pillow==10.3.0
7
+ scipy==1.11.4