cavargas10 commited on
Commit
654c4bf
·
verified ·
1 Parent(s): 2e135b0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -60
app.py CHANGED
@@ -80,7 +80,7 @@ def get_seed(randomize_seed: bool, seed: int) -> int:
80
 
81
  @spaces.GPU
82
  def preprocess_image(
83
- image: dict,
84
  prompt: str = "",
85
  negative_prompt: str = "",
86
  style_name: str = "",
@@ -93,17 +93,26 @@ def preprocess_image(
93
  user_dir = os.path.join(TMP_DIR, session_hash)
94
  logging.info(f"[{session_hash}] Iniciando preprocess_image con prompt: '{prompt[:50]}...'")
95
 
96
- if not image or 'composite' not in image or not isinstance(image['composite'], Image.Image):
97
- logging.error(f"[{session_hash}] La entrada de imagen no es válida o está vacía.")
98
- raise ValueError("Entrada de boceto no válida. Por favor, dibuja algo.")
99
 
100
- input_image = image['composite']
 
101
  width, height = input_image.size
102
  ratio = np.sqrt(1024.0 * 1024.0 / (width * height))
103
  new_width, new_height = int(width * ratio), int(height * ratio)
104
  input_image = input_image.resize((new_width, new_height))
105
- input_image = ImageOps.invert(input_image)
106
 
 
 
 
 
 
 
 
 
 
107
  prompt, negative_prompt = apply_style(style_name, prompt, negative_prompt)
108
 
109
  output_image = pipe_control(
@@ -136,90 +145,53 @@ def image_to_3d(
136
  session_hash = str(req.session_hash)
137
  user_dir = os.path.join(TMP_DIR, session_hash)
138
  logging.info(f"[{session_hash}] Iniciando image_to_3d desde la imagen: {image_path}")
139
-
140
  processed_image = pipeline.preprocess_image(Image.open(image_path))
141
-
142
  outputs = pipeline.run(
143
  processed_image,
144
  seed=seed,
145
  formats=["gaussian", "mesh"],
146
  preprocess_image=False,
147
- sparse_structure_sampler_params={
148
- "steps": ss_sampling_steps,
149
- "cfg_strength": ss_guidance_strength,
150
- },
151
- slat_sampler_params={
152
- "steps": slat_sampling_steps,
153
- "cfg_strength": slat_guidance_strength,
154
- },
155
  )
156
-
157
  logging.info(f"[{session_hash}] Generación del modelo completada. Renderizando video...")
158
  video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']
159
  video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']
160
  video = [np.concatenate([video[i], video_geo[i]], axis=1) for i in range(len(video))]
161
  video_path = os.path.join(user_dir, 'sample.mp4')
162
  imageio.mimsave(video_path, video, fps=15)
163
-
164
  state = pack_state(outputs['gaussian'][0], outputs['mesh'][0])
165
  torch.cuda.empty_cache()
166
  logging.info(f"[{session_hash}] Video renderizado y estado empaquetado. Devolviendo: {video_path}")
167
  return state, video_path
168
 
169
  @spaces.GPU(duration=90)
170
- def extract_glb(
171
- state: dict,
172
- mesh_simplify: float,
173
- texture_size: int,
174
- req: gr.Request,
175
- ) -> Tuple[str, str]:
176
  session_hash = str(req.session_hash)
177
  user_dir = os.path.join(TMP_DIR, session_hash)
178
  logging.info(f"[{session_hash}] Iniciando extract_glb...")
179
-
180
  gs, mesh = unpack_state(state)
181
  glb = postprocessing_utils.to_glb(gs, mesh, simplify=mesh_simplify, texture_size=texture_size, verbose=False)
182
  glb_path = os.path.join(user_dir, 'sample.glb')
183
  glb.export(glb_path)
184
-
185
  torch.cuda.empty_cache()
186
  logging.info(f"[{session_hash}] GLB extraído. Devolviendo: {glb_path}")
187
  return glb_path, glb_path
188
 
189
  def pack_state(gs: Gaussian, mesh: MeshExtractResult) -> dict:
190
  return {
191
- 'gaussian': {
192
- **gs.init_params,
193
- '_xyz': gs._xyz.cpu().numpy(),
194
- '_features_dc': gs._features_dc.cpu().numpy(),
195
- '_scaling': gs._scaling.cpu().numpy(),
196
- '_rotation': gs._rotation.cpu().numpy(),
197
- '_opacity': gs._opacity.cpu().numpy(),
198
- },
199
- 'mesh': {
200
- 'vertices': mesh.vertices.cpu().numpy(),
201
- 'faces': mesh.faces.cpu().numpy(),
202
- },
203
  }
204
 
205
  def unpack_state(state: dict) -> Tuple[Gaussian, edict, str]:
206
- gs = Gaussian(
207
- aabb=state['gaussian']['aabb'],
208
- sh_degree=state['gaussian']['sh_degree'],
209
- mininum_kernel_size=state['gaussian']['mininum_kernel_size'],
210
- scaling_bias=state['gaussian']['scaling_bias'],
211
- opacity_bias=state['gaussian']['opacity_bias'],
212
- scaling_activation=state['gaussian']['scaling_activation'],
213
- )
214
  gs._xyz = torch.tensor(state['gaussian']['_xyz'], device='cuda')
215
  gs._features_dc = torch.tensor(state['gaussian']['_features_dc'], device='cuda')
216
  gs._scaling = torch.tensor(state['gaussian']['_scaling'], device='cuda')
217
  gs._rotation = torch.tensor(state['gaussian']['_rotation'], device='cuda')
218
  gs._opacity = torch.tensor(state['gaussian']['_opacity'], device='cuda')
219
- mesh = edict(
220
- vertices=torch.tensor(state['mesh']['vertices'], device='cuda'),
221
- faces=torch.tensor(state['mesh']['faces'], device='cuda'),
222
- )
223
  return gs, mesh
224
 
225
  @spaces.GPU
@@ -230,7 +202,7 @@ def extract_gaussian(state: dict, req: gr.Request) -> Tuple[str, str]:
230
  gs.save_ply(gaussian_path)
231
  torch.cuda.empty_cache()
232
  return gaussian_path, gaussian_path
233
-
234
  with gr.Blocks(delete_cache=(600, 600)) as demo:
235
  gr.Markdown("""
236
  # UTPL - Conversión de Boceto a objetos 3D usando IA
@@ -241,15 +213,10 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
241
  """)
242
  with gr.Row():
243
  with gr.Column():
244
- with gr.Column():
245
- image_prompt = gr.Image(
246
- label="Image Prompt",
247
- format="png",
248
- image_mode="RGBA",
249
- type="pil",
250
- height=300,
251
- show_label=False
252
- )
253
  with gr.Row():
254
  sketch_btn = gr.Button("Process Sketch")
255
  generate_btn = gr.Button("Generate 3D")
 
80
 
81
  @spaces.GPU
82
  def preprocess_image(
83
+ image: Image.Image,
84
  prompt: str = "",
85
  negative_prompt: str = "",
86
  style_name: str = "",
 
93
  user_dir = os.path.join(TMP_DIR, session_hash)
94
  logging.info(f"[{session_hash}] Iniciando preprocess_image con prompt: '{prompt[:50]}...'")
95
 
96
+ if image is None:
97
+ logging.error(f"[{session_hash}] La entrada de imagen es nula.")
98
+ raise ValueError("La imagen de entrada no puede estar vacía.")
99
 
100
+ input_image = image
101
+
102
  width, height = input_image.size
103
  ratio = np.sqrt(1024.0 * 1024.0 / (width * height))
104
  new_width, new_height = int(width * ratio), int(height * ratio)
105
  input_image = input_image.resize((new_width, new_height))
 
106
 
107
+ if input_image.mode == 'RGBA':
108
+ r, g, b, a = input_image.split()
109
+ rgb_image = Image.merge('RGB', (r, g, b))
110
+ inverted_image = ImageOps.invert(rgb_image)
111
+ inverted_image.putalpha(a)
112
+ input_image = inverted_image
113
+ else:
114
+ input_image = ImageOps.invert(input_image.convert('RGB'))
115
+
116
  prompt, negative_prompt = apply_style(style_name, prompt, negative_prompt)
117
 
118
  output_image = pipe_control(
 
145
  session_hash = str(req.session_hash)
146
  user_dir = os.path.join(TMP_DIR, session_hash)
147
  logging.info(f"[{session_hash}] Iniciando image_to_3d desde la imagen: {image_path}")
 
148
  processed_image = pipeline.preprocess_image(Image.open(image_path))
 
149
  outputs = pipeline.run(
150
  processed_image,
151
  seed=seed,
152
  formats=["gaussian", "mesh"],
153
  preprocess_image=False,
154
+ sparse_structure_sampler_params={"steps": ss_sampling_steps, "cfg_strength": ss_guidance_strength},
155
+ slat_sampler_params={"steps": slat_sampling_steps, "cfg_strength": slat_guidance_strength},
 
 
 
 
 
 
156
  )
 
157
  logging.info(f"[{session_hash}] Generación del modelo completada. Renderizando video...")
158
  video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']
159
  video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']
160
  video = [np.concatenate([video[i], video_geo[i]], axis=1) for i in range(len(video))]
161
  video_path = os.path.join(user_dir, 'sample.mp4')
162
  imageio.mimsave(video_path, video, fps=15)
 
163
  state = pack_state(outputs['gaussian'][0], outputs['mesh'][0])
164
  torch.cuda.empty_cache()
165
  logging.info(f"[{session_hash}] Video renderizado y estado empaquetado. Devolviendo: {video_path}")
166
  return state, video_path
167
 
168
  @spaces.GPU(duration=90)
169
+ def extract_glb(state: dict, mesh_simplify: float, texture_size: int, req: gr.Request) -> Tuple[str, str]:
 
 
 
 
 
170
  session_hash = str(req.session_hash)
171
  user_dir = os.path.join(TMP_DIR, session_hash)
172
  logging.info(f"[{session_hash}] Iniciando extract_glb...")
 
173
  gs, mesh = unpack_state(state)
174
  glb = postprocessing_utils.to_glb(gs, mesh, simplify=mesh_simplify, texture_size=texture_size, verbose=False)
175
  glb_path = os.path.join(user_dir, 'sample.glb')
176
  glb.export(glb_path)
 
177
  torch.cuda.empty_cache()
178
  logging.info(f"[{session_hash}] GLB extraído. Devolviendo: {glb_path}")
179
  return glb_path, glb_path
180
 
181
  def pack_state(gs: Gaussian, mesh: MeshExtractResult) -> dict:
182
  return {
183
+ 'gaussian': {**gs.init_params, '_xyz': gs._xyz.cpu().numpy(), '_features_dc': gs._features_dc.cpu().numpy(), '_scaling': gs._scaling.cpu().numpy(), '_rotation': gs._rotation.cpu().numpy(), '_opacity': gs._opacity.cpu().numpy()},
184
+ 'mesh': {'vertices': mesh.vertices.cpu().numpy(), 'faces': mesh.faces.cpu().numpy()},
 
 
 
 
 
 
 
 
 
 
185
  }
186
 
187
  def unpack_state(state: dict) -> Tuple[Gaussian, edict, str]:
188
+ gs = Gaussian(aabb=state['gaussian']['aabb'], sh_degree=state['gaussian']['sh_degree'], mininum_kernel_size=state['gaussian']['mininum_kernel_size'], scaling_bias=state['gaussian']['scaling_bias'], opacity_bias=state['gaussian']['opacity_bias'], scaling_activation=state['gaussian']['scaling_activation'])
 
 
 
 
 
 
 
189
  gs._xyz = torch.tensor(state['gaussian']['_xyz'], device='cuda')
190
  gs._features_dc = torch.tensor(state['gaussian']['_features_dc'], device='cuda')
191
  gs._scaling = torch.tensor(state['gaussian']['_scaling'], device='cuda')
192
  gs._rotation = torch.tensor(state['gaussian']['_rotation'], device='cuda')
193
  gs._opacity = torch.tensor(state['gaussian']['_opacity'], device='cuda')
194
+ mesh = edict(vertices=torch.tensor(state['mesh']['vertices'], device='cuda'), faces=torch.tensor(state['mesh']['faces'], device='cuda'))
 
 
 
195
  return gs, mesh
196
 
197
  @spaces.GPU
 
202
  gs.save_ply(gaussian_path)
203
  torch.cuda.empty_cache()
204
  return gaussian_path, gaussian_path
205
+
206
  with gr.Blocks(delete_cache=(600, 600)) as demo:
207
  gr.Markdown("""
208
  # UTPL - Conversión de Boceto a objetos 3D usando IA
 
213
  """)
214
  with gr.Row():
215
  with gr.Column():
216
+ with gr.Column():
217
+ # --- ¡MODIFICADO! Cambiamos ImageEditor por Image ---
218
+ image_prompt = gr.Image(label="Input sketch", type="pil", image_mode="RGBA", height=512)
219
+
 
 
 
 
 
220
  with gr.Row():
221
  sketch_btn = gr.Button("Process Sketch")
222
  generate_btn = gr.Button("Generate 3D")