初始化:换发型/换发色/训练发型服务
包含: - 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密钥已脱敏为环境变量,原文件备份在本地
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# liveme_photo_service
|
||||
|
||||
liveme数字写真线上服务代码。依赖webui……
|
||||
@@ -0,0 +1,159 @@
|
||||
import os
|
||||
import sys
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os,sys
|
||||
from gevent import pywsgi, monkey
|
||||
|
||||
monkey.patch_all()
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
import global_variable as global_var
|
||||
import json
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route('/template/list', methods=['POST'])
|
||||
def get_template_list():
|
||||
import os
|
||||
import json
|
||||
try:
|
||||
# 读取data/template.json文件,并返回
|
||||
with open('data/template.json', 'r') as f:
|
||||
template_list = json.load(f)
|
||||
ret_dict = dict(code=0, message='success', data=template_list)
|
||||
# 返回结果作为 JSON 响应
|
||||
return jsonify(ret_dict)
|
||||
|
||||
except Exception as e:
|
||||
ret_dict = dict(code=-1, message=str(e), data=[])
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/user/list', methods=['POST'])
|
||||
def get_user_list():
|
||||
try:
|
||||
# 获取用户文件夹路径
|
||||
user_list_dir = os.path.join(global_var.service_data_dir, 'user_data')
|
||||
|
||||
ret_user_list = []
|
||||
|
||||
# 遍历查找user_list_dir目录下所有的cfg.json文件
|
||||
for root, dirs, files in os.walk(user_list_dir):
|
||||
for file in files:
|
||||
if file != 'cfg.json': continue
|
||||
json_path = os.path.join(root, file)
|
||||
lora_path = os.path.join(root, 'lora.safetensors')
|
||||
if not os.path.exists(lora_path): continue
|
||||
# 读取cfg.json文件
|
||||
with open(json_path, 'r') as f:
|
||||
user_info = json.load(f)
|
||||
user_dict = dict(user_id=user_info['user_id'], face_img_url=user_info['face_img_url'])
|
||||
ret_user_list.append(user_dict)
|
||||
|
||||
ret_dict = dict(code=0, message='success', data=ret_user_list)
|
||||
return jsonify(ret_dict)
|
||||
|
||||
except Exception as e:
|
||||
ret_dict = dict(code=-1, message='error', data=[])
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/user/generate', methods=['POST'])
|
||||
def generate_photo():
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
#判断'user_id'和'base_img'是否在请求参数中
|
||||
assert 'user_id' in request_data and 'base_img' in request_data, 'user_id and base_img is required'
|
||||
user_id = request_data['user_id']
|
||||
base_img_b64 = request_data['base_img']
|
||||
|
||||
user_path = os.path.join(global_var.service_data_dir, 'user_data', user_id)
|
||||
assert os.path.isdir(user_path), 'user_id not exist'
|
||||
user_lora = os.path.join(user_path, 'lora.safetensors')
|
||||
usr_config_path = os.path.join(user_path, 'cfg.json')
|
||||
assert os.path.exists(user_lora) and os.path.exists(usr_config_path), 'lora file or config not exist'
|
||||
|
||||
# 读取用户配置文件
|
||||
with open(usr_config_path, 'r') as f:
|
||||
user_info = json.load(f)
|
||||
lora_md5 = user_info['lora_md5']
|
||||
dst_lora_path = os.path.join(global_var.webui_lora_dir, lora_md5 + '.safetensors')
|
||||
if not os.path.exists(dst_lora_path):
|
||||
os.system(f'cp {user_lora} {dst_lora_path}')
|
||||
|
||||
#将模板图像转化为numpy数组
|
||||
prompt = f'<lora:{lora_md5}:0.8>,easyphoto_face, easyphoto, 1person,face,suit'
|
||||
neg_prompt = '(worst quality:2),(low quality:2),(normal quality:2),lowres,watermark'
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(base_img_b64), np.uint8)
|
||||
base_img = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
# base_img = cv2.resize(base_img, (512, 512))
|
||||
# cv2.imshow('image', base_img)
|
||||
# cv2.waitKey()
|
||||
|
||||
# 生成图片
|
||||
control_net = ControlnetRequestImg2Img(prompt, neg_prompt)
|
||||
control_net.build_body(dst_width=base_img.shape[1], dst_height=base_img.shape[0], cfg_scale=3.5, base_img=base_img)
|
||||
output = control_net.send_request()
|
||||
generate_photo = output['images'][0]
|
||||
|
||||
# 清理硬盘空间
|
||||
os.remove(dst_lora_path)
|
||||
|
||||
# # 将生成的图片转化为base64编码
|
||||
# retval, bytes = cv2.imencode('.png', generate_photo)
|
||||
# generate_photo = base64.b64encode(bytes).decode('utf-8')
|
||||
return jsonify(dict(code=0, message='success', generate_photo_b64=generate_photo))
|
||||
|
||||
except Exception as e:
|
||||
ret_dict = dict(code=-1, message=str(e), data=[])
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
def webd_service():
|
||||
# 用于启动webd的后台服务
|
||||
current_file_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
webd_path = os.path.join(current_file_dir, 'webd', 'webd')
|
||||
|
||||
print('webd server started...')
|
||||
cmd = f"{webd_path} -w {global_var.service_data_dir} -g rlT -l 10219"
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 服务启动的数据目录
|
||||
global_var.service_data_dir = sys.argv[1]
|
||||
|
||||
# 本地webui的lora存储目录
|
||||
global_var.webui_lora_dir = sys.argv[2]
|
||||
|
||||
# webui_server_port
|
||||
global_var.webui_server_port = int(sys.argv[3])
|
||||
|
||||
# server_port
|
||||
global_var.server_port = int(sys.argv[4])
|
||||
|
||||
# 检查webui_lora_dir目录是否存在
|
||||
assert os.path.isdir(global_var.webui_lora_dir), 'webui_lora_dir should be a directory'
|
||||
|
||||
# 检查service_data_dir目录是否存在
|
||||
if not os.path.exists(global_var.service_data_dir):
|
||||
os.makedirs(global_var.service_data_dir, exist_ok=True)
|
||||
else:
|
||||
assert os.path.isdir(global_var.service_data_dir), 'service_data_dir should be a directory'
|
||||
|
||||
# 启动服务
|
||||
# app.run(debug=False, port=global_var.server_port, host='0.0.0.0')
|
||||
|
||||
server = pywsgi.WSGIServer(('0.0.0.0', global_var.server_port), app) # test port
|
||||
server.serve_forever()
|
||||
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
|
||||
if __name__ == '__main__':
|
||||
in_dir = "/mnt/database2/jiangqian/0808/online_orig_train_datas_2"
|
||||
out_dir = "/mnt/database2/jiangqian/0808/online_train_datas_2"
|
||||
|
||||
dirs = os.listdir(in_dir)
|
||||
|
||||
for single_dir in dirs:
|
||||
if "traindata" in single_dir:
|
||||
in_single_dir = os.path.join(in_dir, single_dir)
|
||||
out_single_dir = os.path.join(out_dir, single_dir)
|
||||
|
||||
if not os.path.exists(out_single_dir):
|
||||
os.makedirs(out_single_dir)
|
||||
|
||||
images_dir = os.path.join(out_single_dir, "images")
|
||||
if not os.path.exists(images_dir):
|
||||
os.makedirs(images_dir)
|
||||
|
||||
hairstyle_dir = os.path.join(images_dir, "1_hairstyle")
|
||||
if not os.path.exists(hairstyle_dir):
|
||||
os.makedirs(hairstyle_dir)
|
||||
|
||||
for root, dirs, files in os.walk(in_single_dir):
|
||||
for file in files:
|
||||
in_file = os.path.join(root, file)
|
||||
out_file = os.path.join(hairstyle_dir, file)
|
||||
os.system("cp %s %s" % (in_file, out_file))
|
||||
print("copy %s to %s" % (in_file, out_file))
|
||||
|
||||
|
||||
Executable
+247
@@ -0,0 +1,247 @@
|
||||
import cv2
|
||||
import os
|
||||
import numpy as np
|
||||
import tqdm
|
||||
|
||||
from utils import landmark_processor
|
||||
import base64
|
||||
import requests
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
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=''):
|
||||
url = "http://127.0.0.1:57860/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, large breast, big breast, bad_pictures,easynegative, faceless, no human, white background, simple background, ',
|
||||
"sampler_name": "DPM++ 2M Karras",
|
||||
"batch_size": 1,
|
||||
"steps": 20,
|
||||
"width": img.shape[1],
|
||||
"height": img.shape[0],
|
||||
"cfg_scale": 7.0,
|
||||
"seed": 123456789,
|
||||
"mask_blur": 11,
|
||||
"init_images": [
|
||||
encode_numpy_to_base64(img)
|
||||
],
|
||||
"inpaint_full_res": False,
|
||||
"inpainting_fill": 1,
|
||||
"inpainting_mask_invert": 0,
|
||||
"mask": encode_numpy_to_base64(mask),
|
||||
# "refiner_checkpoint":"majicmixRealistic_v7.safetensors",
|
||||
# "refiner_switch_at": 0.4,
|
||||
"denoising_strength": 0.7,
|
||||
"alwayson_scripts": {
|
||||
# "controlnet": {
|
||||
# "args": [
|
||||
# {
|
||||
# "enabled": True,
|
||||
# "module": "openpose_full",
|
||||
# "model": "openpose",
|
||||
# "weight": 1.0,
|
||||
# # "image": self.read_image(),
|
||||
# "resize_mode": "Crop and Resize",
|
||||
# "low_vram": False,
|
||||
# "processor_res": 512,
|
||||
# "guidance_start": 0.0,
|
||||
# "guidance_end": 1.0,
|
||||
# "control_mode": "Balanced",
|
||||
# "pixel_perfect": False
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
}
|
||||
}
|
||||
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 = "http://127.0.0.1:57860/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 = "http://127.0.0.1:57860/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']
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
hair_dir = '/mnt/database2/jiangqian/0808/exp2-data-zrn-0808/1816523294655647746'
|
||||
|
||||
data2process_list = []
|
||||
|
||||
# 遍历查找hair_dir下的所有npy文件
|
||||
for root, dirs, files in os.walk(hair_dir):
|
||||
for file in files:
|
||||
if file.endswith('.npy'):
|
||||
# 关键点路径
|
||||
pt1k_path = os.path.join(root, file)
|
||||
origin_img_path = pt1k_path[:-4] + '.png'
|
||||
origin_matting_path = pt1k_path[:-4] + '_origin_matting.png'
|
||||
new_matting_path = pt1k_path[:-4] + '_new_matting.png'
|
||||
result_img_path = pt1k_path[:-4] + '_res.png'
|
||||
# 判断上面的文件是否存在
|
||||
if (not os.path.exists(origin_img_path) or not os.path.exists(origin_matting_path)
|
||||
or not os.path.exists(new_matting_path) or not os.path.exists(result_img_path)):
|
||||
continue
|
||||
|
||||
ref_hair_path = pt1k_path[:-4] + '_orig_hair.png'
|
||||
# if not os.path.exists(ref_hair_path):
|
||||
# continue
|
||||
lora_model_path = pt1k_path[:-4] + '_hairstyle_lora.safetensors'
|
||||
# if not os.path.exists(lora_model_path):
|
||||
# continue
|
||||
data2process_list.append([pt1k_path, origin_img_path, origin_matting_path,
|
||||
new_matting_path, result_img_path, ref_hair_path, lora_model_path])
|
||||
|
||||
crop_size = 768
|
||||
|
||||
webui_lora_dir = '/home/student/Documents/workspace_cxt_tianjing_hair/miaoya/webui_home/stable-diffusion-webui/models/Lora'
|
||||
for pt1k_path, origin_img_path, origin_matting_path, new_matting_path, result_img_path, ref_hair_path, lora_model_path in tqdm.tqdm(data2process_list):
|
||||
# if '508417f3-2c71-45cf-a75b-969b27ec7d8f' not in pt1k_path: continue
|
||||
# 读取关键点
|
||||
pt1k = np.load(pt1k_path)
|
||||
# 读取原图
|
||||
origin_img = cv2.imread(origin_img_path)
|
||||
tmp_scale = 1920 / max(origin_img.shape[0], origin_img.shape[1])
|
||||
if tmp_scale < 1.0:
|
||||
origin_img = cv2.resize(origin_img, (0, 0), fx=tmp_scale, fy=tmp_scale, interpolation=cv2.INTER_LANCZOS4)
|
||||
|
||||
print("origin_img shape:", origin_img.shape)
|
||||
# cv2.imshow("origin_img", origin_img)
|
||||
|
||||
# 读取原图抠图
|
||||
origin_matting = cv2.imread(origin_matting_path, cv2.IMREAD_GRAYSCALE)
|
||||
# 读取新图抠图
|
||||
new_matting = cv2.imread(new_matting_path, cv2.IMREAD_GRAYSCALE)
|
||||
# 读取结果图
|
||||
result_img = cv2.imread(result_img_path)
|
||||
print("result_img shape:", result_img.shape)
|
||||
# cv2.imshow("result_img", result_img)
|
||||
# # 读取参考头发
|
||||
# ref_hair = cv2.imread(ref_hair_path)
|
||||
# if max(ref_hair.shape[:2]) < 300: continue
|
||||
|
||||
|
||||
# 如何图像不清晰,进行超分辨率处理
|
||||
# if max(origin_img.shape[:2]) < 1500:
|
||||
# scale_ratio = 2000 / max(origin_img.shape[:2])
|
||||
# result_img = webui_super_res_img(result_img, scale_ratio)
|
||||
# origin_img = cv2.resize(origin_img, (result_img.shape[1], result_img.shape[0]),
|
||||
# interpolation=cv2.INTER_LANCZOS4)
|
||||
# origin_matting = cv2.resize(origin_matting, (result_img.shape[1], result_img.shape[0]))
|
||||
# new_matting = cv2.resize(new_matting, (result_img.shape[1], result_img.shape[0]))
|
||||
# pt1k = pt1k * scale_ratio
|
||||
|
||||
# 获取头发处理的局部区域图像
|
||||
# M = landmark_processor.get_transform_mat_hair_ratio_v1(pt1k, crop_size, ratio=0.30, h_offset=0.32)
|
||||
|
||||
scale = 768 / max(origin_img.shape[0], origin_img.shape[1])
|
||||
M = cv2.getRotationMatrix2D((0, 0), 0, scale)
|
||||
|
||||
dst_size = (int(origin_img.shape[1] * scale), int(origin_img.shape[0] * scale))
|
||||
|
||||
# 高质量的从原图中截取头发区域
|
||||
crop_origin = landmark_processor.high_quality_warpAffine(origin_img, M, dst_size)
|
||||
cv2.imwrite("./crop_origin.png", crop_origin)
|
||||
|
||||
crop_result = landmark_processor.high_quality_warpAffine(result_img, M, dst_size)
|
||||
cv2.imwrite("./crop_result.png", crop_result)
|
||||
# tmp = cv2.warpAffine(origin_img, M, dst_size, flags=cv2.INTER_AREA)
|
||||
|
||||
# 构造重绘的mask
|
||||
matting_merge = np.concatenate([origin_matting[:,:, np.newaxis], new_matting[:,:, np.newaxis]], axis=2)
|
||||
matting_merge = np.max(matting_merge, axis=2)
|
||||
# matting_merge = new_matting
|
||||
crop_matting = cv2.warpAffine(matting_merge, M, dst_size)
|
||||
mask = (crop_matting > 10).astype(np.float32)
|
||||
mask_dilate = cv2.dilate(mask, np.ones((3, 11), np.uint8))
|
||||
final_img = crop_result
|
||||
|
||||
mask_dilate = np.clip(mask_dilate * 255, 0, 255).astype(np.uint8)
|
||||
|
||||
# file_name = os.path.basename(pt1k_path)[:-4]
|
||||
# save_dir = '/home/chinatszrn/Downloads/abc/ref_hair/dst_res/style3_tmp'
|
||||
# cv2.imwrite(os.path.join(save_dir, file_name + '.png'), final_img)
|
||||
# cv2.imwrite(os.path.join(save_dir, file_name + '_mask.png'), mask_dilate)
|
||||
# # cv2.imwrite(os.path.join(save_dir, file_name + '_ref_hair.png'), ref_hair)
|
||||
# continue
|
||||
|
||||
# # 拷贝lora模型
|
||||
# os.system('cp {} {}'.format(lora_model_path, webui_lora_dir))
|
||||
# # 构建prompt提示词
|
||||
# lora_model_name = os.path.basename(pt1k_path)[:-4]
|
||||
|
||||
# 对final_img进行打标
|
||||
# tag_result = webui_tag_by_clip(final_img)
|
||||
tag_result = ''
|
||||
|
||||
# 开始重绘
|
||||
prompt = f'<lora:1816523294655647746_hairstyle_lora:1> titor hairstyle, easyphoto, ' + tag_result
|
||||
# 对发型进行重绘
|
||||
|
||||
# cv2.imshow("final_img_0", final_img)
|
||||
# cv2.imshow("mask_dilate", mask_dilate)
|
||||
# cv2.waitKey(100)
|
||||
|
||||
sd_result = webui_img2img(final_img, mask_dilate, prompt)
|
||||
|
||||
final_img = origin_img.copy()
|
||||
# 将重绘结果恢复到原图
|
||||
M_inv = cv2.invertAffineTransform(M)
|
||||
cv2.warpAffine(sd_result, M_inv, (final_img.shape[1], final_img.shape[0]), dst=final_img,
|
||||
borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.INTER_LANCZOS4)
|
||||
|
||||
# cv2.imshow("final_img", final_img)
|
||||
# cv2.waitKey(0)
|
||||
cv2.imwrite(result_img_path[:-4] + '_sd.png', final_img)
|
||||
|
||||
# ref_hair_scale = final_img.shape[0] / ref_hair.shape[0]
|
||||
# ref_hair = cv2.resize(ref_hair, (0, 0), fx=ref_hair_scale, fy=ref_hair_scale, interpolation=cv2.INTER_LANCZOS4)
|
||||
# img2show = np.concatenate([origin_img, ref_hair, final_img], axis=1)
|
||||
#
|
||||
# # 显示结果
|
||||
# save_dir = '/home/chinatszrn/Downloads/exp'
|
||||
# cv2.imwrite(os.path.join(save_dir, lora_model_name + '.png'), img2show)
|
||||
# # cv2.imshow("origin_img", cv2.resize(img2show, (0, 0), fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA))
|
||||
# cv2.imshow("sd_result", cv2.resize(sd_result, (0, 0), fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA))
|
||||
# cv2.waitKey(1000)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# 服务数据目录
|
||||
service_data_dir = None
|
||||
|
||||
# 生成视频的thread_num
|
||||
video_generation_thread_num = None
|
||||
|
||||
# avatar训练的thread_num
|
||||
avatar_train_thread_num = None
|
||||
|
||||
# 视频生成的任务队列
|
||||
video_generation_task_sq = None
|
||||
|
||||
# avatar训练的任务队列
|
||||
avatar_train_task_sq = None
|
||||
|
||||
# webui的lora存储目录
|
||||
webui_lora_dir = None
|
||||
|
||||
# webui_server_port
|
||||
webui_server_port = None
|
||||
|
||||
# server ip address
|
||||
server_ip = None
|
||||
|
||||
# service port
|
||||
server_port = 10239
|
||||
|
||||
# 是否启动视频的硬件编码
|
||||
video_hardware_encode = True
|
||||
|
||||
#----------------------------------------------
|
||||
|
||||
# 发型lora训练队列
|
||||
hair_style_lora_train_task_sq = None
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
import base64
|
||||
import time
|
||||
|
||||
import requests
|
||||
import cv2
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
import tqdm
|
||||
|
||||
# OpenAI API Key
|
||||
api_key = "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"
|
||||
|
||||
# Function to encode the image
|
||||
def encode_image(image_path):
|
||||
img = cv2.imread(image_path)
|
||||
scale = 500.0 / min(img.shape[:2])
|
||||
img = cv2.resize(img, (0, 0), fx=scale, fy=scale)
|
||||
scaled_path = '/tmp/scaled_image.jpg'
|
||||
cv2.imwrite(scaled_path, img)
|
||||
with open(scaled_path, "rb") as image_file:
|
||||
return base64.b64encode(image_file.read()).decode('utf-8')
|
||||
|
||||
def caption_image(image_path):
|
||||
# Getting the base64 string
|
||||
base64_image = encode_image(image_path)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {api_key}"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"model": "gpt-4-vision-preview",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "As an AI image tagging expert, please provide precise tags for the hairstyle in the image, To enhance CLIP model's understanding of the content. Please provide a detailed description of the hairstyle in the image, including but not limited to the color, style, length, curliness, hairline, highlights, gradients, etc. Your tags should be accurate, non-duplicative, and within a 10-20 word count range. Tags should be comma-separated. No need to provide any safety statements or precautions."
|
||||
},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/jpeg;base64,{base64_image}",
|
||||
"detail": "low"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"max_tokens": 300
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
|
||||
tmp_json = response.json()
|
||||
return tmp_json['choices'][0]['message']['content']
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return ""
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
prompt = caption_image('/home/chinatszrn/Downloads/abc/train_data/style1/07ebac82-4c0f-4dd2-84bd-bc34a059bd9b.png')
|
||||
print(prompt)
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
import gradio as gr
|
||||
import os,re
|
||||
import numpy as np
|
||||
import requests
|
||||
import cv2
|
||||
import base64
|
||||
import json
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
api_service_url = 'http://127.0.0.1:1234'
|
||||
# api_service_url = 'http://i-2.gpushare.com:53412'
|
||||
|
||||
class ChangeFaceGui():
|
||||
def __init__(self):
|
||||
self.template_list = self.get_template_list()
|
||||
self.user_dict = self.get_user_dict()
|
||||
# self.tmp_dir = './tmp'
|
||||
# if not os.path.exists(self.tmp_dir): os.makedirs(self.tmp_dir)
|
||||
self.user_img_list = []
|
||||
# 获取户图片
|
||||
for item in self.user_dict:
|
||||
response = requests.get(item['face_img_url'])
|
||||
image_data = BytesIO(response.content)
|
||||
user_face_img = cv2.imdecode(np.frombuffer(image_data.read(), np.uint8), cv2.IMREAD_COLOR)
|
||||
self.user_img_list.append(user_face_img)
|
||||
item['face_img'] = user_face_img
|
||||
|
||||
# img_path = f'{self.tmp_dir}/{item["user_id"]}.jpg'
|
||||
# if not os.path.exists(img_path):
|
||||
# cv2.imwrite(f'{self.tmp_dir}/{item["user_id"]}.jpg', user_face_img)
|
||||
|
||||
|
||||
#请求得到模板图片的url
|
||||
def get_template_list(self):
|
||||
url = f"{api_service_url}/template/list"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print('请求模板照片成功!!')
|
||||
return(response.json()['data'])
|
||||
|
||||
|
||||
#请求得到用户图片及ID
|
||||
def get_user_dict(self):
|
||||
url = f"{api_service_url}/user/list"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
user_dict = response.json()['data']
|
||||
print('请求用户照片成功!!')
|
||||
return(user_dict)
|
||||
|
||||
|
||||
#获取用户ID
|
||||
def get_user_id(self, user_img):
|
||||
user_small_img = cv2.resize(user_img, (100, 100))
|
||||
mse = []
|
||||
for item in self.user_dict:
|
||||
user_face_img = item['face_img']
|
||||
# cv2.imwrite(f'{self.tmp_dir}/{item["user_id"]}_list.jpg', user_face_img)
|
||||
user_face_img = cv2.resize(user_face_img, (100, 100))
|
||||
# 计算均方误差
|
||||
mse.append(np.mean((user_small_img - user_face_img) ** 2))
|
||||
|
||||
# 找到均方差最小值对应的ID
|
||||
user_id = mse.index(min(mse))
|
||||
user_id = self.user_dict[user_id]['user_id']
|
||||
print('用户ID:', user_id)
|
||||
return user_id
|
||||
|
||||
|
||||
#虚拟试穿模块,输入是模特图和衣服图,输出是虚拟试穿的结果
|
||||
def take_photo(self, template_img, user_img):
|
||||
# if not os.path.exists(self.tmp_dir):os.makedirs(self.tmp_dir)
|
||||
|
||||
if template_img is None or user_img is None:
|
||||
return None
|
||||
|
||||
# 使用 Pillow 加载图像
|
||||
template_img = Image.open(template_img)
|
||||
user_img = Image.open(user_img)
|
||||
|
||||
# 将 Pillow 图像转换为 OpenCV 格式(BGR)
|
||||
template_img = cv2.cvtColor(np.array(template_img), cv2.COLOR_RGB2BGR)
|
||||
user_img = cv2.cvtColor(np.array(user_img), cv2.COLOR_RGB2BGR)
|
||||
|
||||
# 将模板图片转换为base64格式
|
||||
retval, template_bytes = cv2.imencode('.jpg', template_img)
|
||||
encoded_image = base64.b64encode(template_bytes).decode('utf-8')
|
||||
user_id = self.get_user_id(user_img)
|
||||
url = f"{api_service_url}/user/generate"
|
||||
payload = json.dumps({
|
||||
"user_id": user_id,
|
||||
"base_img": encoded_image
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
print('请求api_service.py发送请求!!')
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print('请求api_service.py发送请求成功!!')
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(f"Failed to send request to API service. Status code: {response.status_code}")
|
||||
|
||||
ret_image_b64 = response.json().get('generate_photo_b64')
|
||||
|
||||
if ret_image_b64 is None:
|
||||
raise RuntimeError(f"ret image failed!")
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(ret_image_b64), np.uint8)
|
||||
result_image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
result_image = cv2.cvtColor(result_image, cv2.COLOR_BGR2RGB)
|
||||
return result_image
|
||||
|
||||
|
||||
def start_gui(self):
|
||||
user_img_list = []
|
||||
for item in self.user_img_list:
|
||||
img = cv2.cvtColor(item, cv2.COLOR_BGR2RGB)
|
||||
user_img_list.append(img)
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
with gr.Row():
|
||||
gr.Markdown("# 数字力场效果展示")
|
||||
|
||||
# 换脸
|
||||
with gr.Tab("数字写真"):
|
||||
with gr.Row():
|
||||
gr.Markdown("# 数字写真")
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
#选择模板
|
||||
template_img = gr.Image(label="模版", sources='upload', min_width=384, width=384, height=384, type="filepath", value=self.template_list[0],interactive=True)
|
||||
example_template = gr.Examples(
|
||||
inputs=template_img,
|
||||
examples_per_page=12,
|
||||
examples= self.template_list)
|
||||
with gr.Column():
|
||||
# 选择用户
|
||||
user_img = gr.Image(label="用户", sources='upload', min_width=384, width=384, height=384, type="filepath", value= user_img_list[0],interactive=False)
|
||||
example_user = gr.Examples(
|
||||
inputs=user_img,
|
||||
examples_per_page=12,
|
||||
examples=user_img_list)
|
||||
|
||||
with gr.Column():
|
||||
output_img = gr.Image(label="结果展示", type="numpy", height=576, width=384)
|
||||
with gr.Column():
|
||||
run_button = gr.Button(value="提交")
|
||||
run_button.click(self.take_photo, inputs=[template_img, user_img], outputs=[output_img])
|
||||
|
||||
# #换衣服
|
||||
# with gr.Tab("换衣"):
|
||||
# with gr.Row():
|
||||
# gr.Markdown("# 换衣")
|
||||
# text_button = gr.Button("提交")
|
||||
# # 换发型
|
||||
# with gr.Tab("换发型"):
|
||||
# with gr.Row():
|
||||
# gr.Markdown("# 换发型")
|
||||
# text_button = gr.Button("提交")
|
||||
|
||||
demo.launch(server_name='0.0.0.0', server_port=8080)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
demo = ChangeFaceGui()
|
||||
demo.start_gui()
|
||||
@@ -0,0 +1,102 @@
|
||||
import gradio as gr
|
||||
import os,re
|
||||
import numpy as np
|
||||
import requests
|
||||
import cv2
|
||||
import base64
|
||||
import json
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
# api_service_url = 'http://127.0.0.1:1234'
|
||||
# api_service_url = 'http://i-2.gpushare.com:53412'
|
||||
api_service_url = 'http://service.aicloud.fit:7393/api/hairStyle/v1'
|
||||
|
||||
class ChangeHairGui():
|
||||
# def __init__(self):
|
||||
# a = 1
|
||||
def change_hair(self, user_img, hair_img):
|
||||
|
||||
if user_img is None or user_img is None:
|
||||
return None
|
||||
#
|
||||
# if user_img.shape != hair_img.shape:
|
||||
# hair_img = cv2.resize(hair_img, (user_img.shape[1], user_img.shape[0]))
|
||||
#
|
||||
# alpha = 0.5 # 图像1的权重
|
||||
# beta = 0.5 # 图像2的权重
|
||||
# gamma = 0 # 亮度调整常量(通常为0)
|
||||
#
|
||||
# result_image = cv2.addWeighted(user_img, alpha, hair_img, beta, gamma)
|
||||
|
||||
|
||||
# 将 Pillow 图像转换为 OpenCV 格式(BGR)
|
||||
user_img = cv2.cvtColor(np.array(user_img), cv2.COLOR_RGB2BGR)
|
||||
hair_img = cv2.cvtColor(np.array(hair_img), cv2.COLOR_RGB2BGR)
|
||||
|
||||
# 将模板图片转换为base64格式
|
||||
retval, user_bytes = cv2.imencode('.jpg', user_img)
|
||||
encoded_user_image = base64.b64encode(user_bytes).decode('utf-8')
|
||||
retval, hair_bytes = cv2.imencode('.jpg', hair_img)
|
||||
encoded_hair_image = base64.b64encode(hair_bytes).decode('utf-8')
|
||||
|
||||
url = api_service_url
|
||||
|
||||
# 请求换发型接口
|
||||
payload = json.dumps({
|
||||
"user_img_base64": encoded_user_image,
|
||||
"hair_ref_img_base64": encoded_hair_image
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
print('请求api_service.py发送请求!!')
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print('请求api_service.py发送请求成功!!')
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(f"Failed to send request to API service. Status code: {response.status_code}")
|
||||
|
||||
ret_image_b64 = response.json().get('result')
|
||||
|
||||
if ret_image_b64 is None:
|
||||
raise RuntimeError(f"ret image failed!")
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(ret_image_b64), np.uint8)
|
||||
result_image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
result_image = cv2.cvtColor(result_image, cv2.COLOR_BGR2RGB)
|
||||
|
||||
dst_size = max(result_image.shape[0], result_image.shape[1])
|
||||
M = cv2.getRotationMatrix2D((result_image.shape[1] / 2, result_image.shape[0] / 2), 0, 1)
|
||||
M[:, 2] += np.float32([dst_size / 2 - result_image.shape[1] / 2, dst_size / 2 - result_image.shape[0] / 2])
|
||||
result_image = cv2.warpAffine(result_image, M, (dst_size, dst_size), borderValue=(255, 255, 255))
|
||||
|
||||
return result_image
|
||||
|
||||
|
||||
|
||||
def start_gui(self):
|
||||
with gr.Blocks() as demo:
|
||||
with gr.Row():
|
||||
gr.Markdown("# 数字力场换发型效果展示")
|
||||
|
||||
# 换脸
|
||||
with gr.Tab("换发型"):
|
||||
with gr.Row():
|
||||
gr.Markdown("#换发型")
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
user_img = gr.Image(label="请上传用户图片", type="numpy", height=384, width=384)
|
||||
with gr.Column():
|
||||
hair_img = gr.Image(label="请上传发型图片", type="numpy", height=384, width=384)
|
||||
with gr.Column():
|
||||
output_img = gr.Image(label="结果展示", type="numpy", height=384, width=384, format='png')
|
||||
with gr.Column():
|
||||
run_button = gr.Button(value="提交")
|
||||
run_button.click(self.change_hair, inputs=[user_img, hair_img], outputs=[output_img])
|
||||
|
||||
demo.launch(server_name='0.0.0.0', server_port=8080)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
demo = ChangeHairGui()
|
||||
demo.start_gui()
|
||||
@@ -0,0 +1,120 @@
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os, sys
|
||||
from gevent import pywsgi, monkey
|
||||
from multiprocessing import Process, Queue
|
||||
import glob
|
||||
|
||||
# from gpt4v_caption import caption_image
|
||||
|
||||
# monkey.patch_all()
|
||||
# sys.setrecursionlimit(20000)
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
|
||||
import global_variable as global_var
|
||||
import json
|
||||
|
||||
|
||||
|
||||
def train_hair_lora():
|
||||
import os
|
||||
import json
|
||||
|
||||
try:
|
||||
hair_train_dir = "/mnt/database2/jiangqian/0808/online_train_datas_2"
|
||||
hair_material_dir_list = os.listdir(hair_train_dir)
|
||||
|
||||
for single_hair_material in hair_material_dir_list:
|
||||
# 获取请求参数
|
||||
task_id = str(uuid.uuid4())
|
||||
|
||||
request_data = {}
|
||||
hair_material_dir = os.path.join(hair_train_dir, single_hair_material)
|
||||
print("--------------------hair_material_dir:", hair_material_dir)
|
||||
request_data['hair_material_dir'] = hair_material_dir
|
||||
|
||||
img_dir = os.path.join(hair_material_dir, 'images')
|
||||
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
if not os.path.exists(model_dir):
|
||||
os.makedirs(model_dir)
|
||||
|
||||
#判断img_dir下面是否只有一个文件夹
|
||||
img_dir_list = os.listdir(img_dir)
|
||||
train_image_dir = os.path.join(img_dir, img_dir_list[0])
|
||||
|
||||
#判断文件夹下面是否有图片
|
||||
request_data['train_image_dir'] = train_image_dir
|
||||
|
||||
# 将请求数据放入队列
|
||||
train_thread(request_data)
|
||||
|
||||
# 返回结果
|
||||
print("头发lora训练开始")
|
||||
print("\n\n\n\n")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def train_thread(task_dict):
|
||||
try:
|
||||
hair_material_dir = task_dict['hair_material_dir']
|
||||
images_dir = os.path.join(hair_material_dir, 'images')
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
train_image_dir = task_dict['train_image_dir']
|
||||
tag = ""
|
||||
|
||||
sample_dir = os.path.join(model_dir, 'sample')
|
||||
if not os.path.exists(sample_dir):
|
||||
os.makedirs(sample_dir)
|
||||
sample_txt = os.path.join(sample_dir, 'prompt.txt')
|
||||
with open(sample_txt, 'w') as f_s:
|
||||
f_s.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, '
|
||||
+ tag
|
||||
+ ' --n low quality, worst quality, bad anatomy, bad composition, poor, low effort --h 512 '
|
||||
'--w 512 --s 30 --l 7')
|
||||
|
||||
#训练头发lora
|
||||
cmd_train = (
|
||||
'docker run --rm --gpus all -v /home/student/Documents/workspace_cxt_tianjing_hair/miaoya/kohya_ss_home:/home/chinatszrn -v '
|
||||
'/mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
'--net=host chinatszrn/ubuntu:kohya_ss accelerate launch --num_cpu_threads_per_process=2 "./train_network.py" --enable_bucket '
|
||||
'--min_bucket_reso=256 --max_bucket_reso=1800 --pretrained_model_name_or_path="/mnt/nas_hdd/米亚像馆/models/Stable-diffusion/majicmixRealistic_v7.safetensors" '
|
||||
f'--train_data_dir={images_dir} --resolution="768,768" '
|
||||
f'--output_dir={model_dir} '
|
||||
'--network_alpha="64" --save_model_as=safetensors --network_module=networks.lora --text_encoder_lr=5e-05 '
|
||||
'--unet_lr=0.0001 --network_dim=128 --output_name="hairstyle_lora" --lr_scheduler_num_cycles="20" '
|
||||
'--no_half_vae --learning_rate="0.0001" --lr_scheduler="cosine" --lr_warmup_steps="650" --train_batch_size="1" '
|
||||
'--max_train_steps="2000" --save_every_n_epochs="100" --mixed_precision="fp16" --save_precision="fp16" '
|
||||
'--caption_extension=".txt" --sample_sampler=ddim '
|
||||
f'--sample_prompts={sample_txt} --sample_every_n_epochs="1" '
|
||||
'--seed="1234" --cache_latents --optimizer_type="AdamW8bit" --max_data_loader_n_workers="0" --bucket_reso_steps=64 '
|
||||
'--xformers --bucket_no_upscale --noise_offset=0.0 --tokenizer_cache_dir="/home/chinatszrn/.cache/clip"')
|
||||
print("cmd_train:", cmd_train)
|
||||
os.system(cmd_train)
|
||||
|
||||
lora_path = os.path.join(model_dir, 'hairstyle_lora.safetensors')
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
global_var.webui_lora_dir = '/home/student/Documents/workspace_cxt_tianjing_hair/miaoya/webui_home/stable-diffusion-webui/models/Lora'
|
||||
|
||||
train_hair_lora()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os, sys
|
||||
from gevent import pywsgi, monkey
|
||||
from multiprocessing import Process, Queue
|
||||
import glob
|
||||
|
||||
# from gpt4v_caption import caption_image
|
||||
|
||||
# monkey.patch_all()
|
||||
# sys.setrecursionlimit(20000)
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
import global_variable as global_var
|
||||
import json
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
def send_request(url, state, task_dict):
|
||||
import requests
|
||||
import json
|
||||
|
||||
msg = '头发lora训练失败' if state == -1 else '头发lora训练成功'
|
||||
payload = json.dumps({
|
||||
"task_id": task_dict['task_id'] if task_dict is not None else '',
|
||||
"hair_id": task_dict['hair_id'] if task_dict is not None else '',
|
||||
"state": state,
|
||||
"msg": msg,
|
||||
"is_tj": task_dict['is_tj']
|
||||
})
|
||||
|
||||
print("payload:", payload)
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
|
||||
@app.route('/api/hair/train', methods=['POST'])
|
||||
def train_hair_lora():
|
||||
import os
|
||||
import json
|
||||
task_id = ''
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
assert 'task_id' in request_data, 'task_id is required'
|
||||
task_id = request_data['task_id']
|
||||
assert 'hair_id' in request_data and 'hair_material_dir' in request_data, 'hair_id and hair_material_dir is required'
|
||||
hair_material_dir = request_data['hair_material_dir']
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
img_dir = os.path.join(hair_material_dir, 'images')
|
||||
assert os.path.exists(img_dir), f'{img_dir} not exists'
|
||||
assert os.path.exists(
|
||||
os.path.join(hair_material_dir, 'model')), f'{os.path.join(hair_material_dir, "model")} not exists'
|
||||
|
||||
#判断img_dir下面是否只有一个文件夹
|
||||
img_dir_list = os.listdir(img_dir)
|
||||
assert len(img_dir_list) == 1, f'{img_dir}下面只能有一个文件夹'
|
||||
train_image_dir = os.path.join(img_dir, img_dir_list[0])
|
||||
assert os.path.isdir(train_image_dir), f'{train_image_dir}不是文件夹'
|
||||
# 检查该文件夹是否以数字加下划线开头
|
||||
assert img_dir_list[0].split('_')[0].isdigit(), f'{img_dir_list[0]}不是数字开头'
|
||||
|
||||
#判断文件夹下面是否有图片
|
||||
img_list = glob.glob(train_image_dir + '/*.png')
|
||||
assert len(img_list) > 10, f'{os.path.join(img_dir, img_dir_list[0])}下面图片数量小于10张'
|
||||
request_data['train_image_dir'] = train_image_dir
|
||||
|
||||
# is tianjin company
|
||||
try:
|
||||
request_data['is_tj'] = request_data['is_tj']
|
||||
except Exception as e:
|
||||
print(e)
|
||||
request_data['is_tj'] = '0'
|
||||
|
||||
# 将请求数据放入队列
|
||||
global_var.hair_style_lora_train_task_sq.put(request_data)
|
||||
|
||||
# 返回结果
|
||||
ret_dict = dict(state=0, msg='头发lora训练开始', task_id=task_id)
|
||||
return jsonify(ret_dict)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e), task_id=task_id)
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/api/hair/inference', methods=['POST'])
|
||||
def inference_webui():
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
onediff_url = "http://127.0.0.1:9038/sdapi/v1/img2img"
|
||||
|
||||
try:
|
||||
t1 = time.time()
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
# hd_version_flag = request_data.get('hd_version_flag', False)
|
||||
hair_id = request_data['hair_id']
|
||||
selected_url = url
|
||||
if 'refiner_checkpoint' not in request_json:
|
||||
selected_url = onediff_url
|
||||
request_json['script_name'] = 'onediff_diffusion_model'
|
||||
print('user onediff')
|
||||
|
||||
|
||||
|
||||
# if hd_version_flag:
|
||||
# print('user hd version!!!!!')
|
||||
# lora_file_name = 'hairstyle_hd_lora.safetensors'
|
||||
# else:
|
||||
# lora_file_name = 'hairstyle_lora.safetensors'
|
||||
|
||||
hair_material_dir = request_data.get('hair_material_dir')
|
||||
print(hair_material_dir)
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
|
||||
hd_version_flag = True
|
||||
lora_file_name = 'hairstyle_hd_lora.safetensors'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', lora_file_name)
|
||||
if not os.path.exists(request_lora_path):
|
||||
print('use low resolution lora')
|
||||
hd_version_flag = False
|
||||
lora_file_name = 'hairstyle_lora.safetensors'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', lora_file_name)
|
||||
|
||||
assert os.path.exists(request_lora_path), f'{request_lora_path} not exists'
|
||||
|
||||
if hd_version_flag:
|
||||
tmp_lora_name = f'{hair_id}_hd'
|
||||
else:
|
||||
tmp_lora_name = f'{hair_id}'
|
||||
lora_dst_path = os.path.join(global_var.webui_lora_dir, f'{tmp_lora_name}.safetensors')
|
||||
if not os.path.exists(lora_dst_path):
|
||||
os.system('cp {} {}'.format(request_lora_path, lora_dst_path))
|
||||
request_json['prompt'] = f'<lora:{tmp_lora_name}:1.0>, titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
print('pre_stage cost:', time.time() - t1)
|
||||
|
||||
start_time = time.time()
|
||||
response = requests.post(url=selected_url, json=request_json)
|
||||
print('inference time:', time.time() - start_time)
|
||||
|
||||
ret_json = response.json()
|
||||
# if os.path.exists(lora_dst_path):
|
||||
# os.remove(lora_dst_path)
|
||||
# 返回结果
|
||||
return jsonify(ret_json)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e))
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/api/hair/inference_diy', methods=['POST'])
|
||||
def inference_diy_webui():
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
onediff_url = "http://127.0.0.1:9038/sdapi/v1/img2img"
|
||||
|
||||
try:
|
||||
t1 = time.time()
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
|
||||
selected_url = url
|
||||
if 'refiner_checkpoint' not in request_json:
|
||||
selected_url = onediff_url
|
||||
request_json['script_name'] = 'onediff_diffusion_model'
|
||||
print('user onediff')
|
||||
|
||||
request_json['prompt'] = f'titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
print('pre_stage cost:', time.time() - t1)
|
||||
|
||||
start_time = time.time()
|
||||
response = requests.post(url=selected_url, json=request_json)
|
||||
print('inference time:', time.time() - start_time)
|
||||
|
||||
ret_json = response.json()
|
||||
# if os.path.exists(lora_dst_path):
|
||||
# os.remove(lora_dst_path)
|
||||
# 返回结果
|
||||
return jsonify(ret_json)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e))
|
||||
return jsonify(ret_dict)
|
||||
|
||||
def train_thread(sq, gpu_id):
|
||||
while True:
|
||||
url = 'http://service.aicloud.fit:7393/api/hair/trainCallBack'
|
||||
task_dict = None
|
||||
try:
|
||||
task_dict = sq.get()
|
||||
hair_material_dir = task_dict['hair_material_dir']
|
||||
images_dir = os.path.join(hair_material_dir, 'images')
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
train_image_dir = task_dict['train_image_dir']
|
||||
# tag = task_dict['tag']
|
||||
tag = ""
|
||||
is_tj = task_dict['is_tj']
|
||||
|
||||
sample_dir = os.path.join(model_dir, 'sample')
|
||||
if not os.path.exists(sample_dir):
|
||||
os.makedirs(sample_dir)
|
||||
sample_txt = os.path.join(sample_dir, 'prompt.txt')
|
||||
with open(sample_txt, 'w') as f_s:
|
||||
f_s.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, '
|
||||
+ tag
|
||||
+ ' --n low quality, worst quality, bad anatomy, bad composition, poor, low effort --h 768 '
|
||||
'--w 768 --s 30 --l 7')
|
||||
|
||||
# 给训练图片打标签
|
||||
# cmd_caption = ('docker run --rm --gpus all -v /home/chinatszrn/Documents/miaoya/kohya_ss_home:/home/chinatszrn '
|
||||
# '-v /mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
# '--net=host chinatszrn/ubuntu:kohya_ss accelerate '
|
||||
# 'launch "./finetune/tag_images_by_wd14_tagger.py" --batch_size=2 '
|
||||
# '--general_threshold=0.5 --character_threshold=0.5 --caption_extension=".txt" '
|
||||
# '--model="SmilingWolf/wd-v1-4-convnextv2-tagger-v2" --max_data_loader_n_workers="2" '
|
||||
# '--debug --remove_underscore --frequency_tags --undesired_tags="1girl, 1boy" '
|
||||
# f'"{train_image_dir}"')
|
||||
# os.system(cmd_caption)
|
||||
|
||||
img_path_list = glob.glob(train_image_dir + '/*.png')
|
||||
# 给训练图片打标签, gpt
|
||||
for img_path in img_path_list:
|
||||
# print(img_path)
|
||||
txt_path = img_path[:-4] + '.txt'
|
||||
|
||||
print("tag img_path: ", img_path)
|
||||
# tags = caption_image(img_path)
|
||||
tags = tag
|
||||
with open(txt_path, 'w') as f:
|
||||
f.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, ' + tags)
|
||||
|
||||
#判断是否每个训练图片都有标签文件
|
||||
# for img_path in img_path_list:
|
||||
# assert os.path.exists(img_path[:-4]+'.txt'), f'{img_path}没有对应的标签文件'
|
||||
# with open(img_path[:-4]+'.txt', 'r') as f:
|
||||
# tags = f.readline()
|
||||
# with open(img_path[:-4]+'.txt', 'w') as f:
|
||||
# f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
|
||||
#训练头发lora
|
||||
cmd_train = (
|
||||
'docker run --rm --gpus "device=0" -v /home/student/Documents/workspace_cxt_tianjing_hair/miaoya/kohya_ss_home:/home/chinatszrn -v '
|
||||
'/mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
'--net=host chinatszrn/ubuntu:kohya_ss accelerate launch --num_cpu_threads_per_process=2 "./train_network.py" --enable_bucket '
|
||||
'--min_bucket_reso=256 --max_bucket_reso=2048 --pretrained_model_name_or_path="/mnt/nas_hdd/米亚像馆/models/Stable-diffusion/majicmixRealistic_v7.safetensors" '
|
||||
f'--train_data_dir={images_dir} --resolution="2000,2000" '
|
||||
f'--output_dir={model_dir} '
|
||||
'--network_alpha="64" --save_model_as=safetensors --network_module=networks.lora --text_encoder_lr=5e-05 '
|
||||
'--unet_lr=0.0001 --network_dim=128 --output_name="hairstyle_hd_lora" --lr_scheduler_num_cycles="20" '
|
||||
'--no_half_vae --learning_rate="0.0001" --lr_scheduler="cosine" --lr_warmup_steps="650" --train_batch_size="1" '
|
||||
'--max_train_steps="1500" --save_every_n_epochs="100" --mixed_precision="fp16" --save_precision="fp16" '
|
||||
'--caption_extension=".txt" --sample_sampler=ddim '
|
||||
f'--sample_prompts={sample_txt} --sample_every_n_epochs="1000" '
|
||||
'--seed="1234" --cache_latents --optimizer_type="AdamW8bit" --max_data_loader_n_workers="0" --bucket_reso_steps=64 '
|
||||
'--xformers --bucket_no_upscale --noise_offset=0.0 --tokenizer_cache_dir="/home/chinatszrn/.cache/clip"')
|
||||
print("cmd_train:", cmd_train)
|
||||
os.system(cmd_train)
|
||||
|
||||
lora_path = os.path.join(model_dir, 'hairstyle_hd_lora.safetensors')
|
||||
|
||||
# tianjin callback
|
||||
if is_tj == "1":
|
||||
url = 'http://service.aicloud.fit:7395/api/hair/trainCallBack'
|
||||
|
||||
if not os.path.exists(lora_path):
|
||||
send_request(url, -1, task_dict)
|
||||
else:
|
||||
send_request(url, 0, task_dict)
|
||||
|
||||
except Exception as e:
|
||||
send_request(url, -1, None)
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
global_var.webui_lora_dir = '/gz-fs/models/Lora'
|
||||
|
||||
# avatar训练的任务队列
|
||||
global_var.hair_style_lora_train_task_sq = Queue()
|
||||
p = Process(target=train_thread, args=(
|
||||
global_var.hair_style_lora_train_task_sq, 0))
|
||||
p.start()
|
||||
|
||||
# # 启动服务
|
||||
# app.run(debug=True, port=32678, host='0.0.0.0')
|
||||
|
||||
server = pywsgi.WSGIServer(('0.0.0.0', 32678), app) # test port
|
||||
server.serve_forever()
|
||||
@@ -0,0 +1,362 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os, sys
|
||||
from gevent import pywsgi, monkey
|
||||
from multiprocessing import Process, Queue
|
||||
import glob
|
||||
import datetime
|
||||
# from gpt4v_caption import caption_image
|
||||
|
||||
# monkey.patch_all()
|
||||
# sys.setrecursionlimit(20000)
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
import global_variable as global_var
|
||||
import json
|
||||
#from common.logger import config
|
||||
|
||||
version = "online"
|
||||
if version == "local":
|
||||
current_url = 'http://service.aicloud.fit:7393/'
|
||||
kohya_ss_home_dir = '/home/chinatszrn/Documents/miaoya/kohya_ss_home'
|
||||
webui_lora_dir = '/home/chinatszrn/Documents/miaoya/webui_home/stable-diffusion-webui/models/Lora'
|
||||
inference_use_onediff = False
|
||||
callback_url = 'http://service.aicloud.fit:7395/api/hair/trainCallBack'
|
||||
else:
|
||||
current_url = 'http://0.0.0.0:7393/'
|
||||
kohya_ss_home_dir = '/home/xsl/change_hair/project/kohya_ss_home'
|
||||
webui_lora_dir = '/home/xsl/change_hair/project/onediff/stable-diffusion-webui/models/Lora'
|
||||
inference_use_onediff = False
|
||||
callback_url = 'http://0.0.0.0:8801/api/hair/trainCallBack'
|
||||
base_webui_port = '57860'
|
||||
base_onediff_port = '9038'
|
||||
base_webui_url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
def send_request(url, state, task_dict):
|
||||
import requests
|
||||
import json
|
||||
|
||||
msg = '头发lora训练失败' if state == -1 else '头发lora训练成功'
|
||||
payload = json.dumps({
|
||||
"task_id": task_dict['task_id'] if task_dict is not None else '',
|
||||
"hair_id": task_dict['hair_id'] if task_dict is not None else '',
|
||||
"state": state,
|
||||
"msg": msg,
|
||||
"is_tj": task_dict['is_tj'] if task_dict is not None else "0"
|
||||
})
|
||||
|
||||
print("payload:", payload)
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
|
||||
@app.route('/api/hair/train', methods=['POST'])
|
||||
def train_hair_lora():
|
||||
import os
|
||||
import json
|
||||
task_id = ''
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
assert 'task_id' in request_data, 'task_id is required'
|
||||
task_id = request_data['task_id']
|
||||
assert 'hair_id' in request_data and 'hair_material_dir' in request_data, 'hair_id and hair_material_dir is required'
|
||||
hair_material_dir = request_data['hair_material_dir']
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
img_dir = os.path.join(hair_material_dir, 'images')
|
||||
assert os.path.exists(img_dir), f'{img_dir} not exists'
|
||||
assert os.path.exists(
|
||||
os.path.join(hair_material_dir, 'model')), f'{os.path.join(hair_material_dir, "model")} not exists'
|
||||
|
||||
#判断img_dir下面是否只有一个文件夹
|
||||
img_dir_list = os.listdir(img_dir)
|
||||
assert len(img_dir_list) == 1, f'{img_dir}下面只能有一个文件夹'
|
||||
train_image_dir = os.path.join(img_dir, img_dir_list[0])
|
||||
assert os.path.isdir(train_image_dir), f'{train_image_dir}不是文件夹'
|
||||
# 检查该文件夹是否以数字加下划线开头
|
||||
assert img_dir_list[0].split('_')[0].isdigit(), f'{img_dir_list[0]}不是数字开头'
|
||||
|
||||
#判断文件夹下面是否有图片
|
||||
img_list = glob.glob(train_image_dir + '/*.png')
|
||||
assert len(img_list) > 10, f'{os.path.join(img_dir, img_dir_list[0])}下面图片数量小于10张'
|
||||
request_data['train_image_dir'] = train_image_dir
|
||||
|
||||
# is tianjin company
|
||||
try:
|
||||
request_data['is_tj'] = request_data['is_tj']
|
||||
request_data['device_id'] = request_data['device_id']
|
||||
except Exception as e:
|
||||
print(e)
|
||||
request_data['is_tj'] = '0'
|
||||
request_data['device_id'] = '1'
|
||||
|
||||
# 将请求数据放入队列
|
||||
global_var.hair_style_lora_train_task_sq.put(request_data)
|
||||
|
||||
# 返回结果
|
||||
ret_dict = dict(state=0, msg='头发lora训练开始', task_id=task_id)
|
||||
return jsonify(ret_dict)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e), task_id=task_id)
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/api/hair/inference', methods=['POST'])
|
||||
def inference_webui():
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
|
||||
|
||||
try:
|
||||
t1 = time.time()
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
# hd_version_flag = request_data.get('hd_version_flag', False)
|
||||
hair_id = request_data['hair_id']
|
||||
inference_port = request_data['inference_port']
|
||||
|
||||
if inference_use_onediff and 'refiner_checkpoint' not in request_json:
|
||||
selected_url = base_webui_url.replace(base_webui_port, base_onediff_port)
|
||||
request_json['script_name'] = 'onediff_diffusion_model'
|
||||
print('user onediff')
|
||||
else:
|
||||
selected_url = base_webui_url.replace(base_webui_port, inference_port)
|
||||
|
||||
|
||||
|
||||
# if hd_version_flag:
|
||||
# print('user hd version!!!!!')
|
||||
# lora_file_name = 'hairstyle_hd_lora.safetensors'
|
||||
# else:
|
||||
# lora_file_name = 'hairstyle_lora.safetensors'
|
||||
|
||||
hair_material_dir = request_data.get('hair_material_dir')
|
||||
print(hair_material_dir)
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
|
||||
hd_version_flag = True
|
||||
lora_file_name = 'hairstyle_hd_lora.safetensors'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', lora_file_name)
|
||||
if not os.path.exists(request_lora_path):
|
||||
print('use low resolution lora')
|
||||
hd_version_flag = False
|
||||
lora_file_name = 'hairstyle_lora.safetensors'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', lora_file_name)
|
||||
|
||||
assert os.path.exists(request_lora_path), f'{request_lora_path} not exists'
|
||||
|
||||
if hd_version_flag:
|
||||
tmp_lora_name = f'{hair_id}_hd'
|
||||
else:
|
||||
tmp_lora_name = f'{hair_id}'
|
||||
lora_dst_path = os.path.join(global_var.webui_lora_dir, f'{tmp_lora_name}.safetensors')
|
||||
if not os.path.exists(lora_dst_path):
|
||||
os.system('cp {} {}'.format(request_lora_path, lora_dst_path))
|
||||
request_json['prompt'] = f'<lora:{tmp_lora_name}:1.0>, titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
print('pre_stage cost:', time.time() - t1)
|
||||
|
||||
start_time = time.time()
|
||||
current_time = datetime.datetime.now()
|
||||
print("*********cxt log1, infer***************, {}:{}:{}, {}".format(current_time.hour, current_time.minute,
|
||||
current_time.second, selected_url))
|
||||
response = requests.post(url=selected_url, json=request_json)
|
||||
print('inference time:', time.time() - start_time)
|
||||
|
||||
ret_json = response.json()
|
||||
# if os.path.exists(lora_dst_path):
|
||||
# os.remove(lora_dst_path)
|
||||
# 返回结果
|
||||
return jsonify(ret_json)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e))
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/api/hair/inference_diy', methods=['POST'])
|
||||
def inference_diy_webui():
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
|
||||
try:
|
||||
t1 = time.time()
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
inference_port = request_data['inference_port']
|
||||
|
||||
if inference_use_onediff and 'refiner_checkpoint' not in request_json:
|
||||
selected_url = base_webui_url.replace(base_webui_port, base_onediff_port)
|
||||
request_json['script_name'] = 'onediff_diffusion_model'
|
||||
print('user onediff')
|
||||
else:
|
||||
selected_url = base_webui_url.replace(base_webui_port, inference_port)
|
||||
|
||||
request_json['prompt'] = f'titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
print('pre_stage cost:', time.time() - t1)
|
||||
|
||||
start_time = time.time()
|
||||
current_time = datetime.datetime.now()
|
||||
print("*********cxt log1, diy***************, {}:{}:{}, {}".format(current_time.hour, current_time.minute,
|
||||
current_time.second, selected_url))
|
||||
response = requests.post(url=selected_url, json=request_json)
|
||||
print('inference time:', time.time() - start_time)
|
||||
|
||||
ret_json = response.json()
|
||||
# if os.path.exists(lora_dst_path):
|
||||
# os.remove(lora_dst_path)
|
||||
# 返回结果
|
||||
return jsonify(ret_json)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e))
|
||||
return jsonify(ret_dict)
|
||||
|
||||
def train_thread(sq, gpu_id):
|
||||
while True:
|
||||
url = f'{callback_url}'
|
||||
task_dict = None
|
||||
try:
|
||||
task_dict = sq.get()
|
||||
hair_material_dir = task_dict['hair_material_dir']
|
||||
images_dir = os.path.join(hair_material_dir, 'images')
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
train_image_dir = task_dict['train_image_dir']
|
||||
# tag = task_dict['tag']
|
||||
tag = ""
|
||||
is_tj = task_dict['is_tj']
|
||||
device_id = task_dict['device_id']
|
||||
|
||||
sample_dir = os.path.join(model_dir, 'sample')
|
||||
if not os.path.exists(sample_dir):
|
||||
os.makedirs(sample_dir)
|
||||
sample_txt = os.path.join(sample_dir, 'prompt.txt')
|
||||
with open(sample_txt, 'w') as f_s:
|
||||
f_s.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, '
|
||||
+ tag
|
||||
+ ' --n low quality, worst quality, bad anatomy, bad composition, poor, low effort --h 768 '
|
||||
'--w 768 --s 30 --l 7')
|
||||
|
||||
# 给训练图片打标签
|
||||
# cmd_caption = ('docker run --rm --gpus all -v /home/chinatszrn/Documents/miaoya/kohya_ss_home:/home/chinatszrn '
|
||||
# '-v /mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
# '--net=host chinatszrn/ubuntu:kohya_ss accelerate '
|
||||
# 'launch "./finetune/tag_images_by_wd14_tagger.py" --batch_size=2 '
|
||||
# '--general_threshold=0.5 --character_threshold=0.5 --caption_extension=".txt" '
|
||||
# '--model="SmilingWolf/wd-v1-4-convnextv2-tagger-v2" --max_data_loader_n_workers="2" '
|
||||
# '--debug --remove_underscore --frequency_tags --undesired_tags="1girl, 1boy" '
|
||||
# f'"{train_image_dir}"')
|
||||
# os.system(cmd_caption)
|
||||
|
||||
img_path_list = glob.glob(train_image_dir + '/*.png')
|
||||
# 给训练图片打标签, gpt
|
||||
for img_path in img_path_list:
|
||||
# print(img_path)
|
||||
txt_path = img_path[:-4] + '.txt'
|
||||
|
||||
print("tag img_path: ", img_path)
|
||||
# tags = caption_image(img_path)
|
||||
tags = tag
|
||||
with open(txt_path, 'w') as f:
|
||||
f.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, ' + tags)
|
||||
|
||||
#判断是否每个训练图片都有标签文件
|
||||
# for img_path in img_path_list:
|
||||
# assert os.path.exists(img_path[:-4]+'.txt'), f'{img_path}没有对应的标签文件'
|
||||
# with open(img_path[:-4]+'.txt', 'r') as f:
|
||||
# tags = f.readline()
|
||||
# with open(img_path[:-4]+'.txt', 'w') as f:
|
||||
# f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
|
||||
os.system(f'chmod 777 {model_dir}')
|
||||
#训练头发lora
|
||||
# 原始 Docker 命令(已弃用,改为本地 kohya 环境直接执行):
|
||||
# sudo docker run --rm --privileged=true --gpus "device=1" -v {kohya_ss_home_dir}:/home/chinatszrn ...
|
||||
# chinatszrn/ubuntu:kohya_ss accelerate launch ./train_network.py ...
|
||||
# 本地化改动:
|
||||
# 1. 去掉 docker 外壳,用 kohya conda 环境的 accelerate 直接跑
|
||||
# 2. 基础模型 majicmixRealistic_v7 不存在,改用本机 v1-5-pruned-emaonly
|
||||
# 3. GPU 固定 device=0(单卡)
|
||||
# 4. 去掉 tokenizer_cache_dir(改用 HF 本地缓存 + 离线模式)
|
||||
# 5. 设置 HF_HUB_OFFLINE 避免联网检查
|
||||
kohya_python = '/home/xsl/miniconda3/envs/kohya/bin/python'
|
||||
kohya_workdir = os.path.join(kohya_ss_home_dir, 'kohya_ss')
|
||||
base_model = '/home/xsl/change_hair/project/onediff/stable-diffusion-webui/models/Stable-diffusion/v1-5-pruned-emaonly.safetensors'
|
||||
cmd_train = (
|
||||
f'cd {kohya_workdir} && '
|
||||
f'HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 CUDA_VISIBLE_DEVICES={device_id} '
|
||||
f'/home/xsl/miniconda3/envs/kohya/bin/accelerate launch --num_cpu_threads_per_process=2 "./train_network.py" --enable_bucket '
|
||||
f'--min_bucket_reso=256 --max_bucket_reso=2048 --pretrained_model_name_or_path="{base_model}" '
|
||||
f'--train_data_dir={images_dir} --resolution="2000,2000" '
|
||||
f'--output_dir={model_dir} '
|
||||
'--network_alpha="64" --save_model_as=safetensors --network_module=networks.lora --text_encoder_lr=5e-05 '
|
||||
'--unet_lr=0.0001 --network_dim=128 --output_name="hairstyle_hd_lora" --lr_scheduler_num_cycles="20" '
|
||||
'--no_half_vae --learning_rate="0.0001" --lr_scheduler="cosine" --lr_warmup_steps="650" --train_batch_size="1" '
|
||||
'--max_train_steps="1500" --save_every_n_epochs="100" --mixed_precision="fp16" --save_precision="fp16" '
|
||||
'--caption_extension=".txt" --sample_sampler=ddim '
|
||||
f'--sample_prompts={sample_txt} --sample_every_n_epochs="1000" '
|
||||
'--seed="1234" --cache_latents --optimizer_type="AdamW" --max_data_loader_n_workers="0" --bucket_reso_steps=64 '
|
||||
'--xformers --bucket_no_upscale --noise_offset=0.0')
|
||||
print("cmd_train:", cmd_train)
|
||||
os.system(cmd_train)
|
||||
|
||||
lora_path = os.path.join(model_dir, 'hairstyle_hd_lora.safetensors')
|
||||
|
||||
# tianjin callback
|
||||
if is_tj == "1":
|
||||
url = f'{callback_url}'
|
||||
|
||||
if not os.path.exists(lora_path):
|
||||
send_request(url, -1, task_dict)
|
||||
else:
|
||||
send_request(url, 0, task_dict)
|
||||
|
||||
except Exception as e:
|
||||
send_request(url, -1, None)
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
global_var.webui_lora_dir = webui_lora_dir
|
||||
|
||||
# avatar训练的任务队列
|
||||
global_var.hair_style_lora_train_task_sq = Queue()
|
||||
p = Process(target=train_thread, args=(
|
||||
global_var.hair_style_lora_train_task_sq, 0))
|
||||
p.start()
|
||||
|
||||
# # 启动服务
|
||||
# app.run(debug=True, port=32678, host='0.0.0.0')
|
||||
|
||||
server = pywsgi.WSGIServer(('0.0.0.0', 32678), app) # test port
|
||||
server.serve_forever()
|
||||
|
||||
p.join()
|
||||
@@ -0,0 +1,190 @@
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os,sys
|
||||
from gevent import pywsgi, monkey
|
||||
from multiprocessing import Process, Queue
|
||||
import glob
|
||||
from gpt4v_caption import caption_image
|
||||
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
import json
|
||||
|
||||
def send_request(url, state, task_dict):
|
||||
import requests
|
||||
import json
|
||||
|
||||
msg = '头发lora训练失败' if state == -1 else '头发lora训练成功'
|
||||
payload = json.dumps({
|
||||
"task_id": task_dict['task_id'] if task_dict is not None else '',
|
||||
"hair_id": task_dict['hair_id'] if task_dict is not None else '',
|
||||
"state": state,
|
||||
"msg": msg
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
|
||||
|
||||
def train_hair_lora():
|
||||
import os
|
||||
import json
|
||||
task_id = ''
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = ""
|
||||
assert 'task_id' in request_data, 'task_id is required'
|
||||
task_id = request_data['task_id']
|
||||
assert 'hair_id' in request_data and 'hair_material_dir' in request_data, 'hair_id and hair_material_dir is required'
|
||||
hair_material_dir = request_data['hair_material_dir']
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
img_dir = os.path.join(hair_material_dir,'images')
|
||||
assert os.path.exists(img_dir), f'{img_dir} not exists'
|
||||
assert os.path.exists(os.path.join(hair_material_dir, 'model')), f'{os.path.join(hair_material_dir, "model")} not exists'
|
||||
|
||||
#判断img_dir下面是否只有一个文件夹
|
||||
img_dir_list = os.listdir(img_dir)
|
||||
assert len(img_dir_list) == 1, f'{img_dir}下面只能有一个文件夹'
|
||||
train_image_dir = os.path.join(img_dir,img_dir_list[0])
|
||||
assert os.path.isdir(train_image_dir), f'{train_image_dir}不是文件夹'
|
||||
# 检查该文件夹是否以数字加下划线开头
|
||||
assert img_dir_list[0].split('_')[0].isdigit(), f'{img_dir_list[0]}不是数字开头'
|
||||
|
||||
#判断文件夹下面是否有图片
|
||||
img_list = glob.glob(train_image_dir + '/*.png')
|
||||
assert len(img_list) > 10, f'{os.path.join(img_dir,img_dir_list[0])}下面图片数量小于10张'
|
||||
request_data['train_image_dir'] = train_image_dir
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def inference_webui():
|
||||
import os
|
||||
import requests
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = ""
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
hair_material_dir = request_data.get('hair_material_dir')
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', 'hairstyle_lora.safetensors')
|
||||
assert os.path.exists(request_lora_path), f'{request_lora_path} not exists'
|
||||
|
||||
tmp_lora_name = f'{uuid.uuid4()}'
|
||||
lora_dst_path = ""
|
||||
os.system('cp {} {}'.format(request_lora_path, lora_dst_path))
|
||||
request_json['prompt'] = f'<lora:{tmp_lora_name}:1.0>, titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
response = requests.post(url=url, json=request_json)
|
||||
ret_json = response.json()
|
||||
|
||||
if os.path.exists(lora_dst_path):
|
||||
os.remove(lora_dst_path)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def tag(train_image_dir):
|
||||
img_path_list = glob.glob(train_image_dir + '/*.png')
|
||||
|
||||
# 给训练图片打标签, gpt
|
||||
for img_path in img_path_list:
|
||||
print(img_path)
|
||||
txt_path = img_path[:-4] + '.txt'
|
||||
# if not os.path.exists(txt_path):
|
||||
tags = caption_image(img_path)
|
||||
with open(txt_path, 'w') as f:
|
||||
f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
# else:
|
||||
# continue
|
||||
|
||||
|
||||
def train_thread(sq, gpu_id):
|
||||
while True:
|
||||
url = 'http://service.aicloud.fit:7393/api/hair/trainCallBack'
|
||||
task_dict = None
|
||||
try:
|
||||
task_dict = sq.get()
|
||||
hair_material_dir = task_dict['hair_material_dir']
|
||||
images_dir = os.path.join(hair_material_dir, 'images')
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
train_image_dir = task_dict['train_image_dir']
|
||||
# 给训练图片打标签
|
||||
# cmd_caption = ('docker run --rm --gpus all -v /home/chinatszrn/Documents/miaoya/kohya_ss_home:/home/chinatszrn '
|
||||
# '-v /mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
# '--net=host chinatszrn/ubuntu:kohya_ss accelerate '
|
||||
# 'launch "./finetune/tag_images_by_wd14_tagger.py" --batch_size=2 '
|
||||
# '--general_threshold=0.5 --character_threshold=0.5 --caption_extension=".txt" '
|
||||
# '--model="SmilingWolf/wd-v1-4-convnextv2-tagger-v2" --max_data_loader_n_workers="2" '
|
||||
# '--debug --remove_underscore --frequency_tags --undesired_tags="1girl, 1boy" '
|
||||
# f'"{train_image_dir}"')
|
||||
# os.system(cmd_caption)
|
||||
|
||||
img_path_list = glob.glob(train_image_dir + '/*.png')
|
||||
# 给训练图片打标签, gpt
|
||||
for img_path in img_path_list:
|
||||
tags = caption_image(img_path)
|
||||
txt_path = img_path[:-4]+'.txt'
|
||||
if not os.path.exists(txt_path):
|
||||
with open(txt_path, 'w') as f:
|
||||
f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
else:
|
||||
continue
|
||||
|
||||
|
||||
#判断是否每个训练图片都有标签文件
|
||||
# for img_path in img_path_list:
|
||||
# assert os.path.exists(img_path[:-4]+'.txt'), f'{img_path}没有对应的标签文件'
|
||||
# with open(img_path[:-4]+'.txt', 'r') as f:
|
||||
# tags = f.readline()
|
||||
# with open(img_path[:-4]+'.txt', 'w') as f:
|
||||
# f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
|
||||
#训练头发lora
|
||||
cmd_train = ('docker run --rm --gpus all -v /home/chinatszrn/Documents/miaoya/kohya_ss_home:/home/chinatszrn -v '
|
||||
'/mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
'--net=host chinatszrn/ubuntu:kohya_ss accelerate launch --num_cpu_threads_per_process=2 "./train_network.py" --enable_bucket '
|
||||
'--min_bucket_reso=512 --max_bucket_reso=1800 --pretrained_model_name_or_path="/mnt/nas_hdd/米亚像馆/models/Stable-diffusion/majicmixRealistic_v7.safetensors" '
|
||||
f'--train_data_dir={images_dir} --resolution="1800,1800" '
|
||||
f'--output_dir={model_dir} '
|
||||
'--network_alpha="64" --save_model_as=safetensors --network_module=networks.lora --text_encoder_lr=5e-05 '
|
||||
'--unet_lr=0.0001 --network_dim=128 --output_name="hairstyle_lora" --lr_scheduler_num_cycles="12" '
|
||||
'--no_half_vae --learning_rate="0.0001" --lr_scheduler="cosine" --lr_warmup_steps="96" --train_batch_size="1" '
|
||||
'--max_train_steps="4000" --save_every_n_epochs="100" --mixed_precision="fp16" --save_precision="fp16" '
|
||||
'--seed="1234" --cache_latents --optimizer_type="AdamW8bit" --max_data_loader_n_workers="0" --bucket_reso_steps=64 '
|
||||
'--xformers --bucket_no_upscale --noise_offset=0.0 --tokenizer_cache_dir="/home/chinatszrn/.cache/clip"')
|
||||
os.system(cmd_train)
|
||||
|
||||
lora_path = os.path.join(model_dir, 'hairstyle_lora.safetensors')
|
||||
|
||||
|
||||
if not os.path.exists(lora_path):
|
||||
send_request(url, -1, task_dict)
|
||||
else:
|
||||
send_request(url, 0, task_dict)
|
||||
|
||||
except Exception as e:
|
||||
send_request(url, -1, None)
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
tag("/mnt/database2/online-server/hair-online/hair_lora_train_material/AAVWGW1NN-0KC-33B-24-/images/1_hairstyle")
|
||||
@@ -0,0 +1,37 @@
|
||||
import requests
|
||||
import cv2
|
||||
import numpy as np
|
||||
import base64
|
||||
import sys
|
||||
import json
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = './data/template01.png'
|
||||
img = cv2.imread(path)
|
||||
retval, bytes = cv2.imencode('.jpg', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
user_id = '61AB9097'
|
||||
|
||||
#给api_service.py发送请求
|
||||
url = "http://i-2.gpushare.com:53412/user/generate"
|
||||
payload = json.dumps({
|
||||
"user_id": "61AB9097",
|
||||
"base_img": encoded_image
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(f"Failed to send request to API service. Status code: {response.status_code}")
|
||||
|
||||
ret_image_b64 = response.json().get('generate_photo_b64')
|
||||
|
||||
if ret_image_b64 is None:
|
||||
raise RuntimeError(f"ret image failed!")
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(ret_image_b64), np.uint8)
|
||||
image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
cv2.imshow('image', cv2.resize(image, (0, 0), fx=0.5, fy=0.5))
|
||||
cv2.waitKey()
|
||||
@@ -0,0 +1 @@
|
||||
python api_service.py /hy-tmp/photo_service/service_data /hy-tmp/stable-diffusion-webui/models/Lora 7860 1234
|
||||
@@ -0,0 +1,18 @@
|
||||
import cv2
|
||||
import os
|
||||
import json
|
||||
import base64
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
if __name__ == '__main__':
|
||||
with open('request_json.json', 'r') as f:
|
||||
request_data = json.load(f)
|
||||
request_json = request_data
|
||||
img_base64 = request_json['init_images'][0]
|
||||
mask_base64 = request_json['mask']
|
||||
image = Image.open(io.BytesIO(base64.b64decode(img_base64)))
|
||||
image.save('image.png')
|
||||
mask = Image.open(io.BytesIO(base64.b64decode(mask_base64)))
|
||||
mask.save('mask.png')
|
||||
|
||||
+1663
File diff suppressed because one or more lines are too long
Executable
+106
@@ -0,0 +1,106 @@
|
||||
import io
|
||||
import cv2
|
||||
import base64
|
||||
import requests
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
"""
|
||||
To use this example make sure you've done the following steps before executing:
|
||||
1. Ensure automatic1111 is running in api mode with the controlnet extension.
|
||||
Use the following command in your terminal to activate:
|
||||
./webui.sh --no-half --api
|
||||
2. Validate python environment meet package dependencies.
|
||||
If running in a local repo you'll likely need to pip install cv2, requests and PIL
|
||||
"""
|
||||
|
||||
|
||||
class ControlnetRequestImg2Img:
|
||||
def __init__(self, prompt, net_prompt):
|
||||
self.url = "http://127.0.0.1:7860/sdapi/v1/img2img"
|
||||
self.prompt = prompt
|
||||
self.neg_prompt = net_prompt
|
||||
self.body = None
|
||||
|
||||
def build_body(self, dst_width, dst_height, cfg_scale, base_img):
|
||||
|
||||
self.body = {
|
||||
"prompt": self.prompt,
|
||||
"negative_prompt": self.neg_prompt,
|
||||
"sampler_name": "Restart",
|
||||
"batch_size": 1,
|
||||
"steps": 30,
|
||||
"width": dst_width,
|
||||
"height": dst_height,
|
||||
"cfg_scale": cfg_scale,
|
||||
"seed": -1,
|
||||
"init_images": [
|
||||
self.encode_image_to_base64(base_img)
|
||||
],
|
||||
"denoising_strength": 0.4,
|
||||
"alwayson_scripts": {
|
||||
"controlnet": {
|
||||
"args": [
|
||||
{
|
||||
"enabled": True,
|
||||
"module": "openpose_full",
|
||||
"model": "openpose",
|
||||
"weight": 1.0,
|
||||
# "image": self.read_image(),
|
||||
"resize_mode": "Crop and Resize",
|
||||
"low_vram": False,
|
||||
"processor_res": 512,
|
||||
"guidance_start": 0.0,
|
||||
"guidance_end": 1.0,
|
||||
"control_mode": "Balanced",
|
||||
"pixel_perfect": True
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def send_request(self):
|
||||
response = requests.post(url=self.url, json=self.body)
|
||||
return response.json()
|
||||
|
||||
def encode_image_to_base64(self, img):
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
def read_image(self):
|
||||
img = cv2.imread(self.img_path)
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
def read_mask(self):
|
||||
img = cv2.imread(self.mask)
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
def encode_image_to_base64(img):
|
||||
retval, bytes = cv2.imencode('.jpg', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = '/home/chinatszrn/Downloads/photo_service/service_data/template_data/template01.png'
|
||||
img = cv2.imread(path)
|
||||
prompt = '<lora:5b05d5eeee0188f436d7131c4f0ff52b:0.8>,easyphoto_face, easyphoto, 1person,face,suit'
|
||||
neg_prompt = '(worst quality:2),(low quality:2),(normal quality:2),lowres,watermark'
|
||||
|
||||
|
||||
control_net = ControlnetRequestImg2Img(prompt, neg_prompt)
|
||||
control_net.build_body(dst_width=img.shape[1], dst_height=img.shape[0], cfg_scale=3.5, base_img=img)
|
||||
output = control_net.send_request()
|
||||
result = output['images'][0]
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(result.split(",", 1)[0]), np.uint8)
|
||||
image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
cv2.imshow('image', image)
|
||||
cv2.waitKey()
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
import io
|
||||
import cv2
|
||||
import base64
|
||||
import requests
|
||||
from PIL import Image
|
||||
|
||||
class ControlnetRequestImg2Img:
|
||||
def __init__(self, prompt, net_prompt, path, mask):
|
||||
self.url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
self.prompt = prompt
|
||||
self.neg_prompt = net_prompt
|
||||
self.img_path = path
|
||||
self.mask = mask
|
||||
self.body = None
|
||||
|
||||
def build_body(self):
|
||||
img = cv2.imread(self.img_path)
|
||||
self.body = {
|
||||
"prompt": self.prompt,
|
||||
"negative_prompt": self.neg_prompt,
|
||||
"sampler_name": "DPM++ 2M Karras",
|
||||
"batch_size": 1,
|
||||
"steps": 30,
|
||||
"width": img.shape[1],
|
||||
"height": img.shape[0],
|
||||
"cfg_scale": 7,
|
||||
"seed": -1,
|
||||
"mask_blur": 15,
|
||||
"init_images": [
|
||||
self.read_image()
|
||||
],
|
||||
"inpaint_full_res": True,
|
||||
"inpainting_fill": 1,
|
||||
"inpainting_mask_invert": 1,
|
||||
"mask": self.read_mask(),
|
||||
"denoising_strength": 0.4,
|
||||
"alwayson_scripts": {
|
||||
"controlnet": {
|
||||
"args": [
|
||||
{
|
||||
"enabled": True,
|
||||
"module": "openpose_full",
|
||||
"model": "openpose",
|
||||
"weight": 1.0,
|
||||
"resize_mode": 1,
|
||||
"lowvram": False,
|
||||
"processor_res": 512,
|
||||
"guidance_start": 0.0,
|
||||
"guidance_end": 1.0,
|
||||
"control_mode": 0,
|
||||
"pixel_perfect": True
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
def send_request(self):
|
||||
response = requests.post(url=self.url, json=self.body)
|
||||
return response.json()
|
||||
|
||||
def read_image(self):
|
||||
img = cv2.imread(self.img_path)
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
def read_mask(self):
|
||||
img = cv2.imread(self.mask)
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = '/home/chinatszrn/Downloads/user1_hr.png'
|
||||
mask_path = '/home/chinatszrn/Downloads/user1_hr_mask.png'
|
||||
prompt = 'a woman with long blonde hair and a blue shirt on a gray background with a gray background and a gray background, lyco art, An Gyeon, realistic face, a character portrait'
|
||||
neg_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, moles, large breast, big breast, bad_pictures,easynegative'
|
||||
|
||||
control_net = ControlnetRequestImg2Img(prompt, neg_prompt, path, mask_path)
|
||||
control_net.build_body()
|
||||
output = control_net.send_request()
|
||||
result = output['images'][0]
|
||||
image = Image.open(io.BytesIO(base64.b64decode(result.split(",", 1)[0])))
|
||||
image.save('save2.png')
|
||||
Reference in New Issue
Block a user