包含: - hair_service_sd: 主服务(换发型/换发色/生发,端口8801) - photo_service: LoRA调度+训练(端口32678) - hair_grow_service: 调试测试页(端口8888,含4个测试页) - 批量训练脚本(batch_train_hairstyles.py) - 发际线mask自动识别(hairline_mask.py,4种方案) - 手绘mask换发型(hair_swap_manual.py) - 文档:README.md + LARGE_FILES.md + docs/ 大文件(模型权重200G、训练数据123G)已排除,见 LARGE_FILES.md OSS/COS密钥已脱敏为环境变量,原文件备份在本地
79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
import cv2
|
|
import numpy as np
|
|
|
|
import base64
|
|
import requests
|
|
from common.logger import config
|
|
|
|
version = config.get('default', 'version')
|
|
if version == "local":
|
|
webui_url = 'http://192.168.1.57:57860/'
|
|
else:
|
|
webui_url = 'http://0.0.0.0:57860/'
|
|
|
|
def encode_numpy_to_base64(img):
|
|
retval, bytes = cv2.imencode('.png', img)
|
|
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
|
return encoded_image
|
|
|
|
|
|
def webui_img2img(img, mask, prompt='', denoising_strength=0.35):
|
|
url = f"{webui_url}sdapi/v1/img2img"
|
|
request_dict = {
|
|
"prompt": prompt,
|
|
"negative_prompt": '(nsfw:1.5), ng_deepnegative_v1_75t, (badhandv4:1.2), (worst quality:2), (low quality:2), (normal quality:2), lowres, bad anatomy, bad hands, ((monochrome)), ((grayscale)) watermark, bad_pictures,easynegative',
|
|
"sampler_name": "DPM++ 2M Karras",
|
|
"batch_size": 1,
|
|
"steps": 30,
|
|
"width": img.shape[1],
|
|
"height": img.shape[0],
|
|
"cfg_scale": 7.0,
|
|
"seed": 123456789,
|
|
"mask_blur": 5,
|
|
"init_images": [
|
|
encode_numpy_to_base64(img)
|
|
],
|
|
"inpaint_full_res": False,
|
|
"inpainting_fill": 1,
|
|
"inpainting_mask_invert": 0,
|
|
"mask": encode_numpy_to_base64(mask),
|
|
"denoising_strength": denoising_strength,
|
|
"alwayson_scripts": {
|
|
}
|
|
}
|
|
response = requests.post(url=url, json=request_dict)
|
|
ret_json = response.json()
|
|
result = ret_json['images'][0]
|
|
img = cv2.imdecode(np.frombuffer(base64.b64decode(result.split(",", 1)[0]), np.uint8), cv2.IMREAD_COLOR)
|
|
return img
|
|
|
|
def webui_super_res_img(img, ratio):
|
|
url = f"{webui_url}sdapi/v1/extra-single-image"
|
|
request_dict = {
|
|
"resize_mode": 0,
|
|
"show_extras_results": False,
|
|
"gfpgan_visibility": 0,
|
|
"codeformer_visibility": 1,
|
|
"codeformer_weight": 1,
|
|
"upscaling_resize": ratio,
|
|
"upscaler_1": "8x_NMKD-Superscale_150000_G",
|
|
"upscale_first": False,
|
|
"image": encode_numpy_to_base64(img)
|
|
}
|
|
response = requests.post(url=url, json=request_dict)
|
|
ret_json = response.json()
|
|
result = ret_json['image']
|
|
img = cv2.imdecode(np.frombuffer(base64.b64decode(result), np.uint8), cv2.IMREAD_COLOR)
|
|
return img
|
|
|
|
|
|
def webui_tag_by_clip(img):
|
|
url = f"{webui_url}sdapi/v1/interrogate"
|
|
request_dict = {
|
|
"image": encode_numpy_to_base64(img),
|
|
"model": "clip"
|
|
}
|
|
response = requests.post(url=url, json=request_dict)
|
|
ret_json = response.json()
|
|
return ret_json['caption']
|