File size: 3,578 Bytes
030a8a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a2bc821
030a8a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152c512
030a8a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152c512
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import spaces  # MUST come before torch / any CUDA-touching import
import torch
import torchvision.transforms as T
import gradio as gr
import numpy as np
import cv2
from PIL import Image
from copy import deepcopy
from detrpose import DETR

# Load the model at module scope, .to("cuda") eagerly.
model = DETR(model="detrpose_hgnetv2_l", device="cuda")

transforms = T.Compose(
    [
        T.Resize((640, 640)),
        T.ToTensor(),
    ]
)


@spaces.GPU(duration=30)
def predict(image: "Image.Image", threshold: float = 0.5) -> "Image.Image":
    """Detect multi-person poses in an image using DETRPose-L.

    Args:
        image: Input PIL image.
        threshold: Confidence threshold for keeping detected poses.
    """
    if image is None:
        return None

    im_pil = image.convert("RGB")

    w, h = im_pil.size
    orig_size = torch.tensor([[w, h]]).to("cuda")

    im_data = transforms(im_pil).unsqueeze(0).to("cuda")

    with torch.no_grad():
        outputs = model.model.model(im_data)
        results = model.model.postprocessor(outputs, orig_size)

    scores, labels, keypoints = results
    scores = scores[0].detach().cpu().numpy()
    keypoints = keypoints[0].detach().cpu().numpy()

    idx = scores > threshold
    valid_keypoints = keypoints[idx]

    im_cv2 = cv2.cvtColor(np.array(im_pil), cv2.COLOR_RGB2BGR)
    model.annotator.draw_on(im_cv2, valid_keypoints)

    result_rgb = cv2.cvtColor(im_cv2, cv2.COLOR_BGR2RGB)
    return Image.fromarray(result_rgb)


CSS = """
#col-container { max-width: 1100px; margin: 0 auto; }
.dark .gradio-container { color: var(--body-text-color); }
"""

with gr.Blocks() as demo:
    with gr.Column(elem_id="col-container"):
        gr.Markdown(
            "# DETRPose: Real-Time Multi-Person Pose Estimation\n"
            "Upload an image to detect human poses with skeleton keypoints overlaid. "
            "Powered by [DETRPose-L](https://huggingface.co/SebasJanampa/DETRPose_L_COCO) — "
            "the first real-time end-to-end transformer for multi-person pose estimation."
        )

        with gr.Row():
            with gr.Column(scale=1):
                input_image = gr.Image(
                    type="pil", label="Input Image", sources=["upload", "clipboard"]
                )
                threshold_slider = gr.Slider(
                    minimum=0.1,
                    maximum=0.9,
                    value=0.5,
                    step=0.05,
                    label="Confidence Threshold",
                )
                run_btn = gr.Button("Run", variant="primary")

            with gr.Column(scale=1):
                output_image = gr.Image(
                    type="pil", label="Pose Estimation Result"
                )

        with gr.Accordion("Advanced settings", open=False):
            gr.Markdown(
                "**Confidence Threshold**: Lower this to detect more poses (may include "
                "false positives). Raise it for stricter, more confident detections."
            )

        gr.Examples(
            examples=[
                ["example1.jpg", 0.5],
                ["example2.jpg", 0.5],
            ],
            inputs=[input_image, threshold_slider],
            outputs=output_image,
            fn=predict,
            cache_examples=True,
            cache_mode="lazy",
        )

    run_btn.click(
        fn=predict,
        inputs=[input_image, threshold_slider],
        outputs=output_image,
        api_name="predict",
    )

if __name__ == "__main__":
    demo.launch(mcp_server=True, theme=gr.themes.Citrus(), css=CSS)