CarolineM5 commited on
Commit
377bc40
·
verified ·
1 Parent(s): 032b23e

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +138 -124
app.py CHANGED
@@ -83,141 +83,155 @@ class UNetNoCondWrapper(nn.Module):
83
  # b = base64.b64encode(buf.getvalue()).decode("utf-8")
84
  # return f"data:image/png;base64,{b}"
85
 
86
- def user_inference(img1, img2):
87
- try:
88
- # si numpy array -> PIL
89
- if isinstance(img1, np.ndarray):
90
- img1 = Image.fromarray(img1)
91
- if isinstance(img2, np.ndarray):
92
- img2 = Image.fromarray(img2)
93
- # 4 outputs tests
94
- o1 = img1.copy().resize((512,512))
95
- o2 = img2.copy().resize((512,512))
96
- o3 = img1.transpose(Image.FLIP_LEFT_RIGHT).resize((512,512))
97
- o4 = img2.rotate(90, expand=True).resize((512,512))
98
- return [o1, o2, o3, o4]
99
- except Exception:
100
- blank = Image.new("RGB", (512,512), (200,200,200))
101
- return [blank, blank, blank, blank]
102
 
103
- def build_textured_cube(textures, out_dir=None):
104
  """
105
- Écrit les fichiers dans ./models/<uuid>/ pour être visibles dans le Space.
106
- textures: list de 4 PIL.Image (RGB) -> mapping:
107
- textures[0] -> right
108
- textures[1] -> left
109
- textures[2] -> front
110
- textures[3] -> back
111
- Retourne: (chemin_absolu_obj, out_dir)
 
112
  """
113
- import os, uuid
114
- from pathlib import Path
115
  import tempfile
116
-
117
- # dossier racine "models" dans le repo (sera visible dans Files)
118
- repo_models_dir = os.path.join(os.path.dirname(__file__), "models")
119
- os.makedirs(repo_models_dir, exist_ok=True)
120
-
121
- # crée un sous-dossier unique
122
- if out_dir is None:
123
- out_dir = os.path.join(repo_models_dir, f"cube_{uuid.uuid4().hex}")
124
- os.makedirs(out_dir, exist_ok=True)
125
-
126
- # vérifications
127
- if len(textures) < 4:
128
- raise ValueError("Il faut fournir 4 images dans `textures`.")
129
-
130
- # normaliser taille (utilise la taille de la première texture)
131
- base_w, base_h = textures[0].size
132
- norm_texts = []
133
- for im in textures[:4]:
134
- if im.size != (base_w, base_h):
135
- im = im.resize((base_w, base_h))
136
- norm_texts.append(im.convert("RGB"))
137
-
138
- # top & bottom : textures noires
139
  from PIL import Image
140
- black_top = Image.new("RGB", (base_w, base_h), (0,0,0))
141
- black_bottom = Image.new("RGB", (base_w, base_h), (0,0,0))
142
-
143
- all_texts = norm_texts + [black_top, black_bottom] # order: right,left,front,back,top,bottom
144
 
