mminju commited on
Commit
22f2ce2
ยท
verified ยท
1 Parent(s): c20701a

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +81 -0
  2. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io, base64, numpy as np, torch
2
+ from PIL import Image
3
+ from fastapi import FastAPI, Request
4
+ from fastapi.responses import JSONResponse, PlainTextResponse
5
+ import gradio as gr
6
+ from transformers import AutoImageProcessor, DepthProForDepthEstimation
7
+
8
+ # --------- ์ „์—ญ: ์„œ๋ฒ„๋งŒ ๋„์šฐ๊ณ , ๋ฌด๊ฑฐ์šด ๊ฑด ๋กœ๋”ฉํ•˜์ง€ ์•Š์Œ(์ง€์—ฐ ๋กœ๋”ฉ) ---------
9
+ device = "cuda" if torch.cuda.is_available() else "cpu"
10
+ _proc = None
11
+ _model = None
12
+
13
+ def _lazy_init():
14
+ global _proc, _model
15
+ if _proc is None:
16
+ _proc = AutoImageProcessor.from_pretrained("apple/DepthPro-hf")
17
+ if _model is None:
18
+ _model = DepthProForDepthEstimation.from_pretrained("apple/DepthPro-hf").to(device).eval()
19
+
20
+ def _infer(pil_img: Image.Image):
21
+ _lazy_init()
22
+ H, W = pil_img.height, pil_img.width
23
+ inputs = _proc(images=pil_img.convert("RGB"), return_tensors="pt").to(device)
24
+ with torch.no_grad():
25
+ outputs = _model(**inputs)
26
+ post = _proc.post_process_depth_estimation(outputs, target_sizes=[(H, W)])[0]
27
+ depth = post["predicted_depth"].float().cpu().numpy() # meters
28
+ fov = float(post.get("field_of_view", 0.0))
29
+ focal = float(post.get("focal_length", 0.0))
30
+ return depth, fov, focal
31
+
32
+ # ===================== FastAPI (API ์—”๋“œํฌ์ธํŠธ) =====================
33
+ app = FastAPI()
34
+
35
+ @app.get("/health")
36
+ async def health():
37
+ return PlainTextResponse("ok")
38
+
39
+ @app.post("/depth")
40
+ async def depth_endpoint(request: Request):
41
+ """
42
+ ๋‘ ๊ฐ€์ง€ ์ž…๋ ฅ ๋ชจ๋‘ ์ง€์›:
43
+ 1) Content-Type: application/octet-stream (์›๋ณธ ์ด๋ฏธ์ง€ ๋ฐ”์ดํŠธ)
44
+ 2) Content-Type: application/json {"inputs": "<base64>"}
45
+ """
46
+ ctype = (request.headers.get("content-type") or "").lower()
47
+
48
+ if "application/json" in ctype:
49
+ data = await request.json()
50
+ b64 = data.get("inputs", "")
51
+ if b64.startswith("data:"): # data URL๋„ ํ—ˆ์šฉ
52
+ b64 = b64.split(",", 1)[1]
53
+ image_bytes = base64.b64decode(b64)
54
+ else:
55
+ # ๊ธฐ๋ณธ: octet-stream
56
+ image_bytes = await request.body()
57
+
58
+ img = Image.open(io.BytesIO(image_bytes)).convert("RGB")
59
+ depth, fov, focal = _infer(img)
60
+ H, W = img.height, img.width
61
+
62
+ depth_b64 = base64.b64encode(depth.astype(np.float32).tobytes()).decode("ascii")
63
+ return JSONResponse({
64
+ "height": H, "width": W,
65
+ "focal_px": float(focal),
66
+ "field_of_view": float(fov),
67
+ "depth_flat": depth_b64
68
+ })
69
+
70
+ # ===================== Gradio (ํ…Œ์ŠคํŠธ์šฉ ๋ฏธ๋‹ˆ UI) =====================
71
+ def preview(image: Image.Image):
72
+ depth, _, _ = _infer(image)
73
+ v = depth[np.isfinite(depth)]
74
+ lo, hi = (np.percentile(v, 1), np.percentile(v, 99)) if v.size else (0, 1)
75
+ norm = np.clip((depth - lo) / max(1e-6, hi - lo), 0, 1)
76
+ return Image.fromarray((norm * 255).astype(np.uint8))
77
+
78
+ with gr.Blocks() as demo:
79
+ gr.Markdown("## DepthPro-hf (CPU, ๋ฌด๋ฃŒ Space)\n- API: **POST /depth** (octet-stream ๋˜๋Š” JSON base64)")
80
+ inp = gr.Image(type="pil", label="Input")
81
+ out = gr.Image(label="Depth (preview)")
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi
2
+ gradio>=4.0
3
+ transformers>=4.40
4
+ torch
5
+ pillow
6
+ numpy