|
import os |
|
import io |
|
import json |
|
import numpy as np |
|
import cv2 |
|
|
|
import gradio as gr |
|
|
|
import modules.scripts as scripts |
|
from modules import script_callbacks |
|
from modules.shared import opts |
|
from modules.paths import models_path |
|
|
|
from basicsr.utils.download_util import load_file_from_url |
|
|
|
from scripts.openpose.body import Body |
|
|
|
from PIL import Image |
|
|
|
body_estimation = None |
|
presets_file = os.path.join(scripts.basedir(), "presets.json") |
|
presets = {} |
|
|
|
try: |
|
with open(presets_file) as file: |
|
presets = json.load(file) |
|
except FileNotFoundError: |
|
pass |
|
|
|
def pil2cv(in_image): |
|
out_image = np.array(in_image, dtype=np.uint8) |
|
|
|
if out_image.shape[2] == 3: |
|
out_image = cv2.cvtColor(out_image, cv2.COLOR_RGB2BGR) |
|
return out_image |
|
|
|
def candidate2li(li): |
|
res = [] |
|
for x, y, *_ in li: |
|
res.append([x, y]) |
|
return res |
|
|
|
def subset2li(li): |
|
res = [] |
|
for r in li: |
|
for c in r: |
|
res.append(c) |
|
return res |
|
|
|
class Script(scripts.Script): |
|
def __init__(self) -> None: |
|
super().__init__() |
|
|
|
def title(self): |
|
return "OpenPose Editor" |
|
|
|
def show(self, is_img2img): |
|
return scripts.AlwaysVisible |
|
|
|
def ui(self, is_img2img): |
|
return () |
|
|
|
def on_ui_tabs(): |
|
with gr.Blocks(analytics_enabled=False) as openpose_editor: |
|
with gr.Row(): |
|
with gr.Column(): |
|
width = gr.Slider(label="width", minimum=64, maximum=2048, value=512, step=64, interactive=True) |
|
height = gr.Slider(label="height", minimum=64, maximum=2048, value=512, step=64, interactive=True) |
|
with gr.Row(): |
|
add = gr.Button(value="Add", variant="primary") |
|
|
|
with gr.Row(): |
|
reset_btn = gr.Button(value="Reset") |
|
json_input = gr.UploadButton(label="Load from JSON", file_types=[".json"], elem_id="openpose_json_button") |
|
png_input = gr.UploadButton(label="Detect from Image", file_types=["image"], type="bytes", elem_id="openpose_detect_button") |
|
bg_input = gr.UploadButton(label="Add Background Image", file_types=["image"], elem_id="openpose_bg_button") |
|
with gr.Row(): |
|
preset_list = gr.Dropdown(label="Presets", choices=sorted(presets.keys()), interactive=True) |
|
preset_load = gr.Button(value="Load Preset") |
|
preset_save = gr.Button(value="Save Preset") |
|
|
|
with gr.Column(): |
|
|
|
canvas = gr.HTML('<canvas id="openpose_editor_canvas" width="512" height="512" style="margin: 0.25rem; border-radius: 0.25rem; border: 0.5px solid"></canvas>') |
|
jsonbox = gr.Text(label="json", elem_id="jsonbox", visible=False) |
|
with gr.Row(): |
|
json_output = gr.Button(value="Save JSON") |
|
png_output = gr.Button(value="Save PNG") |
|
send_t2t = gr.Button(value="Send to txt2img") |
|
send_i2i = gr.Button(value="Send to img2img") |
|
control_net_max_models_num = getattr(opts, 'control_net_max_models_num', 0) |
|
select_target_index = gr.Dropdown([str(i) for i in range(control_net_max_models_num)], label="Send to", value="0", interactive=True, visible=(control_net_max_models_num > 1)) |
|
|
|
def estimate(file): |
|
global body_estimation |
|
|
|
if body_estimation is None: |
|
model_path = os.path.join(models_path, "openpose", "body_pose_model.pth") |
|
if not os.path.isfile(model_path): |
|
body_model_path = "https://huggingface.co/lllyasviel/ControlNet/resolve/main/annotator/ckpts/body_pose_model.pth" |
|
load_file_from_url(body_model_path, model_dir=os.path.join(models_path, "openpose")) |
|
body_estimation = Body(model_path) |
|
|
|
stream = io.BytesIO(file) |
|
img = Image.open(stream) |
|
candidate, subset = body_estimation(pil2cv(img)) |
|
|
|
result = { |
|
"candidate": candidate2li(candidate), |
|
"subset": subset2li(subset), |
|
} |
|
|
|
return str(result).replace("'", '"') |
|
|
|
def savePreset(name, data): |
|
if name: |
|
presets[name] = json.loads(data) |
|
with open(presets_file, "w") as file: |
|
json.dump(presets, file) |
|
return gr.update(choices=sorted(presets.keys()), value=name), json.dumps(data) |
|
return gr.update(), gr.update() |
|
|
|
dummy_component = gr.Label(visible=False) |
|
preset = gr.Text(visible=False) |
|
width.change(None, [width, height], None, _js="(w, h) => {resizeCanvas(w, h)}") |
|
height.change(None, [width, height], None, _js="(w, h) => {resizeCanvas(w, h)}") |
|
png_output.click(None, [], None, _js="savePNG") |
|
bg_input.upload(None, [bg_input], [width, height], _js="addBackground") |
|
png_input.upload(estimate, png_input, jsonbox) |
|
png_input.upload(None, png_input, [width, height], _js="addBackground") |
|
add.click(None, [], None, _js="addPose") |
|
send_t2t.click(None, select_target_index, None, _js="(i) => {sendImage('txt2img', i)}") |
|
send_i2i.click(None, select_target_index, None, _js="(i) => {sendImage('img2img', i)}") |
|
reset_btn.click(None, [], None, _js="resetCanvas") |
|
json_input.upload(None, json_input, [width, height], _js="loadJSON") |
|
json_output.click(None, None, None, _js="saveJSON") |
|
preset_save.click(savePreset, [dummy_component, dummy_component], [preset_list, preset], _js="savePreset") |
|
preset_load.click(None, preset, [width, height], _js="loadPreset") |
|
preset_list.change(lambda selected: json.dumps(presets[selected]), preset_list, preset) |
|
|
|
return [(openpose_editor, "OpenPose Editor", "openpose_editor")] |
|
|
|
script_callbacks.on_ui_tabs(on_ui_tabs) |
|
|