CarolineM5 commited on
Commit
04fbcf3
·
verified ·
1 Parent(s): 6324410

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +17 -26
app.py CHANGED
@@ -200,46 +200,46 @@ def build_textured_cube(pil_imgs, face_rotations=None):
200
 
201
  # --- géométrie : définir quads par face (CCW en regardant la face de l'extérieur)
202
  # Convention: +X = right, +Y = front, +Z = up
203
- # Les 8 coins (pour référence)
204
  # (-x,-y,-z), ( x,-y,-z), ( x, y,-z), (-x, y,-z),
205
  # (-x,-y, z), ( x,-y, z), ( x, y, z), (-x, y, z)
206
  quads = {
207
- # top (+Z) : regarder depuis +Z (au-dessus)
208
  "front": [
209
  (-half_x, -half_y, half_z),
210
  ( half_x, -half_y, half_z),
211
  ( half_x, half_y, half_z),
212
  (-half_x, half_y, half_z),
213
  ],
214
- # right (+X) : regarder depuis +X (côté droit)
215
  "right": [
216
  ( half_x, -half_y, -half_z),
217
  ( half_x, half_y, -half_z),
218
  ( half_x, half_y, half_z),
219
  ( half_x, -half_y, half_z),
220
  ],
221
- # bottom (-Z) : regarder depuis -Z (dessous)
222
  "back": [
223
  (-half_x, half_y, -half_z),
224
  ( half_x, half_y, -half_z),
225
  ( half_x, -half_y, -half_z),
226
  (-half_x, -half_y, -half_z),
227
  ],
228
- # left (-X) : regarder depuis -X (côté gauche)
229
  "left": [
230
  (-half_x, -half_y, half_z),
231
  (-half_x, half_y, half_z),
232
  (-half_x, half_y, -half_z),
233
  (-half_x, -half_y, -half_z),
234
  ],
235
- # front (+Y) : regarder depuis +Y (face avant)
236
  "top": [
237
  (-half_x, half_y, -half_z),
238
  (-half_x, half_y, half_z),
239
  ( half_x, half_y, half_z),
240
  ( half_x, half_y, -half_z),
241
  ],
242
- # back (-Y) : regarder depuis -Y (face arrière)
243
  "bottom": [
244
  ( half_x, -half_y, -half_z),
245
  ( half_x, -half_y, half_z),
@@ -248,28 +248,24 @@ def build_textured_cube(pil_imgs, face_rotations=None):
248
  ],
249
  }
250
 
251
- # --- écrire l'OBJ (24 vertices, 24 vt, triangulé) selon face_order demandé ---
252
  face_order = ["top", "right", "bottom", "left", "front", "back"]
253
- # face_order = ["back", "left", "top", "front", "right", "bottom"]
254
  obj_path = os.path.join(tmpdir, "parallelep.obj")
255
  with open(obj_path, "w", encoding="utf-8") as f:
256
  f.write("# Parallelepiped OBJ generated by build_textured_cube\n")
257
  f.write("mtllib parallelep.mtl\n\n")
258
 
259
- # écrire vertices : 4 par face, dans l'ordre face_order
260
  for face_name in face_order:
261
  for v in quads[face_name]:
262
  f.write("v {:.6f} {:.6f} {:.6f}\n".format(*v))
263
  f.write("\n")
264
 
265
- # écrire UVs : 4 UVs par face (0..1). On garde origine UV bas-gauche.
266
  uvs = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)]
267
  for _ in range(6):
268
  for (u, v) in uvs:
269
  f.write("vt {:.6f} {:.6f}\n".format(u, v))
270
  f.write("\n")
271
 
272
- # faces (2 triangles par face), en s'assurant que les matériaux correspondent
273
  for i, face_name in enumerate(face_order):
274
  f.write(f"usemtl m_{face_name}\n")
275
  v_base = i * 4 + 1
@@ -284,7 +280,6 @@ def build_textured_cube(pil_imgs, face_rotations=None):
284
  except Exception:
285
  pass
286
 
287
- # vérifications rapides
288
  for fname in ["parallelep.obj", "parallelep.mtl"] + list(tex_names.values()):
289
  p = os.path.join(tmpdir, fname)
290
  if not os.path.exists(p):
