AlbeRota commited on
Commit
f7eee2e
·
1 Parent(s): b14eae2
Files changed (4) hide show
  1. .gitignore +2 -1
  2. app.py +66 -21
  3. tmp/config.log +2 -1
  4. tmp/models.log +2 -0
.gitignore CHANGED
@@ -1 +1,2 @@
1
- .venv/
 
 
1
+ .venv/
2
+ sample_images/
app.py CHANGED
@@ -2,6 +2,7 @@
2
 
3
  from __future__ import annotations
4
 
 
5
  import sys
6
  from pathlib import Path
7
  from typing import NamedTuple
@@ -12,7 +13,10 @@ if _REPO_ROOT not in sys.path:
12
  sys.path.insert(0, str(_REPO_ROOT))
13
 
14
  _GRADIO_DIR = Path(__file__).resolve().parent
15
- import spaces
 
 
 
16
  import gradio as gr
17
  import numpy as np
18
  import torch
@@ -73,16 +77,28 @@ def _get_assets() -> HFAssets:
73
  return _cached_assets
74
 
75
 
 
 
 
 
76
  def _get_sample_image_paths() -> list[str]:
77
- """Return sorted paths of sample images from the downloaded assets."""
 
78
  assets = _get_assets()
79
- if not assets.sample_images_dir.is_dir():
 
80
  return []
81
- paths = [
82
- str(p)
83
- for p in sorted(assets.sample_images_dir.iterdir())
84
- if p.is_file() and p.suffix.lower() in IMAGE_EXTENSIONS
85
- ]
 
 
 
 
 
 
86
  return paths
87
 
88
 
@@ -113,13 +129,12 @@ def _get_model(device: str):
113
 
114
  def build_ui():
115
  _get_assets()
116
-
117
  device = "cuda" if torch.cuda.is_available() else "cpu"
118
  # Start loading the model in the background so it is ready (or nearly ready) by first use.
119
  print(f"Initializing model on {device}...")
120
  _get_model(device)
121
 
122
- @spaces.GPU
123
  def run_inference(image: np.ndarray | None) -> np.ndarray | None:
124
  """Run reflection removal using the cached model. Returns RGB numpy [H,W,3] in 0–255 or None."""
125
  if image is None:
@@ -134,9 +149,15 @@ def build_ui():
134
  tensor = TF.resize(tensor, [target_side, target_side], antialias=True)
135
  tensor = tensor.to(ura_model.device, dtype=torch.float32)
136
  mask = tensor.mean(1, keepdim=True) > 0.9 # [1, 1, S, S]
 
 
137
  with torch.no_grad():
 
138
  diffuse = ura_model(images=tensor, inpaint_mask_override=mask)
 
139
  diffuse = diffuse.cpu()
 
 
140
  diffuse = TF.resize(diffuse, [h, w], antialias=True)
141
  out = diffuse[0].numpy().transpose(1, 2, 0)
142
  out = (np.clip(out, 0.0, 1.0) * 255).astype(np.uint8)
@@ -178,12 +199,12 @@ def build_ui():
178
  with gr.Row():
179
  inp = gr.Image(
180
  type="numpy",
181
- label="Image input",
182
  height=600,
183
  width=600,
184
  )
