TKOSEI commited on
Commit
2d95390
·
verified ·
1 Parent(s): 0623028
Files changed (1) hide show
  1. app.py +0 -482
app.py DELETED
@@ -1,482 +0,0 @@
1
-
2
- import cv2
3
- import torch
4
- from PIL import Image, ImageOps
5
- import numpy as np
6
- import gradio as gr
7
- import math
8
- import os
9
- import zipfile
10
- import trimesh
11
- import pygltflib
12
- from scipy.ndimage import median_filter
13
-
14
-
15
- # Depth-Anything V2 model setup (assuming the repository is cloned and weights downloaded)
16
- from depth_anything_v2.dpt import DepthAnythingV2
17
-
18
- DEVICE = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
19
-
20
- model_configs = {
21
- 'vits': {'encoder': 'vits', 'features': 64, 'out_channels': [48, 96, 192, 384]},
22
- 'vitb': {'encoder': 'vitb', 'features': 128, 'out_channels': [96, 192, 384, 768]},
23
- 'vitl': {'encoder': 'vitl', 'features': 256, 'out_channels': [256, 512, 1024, 1024]},
24
- 'vitg': {'encoder': 'vitg', 'features': 384, 'out_channels': [1536, 1536, 1536, 1536]}
25
- }
26
-
27
- encoder = 'vitl' # or 'vits', 'vitb', 'vitg'
28
-
29
- model = DepthAnythingV2(**model_configs[encoder])
30
- model.load_state_dict(torch.load(f'depth_anything_v2_{encoder}.pth', map_location='cpu'))
31
- model = model.to(DEVICE).eval()
32
-
33
- # Helper functions (from your notebook)
34
- def quaternion_multiply(q1, q2):
35
- x1, y1, z1, w1 = q1
36
- x2, y2, z2, w2 = q2
37
- return [
38
- w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2,
39
- w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2,
40
- w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2,
41
- w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2,
42
- ]
43
-
44
-
45
- def glb_add_lights(path_input, path_output):
46
- """
47
- Adds directional lights in the horizontal plane to the glb file.
48
- :param path_input: path to input glb
49
- :param path_output: path to output glb
50
- :return: None
51
- """
52
- glb = pygltflib.GLTF2().load(path_input)
53
-
54
- N = 3 # default max num lights in Babylon.js is 4
55
- angle_step = 2 * math.pi / N
56
- elevation_angle = math.radians(75)
57
-
58
- light_colors = [
59
- [1.0, 0.0, 0.0],
60
- [0.0, 1.0, 0.0],
61
- [0.0, 0.0, 1.0],
62
- ]
63
-
64
- lights_extension = {
65
- "lights": [
66
- {"type": "directional", "color": light_colors[i], "intensity": 2.0}
67
- for i in range(N)
68
- ]
69
- }
70
-
71
- if "KHR_lights_punctual" not in glb.extensionsUsed:
72
- glb.extensionsUsed.append("KHR_lights_punctual")
73
- glb.extensions["KHR_lights_punctual"] = lights_extension
74
-
75
- light_nodes = []
76
- for i in range(N):
77
- angle = i * angle_step
78
-
79
- pos_rot = [0.0, 0.0, math.sin(angle / 2), math.cos(angle / 2)]
80
- elev_rot = [
81
- math.sin(elevation_angle / 2),
82
- 0.0,
83
- 0.0,
84
- math.cos(elevation_angle / 2),
85
- ]
86
- rotation = quaternion_multiply(pos_rot, elev_rot)
87
-
88
- node = {
89
- "rotation": rotation,
90
- "extensions": {"KHR_lights_punctual": {"light": i}},
91
- }
92
- light_nodes.append(node)
93
-
94
- light_node_indices = list(range(len(glb.nodes), len(glb.nodes) + N))
95
- glb.nodes.extend(light_nodes)
96
-
97
- root_node_index = glb.scenes[glb.scene].nodes[0]
98
- root_node = glb.nodes[root_node_index]
99
- if hasattr(root_node, "children"):
100
- root_node.children.extend(light_node_indices)
101
- else:
102
- root_node.children = light_node_indices
103
-
104
- glb.save(path_output)
105
-
106
-
107
- def extrude_depth_3d(
108
- path_rgb,
109
- path_depth,
110
- path_out_base="../",
111
- alpha=1.0,
112
- invert=0,
113
- output_model_scale=100,
114
- filter_size=3,
115
- coef_near=0.0,
116
- coef_far=1.0,
117
- emboss=0.3,
118
- f_thic=0.05,
119
- f_near=-0.15,
120
- f_back=0.01,
121
- vertex_colors=True,
122
- scene_lights=True,
123
- prepare_for_3d_printing=False,
124
- zip_outputs=False,
125
- ):
126
- f_far_inner = -emboss
127
- f_far_outer = f_far_inner - f_back
128
-
129
- f_near = max(f_near, f_far_inner)
130
-
131
- depth_image = Image.open(path_depth)
132
- mono_image = Image.open(path_rgb).convert("L")
133
-
134
- if invert==1:
135
- mono_image = ImageOps.invert(mono_image)
136
-
137
- w, h = depth_image.size
138
- d_max = max(w, h)
139
- depth_image = np.array(depth_image).astype(np.double)
140
- mono_image = np.array(mono_image).astype(np.double)
141
- z_min, z_max = np.min(depth_image), np.max(depth_image)
142
- m_min, m_max = np.min(mono_image), np.max(mono_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
- z_min, z_max = np.min(depth_image), np.max(depth_image)
147
- depth_image = (depth_image - z_min) / (z_max - z_min)
148
- mono_image = median_filter(mono_image, size=5)
149
- mono_image = (mono_image.astype(np.double) - m_min) / (m_max - m_min)
150
- mono_image_new = np.where(depth_image == coef_far, 1, mono_image)
151
- m_min=np.min(mono_image_new)
152
- mono_image_new = np.where(depth_image == coef_far, 0, mono_image)
153
- m_max=np.max(mono_image_new)
154
- mono_image = np.where(depth_image == coef_far, m_min, mono_image)
155
- mono_image = (mono_image - m_min) / (m_max - m_min)
156
- depth_image = np.where(depth_image != 1.0, (1-alpha) * depth_image + alpha * mono_image, depth_image)
157
- #depth_image_new[depth_image < coef_near] = 0
158
- #depth_image_new[depth_image > coef_far] = 1
159
- #depth_image_new[depth_image_new < 0] = 0
160
- depth_image = median_filter(depth_image, size=filter_size)
161
- depth_image = emboss*(depth_image - np.min(depth_image)) / (np.max(depth_image) - np.min(depth_image))
162
- Image.fromarray((depth_image * 255).astype(np.uint8)).convert("L").save(path_out_base+".png")
163
- rgb_image = np.array(
164
- Image.open(path_rgb).convert("RGB").resize((w, h), Image.Resampling.LANCZOS)
165
- )
166
-
167
- w_norm = w / float(d_max - 1)
168
- h_norm = h / float(d_max - 1)
169
- w_half = w_norm / 2
170
- h_half = h_norm / 2
171
-
172
- x, y = np.meshgrid(np.arange(w), np.arange(h))
173
- x = x / float(d_max - 1) - w_half # [-w_half, w_half]
174
- y = -y / float(d_max - 1) + h_half # [-h_half, h_half]
175
- z = -depth_image # -depth_emboss (far) - 0 (near)
176
- vertices_2d = np.stack((x, y, z), axis=-1)
177
- vertices = vertices_2d.reshape(-1, 3)
178
- colors = rgb_image[:, :, :3].reshape(-1, 3) / 255.0
179
-
180
- faces = []
181
- for y in range(h - 1):
182
- for x in range(w - 1):
183
- idx = y * w + x
184
- faces.append([idx, idx + w, idx + 1])
185
- faces.append([idx + 1, idx + w, idx + 1 + w])
186
-
187
- # OUTER frame
188
-
189
- nv = len(vertices)
190
- vertices = np.append(
191
- vertices,
192
- [
193
- [-w_half - f_thic, -h_half - f_thic, f_near], # 00
194
- [-w_half - f_thic, -h_half - f_thic, f_far_outer], # 01
195
- [w_half + f_thic, -h_half - f_thic, f_near], # 02
196
- [w_half + f_thic, -h_half - f_thic, f_far_outer], # 03
197
- [w_half + f_thic, h_half + f_thic, f_near], # 04
198
- [w_half + f_thic, h_half + f_thic, f_far_outer], # 05
199
- [-w_half - f_thic, h_half + f_thic, f_near], # 06
200
- [-w_half - f_thic, h_half + f_thic, f_far_outer], # 07
201
- ],
202
- axis=0,
203
- )
204
- faces.extend(
205
- [
206
- [nv + 0, nv + 1, nv + 2],
207
- [nv + 2, nv + 1, nv + 3],
208
- [nv + 2, nv + 3, nv + 4],
209
- [nv + 4, nv + 3, nv + 5],
210
- [nv + 4, nv + 5, nv + 6],
211
- [nv + 6, nv + 5, nv + 7],
212
- [nv + 6, nv + 7, nv + 0],
213
- [nv + 0, nv + 7, nv + 1],
214
- ]
215
- )
216
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * 8, axis=0)
217
-
218
- # INNER frame
219
-
220
- nv = len(vertices)
221
- vertices_left_data = vertices_2d[:, 0] # H x 3
222
- vertices_left_frame = vertices_2d[:, 0].copy() # H x 3
223
- vertices_left_frame[:, 2] = f_near
224
- vertices = np.append(vertices, vertices_left_data, axis=0)
225
- vertices = np.append(vertices, vertices_left_frame, axis=0)
226
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 * h), axis=0)
227
- for i in range(h - 1):
228
- nvi_d = nv + i
229
- nvi_f = nvi_d + h
230
- faces.append([nvi_d, nvi_f, nvi_d + 1])
231
- faces.append([nvi_d + 1, nvi_f, nvi_f + 1])
232
-
233
- nv = len(vertices)
234
- vertices_right_data = vertices_2d[:, -1] # H x 3
235
- vertices_right_frame = vertices_2d[:, -1].copy() # H x 3
236
- vertices_right_frame[:, 2] = f_near
237
- vertices = np.append(vertices, vertices_right_data, axis=0)
238
- vertices = np.append(vertices, vertices_right_frame, axis=0)
239
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 * h), axis=0)
240
- for i in range(h - 1):
241
- nvi_d = nv + i
242
- nvi_f = nvi_d + h
243
- faces.append([nvi_d, nvi_d + 1, nvi_f])
244
- faces.append([nvi_d + 1, nvi_f + 1, nvi_f])
245
-
246
- nv = len(vertices)
247
- vertices_top_data = vertices_2d[0, :] # H x 3
248
- vertices_top_frame = vertices_2d[0, :].copy() # H x 3
249
- vertices_top_frame[:, 2] = f_near
250
- vertices = np.append(vertices, vertices_top_data, axis=0)
251
- vertices = np.append(vertices, vertices_top_frame, axis=0)
252
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 * w), axis=0)
253
- for i in range(w - 1):
254
- nvi_d = nv + i
255
- nvi_f = nvi_d + w
256
- faces.append([nvi_d, nvi_d + 1, nvi_f])
257
- faces.append([nvi_d + 1, nvi_f + 1, nvi_f])
258
-
259
- nv = len(vertices)
260
- vertices_bottom_data = vertices_2d[-1, :] # H x 3
261
- vertices_bottom_frame = vertices_2d[-1, :].copy() # H x 3
262
- vertices_bottom_frame[:, 2] = f_near
263
- vertices = np.append(vertices, vertices_bottom_data, axis=0)
264
- vertices = np.append(vertices, vertices_bottom_frame, axis=0)
265
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 * w), axis=0)
266
- for i in range(w - 1):
267
- nvi_d = nv + i
268
- nvi_f = nvi_d + w
269
- faces.append([nvi_d, nvi_f, nvi_d + 1])
270
- faces.append([nvi_d + 1, nvi_f, nvi_f + 1])
271
-
272
- # FRONT frame
273
-
274
- nv = len(vertices)
275
- vertices = np.append(
276
- vertices,
277
- [
278
- [-w_half - f_thic, -h_half - f_thic, f_near],
279
- [-w_half - f_thic, h_half + f_thic, f_near],
280
- ],
281
- axis=0,
282
- )
283
- vertices = np.append(vertices, vertices_left_frame, axis=0)
284
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 + h), axis=0)
285
- for i in range(h - 1):
286
- faces.append([nv, nv + 2 + i + 1, nv + 2 + i])
287
- faces.append([nv, nv + 2, nv + 1])
288
-
289
- nv = len(vertices)
290
- vertices = np.append(
291
- vertices,
292
- [
293
- [w_half + f_thic, h_half + f_thic, f_near],
294
- [w_half + f_thic, -h_half - f_thic, f_near],
295
- ],
296
- axis=0,
297
- )
298
- vertices = np.append(vertices, vertices_right_frame, axis=0)
299
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 + h), axis=0)
300
- for i in range(h - 1):
301
- faces.append([nv, nv + 2 + i, nv + 2 + i + 1])
302
- faces.append([nv, nv + h + 1, nv + 1])
303
-
304
- nv = len(vertices)
305
- vertices = np.append(
306
- vertices,
307
- [
308
- [w_half + f_thic, h_half + f_thic, f_near],
309
- [-w_half - f_thic, h_half + f_thic, f_near],
310
- ],
311
- axis=0,
312
- )
313
- vertices = np.append(vertices, vertices_top_frame, axis=0)
314
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 + w), axis=0)
315
- for i in range(w - 1):
316
- faces.append([nv, nv + 2 + i, nv + 2 + i + 1])
317
- faces.append([nv, nv + 1, nv + 2])
318
-
319
- nv = len(vertices)
320
- vertices = np.append(
321
- vertices,
322
- [
323
- [-w_half - f_thic, -h_half - f_thic, f_near],
324
- [w_half + f_thic, -h_half - f_thic, f_near],
325
- ],
326
- axis=0,
327
- )
328
- vertices = np.append(vertices, vertices_bottom_frame, axis=0)
329
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * (2 + w), axis=0)
330
- for i in range(w - 1):
331
- faces.append([nv, nv + 2 + i + 1, nv + 2 + i])
332
- faces.append([nv, nv + 1, nv + w + 1])
333
-
334
- # BACK frame
335
-
336
- nv = len(vertices)
337
- vertices = np.append(
338
- vertices,
339
- [
340
- [-w_half - f_thic, -h_half - f_thic, f_far_outer], # 00
341
- [w_half + f_thic, -h_half - f_thic, f_far_outer], # 01
342
- [w_half + f_thic, h_half + f_thic, f_far_outer], # 02
343
- [-w_half - f_thic, h_half + f_thic, f_far_outer], # 03
344
- ],
345
- axis=0,
346
- )
347
- faces.extend(
348
- [
349
- [nv + 0, nv + 2, nv + 1],
350
- [nv + 2, nv + 0, nv + 3],
351
- ]
352
- )
353
- colors = np.append(colors, [[0.5, 0.5, 0.5]] * 4, axis=0)
354
-
355
-
356
- trimesh_kwargs = {}
357
- if vertex_colors:
358
- trimesh_kwargs["vertex_colors"] = colors
359
- mesh = trimesh.Trimesh(vertices=vertices, faces=faces, **trimesh_kwargs)
360
-
361
- mesh.merge_vertices()
362
-
363
- current_max_dimension = max(mesh.extents)
364
- scaling_factor = output_model_scale / current_max_dimension
365
- mesh.apply_scale(scaling_factor)
366
-
367
- if prepare_for_3d_printing:
368
- rotation_mat = trimesh.transformations.rotation_matrix(
369
- np.radians(0), [0.5, 0, 0]
370
- )
371
- mesh.apply_transform(rotation_mat)
372
-
373
- if path_out_base is None:
374
- path_out_base = os.path.splitext(path_depth)[0].replace("_16bit", "")
375
- path_out_glb = path_out_base + ".glb"
376
- path_out_stl = path_out_base + ".stl"
377
- path_out_obj = path_out_base + ".obj"
378
-
379
- mesh.export(path_out_stl, file_type="stl")
380
- """
381
- mesh.export(path_out_glb, file_type="glb")
382
- if scene_lights:
383
- glb_add_lights(path_out_glb, path_out_glb)
384
- mesh.export(path_out_obj, file_type="obj")
385
-
386
- if zip_outputs:
387
- with zipfile.ZipFile(path_out_glb + ".zip", "w", zipfile.ZIP_DEFLATED) as zipf:
388
- arcname = os.path.basename(os.path.splitext(path_out_glb)[0]) + ".glb"
389
- zipf.write(path_out_glb, arcname=arcname)
390
- path_out_glb = path_out_glb + ".zip"
391
- with zipfile.ZipFile(path_out_stl + ".zip", "w", zipfile.ZIP_DEFLATED) as zipf:
392
- arcname = os.path.basename(os.path.splitext(path_out_stl)[0]) + ".stl"
393
- zipf.write(path_out_stl, arcname=arcname)
394
- path_out_stl = path_out_stl + ".zip"
395
- with zipfile.ZipFile(path_out_obj + ".zip", "w", zipfile.ZIP_DEFLATED) as zipf:
396
- arcname = os.path.basename(os.path.splitext(path_out_obj)[0]) + ".obj"
397
- zipf.write(path_out_obj, arcname=arcname)
398
- path_out_obj = path_out_obj + ".zip"
399
- """
400
- return path_out_glb, path_out_stl, path_out_obj
401
-
402
- def scale_to_width(img, length):
403
- if img.width < img.height:
404
- width = length
405
- height = round(img.height * length / img.width)
406
- else:
407
- width = round(img.width * length / img.height)
408
- height = length
409
- return (width,height)
410
-
411
-
412
- # Gradio Interface function
413
- def process_image_and_generate_stl(image_input, depth_near, depth_far, thickness, alpha):
414
- # Depth Estimation
415
- raw_img = cv2.imread(image_input)
416
- depth = model.infer_image(raw_img) # HxW raw depth map in numpy
417
-
418
- # Save depth map temporarily
419
- depth_output_path = "output_depth.png"
420
- cv2.imwrite(depth_output_path, depth)
421
-
422
- # Prepare images for 3D model generation
423
- img_rgb = image_input
424
- img_depth = depth_output_path
425
- inv = 0 # Assuming no inversion for now, based on previous code
426
- # Image.open(img_rgb).convert("L").save("example_1_black.png") # This line might not be necessary for the final output
427
- size = scale_to_width(Image.open(img_rgb), 512)
428
- Image.open(img_rgb).resize(size, Image.Resampling.LANCZOS).save("one.png") # Use Resampling.LANCZOS
429
- if inv == 1:
430
- Image.open(img_depth).convert(mode="F").resize(size, Image.Resampling.BILINEAR).convert("I").save("two.png") # Use Resampling.BILINEAR
431
- else:
432
- img=Image.open(img_depth).convert(mode="F").resize(size, Image.Resampling.BILINEAR).convert("I") # Use Resampling.BILINEAR
433
- img = np.array(img).astype(np.double)
434
- im_max=np.max(img)
435
- im_min=np.min(img)
436
- img=(1-(img-im_min)/(im_max-im_min))*im_max
437
- img=Image.fromarray(img)
438
- img.convert("I").save("two.png")
439
-
440
-
441
- # 3D Model Generation
442
- output_path_base = "generated_relief"
443
- glb_path, stl_path, obj_path = extrude_depth_3d(
444
- "one.png",
445
- "two.png",
446
- alpha=alpha,
447
- invert=inv,
448
- path_out_base=output_path_base,
449
- output_model_scale=100,
450
- filter_size=5, # Using 5 based on previous code
451
- coef_near=depth_near,
452
- coef_far=depth_far,
453
- emboss=thickness,
454
- f_thic=0.0, # Using 0.0 based on previous code
455
- f_near=-thickness, # Using -thickness based on previous code
456
- f_back=0.01, # Using 0.01 based on previous code
457
- vertex_colors=True,
458
- scene_lights=True,
459
- prepare_for_3d_printing=True,
460
- )
461
-
462
- return stl_path # Return the path to the generated STL file
463
-
464
-
465
- # Gradio Interface definition
466
- iface = gr.Interface(
467
- fn=process_image_and_generate_stl,
468
- inputs=[
469
- gr.Image(type="filepath", label="Upload Image"),
470
- gr.Slider(minimum=0, maximum=1.0, value=0, label="Depth Near"),
471
- gr.Slider(minimum=0, maximum=1.0, value=1.0, label="Depth Far"),
472
- gr.Slider(minimum=0.1, maximum=1.0, value=0.3, label="Thickness"),
473
- gr.Slider(minimum=0, maximum=1.0, value=0.05, label="Alpha"),
474
- ],
475
- outputs=gr.File(label="Download STL File"), # Use gr.File() for file downloads
476
- title="Image to 2.5D Relief Model Generator",
477
- description="Upload an image, set parameters, and generate a 2.5D relief model (.stl file)."
478
- )
479
-
480
- # Launch the interface (for local testing)
481
- if __name__ == "__main__":
482
- iface.launch(debug=True)