|
|
""" |
|
|
OpenPose Preprocessor for ControlNet |
|
|
A simple Gradio application for pose detection. |
|
|
""" |
|
|
|
|
|
import gradio as gr |
|
|
import numpy as np |
|
|
from PIL import Image |
|
|
import torch |
|
|
|
|
|
|
|
|
DEVICE = "cuda" if torch.cuda.is_available() else "cpu" |
|
|
print(f"Using device: {DEVICE}") |
|
|
|
|
|
|
|
|
_openpose_detector = None |
|
|
_dwpose_detector = None |
|
|
|
|
|
|
|
|
def get_openpose_detector(): |
|
|
"""Get or create OpenPose detector.""" |
|
|
global _openpose_detector |
|
|
if _openpose_detector is None: |
|
|
from controlnet_aux import OpenposeDetector |
|
|
_openpose_detector = OpenposeDetector.from_pretrained("lllyasviel/Annotators") |
|
|
return _openpose_detector |
|
|
|
|
|
|
|
|
def get_dwpose_detector(): |
|
|
"""Get or create DWPose detector using easy-dwpose.""" |
|
|
global _dwpose_detector |
|
|
if _dwpose_detector is None: |
|
|
from easy_dwpose import DWposeDetector |
|
|
_dwpose_detector = DWposeDetector(device=DEVICE) |
|
|
return _dwpose_detector |
|
|
|
|
|
|
|
|
def detect_pose(image, model_type, detect_hand, detect_face, detect_resolution): |
|
|
"""Main pose detection function.""" |
|
|
if image is None: |
|
|
return None |
|
|
|
|
|
try: |
|
|
|
|
|
if isinstance(image, np.ndarray): |
|
|
image = Image.fromarray(image) |
|
|
|
|
|
|
|
|
if image.mode != "RGB": |
|
|
image = image.convert("RGB") |
|
|
|
|
|
|
|
|
original_size = image.size |
|
|
ratio = detect_resolution / max(original_size) |
|
|
new_size = (int(original_size[0] * ratio), int(original_size[1] * ratio)) |
|
|
image_resized = image.resize(new_size, Image.Resampling.LANCZOS) |
|
|
|
|
|
|
|
|
if model_type == "DWPose": |
|
|
detector = get_dwpose_detector() |
|
|
result = detector( |
|
|
image_resized, |
|
|
output_type="pil", |
|
|
include_hands=detect_hand, |
|
|
include_face=detect_face |
|
|
) |
|
|
elif model_type == "OpenPose (Full)": |
|
|
detector = get_openpose_detector() |
|
|
result = detector( |
|
|
image_resized, |
|
|
hand_and_face=True, |
|
|
output_type="pil" |
|
|
) |
|
|
elif model_type == "OpenPose (Face Only)": |
|
|
detector = get_openpose_detector() |
|
|
result = detector( |
|
|
image_resized, |
|
|
include_body=False, |
|
|
include_hand=False, |
|
|
include_face=True, |
|
|
output_type="pil" |
|
|
) |
|
|
elif model_type == "OpenPose (Hand)": |
|
|
detector = get_openpose_detector() |
|
|
result = detector( |
|
|
image_resized, |
|
|
include_body=True, |
|
|
include_hand=True, |
|
|
include_face=False, |
|
|
output_type="pil" |
|
|
) |
|
|
else: |
|
|
|
|
|
detector = get_openpose_detector() |
|
|
result = detector( |
|
|
image_resized, |
|
|
hand_and_face=detect_hand and detect_face, |
|
|
output_type="pil" |
|
|
) |
|
|
|
|
|
|
|
|
if result is not None and hasattr(result, 'size') and result.size != original_size: |
|
|
result = result.resize(original_size, Image.Resampling.LANCZOS) |
|
|
|
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Error during processing: {str(e)}") |
|
|
import traceback |
|
|
traceback.print_exc() |
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks( |
|
|
title="𦴠OpenPose Preprocessor", |
|
|
theme=gr.themes.Soft() |
|
|
) as demo: |
|
|
|
|
|
gr.Markdown( |
|
|
""" |
|
|
# 𦴠OpenPose Preprocessor for ControlNet |
|
|
|
|
|
High-quality pose detection with multiple models. Upload an image and get pose skeleton for ControlNet. |
|
|
""" |
|
|
) |
|
|
|
|
|
gr.Markdown(f"**Device**: `{DEVICE}` {'π' if DEVICE == 'cuda' else 'π’'}") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
input_image = gr.Image(label="π· Input Image", type="pil", height=400) |
|
|
|
|
|
model_type = gr.Dropdown( |
|
|
label="π€ Model", |
|
|
choices=["DWPose", "OpenPose", "OpenPose (Full)", "OpenPose (Face Only)", "OpenPose (Hand)"], |
|
|
value="DWPose", |
|
|
info="DWPose is recommended for best accuracy" |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
detect_hand = gr.Checkbox(label="π Detect Hands", value=True) |
|
|
detect_face = gr.Checkbox(label="π Detect Face", value=True) |
|
|
|
|
|
detect_resolution = gr.Slider( |
|
|
label="π Detection Resolution", |
|
|
minimum=256, |
|
|
maximum=2048, |
|
|
value=512, |
|
|
step=64, |
|
|
info="Higher = more accurate but slower" |
|
|
) |
|
|
|
|
|
process_btn = gr.Button("π Detect Pose", variant="primary", size="lg") |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
output_image = gr.Image(label="π¨ Output Pose", type="pil", height=400) |
|
|
|
|
|
gr.Markdown( |
|
|
""" |
|
|
### π Tips |
|
|
- **DWPose** is recommended for best accuracy, especially for hands and complex poses |
|
|
- **OpenPose (Full)** detects body, face, and hands together |
|
|
- Higher **Detection Resolution** improves accuracy but increases processing time |
|
|
- The output image can be directly used with ControlNet OpenPose models |
|
|
|
|
|
### βοΈ Options |
|
|
- **Detect Hands/Face** checkboxes work with DWPose and basic OpenPose modes |
|
|
- For preset modes like "OpenPose (Full)", these options are ignored |
|
|
""" |
|
|
) |
|
|
|
|
|
process_btn.click( |
|
|
fn=detect_pose, |
|
|
inputs=[input_image, model_type, detect_hand, detect_face, detect_resolution], |
|
|
outputs=[output_image] |
|
|
) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=7860 |
|
|
) |
|
|
|