sajidali110 commited on
Commit
63a5ba2
ยท
verified ยท
1 Parent(s): 522dcbd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -133
app.py CHANGED
@@ -1,188 +1,109 @@
1
  import os
2
  import glob
 
3
  import gradio as gr
4
  import spaces # required for ZeroGPU
5
  import torch # noqa: F401 (also required by `spaces` for its CUDA patching)
6
  import onnxruntime as ort
7
  import numpy as np
8
- from PIL import Image, ImageDraw
9
  import cv2
10
  import tempfile
11
 
 
 
 
12
  # -----------------------------------------------------------------
13
- # FIX: onnxruntime's CUDAExecutionProvider needs libcublasLt.so /
14
- # libcudnn.so etc. at runtime. Those files ARE installed (they ship
15
- # inside the `nvidia-cublas-cu12` / `nvidia-cudnn-cu12` packages that
16
- # come with torch) but they live under site-packages/nvidia/*/lib,
17
- # which is NOT on the system's shared-library search path โ€” so the
18
- # CUDA provider fails to load with "libcublasLt.so.12: cannot open
19
- # shared object file" and onnxruntime silently falls back to CPU.
20
- # We point the dynamic linker at the right folders ourselves, and
21
- # also ask onnxruntime to preload what it can find. This must run
22
- # BEFORE any InferenceSession with CUDAExecutionProvider is created.
23
  # -----------------------------------------------------------------
24
  def _fix_cuda_library_path():
 
25
  try:
26
  import nvidia
27
- nvidia_root = os.path.dirname(nvidia.__file__)
28
- lib_dirs = glob.glob(os.path.join(nvidia_root, "*", "lib"))
29
- if lib_dirs:
30
- existing = os.environ.get("LD_LIBRARY_PATH", "")
31
- os.environ["LD_LIBRARY_PATH"] = ":".join(lib_dirs) + (":" + existing if existing else "")
32
- print("[ORT] Added to LD_LIBRARY_PATH:", lib_dirs)
33
  except Exception as e:
34
- print("[ORT] Could not locate nvidia pip lib dirs:", e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  try:
37
- ort.preload_dlls() # onnxruntime >= 1.21; harmless no-op-ish if it fails
38
- print("[ORT] preload_dlls() succeeded")
39
  except Exception as e:
40
  print("[ORT] preload_dlls() unavailable/failed (non-fatal):", e)
41
 
42
 
43
  _fix_cuda_library_path()
44
 
45
- MODEL_PATH = "birefnet-general.onnx"
46
-
47
- # -----------------------------------------------------------------
48
- # IMPORTANT: do NOT create the CUDA InferenceSession here at import
49
- # time. ZeroGPU only attaches a real GPU to the process while a
50
- # @spaces.GPU-decorated function is executing โ€” outside of that, this
51
- # process has no GPU, so building a CUDAExecutionProvider session here
52
- # would fail. Instead we build it lazily, from inside the decorated
53
- # function below. Note: ZeroGPU may run each call in a fresh worker,
54
- # so this "cache" mainly exists for the case where it doesn't โ€” don't
55
- # rely on it for performance, just correctness.
56
- # -----------------------------------------------------------------
57
  _session = None
58
- _input_name = None
59
- _output_name = None
60
 
61
 
62
  def get_session():
63
- global _session, _input_name, _output_name
64
  if _session is None:
65
  _session = ort.InferenceSession(
66
  MODEL_PATH,
67
  providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
68
  )
69
- _input_name = _session.get_inputs()[0].name
70
- _output_name = _session.get_outputs()[0].name
71
  print("[ORT] active providers:", _session.get_providers())
72
- return _session, _input_name, _output_name
73
-
74
 
75
 
76
- @spaces.GPU(duration=30) # bump this if a cold-start (first call / model load) needs more time
77
  def run_inference(inp):
78
- session, input_name, output_name = get_session()
 
 
79
  return session.run([output_name], {input_name: inp})[0]
80
 
81
 
82
- def remove_bg(
83
- image,
84
- show_box=False,
85
- canvas_size=1200,
86
- padding=15
87
- ):
88
  img = np.array(image.convert("RGB"))
89
  h, w = img.shape[:2]
90
- inp = cv2.resize(img, (1024, 1024))
91
- inp = inp.astype(np.float32) / 255.0
92
  inp = np.transpose(inp, (2, 0, 1))
93
  inp = np.expand_dims(inp, 0)
94
 
95
  pred = run_inference(inp)
 
 
96
 
97
- mask = pred[0][0]
98
- mask = cv2.resize(mask, (w, h))
99
- mask = np.clip(mask, 0, 1)
100
- alpha = (mask * 255).astype(np.uint8)
101
- ys, xs = np.where(alpha > 20)
102
- if len(xs) == 0 or len(ys) == 0:
103
- raise Exception("No object detected")
104
- x1 = int(xs.min())
105
- x2 = int(xs.max())
106
- y1 = int(ys.min())
107
- y2 = int(ys.max())
108
- # -----------------------------------
109
- # Crop object
110
- # -----------------------------------
111
- obj_rgb = img[y1:y2 + 1, x1:x2 + 1]
112
- obj_alpha = alpha[y1:y2 + 1, x1:x2 + 1]
113
- obj_rgba = np.dstack([obj_rgb, obj_alpha])
114
- obj = Image.fromarray(obj_rgba)
115
- obj_w = obj.width
116
- obj_h = obj.height
117
- # -----------------------------------
118
- # Scale while preserving MIN padding
119
- # -----------------------------------
120
-
121
- max_w = canvas_size - (padding * 2)
122
- max_h = canvas_size - (padding * 2)
123
-
124
- scale_w = max_w / obj_w
125
- scale_h = max_h / obj_h
126
-
127
- scale = min(scale_w, scale_h)
128
-
129
- new_w = round(obj_w * scale)
130
- new_h = round(obj_h * scale)
131
-
132
- obj = obj.resize(
133
- (new_w, new_h),
134
- Image.LANCZOS
135
- )
136
- # -----------------------------------
137
- # White canvas
138
- # -----------------------------------
139
- canvas = Image.new(
140
- "RGBA",
141
- (canvas_size, canvas_size),
142
- (255, 255, 255, 255)
143
- )
144
- paste_x = (canvas_size - new_w) // 2
145
- paste_y = (canvas_size - new_h) // 2
146
- canvas.paste(
147
- obj,
148
- (paste_x, paste_y),
149
- obj
150
- )
151
- result = canvas.convert("RGB")
152
- # -----------------------------------
153
- # Optional bounding box
154
- # -----------------------------------
155
- if show_box:
156
- draw = ImageDraw.Draw(result)
157
- draw.rectangle(
158
- [
159
- paste_x,
160
- paste_y,
161
- paste_x + new_w,
162
- paste_y + new_h
163
- ],
164
- outline=(0, 100, 255),
165
- width=4
166
- )
167
- tmp = tempfile.NamedTemporaryFile(
168
- suffix=".png",
169
- delete=False
170
- )
171
- result.save(
172
- tmp.name,
173
- format="PNG"
174
- )
175
  return tmp.name
176
 
177
 
178
  demo = gr.Interface(
179
  fn=remove_bg,
180
- inputs=[
181
- gr.Image(type="pil"),
182
- gr.Checkbox(value=False),
183
- gr.Number(value=1200),
184
- gr.Number(value=15)
185
- ],
186
  outputs=gr.File(),
187
  api_name="remove_bg"
188
  )
 
1
  import os
2
  import glob
3
+ import site
4
  import gradio as gr
5
  import spaces # required for ZeroGPU
6
  import torch # noqa: F401 (also required by `spaces` for its CUDA patching)
7
  import onnxruntime as ort
8
  import numpy as np
9
+ from PIL import Image
10
  import cv2
11
  import tempfile
12
 
13
+ MODEL_PATH = "birefnet-general.onnx"
14
+
15
+
16
  # -----------------------------------------------------------------
17
+ # Infra fix (keep this): points the dynamic linker at the CUDA libs
18
+ # so onnxruntime can actually use the GPU instead of silently
19
+ # falling back to CPU. Nothing to do with image editing โ€” leave as is.
 
 
 
 
 
 
 
20
  # -----------------------------------------------------------------
21
  def _fix_cuda_library_path():
22
+ lib_dirs = set()
23
  try:
24
  import nvidia
25
+ for root in list(nvidia.__path__):
26
+ lib_dirs.update(glob.glob(os.path.join(root, "*", "lib")))
 
 
 
 
27
  except Exception as e:
28
+ print("[ORT] nvidia namespace import lookup failed:", e)
29
+
30
+ if not lib_dirs:
31
+ search_roots = []
32
+ try:
33
+ search_roots += site.getsitepackages()
34
+ except Exception:
35
+ pass
36
+ try:
37
+ search_roots.append(site.getusersitepackages())
38
+ except Exception:
39
+ pass
40
+ for root in search_roots:
41
+ lib_dirs.update(glob.glob(os.path.join(root, "nvidia", "*", "lib")))
42
+
43
+ if lib_dirs:
44
+ lib_dirs = sorted(lib_dirs)
45
+ existing = os.environ.get("LD_LIBRARY_PATH", "")
46
+ os.environ["LD_LIBRARY_PATH"] = ":".join(lib_dirs) + (":" + existing if existing else "")
47
+ print("[ORT] Added to LD_LIBRARY_PATH:", lib_dirs)
48
+ else:
49
+ print("[ORT] WARNING: no nvidia CUDA lib directories found on disk.")
50
 
51
  try:
52
+ ort.preload_dlls()
53
+ print("[ORT] preload_dlls() called")
54
  except Exception as e:
55
  print("[ORT] preload_dlls() unavailable/failed (non-fatal):", e)
56
 
57
 
58
  _fix_cuda_library_path()
59
 
60
+ # Lazy session โ€” built the first time it's needed, inside the GPU call
61
+ # (ZeroGPU only attaches a real GPU while @spaces.GPU is running).
 
 
 
 
 
 
 
 
 
 
62
  _session = None
 
 
63
 
64
 
65
  def get_session():
66
+ global _session
67
  if _session is None:
68
  _session = ort.InferenceSession(
69
  MODEL_PATH,
70
  providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
71
  )
 
 
72
  print("[ORT] active providers:", _session.get_providers())
73
+ return _session
 
74
 
75
 
76
+ @spaces.GPU(duration=30)
77
  def run_inference(inp):
78
+ session = get_session()
79
+ input_name = session.get_inputs()[0].name
80
+ output_name = session.get_outputs()[0].name
81
  return session.run([output_name], {input_name: inp})[0]
82
 
83
 
84
+ def remove_bg(image):
 
 
 
 
 
85
  img = np.array(image.convert("RGB"))
86
  h, w = img.shape[:2]
87
+
88
+ inp = cv2.resize(img, (1024, 1024)).astype(np.float32) / 255.0
89
  inp = np.transpose(inp, (2, 0, 1))
90
  inp = np.expand_dims(inp, 0)
91
 
92
  pred = run_inference(inp)
93
+ mask = cv2.resize(pred[0][0], (w, h))
94
+ alpha = (np.clip(mask, 0, 1) * 255).astype(np.uint8)
95
 
96
+ rgba = np.dstack([img, alpha])
97
+ result = Image.fromarray(rgba)
98
+
99
+ tmp = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
100
+ result.save(tmp.name, format="PNG")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  return tmp.name
102
 
103
 
104
  demo = gr.Interface(
105
  fn=remove_bg,
106
+ inputs=gr.Image(type="pil"),
 
 
 
 
 
107
  outputs=gr.File(),
108
  api_name="remove_bg"
109
  )