145
- # Sauvegarde textures dans out_dir
146
- tex_filenames = []
147
- for i, im in enumerate(all_texts):
148
- fn = f"tex_{i}.png"
149
- path = os.path.join(out_dir, fn)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  im.save(path, format="PNG")
151
- tex_filenames.append(fn) # NOTE: on garde juste le basename pour le .mtl
152
-
153
- # Écrire le .mtl (utilise seulement les basenames car .mtl est dans le même dossier)
154
- mtl_name = "cube.mtl"
155
- mtl_path = os.path.join(out_dir, mtl_name)
156
- with open(mtl_path, "w") as f:
157
- f.write("# cube materials\n")
158
- names = ["mat_right", "mat_left", "mat_front", "mat_back", "mat_top", "mat_bottom"]
159
- for name, tex in zip(names, tex_filenames):
160
- f.write(f"newmtl {name}\n")
161
- f.write(" Ns 10\n")
162
- f.write(" Ka 1.000 1.000 1.000\n")
163
- f.write(" Kd 1.000 1.000 1.000\n")
164
- # map_Kd doit référencer le fichier image *tel quel* (basename)
165
- f.write(f" map_Kd {tex}\n\n")
166
-
167
- # Écrire l'OBJ triangulé (vt par face)
168
- obj_name = "cube.obj"
169
- obj_path = os.path.join(out_dir, obj_name)
170
- with open(obj_path, "w") as f:
171
- f.write(f"mtllib {mtl_name}\n")
172
- f.write("o CubeTextured\n")
173
-
174
- # vertices (v1..v8)
 
 
 
 
175
  verts = [
176
- (-1.0, -1.0, -1.0), # v1 (1)
177
- ( 1.0, -1.0, -1.0), # v2 (2)
178
- ( 1.0, 1.0, -1.0), # v3 (3)
179
- (-1.0, 1.0, -1.0), # v4 (4)
180
- (-1.0, -1.0, 1.0), # v5 (5)
181
- ( 1.0, -1.0, 1.0), # v6 (6)
182
- ( 1.0, 1.0, 1.0), # v7 (7)
183
- (-1.0, 1.0, 1.0), # v8 (8)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  ]
185
  for v in verts:
186
- f.write(f"v {v[0]} {v[1]} {v[2]}\n")
187
-
188
- # vt : 4 par face (0,0),(1,0),(1,1),(0,1)
189
- uv_coords = [(0.0,0.0),(1.0,0.0),(1.0,1.0),(0.0,1.0)]
 
 
 
 
 
 
 
190
  for _ in range(6):
191
- for uv in uv_coords:
192
- f.write(f"vt {uv[0]} {uv[1]}\n")
193
-
194
- # faces (triangle pairs) ; ordre des matériaux = right,left,front,back,top,bottom
195
- faces = {
196
- "mat_right": [2,6,7,3], # x = +1
197
- "mat_left": [5,1,4,8], # x = -1
198
- "mat_front": [5,6,7,8], # z = +1
199
- "mat_back": [1,2,3,4], # z = -1
200
- "mat_top": [4,3,7,8], # y = +1
201
- "mat_bottom":[1,5,6,2], # y = -1
202
- }
203
-
204
- # écriture en même ordre que les vt (i.e. 0..5)
205
- mats_order = ["mat_right","mat_left","mat_front","mat_back","mat_top","mat_bottom"]
206
- for i, mat in enumerate(mats_order):
207
- verts_idx = faces[mat]
208
- vt_base = i*4 + 1
209
- a, b, c, d = verts_idx
210
- v1 = f"{a}/{vt_base}"
211
- v2 = f"{b}/{vt_base+1}"
212
- v3 = f"{c}/{vt_base+2}"
213
- v4 = f"{d}/{vt_base+3}"
214
- f.write(f"usemtl {mat}\n")
215
- f.write(f"f {v1} {v2} {v3}\n")
216
- f.write(f"f {v1} {v3} {v4}\n")
217
-
218
- # Retourne le chemin absolu vers .obj (Gradio accepte ça)
219
- print(obj_path)
220
- return os.path.abspath(obj_path), out_dir
 
 
221
 
222
  # -------------------------
223
  # Fonction appelée par Gradio
 
83
  # b = base64.b64encode(buf.getvalue()).decode("utf-8")
84
  # return f"data:image/png;base64,{b}"
85
 
86
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
+ def build_textured_cube(pil_imgs):
89
  """
90
+ Crée un .obj/.mtl et les textures pour un cube dont 4 faces latérales
91
+ sont les images données (ordre attendu : [right, left, front, back]) et
92
+ les faces top/bottom sont noires.
93
+
94
+ Entrée:
95
+ pil_imgs: liste de 4 PIL.Image (RGB)
96
+ Retour:
97
+ (obj_path_abs, tmpdir) # obj_path absolu vers cube.obj, tmpdir contient aussi les textures et le .mtl
98
  """
99
+ import os
 
100
  import tempfile
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  from PIL import Image
 
 
 
 
102
 
103
+ # Vérifications minimales
104
+ if not (isinstance(pil_imgs, (list, tuple)) and len(pil_imgs) >= 4):
105
+ raise ValueError("build_textured_cube attend une liste/tuple de 4 images PIL.")
106
+
107
+ # créer dossier temporaire
108
+ tmpdir = tempfile.mkdtemp(prefix="cube_")
109
+ # nom des textures (gardés simples)
110
+ tex_names = {
111
+ "right": "tex_right.png",
112
+ "left": "tex_left.png",
113
+ "front": "tex_front.png",
114
+ "back": "tex_back.png",
115
+ "top": "tex_top.png",
116
+ "bottom": "tex_bottom.png",
117
+ }
118
+
119
+ # uniformiser la taille des textures sur la taille de la première image
120
+ base_w, base_h = pil_imgs[0].size
121
+
122
+ # convertir et sauvegarder les 4 images fournies
123
+ mapping = ["right", "left", "front", "back"]
124
+ for img, name in zip(pil_imgs[:4], mapping):
125
+ im = img.convert("RGB")
126
+ if im.size != (base_w, base_h):
127
+ im = im.resize((base_w, base_h), Image.LANCZOS)
128
+ path = os.path.join(tmpdir, tex_names[name])
129
  im.save(path, format="PNG")
130
+
131
+ # créer faces top et bottom noires (même taille)
132
+ black = Image.new("RGB", (base_w, base_h), (0, 0, 0))
133
+ black.save(os.path.join(tmpdir, tex_names["top"]), format="PNG")
134
+ black.save(os.path.join(tmpdir, tex_names["bottom"]), format="PNG")
135
+
136
+ # écrire le .mtl
137
+ mtl_path = os.path.join(tmpdir, "cube.mtl")
138
+ with open(mtl_path, "w", encoding="utf-8") as f:
139
+ for mat_name, tex_file in tex_names.items():
140
+ f.write(f"newmtl m_{mat_name}\n")
141
+ f.write("Ka 1.000 1.000 1.000\n")
142
+ f.write("Kd 1.000 1.000 1.000\n")
143
+ f.write("Ks 0.000 0.000 0.000\n")
144
+ f.write("d 1.0\n")
145
+ f.write("illum 2\n")
146
+ f.write(f"map_Kd {tex_file}\n\n")
147
+
148
+ # écrire le .obj (24 sommets - 4 par face pour avoir des UV distincts)
149
+ obj_path = os.path.join(tmpdir, "cube.obj")
150
+ with open(obj_path, "w", encoding="utf-8") as f:
151
+ f.write("# Cube OBJ generated by build_textured_cube\n")
152
+ f.write("mtllib cube.mtl\n\n")
153
+
154
+ # définir 24 vertices (4 par face)
155
+ # cube de côté 1 centré en 0
156
+ s = 0.5
157
+ # each face uses its own 4 vertices (to allow distinct UVs)
158
  verts = [
159
+ # right (+X)
160
+ ( s, -s, -s),
161
+ ( s, s, -s),
162
+ ( s, s, s),
163
+ ( s, -s, s),
164
+ # left (-X)
165
+ (-s, -s, s),
166
+ (-s, s, s),
167
+ (-s, s, -s),
168
+ (-s, -s, -s),
169
+ # front (+Y)
170
+ (-s, s, -s),
171
+ (-s, s, s),
172
+ ( s, s, s),
173
+ ( s, s, -s),
174
+ # back (-Y)
175
+ ( s, -s, -s),
176
+ ( s, -s, s),
177
+ (-s, -s, s),
178
+ (-s, -s, -s),
179
+ # top (+Z)
180
+ (-s, -s, s),
181
+ ( s, -s, s),
182
+ ( s, s, s),
183
+ (-s, s, s),
184
+ # bottom (-Z)
185
+ (-s, s, -s),
186
+ ( s, s, -s),
187
+ ( s, -s, -s),
188
+ (-s, -s, -s),
189
  ]
190
  for v in verts:
191
+ f.write("v {:.6f} {:.6f} {:.6f}\n".format(*v))
192
+ f.write("\n")
193
+
194
+ # écrire les coordonnées de texture (pour chaque face on mappe (0,0)-(1,1))
195
+ uvs = [
196
+ (0.0, 0.0),
197
+ (1.0, 0.0),
198
+ (1.0, 1.0),
199
+ (0.0, 1.0),
200
+ ]
201
+ # répéter pour les 6 faces (4 uv each)
202
  for _ in range(6):
203
+ for uv in uvs:
204
+ f.write("vt {:.6f} {:.6f}\n".format(uv[0], uv[1]))
205
+ f.write("\n")
206
+
207
+ # maintenant définir les faces en utilisant v/t indices (1-indexed)
208
+ # ordre des faces et indices (chaque face a 4 sommets consécutifs)
209
+ # face vertex index start positions (1-based)
210
+ # right: verts 1..4 -> vertex indices 1..4, uv 1..4
211
+ # left: verts 5..8 -> 5..8, uv 5..8
212
+ # front: 9..12
213
+ # back: 13..16
214
+ # top: 17..20
215
+ # bottom:21..24
216
+ face_order = ["right", "left", "front", "back", "top", "bottom"]
217
+ vert_base = 1
218
+ uv_base = 1
219
+ for i, face_name in enumerate(face_order):
220
+ f.write(f"usemtl m_{face_name}\n")
221
+ # indices for this face
222
+ v1 = vert_base + i*4
223
+ v2 = v1 + 1
224
+ v3 = v1 + 2
225
+ v4 = v1 + 3
226
+ t1 = uv_base + i*4
227
+ t2 = t1 + 1
228
+ t3 = t1 + 2
229
+ t4 = t1 + 3
230
+ # écrire la face comme quad (v/t)
231
+ f.write(f"f {v1}/{t1} {v2}/{t2} {v3}/{t3} {v4}/{t4}\n\n")
232
+
233
+ # retourner le chemin absolu du .obj et le dossier temporaire
234
+ return (os.path.abspath(obj_path), tmpdir)
235
 
236
  # -------------------------
237
  # Fonction appelée par Gradio