postprocess
This commit is contained in:
parent
8fb4f8753d
commit
fef7bbbc8e
File diff suppressed because it is too large
Load Diff
97
app.py
97
app.py
|
@ -3,14 +3,94 @@ import hashlib
|
|||
import json
|
||||
import random
|
||||
import uuid
|
||||
import cv2
|
||||
from flask import Flask, request, jsonify
|
||||
import sys
|
||||
import os
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
import numpy as np
|
||||
import websocket
|
||||
import openpose_gen as opg
|
||||
|
||||
from comfy_socket import get_images
|
||||
from postprocessing import expo_shuffle_image_steps, expo_add_to_background_image
|
||||
sys.path.append('./')
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
info = json.load(open('info.json'))
|
||||
|
||||
comfyui_address = info['comfyui_address']
|
||||
expo_raw_sd_dir = info['expo_raw_sd_dir']
|
||||
expo_openpose_dir = info['expo_openpose_dir']
|
||||
expo_postprocessed_dir = info['expo_postprocessed_dir']
|
||||
expo_postprocess_temp_dir = info['expo_postprocess_temp_dir']
|
||||
|
||||
@app.route('/expo_fencing_pose', methods=['POST'])
|
||||
def expo_fencing_pose():
|
||||
if request.is_json:
|
||||
data = request.get_json()
|
||||
coordinates = data['coordinates']
|
||||
canvas_size = data['canvas_size']
|
||||
batch = data['batch']
|
||||
step = data['step']
|
||||
|
||||
if coordinates is None or canvas_size is None or 'batch' not in data or 'step' not in data:
|
||||
return jsonify({"status": "error", "message": "Missing data"}), 422
|
||||
|
||||
openpose_image_path = opg.expo_save_bodypose(canvas_size[0], canvas_size[1], coordinates, batch, step)
|
||||
print(openpose_image_path)
|
||||
expo_fencer_prompt(openpose_image_path, batch, step)
|
||||
|
||||
return jsonify({"status": "success", "message": "Data received"}), 201
|
||||
else:
|
||||
return jsonify({"status": "error", "message": "Request must be JSON"}), 415
|
||||
|
||||
def expo_fencer_prompt(openpose_image_path, batch, step):
|
||||
|
||||
prompt = json.loads(open("./prompts/fencer_03.json", "r", encoding="utf-8").read())
|
||||
|
||||
openpose_image_name = opg.upload_image(openpose_image_path)
|
||||
opg.upload_image("./images/ref_black.png", "ref_black.png")
|
||||
|
||||
print(openpose_image_name)
|
||||
|
||||
prompt["3"]["inputs"]["seed"] = random.randint(0, 10000000000)
|
||||
prompt["29"]["inputs"]['image'] = "ref_black.png"
|
||||
prompt["17"]["inputs"]['image'] = openpose_image_name
|
||||
|
||||
client_id = hashlib.sha256(str(random.getrandbits(256)).encode('utf-8')).hexdigest()
|
||||
ws = websocket.WebSocket()
|
||||
ws.connect("ws://{}/ws?clientId={}".format(comfyui_address, client_id))
|
||||
images = get_images(ws, prompt, client_id)
|
||||
for node_id in images:
|
||||
for idx, image_data in enumerate(images[node_id]):
|
||||
image = Image.open(io.BytesIO(image_data))
|
||||
image_path = os.path.join(expo_raw_sd_dir, f"{batch}_{step}.png")
|
||||
image.save(image_path)
|
||||
|
||||
def expo_clear_images():
|
||||
for file in os.listdir(expo_openpose_dir):
|
||||
os.remove(os.path.join(expo_openpose_dir, file))
|
||||
for file in os.listdir(expo_raw_sd_dir):
|
||||
os.remove(os.path.join(expo_raw_sd_dir, file))
|
||||
|
||||
@app.route('/expo_postprocess', methods=['POST'])
|
||||
def expo_postprocess():
|
||||
print("Postprocessing")
|
||||
os.makedirs(expo_postprocess_temp_dir, exist_ok=True)
|
||||
|
||||
shuffled_images_paths = expo_shuffle_image_steps()
|
||||
background_path = os.path.join(expo_postprocess_temp_dir, 'background.png')
|
||||
if not os.path.exists(background_path):
|
||||
background = np.zeros((1000, 1500, 3), dtype=np.uint8)
|
||||
cv2.imwrite(background_path, background)
|
||||
|
||||
expo_add_to_background_image(background_path, shuffled_images_paths[0][0], 0, 0)
|
||||
cv2.imwrite(os.path.join(expo_postprocessed_dir, 'postprocessed.png'), background)
|
||||
|
||||
# expo_clear_images()
|
||||
|
||||
@app.route('/gen_image', methods=['POST'])
|
||||
def gen_image():
|
||||
if request.is_json:
|
||||
|
@ -23,7 +103,7 @@ def gen_image():
|
|||
return jsonify({"status": "error", "message": "Missing data"}), 422
|
||||
|
||||
openpose_image_path = opg.save_bodypose(canvas_size[0], canvas_size[1], coordinates, pid)
|
||||
# gen_fencer_prompt(openpose_image_path, pid, opg.server_address)
|
||||
# gen_fencer_prompt(openpose_image_path, pid, comfyui_address)
|
||||
|
||||
return jsonify({"status": "success", "message": "Data received"}), 201
|
||||
else:
|
||||
|
@ -46,14 +126,12 @@ def gen_group_pic():
|
|||
coordinates_list[i] = coordinates_list[i]['coordinates']
|
||||
|
||||
openpose_image_path = opg.save_bodypose_mulit(canvas_size[0], canvas_size[1], coordinates_list, pid)
|
||||
gen_group_pic_prompt(openpose_image_path, base_image, pid, opg.server_address)
|
||||
gen_group_pic_prompt(openpose_image_path, base_image, pid, comfyui_address)
|
||||
|
||||
return jsonify({"status": "success", "message": "Data received"}), 201
|
||||
else:
|
||||
return jsonify({"status": "error", "message": "Request must be JSON"}), 415
|
||||
|
||||
|
||||
|
||||
def gen_fencer_prompt(openpose_image_path, pid, comfyUI_address):
|
||||
with open("./prompts/fencerAPI.json", "r") as f:
|
||||
prompt_json = f.read()
|
||||
|
@ -81,6 +159,9 @@ def gen_group_pic_prompt(openpose_image_path, base_image, pid, comfyUI_address):
|
|||
prompt["14"]["inputs"]['image'] = base_image_name
|
||||
|
||||
opg.queue_prompt(prompt, comfyUI_address)
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
expo_postprocess()
|
||||
# app.run(debug=True)
|
|
@ -0,0 +1,48 @@
|
|||
import random
|
||||
import websocket #NOTE: websocket-client (https://github.com/websocket-client/websocket-client)
|
||||
import uuid
|
||||
import json
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
|
||||
server_address = "127.0.0.1:8188"
|
||||
|
||||
def queue_prompt(prompt, client_id):
|
||||
p = {"prompt": prompt, "client_id": client_id}
|
||||
data = json.dumps(p).encode('utf-8')
|
||||
req = urllib.request.Request("http://{}/prompt".format(server_address), data=data)
|
||||
return json.loads(urllib.request.urlopen(req).read())
|
||||
|
||||
|
||||
def get_image(filename, subfolder, folder_type):
|
||||
data = {"filename": filename, "subfolder": subfolder, "type": folder_type}
|
||||
url_values = urllib.parse.urlencode(data)
|
||||
with urllib.request.urlopen("http://{}/view?{}".format(server_address, url_values)) as response:
|
||||
return response.read()
|
||||
|
||||
def get_history(prompt_id):
|
||||
with urllib.request.urlopen("http://{}/history/{}".format(server_address, prompt_id)) as response:
|
||||
return json.loads(response.read())
|
||||
|
||||
def get_images(ws, prompt, client_id):
|
||||
prompt_id = queue_prompt(prompt, client_id)['prompt_id']
|
||||
output_images = {}
|
||||
current_node = ""
|
||||
while True:
|
||||
out = ws.recv()
|
||||
if isinstance(out, str):
|
||||
message = json.loads(out)
|
||||
if message['type'] == 'executing':
|
||||
data = message['data']
|
||||
if data['prompt_id'] == prompt_id:
|
||||
if data['node'] is None:
|
||||
break #Execution is done
|
||||
else:
|
||||
current_node = data['node']
|
||||
else:
|
||||
if current_node == 'save_image_websocket_node':
|
||||
images_output = output_images.get(current_node, [])
|
||||
images_output.append(out[8:])
|
||||
output_images[current_node] = images_output
|
||||
|
||||
return output_images
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"comfyui_address": "localhost:8188",
|
||||
"expo_raw_sd_dir": "output/expo_raw_sd",
|
||||
"expo_openpose_dir": "output/expo_openpose",
|
||||
"expo_postprocessed_dir": "output/expo_postprocessed",
|
||||
"expo_postprocess_temp_dir": "output/expo_postprocess_temp"
|
||||
}
|
|
@ -13,12 +13,29 @@ import sys
|
|||
import hashlib
|
||||
sys.path.append('./')
|
||||
|
||||
server_address = "localhost:8188"
|
||||
# read json from info.json
|
||||
info = json.load(open('info.json'))
|
||||
server_address = info['comfyui_address']
|
||||
expo_openpose_dir = info['expo_openpose_dir']
|
||||
|
||||
def coordinates_to_keypoints(coordinates: list) -> List[skel.Keypoint]:
|
||||
keypoints = [skel.Keypoint(coordinates[i], coordinates[i + 1]) for i in range(0, len(coordinates), 3)]
|
||||
return keypoints
|
||||
|
||||
def expo_save_bodypose(width: int, height: int, coordinates: list, batch: int, step: int) -> None:
|
||||
canvas = np.zeros((height, width, 3), dtype=np.uint8)
|
||||
keypoints = coordinates_to_keypoints(coordinates)
|
||||
canvas = skel.draw_bodypose(canvas, keypoints, skel.coco_limbSeq, skel.coco_colors)
|
||||
|
||||
# Save as {batch}_{step}.png, {batch}_{step}.png, ...
|
||||
if not os.path.exists(expo_openpose_dir):
|
||||
os.makedirs(expo_openpose_dir)
|
||||
image_path = os.path.join(expo_openpose_dir, '%d_%d.png' % (batch, step))
|
||||
image_path = image_path.replace('\\', '/')
|
||||
cv2.imwrite(image_path, canvas)
|
||||
|
||||
return image_path
|
||||
|
||||
def save_bodypose(width: int, height: int, coordinates: list, pid: str) -> None:
|
||||
if not hasattr(save_bodypose, 'counter'):
|
||||
save_bodypose.counter = 0 # Initialize the counter attribute
|
||||
|
@ -57,13 +74,17 @@ def save_bodypose_mulit(width: int, height: int, coordinates_list: list, pid: st
|
|||
|
||||
return image_path
|
||||
|
||||
def queue_prompt(prompt, server_address):
|
||||
def queue_prompt(prompt):
|
||||
p = {"prompt": prompt}
|
||||
data = json.dumps(p).encode('utf-8')
|
||||
req = request.Request("http://{}/prompt".format(server_address), data=data)
|
||||
request.urlopen(req)
|
||||
|
||||
def upload_image(input_image, name, server_address, image_type="input", overwrite=True):
|
||||
def upload_image(input_image, image_name="", image_type="input", overwrite=True) -> str:
|
||||
if image_name == "":
|
||||
# generate a random name here
|
||||
image_name = hashlib.sha256(str(random.getrandbits(256)).encode('utf-8')).hexdigest() + ".png"
|
||||
|
||||
# Check if input_image is a valid file path
|
||||
if isinstance(input_image, str) and os.path.isfile(input_image):
|
||||
file = open(input_image, 'rb')
|
||||
|
@ -75,7 +96,7 @@ def upload_image(input_image, name, server_address, image_type="input", overwrit
|
|||
try:
|
||||
multipart_data = MultipartEncoder(
|
||||
fields={
|
||||
'image': (name, file, 'image/png'),
|
||||
'image': (image_name, file, 'image/png'),
|
||||
'type': image_type,
|
||||
'overwrite': str(overwrite).lower()
|
||||
}
|
||||
|
@ -85,12 +106,12 @@ def upload_image(input_image, name, server_address, image_type="input", overwrit
|
|||
headers = {'Content-Type': multipart_data.content_type}
|
||||
request = urllib.request.Request("http://{}/upload/image".format(server_address), data=data, headers=headers)
|
||||
with urllib.request.urlopen(request) as response:
|
||||
return response.read()
|
||||
return json.loads(response.read().decode('utf-8'))["name"]
|
||||
finally:
|
||||
if close_file:
|
||||
file.close()
|
||||
|
||||
def upload_image_circular_queue(image_path, size, unqiue_id, server_address):
|
||||
def upload_image_circular_queue(image_path, size, unqiue_id):
|
||||
# create a dict in this function to store the counter for each unique_id, key is the unique_id, value is the counter
|
||||
if not hasattr(upload_image_circular_queue, 'id_counter_dict'):
|
||||
upload_image_circular_queue.id_counter_dict = {}
|
||||
|
@ -100,7 +121,7 @@ def upload_image_circular_queue(image_path, size, unqiue_id, server_address):
|
|||
|
||||
image_name = hashlib.sha256((unqiue_id + str(upload_image_circular_queue.id_counter_dict[unqiue_id])).encode('utf-8')).hexdigest() + ".png"
|
||||
upload_image_circular_queue.id_counter_dict[unqiue_id] += 1 % size
|
||||
upload_image(image_path, image_name, server_address)
|
||||
upload_image(image_path, image_name)
|
||||
|
||||
return image_name
|
||||
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
import json
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
import subprocess
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
info = json.load(open('info.json'))
|
||||
expo_raw_sd_dir = info['expo_raw_sd_dir']
|
||||
expo_postprocessed_dir = info['expo_postprocessed_dir']
|
||||
expo_postprocess_temp_dir = info['expo_postprocess_temp_dir']
|
||||
|
||||
def expo_get_step_by_name(image_name: str) -> int:
|
||||
return int(image_name.split('_')[1].split('.')[0])
|
||||
|
||||
def expo_get_batch_by_name(image_name: str) -> int:
|
||||
return int(image_name.split('_')[0])
|
||||
|
||||
def expo_shuffle_image_steps() -> list[list[str]]:
|
||||
images = {}
|
||||
|
||||
# Read and categorize image paths by step
|
||||
for image_name in os.listdir(expo_raw_sd_dir):
|
||||
step = expo_get_step_by_name(image_name)
|
||||
image_path = os.path.join(expo_raw_sd_dir, image_name)
|
||||
if step in images:
|
||||
images[step].append(image_path)
|
||||
else:
|
||||
images[step] = [image_path]
|
||||
|
||||
# Shuffle the image paths for each step
|
||||
for step_images in images.values():
|
||||
random.shuffle(step_images)
|
||||
|
||||
# Convert the dictionary to a 2D list and find the minimum length
|
||||
shuffled_images = list(images.values())
|
||||
min_length = min(len(step_images) for step_images in shuffled_images)
|
||||
|
||||
# Crop each list to the minimum length
|
||||
shuffled_images = [step_images[:min_length] for step_images in shuffled_images]
|
||||
|
||||
# finally, get the first image of each step, put them in a list, then the second image of each step, basically transpose the list
|
||||
shuffled_images = list(map(list, zip(*shuffled_images)))
|
||||
|
||||
return shuffled_images
|
||||
|
||||
def expo_add_to_background_image(background_path: str, image_path: str, output_path: str, x: int, y: int) -> str:
|
||||
# Use ImageMagick to blend the image with the background using Linear Light blend mode
|
||||
command = [
|
||||
"magick",
|
||||
background_path,
|
||||
image_path,
|
||||
"-geometry", f"+{x}+{y}",
|
||||
"-compose", "LinearLight",
|
||||
"-composite",
|
||||
output_path
|
||||
]
|
||||
subprocess.run(command, check=True)
|
||||
|
||||
return output_path
|
||||
|
||||
def expo_add_logo(background_path: str, image_path: str, output_path: str, x: int, y: int) -> str:
|
||||
# Use ImageMagick to blend the image with the background using normal blend mode
|
||||
command = [
|
||||
"magick",
|
||||
background_path,
|
||||
image_path,
|
||||
"-geometry", f"+{x}+{y}",
|
||||
"-compose", "Over",
|
||||
"-composite",
|
||||
output_path
|
||||
]
|
||||
subprocess.run(command, check=True)
|
||||
|
||||
return output_path
|
||||
|
||||
def expo_resize_fencer(image_path: str, output_path: str, width: int, height: int) -> str:
|
||||
# Use ImageMagick to resize the image
|
||||
command = [
|
||||
"magick",
|
||||
image_path,
|
||||
"-resize", f"{width}x{height}",
|
||||
output_path
|
||||
]
|
||||
subprocess.run(command, check=True)
|
||||
return output_path
|
||||
|
||||
def expo_resize_fencers(path_list: list[str], is_left: bool, width: int, height: int) -> list[str]:
|
||||
output_dir = os.path.join(expo_postprocess_temp_dir, f"{'left' if is_left else 'right'}_fencers")
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
resized_paths = [os.path.join(output_dir, f"{i}.png") for i in range(len(path_list))]
|
||||
futures_to_index = {}
|
||||
|
||||
with ThreadPoolExecutor() as executor:
|
||||
for i, image_path in enumerate(path_list):
|
||||
output_path = resized_paths[i]
|
||||
future = executor.submit(expo_resize_fencer, image_path, output_path, width, height)
|
||||
futures_to_index[future] = i
|
||||
|
||||
for future in as_completed(futures_to_index):
|
||||
index = futures_to_index[future]
|
||||
resized_paths[index] = future.result()
|
||||
|
||||
return resized_paths
|
||||
|
||||
def expo_motion_blur_fencer(image_path: str, output_path: str, sigma: float, direction: float) -> str:
|
||||
# Use ImageMagick to apply motion blur to the image with the specified direction
|
||||
command = [
|
||||
"magick",
|
||||
image_path,
|
||||
"-motion-blur", f"0x{sigma}+{direction}",
|
||||
output_path
|
||||
]
|
||||
subprocess.run(command, check=True)
|
||||
return output_path
|
||||
|
||||
def expo_motion_blur_fencers(path_list: list[str], is_left: bool) -> list[str]:
|
||||
futures = []
|
||||
|
||||
with ThreadPoolExecutor() as executor:
|
||||
for i, image_path in enumerate(path_list):
|
||||
sigma = 15 - 15 * i / (len(path_list) - 1)
|
||||
direction = 0 if is_left else 180
|
||||
future = executor.submit(expo_motion_blur_fencer, image_path, image_path, sigma, direction)
|
||||
futures.append(future)
|
||||
|
||||
for future in as_completed(futures):
|
||||
future.result()
|
||||
|
||||
def expo_overlay_bg_gradient(image_path: str, output_path: str, bg_gradient_path: str) -> str:
|
||||
# Use ImageMagick to overlay the image with a background gradient
|
||||
command = [
|
||||
"magick",
|
||||
image_path,
|
||||
bg_gradient_path,
|
||||
"-compose", "Overlay",
|
||||
"-composite",
|
||||
output_path
|
||||
]
|
||||
subprocess.run(command, check=True)
|
||||
return output_path
|
||||
|
||||
def expo_decrese_opacity(image_path: str, output_path: str, opacity: int) -> str:
|
||||
# Use ImageMagick to decrease the opacity of the image
|
||||
command = [
|
||||
"magick",
|
||||
image_path,
|
||||
"-channel", "A",
|
||||
"-evaluate", "multiply", f"{opacity/100}",
|
||||
output_path
|
||||
]
|
||||
subprocess.run(command, check=True)
|
||||
return output_path
|
||||
|
||||
def expo_decrese_opacities(path_list: list[str]) -> list[str]:
|
||||
futures = []
|
||||
with ThreadPoolExecutor() as executor:
|
||||
for i, image_path in enumerate(path_list):
|
||||
opacity = 30 + 70 * i / (len(path_list) - 1)
|
||||
future = executor.submit(expo_decrese_opacity, image_path, image_path, opacity)
|
||||
futures.append(future)
|
||||
|
||||
for future in as_completed(futures):
|
||||
future.result()
|
||||
|
||||
def output_to_display_folder(output_image_paths):
|
||||
# copy the output images to the display folder (expo_postprocessed_dir)
|
||||
# the format is {session}_{candidate}.png, this session should be the max session from expo_postprocess_dir, the candidate should be the index of the output_image_paths
|
||||
session = str(current_session()).zfill(5)
|
||||
for i, image_path in enumerate(output_image_paths):
|
||||
candidate = str(i).zfill(5)
|
||||
output_image_path = os.path.join(expo_postprocessed_dir, f"{session}_{candidate}.png")
|
||||
# copy the image
|
||||
shutil.copy(image_path, output_image_path)
|
||||
|
||||
def current_session():
|
||||
max_session = 0
|
||||
|
||||
for file in os.listdir(expo_postprocessed_dir):
|
||||
if file.endswith(".png"):
|
||||
session = int(file.split("_")[0])
|
||||
if session > max_session:
|
||||
max_session = session
|
||||
|
||||
return max_session + 1
|
||||
|
||||
def expo_postprocess():
|
||||
print("Postprocessing")
|
||||
os.makedirs(expo_postprocess_temp_dir, exist_ok=True)
|
||||
|
||||
shuffled_images_paths = expo_shuffle_image_steps()
|
||||
background_path = os.path.join(expo_postprocess_temp_dir, 'background.png')
|
||||
logo_path = os.path.join(expo_postprocess_temp_dir, 'logo.png')
|
||||
if not os.path.exists(background_path):
|
||||
background = np.zeros((720, 1080, 3), dtype=np.uint8)
|
||||
cv2.imwrite(background_path, background)
|
||||
|
||||
bg_gradient_folder = os.path.join(expo_postprocess_temp_dir, 'bg_gradient')
|
||||
bg_gradients = [os.path.join(bg_gradient_folder, f"{i:02d}.png") for i in range(4)]
|
||||
|
||||
output_files = []
|
||||
|
||||
for i, candidate_list in enumerate(shuffled_images_paths):
|
||||
left_fencer_paths = expo_resize_fencers(candidate_list, True, 500, 500)
|
||||
expo_motion_blur_fencers(left_fencer_paths, True)
|
||||
expo_decrese_opacities(left_fencer_paths)
|
||||
|
||||
temp_output_path = os.path.join(expo_postprocess_temp_dir, f"temp_{i}.png")
|
||||
output_files.append(temp_output_path)
|
||||
temp_background_path = background_path
|
||||
for j, left_fencer_path in enumerate(left_fencer_paths):
|
||||
x_position = 65 * math.pow(j, 1.3) - 132
|
||||
y_position = 192
|
||||
expo_add_to_background_image(temp_background_path, left_fencer_path, temp_output_path, x_position, y_position)
|
||||
temp_background_path = temp_output_path
|
||||
|
||||
expo_overlay_bg_gradient(temp_output_path, temp_output_path, bg_gradients[i])
|
||||
expo_add_logo(temp_output_path, logo_path, temp_output_path, 750, 700)
|
||||
|
||||
output_to_display_folder(output_files)
|
||||
|
||||
if __name__ == '__main__':
|
||||
expo_postprocess()
|
|
@ -0,0 +1,218 @@
|
|||
{
|
||||
"3": {
|
||||
"inputs": {
|
||||
"seed": 695262830308132,
|
||||
"steps": 3,
|
||||
"cfg": 2,
|
||||
"sampler_name": "dpmpp_sde",
|
||||
"scheduler": "karras",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"32",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"22",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"22",
|
||||
1
|
||||
],
|
||||
"latent_image": [
|
||||
"5",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler",
|
||||
"_meta": {
|
||||
"title": "KSampler"
|
||||
}
|
||||
},
|
||||
"4": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaperXL_sfwLightningDPMSDE.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple",
|
||||
"_meta": {
|
||||
"title": "Load Checkpoint"
|
||||
}
|
||||
},
|
||||
"5": {
|
||||
"inputs": {
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"batch_size": 1
|
||||
},
|
||||
"class_type": "EmptyLatentImage",
|
||||
"_meta": {
|
||||
"title": "Empty Latent Image"
|
||||
}
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": "A fencer in full gear, fencing sword, 1 human, empty background, dark background, dark, empty, 1 sword, sword in hand",
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Positive)"
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"4",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode",
|
||||
"_meta": {
|
||||
"title": "VAE Decode"
|
||||
}
|
||||
},
|
||||
"17": {
|
||||
"inputs": {
|
||||
"image": "3bdafb967cede879cabdc2f1277ce5ae8fde8f4a1ff1f0c821fb9b7890bfa252.png",
|
||||
"upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage",
|
||||
"_meta": {
|
||||
"title": "Load Image"
|
||||
}
|
||||
},
|
||||
"22": {
|
||||
"inputs": {
|
||||
"strength": 0.98,
|
||||
"start_percent": 0,
|
||||
"end_percent": 1,
|
||||
"positive": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"40",
|
||||
0
|
||||
],
|
||||
"control_net": [
|
||||
"43",
|
||||
0
|
||||
],
|
||||
"image": [
|
||||
"17",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"4",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "ControlNetApplyAdvanced",
|
||||
"_meta": {
|
||||
"title": "Apply ControlNet"
|
||||
}
|
||||
},
|
||||
"28": {
|
||||
"inputs": {
|
||||
"ipadapter_file": "ip-adapter-plus_sdxl_vit-h.safetensors"
|
||||
},
|
||||
"class_type": "IPAdapterModelLoader",
|
||||
"_meta": {
|
||||
"title": "IPAdapter Model Loader"
|
||||
}
|
||||
},
|
||||
"29": {
|
||||
"inputs": {
|
||||
"image": "ref_black.png",
|
||||
"upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage",
|
||||
"_meta": {
|
||||
"title": "Load Image"
|
||||
}
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"clip_name": "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
|
||||
},
|
||||
"class_type": "CLIPVisionLoader",
|
||||
"_meta": {
|
||||
"title": "Load CLIP Vision"
|
||||
}
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"weight": 1.3,
|
||||
"weight_type": "style and composition",
|
||||
"combine_embeds": "norm average",
|
||||
"start_at": 0,
|
||||
"end_at": 1,
|
||||
"embeds_scaling": "K+V w/ C penalty",
|
||||
"model": [
|
||||
"4",
|
||||
0
|
||||
],
|
||||
"ipadapter": [
|
||||
"28",
|
||||
0
|
||||
],
|
||||
"image": [
|
||||
"29",
|
||||
0
|
||||
],
|
||||
"clip_vision": [
|
||||
"31",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "IPAdapterAdvanced",
|
||||
"_meta": {
|
||||
"title": "IPAdapter Advanced"
|
||||
}
|
||||
},
|
||||
"40": {
|
||||
"inputs": {
|
||||
"text": "blurry, drawing, horror, distorted, malformed, naked, cartoon, anime, out of focus, dull, muted colors, boring pose, no action, distracting background, colorful, (face:5.0), bad hand, (bad anatomy:5.0), worst quality, ai generated images, low quality, average quality, smoke, background, three arms, three hands, white light, (light:5.0), (shadow:5.0), (floor:5.0), 2 sword, multiple sword\n\nembedding:ac_neg1, embedding:ac_neg2, embedding:badhandv4, embedding:DeepNegative_xl_v1, embedding:NEGATIVE_HANDS, embedding:negativeXL_D, embedding:'unaestheticXL_cbp62 -neg.safetensors', embedding:verybadimagenegative_v1.3, embedding:ziprealism_neg, ",
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Negative)"
|
||||
}
|
||||
},
|
||||
"43": {
|
||||
"inputs": {
|
||||
"control_net_name": "diffusion_pytorch_model.safetensors",
|
||||
"model": [
|
||||
"4",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "DiffControlNetLoader",
|
||||
"_meta": {
|
||||
"title": "Load ControlNet Model (diff)"
|
||||
}
|
||||
},
|
||||
"save_image_websocket_node": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImageWebsocket",
|
||||
"_meta": {
|
||||
"title": "SaveImageWebsocket"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
{
|
||||
"3": {
|
||||
"inputs": {
|
||||
"seed": 695262830308132,
|
||||
"steps": 3,
|
||||
"cfg": 2,
|
||||
"sampler_name": "dpmpp_sde",
|
||||
"scheduler": "karras",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"32",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"22",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"22",
|
||||
1
|
||||
],
|
||||
"latent_image": [
|
||||
"5",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler",
|
||||
"_meta": {
|
||||
"title": "KSampler"
|
||||
}
|
||||
},
|
||||
"4": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaperXL_sfwLightningDPMSDE.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple",
|
||||
"_meta": {
|
||||
"title": "Load Checkpoint"
|
||||
}
|
||||
},
|
||||
"5": {
|
||||
"inputs": {
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"batch_size": 1
|
||||
},
|
||||
"class_type": "EmptyLatentImage",
|
||||
"_meta": {
|
||||
"title": "Empty Latent Image"
|
||||
}
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": "A fencer in full gear, fencing sword, 1 human, empty background, dark background, dark, empty, 1 sword, sword in hand",
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Positive)"
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"4",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode",
|
||||
"_meta": {
|
||||
"title": "VAE Decode"
|
||||
}
|
||||
},
|
||||
"17": {
|
||||
"inputs": {
|
||||
"image": "ef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d.png",
|
||||
"upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage",
|
||||
"_meta": {
|
||||
"title": "Load Image"
|
||||
}
|
||||
},
|
||||
"22": {
|
||||
"inputs": {
|
||||
"strength": 0.98,
|
||||
"start_percent": 0,
|
||||
"end_percent": 1,
|
||||
"positive": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"40",
|
||||
0
|
||||
],
|
||||
"control_net": [
|
||||
"43",
|
||||
0
|
||||
],
|
||||
"image": [
|
||||
"17",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"4",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "ControlNetApplyAdvanced",
|
||||
"_meta": {
|
||||
"title": "Apply ControlNet"
|
||||
}
|
||||
},
|
||||
"28": {
|
||||
"inputs": {
|
||||
"ipadapter_file": "ip-adapter-plus_sdxl_vit-h.safetensors"
|
||||
},
|
||||
"class_type": "IPAdapterModelLoader",
|
||||
"_meta": {
|
||||
"title": "IPAdapter Model Loader"
|
||||
}
|
||||
},
|
||||
"29": {
|
||||
"inputs": {
|
||||
"image": "ref_black.png",
|
||||
"upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage",
|
||||
"_meta": {
|
||||
"title": "Load Image"
|
||||
}
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"clip_name": "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
|
||||
},
|
||||
"class_type": "CLIPVisionLoader",
|
||||
"_meta": {
|
||||
"title": "Load CLIP Vision"
|
||||
}
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"weight": 1.3,
|
||||
"weight_type": "style and composition",
|
||||
"combine_embeds": "norm average",
|
||||
"start_at": 0,
|
||||
"end_at": 1,
|
||||
"embeds_scaling": "K+V w/ C penalty",
|
||||
"model": [
|
||||
"4",
|
||||
0
|
||||
],
|
||||
"ipadapter": [
|
||||
"28",
|
||||
0
|
||||
],
|
||||
"image": [
|
||||
"29",
|
||||
0
|
||||
],
|
||||
"clip_vision": [
|
||||
"31",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "IPAdapterAdvanced",
|
||||
"_meta": {
|
||||
"title": "IPAdapter Advanced"
|
||||
}
|
||||
},
|
||||
"40": {
|
||||
"inputs": {
|
||||
"text": "blurry, drawing, horror, distorted, malformed, naked, cartoon, anime, out of focus, dull, muted colors, boring pose, no action, distracting background, colorful, (face:5.0), bad hand, (bad anatomy:5.0), worst quality, ai generated images, low quality, average quality, smoke, background, three arms, three hands, white light, (light:5.0), (shadow:5.0), (floor:5.0), 2 sword, multiple sword\n\nembedding:ac_neg1, embedding:ac_neg2, embedding:badhandv4, embedding:DeepNegative_xl_v1, embedding:NEGATIVE_HANDS, embedding:negativeXL_D, embedding:'unaestheticXL_cbp62 -neg.safetensors', embedding:verybadimagenegative_v1.3, embedding:ziprealism_neg, ",
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Negative)"
|
||||
}
|
||||
},
|
||||
"43": {
|
||||
"inputs": {
|
||||
"control_net_name": "diffusion_pytorch_model.safetensors",
|
||||
"model": [
|
||||
"4",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "DiffControlNetLoader",
|
||||
"_meta": {
|
||||
"title": "Load ControlNet Model (diff)"
|
||||
}
|
||||
},
|
||||
"save_image_websocket_node": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"51",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImageWebsocket",
|
||||
"_meta": {
|
||||
"title": "SaveImageWebsocket"
|
||||
}
|
||||
},
|
||||
"51": {
|
||||
"inputs": {
|
||||
"model": "silueta",
|
||||
"alpha_matting": "true",
|
||||
"alpha_matting_foreground_threshold": 240,
|
||||
"alpha_matting_background_threshold": 20,
|
||||
"alpha_matting_erode_size": 10,
|
||||
"post_process_mask": "false",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ImageSegmentation",
|
||||
"_meta": {
|
||||
"title": "ImageSegmentation"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
"3": {
|
||||
"class_type": "KSampler",
|
||||
"inputs": {
|
||||
"cfg": 8,
|
||||
"denoise": 1,
|
||||
"latent_image": [
|
||||
"5",
|
||||
0
|
||||
],
|
||||
"model": [
|
||||
"4",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"7",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"sampler_name": "euler",
|
||||
"scheduler": "normal",
|
||||
"seed": 8566257,
|
||||
"steps": 20
|
||||
}
|
||||
},
|
||||
"4": {
|
||||
"class_type": "CheckpointLoaderSimple",
|
||||
"inputs": {
|
||||
"ckpt_name": "counterfeitxl_v25.safetensors"
|
||||
}
|
||||
},
|
||||
"5": {
|
||||
"class_type": "EmptyLatentImage",
|
||||
"inputs": {
|
||||
"batch_size": 1,
|
||||
"height": 1024,
|
||||
"width": 1024
|
||||
}
|
||||
},
|
||||
"6": {
|
||||
"class_type": "CLIPTextEncode",
|
||||
"inputs": {
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
],
|
||||
"text": "masterpiece best quality girl"
|
||||
}
|
||||
},
|
||||
"7": {
|
||||
"class_type": "CLIPTextEncode",
|
||||
"inputs": {
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
],
|
||||
"text": "bad hands"
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"class_type": "VAEDecode",
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"4",
|
||||
2
|
||||
]
|
||||
}
|
||||
},
|
||||
"save_image_websocket_node": {
|
||||
"class_type": "SaveImageWebsocket",
|
||||
"inputs": {
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
ws = websocket.WebSocket()
|
||||
ws.connect("ws://{}/ws?clientId={}".format(server_address, client_id))
|
||||
images = get_images(ws, prompt)
|
||||
for node_id in images:
|
||||
for idx, image_data in enumerate(images[node_id]):
|
||||
image = Image.open(io.BytesIO(image_data))
|
||||
image_path = os.path.join(info['expo_raw_sd_dir'], f"{node_id}_{idx}.png")
|
||||
image.save(image_path)
|
|
@ -1,13 +1,15 @@
|
|||
#This is an example that uses the websockets api and the SaveImageWebsocket node to get images directly without
|
||||
#them being saved to disk
|
||||
|
||||
import random
|
||||
import websocket #NOTE: websocket-client (https://github.com/websocket-client/websocket-client)
|
||||
import uuid
|
||||
import json
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
|
||||
server_address = "127.0.0.1:8188"
|
||||
info = json.load(open('info.json'))
|
||||
server_address = info['comfyui_address']
|
||||
client_id = str(uuid.uuid4())
|
||||
|
||||
def queue_prompt(prompt):
|
||||
|
@ -81,15 +83,15 @@ prompt_text = """
|
|||
"4": {
|
||||
"class_type": "CheckpointLoaderSimple",
|
||||
"inputs": {
|
||||
"ckpt_name": "v1-5-pruned-emaonly.safetensors"
|
||||
"ckpt_name": "counterfeitxl_v25.safetensors"
|
||||
}
|
||||
},
|
||||
"5": {
|
||||
"class_type": "EmptyLatentImage",
|
||||
"inputs": {
|
||||
"batch_size": 1,
|
||||
"height": 512,
|
||||
"width": 512
|
||||
"height": 1024,
|
||||
"width": 1024
|
||||
}
|
||||
},
|
||||
"6": {
|
||||
|
@ -137,23 +139,33 @@ prompt_text = """
|
|||
}
|
||||
"""
|
||||
|
||||
prompt = json.loads(prompt_text)
|
||||
|
||||
#set the text prompt for our positive CLIPTextEncode
|
||||
prompt["6"]["inputs"]["text"] = "masterpiece best quality man"
|
||||
|
||||
#set the seed for our KSampler node
|
||||
prompt["3"]["inputs"]["seed"] = 5
|
||||
|
||||
import os
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
prompt = json.loads(open("./prompts/fencer_02.json", "r", encoding="utf-8").read())
|
||||
# prompt["6"]["inputs"]["text"] = "masterpiece best quality man"
|
||||
prompt["3"]["inputs"]["seed"] = random.randint(0, 10000000000)
|
||||
ws = websocket.WebSocket()
|
||||
ws.connect("ws://{}/ws?clientId={}".format(server_address, client_id))
|
||||
images = get_images(ws, prompt)
|
||||
for node_id in images:
|
||||
for idx, image_data in enumerate(images[node_id]):
|
||||
image = Image.open(io.BytesIO(image_data))
|
||||
image_path = os.path.join(info['expo_raw_sd_dir'], f"{node_id}_{idx}.png")
|
||||
image.save(image_path)
|
||||
|
||||
#Commented out code to display the output images:
|
||||
|
||||
# #Commented out code to display the output images:
|
||||
# for node_id in images:
|
||||
# for image_data in images[node_id]:
|
||||
# for idx, image_data in enumerate(images[node_id]):
|
||||
# from PIL import Image
|
||||
# import io
|
||||
# image = Image.open(io.BytesIO(image_data))
|
||||
# image.show()
|
||||
# image_path = os.path.join(output_dir, f"{node_id}_{idx}.png")
|
||||
# image.save(image_path)
|
||||
|
||||
|
|
|
@ -189,25 +189,25 @@ def draw_bodypose(canvas: ndarray, keypoints: List[Keypoint], limbSeq, colors, x
|
|||
if keypoints is None or len(keypoints) == 0:
|
||||
return canvas
|
||||
|
||||
# for (k1_index, k2_index), color in zip(limbSeq, colors):
|
||||
# keypoint1 = keypoints[k1_index]
|
||||
# keypoint2 = keypoints[k2_index]
|
||||
for (k1_index, k2_index), color in zip(limbSeq, colors):
|
||||
keypoint1 = keypoints[k1_index]
|
||||
keypoint2 = keypoints[k2_index]
|
||||
|
||||
# if keypoint1 is None or keypoint2 is None or keypoint1.confidence == 0 or keypoint2.confidence == 0 or keypoint1.x <= 0 or keypoint1.y <= 0 or keypoint2.x <= 0 or keypoint2.y <= 0:
|
||||
# # if keypoint1 is None or keypoint1.confidence == 0:
|
||||
# # print(f"keypoint failed: {k1_index}")
|
||||
# # if keypoint2 is None or keypoint2.confidence == 0:
|
||||
# # print(f"keypoint failed: {k2_index}")
|
||||
# continue
|
||||
if keypoint1 is None or keypoint2 is None or keypoint1.confidence == 0 or keypoint2.confidence == 0 or keypoint1.x <= 0 or keypoint1.y <= 0 or keypoint2.x <= 0 or keypoint2.y <= 0:
|
||||
# if keypoint1 is None or keypoint1.confidence == 0:
|
||||
# print(f"keypoint failed: {k1_index}")
|
||||
# if keypoint2 is None or keypoint2.confidence == 0:
|
||||
# print(f"keypoint failed: {k2_index}")
|
||||
continue
|
||||
|
||||
# Y = np.array([keypoint1.x, keypoint2.x]) * float(W)
|
||||
# X = np.array([keypoint1.y, keypoint2.y]) * float(H)
|
||||
# mX = np.mean(X)
|
||||
# mY = np.mean(Y)
|
||||
# length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
|
||||
# angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
|
||||
# polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth*stick_scale), int(angle), 0, 360, 1)
|
||||
# cv2.fillConvexPoly(canvas, polygon, [int(float(c) * 0.6) for c in color])
|
||||
Y = np.array([keypoint1.x, keypoint2.x]) * float(W)
|
||||
X = np.array([keypoint1.y, keypoint2.y]) * float(H)
|
||||
mX = np.mean(X)
|
||||
mY = np.mean(Y)
|
||||
length = ((X[0] - X[1]) ** 2 + (Y[0] - Y[1]) ** 2) ** 0.5
|
||||
angle = math.degrees(math.atan2(X[0] - X[1], Y[0] - Y[1]))
|
||||
polygon = cv2.ellipse2Poly((int(mY), int(mX)), (int(length / 2), stickwidth*stick_scale), int(angle), 0, 360, 1)
|
||||
cv2.fillConvexPoly(canvas, polygon, [int(float(c) * 0.6) for c in color])
|
||||
|
||||
for keypoint, color in zip(keypoints, colors):
|
||||
if keypoint is None or keypoint.confidence == 0 or keypoint.x <= 0 or keypoint.y <= 0:
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
750
|
Loading…
Reference in New Issue