Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
|
@@ -102,26 +102,32 @@ def user_inference(img1, img2):
|
|
| 102 |
|
| 103 |
def build_textured_cube(textures, out_dir=None):
|
| 104 |
"""
|
|
|
|
| 105 |
textures: list de 4 PIL.Image (RGB) -> mapping:
|
| 106 |
textures[0] -> right
|
| 107 |
textures[1] -> left
|
| 108 |
textures[2] -> front
|
| 109 |
textures[3] -> back
|
| 110 |
-
out_dir: dossier de sortie optionnel
|
| 111 |
Retourne: (chemin_absolu_obj, out_dir)
|
| 112 |
"""
|
| 113 |
-
import os,
|
|
|
|
|
|
|
| 114 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
if out_dir is None:
|
| 116 |
-
out_dir =
|
| 117 |
-
|
| 118 |
-
os.makedirs(out_dir, exist_ok=True)
|
| 119 |
|
| 120 |
-
#
|
| 121 |
if len(textures) < 4:
|
| 122 |
raise ValueError("Il faut fournir 4 images dans `textures`.")
|
| 123 |
|
| 124 |
-
#
|
| 125 |
base_w, base_h = textures[0].size
|
| 126 |
norm_texts = []
|
| 127 |
for im in textures[:4]:
|
|
@@ -129,21 +135,22 @@ def build_textured_cube(textures, out_dir=None):
|
|
| 129 |
im = im.resize((base_w, base_h))
|
| 130 |
norm_texts.append(im.convert("RGB"))
|
| 131 |
|
| 132 |
-
#
|
|
|
|
| 133 |
black_top = Image.new("RGB", (base_w, base_h), (0,0,0))
|
| 134 |
black_bottom = Image.new("RGB", (base_w, base_h), (0,0,0))
|
| 135 |
|
| 136 |
-
all_texts = norm_texts + [black_top, black_bottom] # order:
|
| 137 |
|
| 138 |
-
#
|
| 139 |
tex_filenames = []
|
| 140 |
for i, im in enumerate(all_texts):
|
| 141 |
fn = f"tex_{i}.png"
|
| 142 |
path = os.path.join(out_dir, fn)
|
| 143 |
im.save(path, format="PNG")
|
| 144 |
-
tex_filenames.append(fn)
|
| 145 |
|
| 146 |
-
#
|
| 147 |
mtl_name = "cube.mtl"
|
| 148 |
mtl_path = os.path.join(out_dir, mtl_name)
|
| 149 |
with open(mtl_path, "w") as f:
|
|
@@ -154,9 +161,10 @@ def build_textured_cube(textures, out_dir=None):
|
|
| 154 |
f.write(" Ns 10\n")
|
| 155 |
f.write(" Ka 1.000 1.000 1.000\n")
|
| 156 |
f.write(" Kd 1.000 1.000 1.000\n")
|
|
|
|
| 157 |
f.write(f" map_Kd {tex}\n\n")
|
| 158 |
|
| 159 |
-
#
|
| 160 |
obj_name = "cube.obj"
|
| 161 |
obj_path = os.path.join(out_dir, obj_name)
|
| 162 |
with open(obj_path, "w") as f:
|
|
@@ -177,14 +185,13 @@ def build_textured_cube(textures, out_dir=None):
|
|
| 177 |
for v in verts:
|
| 178 |
f.write(f"v {v[0]} {v[1]} {v[2]}\n")
|
| 179 |
|
| 180 |
-
#
|
| 181 |
uv_coords = [(0.0,0.0),(1.0,0.0),(1.0,1.0),(0.0,1.0)]
|
| 182 |
-
for
|
| 183 |
for uv in uv_coords:
|
| 184 |
f.write(f"vt {uv[0]} {uv[1]}\n")
|
| 185 |
|
| 186 |
-
#
|
| 187 |
-
# right, left, front, back, top, bottom
|
| 188 |
faces = {
|
| 189 |
"mat_right": [2,6,7,3], # x = +1
|
| 190 |
"mat_left": [5,1,4,8], # x = -1
|
|
@@ -194,28 +201,22 @@ def build_textured_cube(textures, out_dir=None):
|
|
| 194 |
"mat_bottom":[1,5,6,2], # y = -1
|
| 195 |
}
|
| 196 |
|
| 197 |
-
#
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
# We'll iterate in the exact same order as vt emission (0..5)
|
| 202 |
-
# vt indices start at 1
|
| 203 |
-
for i, mat in enumerate(["mat_right","mat_left","mat_front","mat_back","mat_top","mat_bottom"]):
|
| 204 |
-
verts_idx = faces[mat] # list of 4 vertex indices
|
| 205 |
vt_base = i*4 + 1
|
| 206 |
-
# triangles: (a,b,c) and (a,c,d)
|
| 207 |
a, b, c, d = verts_idx
|
| 208 |
v1 = f"{a}/{vt_base}"
|
| 209 |
v2 = f"{b}/{vt_base+1}"
|
| 210 |
v3 = f"{c}/{vt_base+2}"
|
| 211 |
v4 = f"{d}/{vt_base+3}"
|
| 212 |
f.write(f"usemtl {mat}\n")
|
| 213 |
-
# first triangle
|
| 214 |
f.write(f"f {v1} {v2} {v3}\n")
|
| 215 |
-
# second triangle
|
| 216 |
f.write(f"f {v1} {v3} {v4}\n")
|
| 217 |
|
| 218 |
-
|
|
|
|
| 219 |
|
| 220 |
# -------------------------
|
| 221 |
# Fonction appelée par Gradio
|
|
|
|
| 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]:
|
|
|
|
| 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:
|
|
|
|
| 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:
|
|
|
|
| 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
|
|
|
|
| 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 |
+
return os.path.abspath(obj_path), out_dir
|
| 220 |
|
| 221 |
# -------------------------
|
| 222 |
# Fonction appelée par Gradio
|