Alpeccaai / app.py
CREATORJD's picture
Update (#2)
5128014
Raw
History Blame Contribute Delete
4.04 kB
"""
Alpeccaai Pose β€” Hugging Face Space (ZeroGPU)
Runs DWPose / RTMPose whole-body 2D pose via rtmlib and returns keypoint JSON
in the exact format RIGFORGE's "AI keypoints -> Import pose keypoints" reads.
Endpoint: /detect (the RIGFORGE "Detect via HF Space" button calls this).
"""
import os, json, tempfile
import numpy as np
import cv2
import gradio as gr
# ZeroGPU: CUDA is only visible INSIDE a @spaces.GPU function, so the model is
# built lazily on first call (see get_model). Off ZeroGPU this is a no-op.
try:
import spaces
gpu = spaces.GPU(duration=60)
except Exception:
def gpu(fn):
return fn
# COCO-17 body order == first 17 COCO-WholeBody points == RIGFORGE's order:
# 0 nose 1 L_eye 2 R_eye 3 L_ear 4 R_ear 5 L_sho 6 R_sho 7 L_elb 8 R_elb
# 9 L_wri 10 R_wri 11 L_hip 12 R_hip 13 L_knee 14 R_knee 15 L_ank 16 R_ank
SKELETON = [(5,7),(7,9),(6,8),(8,10),(5,6),(11,12),(5,11),(6,12),
(11,13),(13,15),(12,14),(14,16),(0,5),(0,6)]
_model = None
def get_model():
global _model
if _model is None:
import onnxruntime as ort
from rtmlib import Wholebody
dev = "cuda" if "CUDAExecutionProvider" in ort.get_available_providers() else "cpu"
_model = Wholebody(mode="balanced", backend="onnxruntime", device=dev)
return _model
def _openpose18(b):
"""COCO-17 -> OpenPose-COCO18 flat list (neck = shoulder midpoint)."""
neck = [(b[5][0]+b[6][0])/2, (b[5][1]+b[6][1])/2, min(b[5][2], b[6][2])]
order = [b[0], neck, b[6], b[8], b[10], b[5], b[7], b[9],
b[12], b[14], b[16], b[11], b[13], b[15], b[2], b[1], b[4], b[3]]
flat = []
for x, y, s in order:
flat += [float(x), float(y), float(s)]
return flat
@gpu
def detect(image, conf=0.3):
if image is None:
raise gr.Error("Upload a single, isolated character figure (not a sheet).")
rgb = np.array(image.convert("RGB"))
bgr = rgb[:, :, ::-1].copy()
h, w = bgr.shape[:2]
kpts, scores = get_model()(bgr)
if kpts is None or len(kpts) == 0:
raise gr.Error("No person detected. Use a clean front T/A-pose crop.")
p = int(np.argmax(scores.mean(axis=1)))
kp, sc = kpts[p], scores[p]
body = [[float(kp[i][0]), float(kp[i][1]), float(sc[i])] for i in range(17)]
out = {
"format": "coco17",
"canvas_width": int(w), "canvas_height": int(h),
"keypoints": body,
"people": [{"pose_keypoints_2d": _openpose18(body)}],
"model": "rtmlib.Wholebody(balanced)",
}
prev = rgb.copy()
r = max(3, w // 200); lw = max(2, w // 300)
for x, y, s in body:
if s >= conf:
cv2.circle(prev, (int(x), int(y)), r, (61, 240, 224), -1)
for a, b in SKELETON:
if body[a][2] >= conf and body[b][2] >= conf:
cv2.line(prev, (int(body[a][0]), int(body[a][1])),
(int(body[b][0]), int(body[b][1])), (255, 61, 127), lw)
path = os.path.join(tempfile.gettempdir(), "rigpose.json")
with open(path, "w") as f:
json.dump(out, f, indent=2)
return prev, path
with gr.Blocks(title="Alpeccaai Pose") as demo:
gr.Markdown(
"# Alpeccaai Pose β€” DWPose keypoints\n"
"Upload **one isolated character figure** (front T/A-pose is best β€” *not* a "
"multi-pose reference sheet). Returns whole-body 2D keypoints as JSON for "
"RIGFORGE β†’ **AI keypoints β†’ Import pose keypoints**, or call `/detect` from "
"the in-tool **Detect via HF Space** button."
)
with gr.Row():
inp = gr.Image(type="pil", label="Single character figure")
with gr.Column():
conf = gr.Slider(0.0, 1.0, value=0.3, label="Keypoint confidence threshold")
btn = gr.Button("Detect", variant="primary")
with gr.Row():
out_img = gr.Image(label="Detected skeleton")
out_file = gr.File(label="rigpose.json")
btn.click(detect, inputs=[inp, conf], outputs=[out_img, out_file], api_name="detect")
if __name__ == "__main__":
demo.launch()