sciencellama commited on
Commit
5b41476
Β·
verified Β·
1 Parent(s): cd54749

Return depth as 16-bit PNG via gr.File (preserve full precision)

Browse files
Files changed (1) hide show
  1. app.py +31 -10
app.py CHANGED
@@ -56,6 +56,8 @@ except Exception as _e:
56
  print(f"[warn] gradio_client patch failed: {_e}")
57
  # ─────────────────────────────────────────────────────────────────────────────
58
 
 
 
59
  import numpy as np
60
  import spaces
61
  import torch
@@ -75,22 +77,40 @@ def _get_pipe(task: str):
75
  return _pipes[task]
76
 
77
 
78
- def _to_8bit(img: Image.Image) -> Image.Image:
79
- """colorize_depth_map was modified to return 16-bit grayscale (uint16).
80
- Gradio serialises via webp which drops the upper byte, yielding an almost-
81
- white image. Convert to proper 8-bit L before handing back to Gradio.
 
 
 
 
82
  """
83
  arr = np.array(img)
 
 
84
  if arr.dtype == np.uint16:
85
- arr = (arr >> 8).astype(np.uint8) # high byte β†’ full 8-bit range
86
- return Image.fromarray(arr, mode="L")
87
- return img
 
 
 
 
 
 
 
 
 
 
 
88
 
89
 
90
  @spaces.GPU
91
  def infer_depth(image_path):
92
  pipe = _get_pipe("depth")
93
- return _to_8bit(infer_pipe(pipe, image_path, "depth", SEED, device))
 
94
 
95
 
96
  @spaces.GPU
@@ -101,11 +121,12 @@ def infer_normal(image_path):
101
 
102
  with gr.Blocks(title="Lotus 1 - Depth + Normal") as demo:
103
  gr.Markdown("# Lotus 1 - Depth & Normal")
104
- gr.Markdown("API: `/depth` returns depth map, `/normal` returns normal map.")
 
105
 
106
  with gr.Tab("Depth"):
107
  d_in = gr.Image(label="Input", type="filepath")
108
- d_out = gr.Image(label="Depth (g)")
109
  d_btn = gr.Button("Run depth")
110
  d_btn.click(infer_depth, inputs=d_in, outputs=d_out, api_name="depth")
111
 
 
56
  print(f"[warn] gradio_client patch failed: {_e}")
57
  # ─────────────────────────────────────────────────────────────────────────────
58
 
59
+ import tempfile
60
+
61
  import numpy as np
62
  import spaces
63
  import torch
 
77
  return _pipes[task]
78
 
79
 
80
+ def _save_16bit_png(img: Image.Image) -> str:
81
+ """Save the depth map as a true 16-bit PNG and return the path.
82
+
83
+ colorize_depth_map (modified previously) already returns a uint16 PIL
84
+ Image. The default gr.Image output would re-encode it as 8-bit webp,
85
+ which destroys the upper byte and yields visible stepping in the
86
+ fabricated relief (~20 Β΅m per step over a 5 mm relief). Returning
87
+ a file path via gr.File bypasses Gradio's image processing entirely.
88
  """
89
  arr = np.array(img)
90
+ fd, tmp_path = tempfile.mkstemp(suffix='_depth16.png')
91
+ os.close(fd)
92
  if arr.dtype == np.uint16:
93
+ # Native 16-bit path β€” preserve all 65,536 levels
94
+ Image.fromarray(arr, mode="I;16").save(tmp_path, format="PNG")
95
+ elif arr.dtype == np.uint8:
96
+ # Up-promote to 16-bit (no extra precision, but consistent output)
97
+ arr16 = arr.astype(np.uint16) * 257 # 0->0, 255->65535
98
+ Image.fromarray(arr16, mode="I;16").save(tmp_path, format="PNG")
99
+ else:
100
+ # Float / other β€” normalise to 16-bit
101
+ a = arr.astype(np.float32)
102
+ rng = max(a.max() - a.min(), 1e-9)
103
+ a = (a - a.min()) / rng
104
+ Image.fromarray((a * 65535).astype(np.uint16),
105
+ mode="I;16").save(tmp_path, format="PNG")
106
+ return tmp_path
107
 
108
 
109
  @spaces.GPU
110
  def infer_depth(image_path):
111
  pipe = _get_pipe("depth")
112
+ img = infer_pipe(pipe, image_path, "depth", SEED, device)
113
+ return _save_16bit_png(img)
114
 
115
 
116
  @spaces.GPU
 
121
 
122
  with gr.Blocks(title="Lotus 1 - Depth + Normal") as demo:
123
  gr.Markdown("# Lotus 1 - Depth & Normal")
124
+ gr.Markdown("API: `/depth` returns a **16-bit grayscale PNG** depth map, "
125
+ "`/normal` returns an RGB normal map.")
126
 
127
  with gr.Tab("Depth"):
128
  d_in = gr.Image(label="Input", type="filepath")
129
+ d_out = gr.File(label="Depth (16-bit PNG)")
130
  d_btn = gr.Button("Run depth")
131
  d_btn.click(infer_depth, inputs=d_in, outputs=d_out, api_name="depth")
132