@@ -295,15 +290,14 @@ def build_textured_cube(pil_imgs, face_rotations=None):
295
 
296
 
297
  # -------------------------
298
- # Fonction appelée par Gradio
299
- # retourne : 4 miniatures (PIL) + chemin vers le .obj (str)
300
  # -------------------------
301
  def run(fibers: Image.Image, rings: Image.Image, num_steps: int):
302
  try:
303
  outputs = inference(fibers, rings, num_steps)
304
  if not (isinstance(outputs, (list, tuple)) and len(outputs) >= 4):
305
  raise ValueError("user_inference doit renvoyer une liste/tuple de 4 images.")
306
- # Prendre les 4 premières images et convertir en PIL RGB
307
  pil_imgs = []
308
  for im in outputs[:4]:
309
  if isinstance(im, np.ndarray):
@@ -313,19 +307,15 @@ def run(fibers: Image.Image, rings: Image.Image, num_steps: int):
313
  print(im.size)
314
  pil_imgs.append(im)
315
 
316
- # miniatures affichées dans l'UI
317
  thumbs = [im.copy() for im in pil_imgs]
318
 
319
- # construire le .obj + textures
320
  obj_path, tmpdir = build_textured_cube(pil_imgs)
321
 
322
- # IMPORTANT: on renvoie le chemin absolu vers le fichier .obj
323
- # Gradio/Spaces chargera le modèle 3D depuis ce fichier et les textures
324
- # doivent être dans le même dossier que le .obj (ce qui est le cas).
325
  return (*thumbs, obj_path)
326
  except Exception as e:
327
  traceback.print_exc()
328
- # en cas d'erreur, renvoyer 4 images grises et None pour le modèle
329
  blank = Image.new("RGB", (256,256), (220,220,220))
330
  return (blank, blank, blank, blank, None)
331
 
@@ -333,6 +323,7 @@ def run(fibers: Image.Image, rings: Image.Image, num_steps: int):
333
  # Interface Gradio
334
  # -------------------------
335
  with gr.Blocks(title="Photorealistic wood generator (4 faces)") as demo:
 
336
  gr.Markdown("""Upload 2 images (four fiber maps and four ring maps) corresponding to the board faces. The model will return four generated images (one per face), produced in a single coherent pass.
337
  Set the number of inference steps. Higher values can improve quality but increase processing time.""")
338
  with gr.Row():
@@ -344,10 +335,10 @@ with gr.Blocks(title="Photorealistic wood generator (4 faces)") as demo:
344
  with gr.Column(scale=2):
345
  model3d_out = gr.Model3D(label="3D board")
346
  with gr.Row():
347
- out1 = gr.Image(width=600, height=600, label="Front")
348
- out2 = gr.Image(width=600, height=600,label="Right")
349
- out3 = gr.Image(width=600, height=600,label="Back")
350
- out4 = gr.Image(width=600, height=600,label="Left")
351
 
352
  run_btn.click(fn=run, inputs=[inp1, inp2, inp3], outputs=[out1, out2, out3, out4, model3d_out])
353
 
 
200
 
201
  # --- géométrie : définir quads par face (CCW en regardant la face de l'extérieur)
202
  # Convention: +X = right, +Y = front, +Z = up
203
+ # 8 corners:
204
  # (-x,-y,-z), ( x,-y,-z), ( x, y,-z), (-x, y,-z),
205
  # (-x,-y, z), ( x,-y, z), ( x, y, z), (-x, y, z)