185
  out_slider = gr.ImageSlider(
186
- label="Input",
187
  type="numpy",
188
  height=600,
189
  show_label=True,
@@ -208,7 +229,7 @@ def build_ui():
208
  [GitHub](https://github.com/alberto-rota/UnReflectAnything) ⋅
209
  [Model Card](https://huggingface.co/AlbeRota/UnReflectAnything) ⋅
210
  [Paper](https://arxiv.org/abs/2512.09583) ⋅
211
- [Contact](mailto:alberto1.rota@polimi.it)
212
  """)
213
  return demo
214
 
@@ -221,15 +242,39 @@ def _launch_allowed_paths():
221
  paths = [str(_GRADIO_DIR)]
222
  try:
223
  assets = _get_assets()
224
- if assets.sample_images_dir.is_dir():
225
- paths.append(str(assets.sample_images_dir))
226
- except Exception:
227
- pass
 
 
 
 
 
228
  return paths
229
 
230
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  if __name__ == "__main__":
232
- demo.launch(
233
- allowed_paths=_launch_allowed_paths(),
234
- theme=gr.themes.Soft(primary_hue="orange", secondary_hue="blue"),
235
- )
 
2
 
3
  from __future__ import annotations
4
 
5
+ import shutil
6
  import sys
7
  from pathlib import Path
8
  from typing import NamedTuple
 
13
  sys.path.insert(0, str(_REPO_ROOT))
14
 
15
  _GRADIO_DIR = Path(__file__).resolve().parent
16
+ try:
17
+ import spaces
18
+ except ModuleNotFoundError:
19
+ spaces = None
20
  import gradio as gr
21
  import numpy as np
22
  import torch
 
77
  return _cached_assets
78
 
79
 
80
+ # Local copy of sample images under cwd so Gradio never needs allowed_paths for examples
81
+ _SAMPLE_IMAGES_COPY_DIR: Path | None = None
82
+
83
+
84
  def _get_sample_image_paths() -> list[str]:
85
+ """Return paths of sample images under cwd (copied from HF cache) so Gradio can use them without allowed_paths."""
86
+ global _SAMPLE_IMAGES_COPY_DIR
87
  assets = _get_assets()
88
+ src = assets.sample_images_dir
89
+ if not src.is_dir():
90
  return []
91
+ dest = _GRADIO_DIR / "sample_images"
92
+ dest.mkdir(parents=True, exist_ok=True)
93
+ paths = []
94
+ for p in sorted(src.iterdir()):
95
+ if not p.is_file() or p.suffix.lower() not in IMAGE_EXTENSIONS:
96
+ continue
97
+ dst_file = dest / p.name
98
+ if not dst_file.exists() or dst_file.stat().st_mtime < p.stat().st_mtime:
99
+ shutil.copy2(p, dst_file)
100
+ paths.append(str(dst_file.resolve()))
101
+ _SAMPLE_IMAGES_COPY_DIR = dest
102
  return paths
103
 
104
 
 
129
 
130
  def build_ui():
131
  _get_assets()
 
132
  device = "cuda" if torch.cuda.is_available() else "cpu"
133
  # Start loading the model in the background so it is ready (or nearly ready) by first use.
134
  print(f"Initializing model on {device}...")
135
  _get_model(device)
136
 
137
+ @spaces.GPU if spaces else lambda x: x
138
  def run_inference(image: np.ndarray | None) -> np.ndarray | None:
139
  """Run reflection removal using the cached model. Returns RGB numpy [H,W,3] in 0–255 or None."""
140
  if image is None:
 
149
  tensor = TF.resize(tensor, [target_side, target_side], antialias=True)
150
  tensor = tensor.to(ura_model.device, dtype=torch.float32)
151
  mask = tensor.mean(1, keepdim=True) > 0.9 # [1, 1, S, S]
152
+ import time
153
+
154
  with torch.no_grad():
155
+ start_time = time.time()
156
  diffuse = ura_model(images=tensor, inpaint_mask_override=mask)
157
+ end_time = time.time()
158
  diffuse = diffuse.cpu()
159
+ inference_time_ms = (end_time - start_time) * 1000
160
+ gr.Success(f"Inference time: {inference_time_ms:.1f} ms")
161
  diffuse = TF.resize(diffuse, [h, w], antialias=True)
162
  out = diffuse[0].numpy().transpose(1, 2, 0)
163
  out = (np.clip(out, 0.0, 1.0) * 255).astype(np.uint8)
 
199
  with gr.Row():
200
  inp = gr.Image(
201
  type="numpy",
202
+ label="Input",
203
  height=600,
204
  width=600,
205
  )
206
  out_slider = gr.ImageSlider(
207
+ label="Output",
208
  type="numpy",
209
  height=600,
210
  show_label=True,
 
229
  [GitHub](https://github.com/alberto-rota/UnReflectAnything) ⋅
230
  [Model Card](https://huggingface.co/AlbeRota/UnReflectAnything) ⋅
231
  [Paper](https://arxiv.org/abs/2512.09583) ⋅
232
+ [Contact](mailto:alberto1.rota@polimi.it)
233
  """)
234
  return demo
235
 
 
242
  paths = [str(_GRADIO_DIR)]
243
  try:
244
  assets = _get_assets()
245
+ sample_dir = assets.sample_images_dir
246
+ if sample_dir.is_dir():
247
+ paths.append(str(sample_dir.resolve()))
248
+ # Also allow parent (snapshot root) in case Gradio resolves paths from repo root
249
+ parent = sample_dir.parent
250
+ if parent.is_dir():
251
+ paths.append(str(parent.resolve()))
252
+ except Exception as e:
253
+ print(f"Warning: could not add HF sample_images to allowed_paths: {e}")
254
  return paths
255
 
256
 
257
+ def _launch_kwargs():
258
+ """Default kwargs for launch() so allowed_paths are always set (e.g. when HF Spaces runs demo.launch())."""
259
+ return {
260
+ "allowed_paths": _launch_allowed_paths(),
261
+ "theme": gr.themes.Soft(primary_hue="orange", secondary_hue="blue"),
262
+ }
263
+
264
+
265
+ # Ensure launch() always receives allowed_paths (e.g. when HF Spaces runner calls demo.launch() without args)
266
+ _original_launch = demo.launch
267
+
268
+
269
+ def _launch_with_allowed_paths(*args, **kwargs):
270
+ for key, value in _launch_kwargs().items():
271
+ if key not in kwargs:
272
+ kwargs[key] = value
273
+ return _original_launch(*args, **kwargs)
274
+
275
+
276
+ demo.launch = _launch_with_allowed_paths
277
+
278
+
279
  if __name__ == "__main__":
280
+ demo.launch()
 
 
 
tmp/config.log CHANGED
@@ -1 +1,2 @@
1
- 2026-02-11 20:08:17,718 - utilities.config - CONFIG - CONFIG DISTRIBUTE is 'singlegpu' even though multiple GPUs are available
 
 
1
+ 2026-02-11 21:26:27,642 - utilities.config - CONFIG - CONFIG DISTRIBUTE is 'singlegpu' even though multiple GPUs are available
2
+ 2026-02-11 21:26:32,739 - utilities.config - CONFIG - CONFIG DISTRIBUTE is 'singlegpu' even though multiple GPUs are available
tmp/models.log ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ 2026-02-11 21:26:30,960 - models - MODEL - MODEL Decoder 'diffuse' frozen due to DECODER_LR=0.0
2
+ 2026-02-11 21:26:35,539 - models - MODEL - MODEL Decoder 'diffuse' frozen due to DECODER_LR=0.0