206
  quads = {
207
+ # top (+Z) : look from +Z
208
  "front": [
209
  (-half_x, -half_y, half_z),
210
  ( half_x, -half_y, half_z),
211
  ( half_x, half_y, half_z),
212
  (-half_x, half_y, half_z),
213
  ],
214
+ # right (+X) : look from +X
215
  "right": [
216
  ( half_x, -half_y, -half_z),
217
  ( half_x, half_y, -half_z),
218
  ( half_x, half_y, half_z),
219
  ( half_x, -half_y, half_z),
220
  ],
221
+ # bottom (-Z) : look from -Z
222
  "back": [
223
  (-half_x, half_y, -half_z),
224
  ( half_x, half_y, -half_z),
225
  ( half_x, -half_y, -half_z),
226
  (-half_x, -half_y, -half_z),
227
  ],
228
+ # left (-X) : look from -X
229
  "left": [
230
  (-half_x, -half_y, half_z),
231
  (-half_x, half_y, half_z),
232
  (-half_x, half_y, -half_z),
233
  (-half_x, -half_y, -half_z),
234
  ],
235
+ # front (+Y) : look from +Y
236
  "top": [
237
  (-half_x, half_y, -half_z),
238
  (-half_x, half_y, half_z),
239
  ( half_x, half_y, half_z),
240
  ( half_x, half_y, -half_z),
241
  ],
242
+ # back (-Y) : look from -Y
243
  "bottom": [
244
  ( half_x, -half_y, -half_z),
245
  ( half_x, -half_y, half_z),
 
248
  ],
249
  }
250
 
251
+
252
  face_order = ["top", "right", "bottom", "left", "front", "back"]
 
253
  obj_path = os.path.join(tmpdir, "parallelep.obj")
254
  with open(obj_path, "w", encoding="utf-8") as f:
255
  f.write("# Parallelepiped OBJ generated by build_textured_cube\n")
256
  f.write("mtllib parallelep.mtl\n\n")
257
 
 
258
  for face_name in face_order:
259
  for v in quads[face_name]:
260
  f.write("v {:.6f} {:.6f} {:.6f}\n".format(*v))
261
  f.write("\n")
262
 
 
263
  uvs = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)]
264
  for _ in range(6):
265
  for (u, v) in uvs:
266
  f.write("vt {:.6f} {:.6f}\n".format(u, v))
267
  f.write("\n")
268
 
 
269
  for i, face_name in enumerate(face_order):
270
  f.write(f"usemtl m_{face_name}\n")
271
  v_base = i * 4 + 1
 
280
  except Exception:
281
  pass
282
 
 
283
  for fname in ["parallelep.obj", "parallelep.mtl"] + list(tex_names.values()):
284
  p = os.path.join(tmpdir, fname)
285
  if not os.path.exists(p):
 
290
 
291
 
292
  # -------------------------
293
+ # return : 4 img (PIL) + path to .obj (str)
 
294
  # -------------------------
295
  def run(fibers: Image.Image, rings: Image.Image, num_steps: int):
296
  try:
297
  outputs = inference(fibers, rings, num_steps)
298
  if not (isinstance(outputs, (list, tuple)) and len(outputs) >= 4):
299
  raise ValueError("user_inference doit renvoyer une liste/tuple de 4 images.")
300
+
301
  pil_imgs = []
302
  for im in outputs[:4]:
303
  if isinstance(im, np.ndarray):
 
307
  print(im.size)
308
  pil_imgs.append(im)
309
 
310
+
311
  thumbs = [im.copy() for im in pil_imgs]
312
 
313
+
314
  obj_path, tmpdir = build_textured_cube(pil_imgs)
315
 
 
 
 
316
  return (*thumbs, obj_path)
317
  except Exception as e:
318
  traceback.print_exc()
 
319
  blank = Image.new("RGB", (256,256), (220,220,220))
320
  return (blank, blank, blank, blank, None)
321
 
 
323
  # Interface Gradio
324
  # -------------------------
325
  with gr.Blocks(title="Photorealistic wood generator (4 faces)") as demo:
326
+ gr.HTML("<h1 style='text-align:center; margin-bottom:8px;'>Photorealistic wood generator (4 faces)</h1>")
327
  gr.Markdown("""Upload 2 images (four fiber maps and four ring maps) corresponding to the board faces. The model will return four generated images (one per face), produced in a single coherent pass.
328
  Set the number of inference steps. Higher values can improve quality but increase processing time.""")
329
  with gr.Row():
 
335
  with gr.Column(scale=2):
336
  model3d_out = gr.Model3D(label="3D board")
337
  with gr.Row():
338
+ out1 = gr.Image(label="Front")
339
+ out2 = gr.Image(label="Right")
340
+ out3 = gr.Image(label="Back")
341
+ out4 = gr.Image(label="Left")
342
 
343
  run_btn.click(fn=run, inputs=[inp1, inp2, inp3], outputs=[out1, out2, out3, out4, model3d_out])
344