初始化换发型项目:3个微服务代码 + 部署脚本
包含: - hair_service_sd: 换发型/换发色算法服务 (端口 8801) - photo_service: LoRA 训练调度服务 (端口 32678) - stable-diffusion-webui: SD WebUI 推理服务 (端口 57860) - kohya_ss_home: 训练环境代码 - meidaojia: 监控测试脚本 - setup.sh: 一键部署脚本 (conda环境恢复 + 配置生成 + 完整性检查) - start_all_services.sh: 启动3个服务 - configure.ini.template: 路径模板化 (BASE_DIR自动推导) - conda_envs/py310.yml: py310 环境定义 大文件 (weights/, models/, data/, conda_envs/*.tar.gz 等) 通过 .gitignore 排除, 由网盘单独上传。
This commit is contained in:
@@ -0,0 +1,350 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import torch
|
||||
import json
|
||||
import time
|
||||
import re
|
||||
import os
|
||||
from process_modules import Get_Landmark, Process_Data
|
||||
from utils import landmark_processor
|
||||
|
||||
class GenderClassifyProcessor(object):
|
||||
def __init__(self, gpu_id=0):
|
||||
model_path = "./weights/gender_models"
|
||||
self.output_img_size = 128
|
||||
if not os.path.exists(model_path):
|
||||
print("GenderClassifyProcessor don't have model!")
|
||||
|
||||
if gpu_id == 'cpu':
|
||||
self.device = torch.device(gpu_id)
|
||||
else:
|
||||
self.device = torch.device('cuda:{0}'.format(gpu_id))
|
||||
|
||||
self.gender_model = cv2.dnn.readNetFromCaffe(os.path.join(model_path, "gender.prototxt"), os.path.join(model_path, "gender.caffemodel"))
|
||||
|
||||
def forward(self, img, landmark_137):
|
||||
|
||||
image_to_face_mat = landmark_processor.get_transform_mat_sex(landmark_137, self.output_img_size)
|
||||
gender_img = cv2.warpAffine(img, image_to_face_mat, (self.output_img_size, self.output_img_size), cv2.INTER_LANCZOS4)
|
||||
inpBlob = cv2.dnn.blobFromImage(gender_img, 1.0, (self.output_img_size, self.output_img_size), (0, 0, 0), swapRB=False,
|
||||
crop=False)
|
||||
self.gender_model.setInput(inpBlob)
|
||||
output = self.gender_model.forward()
|
||||
|
||||
is_female = True
|
||||
if output[0][0] > output[0][1]:
|
||||
is_female = False
|
||||
return is_female
|
||||
|
||||
|
||||
class Prepare_Ref_HairStyle_Data(object):
|
||||
def __init__(self, gpu, device_id):
|
||||
if gpu and torch.cuda.is_available():
|
||||
self.device = torch.device("cuda:%d" % device_id if device_id >= 0 else "cpu")
|
||||
self.cuda = True
|
||||
else:
|
||||
self.device = torch.device("cpu")
|
||||
self.cuda = False
|
||||
|
||||
self.process_data = Process_Data(gpu, device_id)
|
||||
self.get_landmark = Get_Landmark(gpu_id=device_id)
|
||||
self.gender_classify = GenderClassifyProcessor(gpu_id=device_id)
|
||||
|
||||
def get_prepare_ref_768_color_data(self, ref_rgb_8uc3_orisize):
|
||||
ref_landmark_1k2_f_orisize = self.get_landmark.forward(ref_rgb_8uc3_orisize)
|
||||
ref_rgb_8uc3_color_768, ref_matting_8uc3_color_768, ref_baldseg_8uc3_color_768, ref_landmark_f1k2_color_768 = \
|
||||
self.process_data.get_prepare_ref_768_bald_data(ref_rgb_8uc3_orisize, ref_landmark_1k2_f_orisize)
|
||||
|
||||
return ref_rgb_8uc3_color_768, ref_matting_8uc3_color_768, ref_baldseg_8uc3_color_768, ref_landmark_f1k2_color_768
|
||||
|
||||
def get_prepare_ref_768_color_data_landmark1k(self, ref_rgb_8uc3_orisize,ref_landmark_1k2_f_orisize):
|
||||
# ref_landmark_1k2_f_orisize = self.get_landmark.inference(ref_rgb_8uc3_orisize)
|
||||
ref_rgb_8uc3_color_768, ref_matting_8uc3_color_768, ref_baldseg_8uc3_color_768, ref_landmark_f1k2_color_768 = \
|
||||
self.process_data.get_prepare_ref_768_bald_data(ref_rgb_8uc3_orisize, ref_landmark_1k2_f_orisize)
|
||||
|
||||
return ref_rgb_8uc3_color_768, ref_matting_8uc3_color_768, ref_baldseg_8uc3_color_768, ref_landmark_f1k2_color_768
|
||||
|
||||
def calculate_hair_ratio_after_align(self, hair_mask, origin_landmark1k, img_size=768):
|
||||
image_to_face_mat = landmark_processor.get_transform_mat_hair_ratio_v1(origin_landmark1k, 768, ratio=0.35, h_offset=0.32)
|
||||
hair_mask_align = cv2.warpAffine(hair_mask, image_to_face_mat, (img_size, img_size))
|
||||
|
||||
hair_rect = cv2.boundingRect(hair_mask_align[:, :, :1])
|
||||
hair_mask_ratio = hair_rect[2] * hair_rect[3] / (img_size * img_size)
|
||||
return hair_mask_ratio
|
||||
|
||||
def check_female_hair_ratio(self, origin_img_8uc3, landmark_1k2_f_orisize):
|
||||
ref_matte_fg_8uc3_orisize, ref_matte_pred_8uc1_orisize = self.process_data.generator_matte.matte_inference(origin_img_8uc3, landmark_1k2_f_orisize)
|
||||
ref_matte_pred_8uc3_orisize = np.repeat(ref_matte_pred_8uc1_orisize[:, :, np.newaxis], 3, axis=2)
|
||||
hairstyle_M = self.process_data.get_hair_M_girl_v1(landmark_1k2_f_orisize)
|
||||
ref_rgb_8uc3_768 = cv2.warpAffine(ref_matte_pred_8uc3_orisize, hairstyle_M, (768, 768))
|
||||
|
||||
# cv2.imshow("ref_rgb_8uc3_768", ref_rgb_8uc3_768)
|
||||
# cv2.waitKey()
|
||||
|
||||
edge_width = 5
|
||||
if (ref_rgb_8uc3_768[-edge_width:, :, :]).max() > 0 or (ref_rgb_8uc3_768[:, -edge_width:, :]).max() > 0 or (ref_rgb_8uc3_768[:, :edge_width, :]).max() > 0:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_prepare_ref_768_data(self, ref_rgb_8uc3_orisize, long_flag=False):
|
||||
|
||||
ref_landmark_1k2_f_orisize = self.get_landmark.forward(ref_rgb_8uc3_orisize)
|
||||
|
||||
# ref_matte_fg_8uc3_orisize, ref_matte_pred_8uc1_orisize = self.process_data.generator_matte.matte_inference(
|
||||
# ref_rgb_8uc3_orisize, ref_landmark_1k2_f_orisize)
|
||||
ref_landmark_137kpts_f_orisize = landmark_processor.pts_1k_to_137(ref_landmark_1k2_f_orisize)
|
||||
gender_res = self.gender_classify.forward(ref_rgb_8uc3_orisize, ref_landmark_137kpts_f_orisize)
|
||||
|
||||
# hair_ratio = self.calculate_hair_ratio_after_align(ref_rgb_8uc3_orisize, ref_landmark_1k2_f_orisize)
|
||||
# if hair_ratio > 0.3:
|
||||
# ratio = 2
|
||||
# else:
|
||||
# if gender_res:
|
||||
# ratio = 1
|
||||
# else:
|
||||
# ratio = 0
|
||||
if not gender_res:
|
||||
ratio = 0
|
||||
else:
|
||||
check_res = self.check_female_hair_ratio(ref_rgb_8uc3_orisize, ref_landmark_137kpts_f_orisize)
|
||||
if check_res:
|
||||
ratio = 1
|
||||
else:
|
||||
ratio = 2
|
||||
if gender_res:
|
||||
gender = "girl"
|
||||
else:
|
||||
gender = "boy"
|
||||
print("gender: ", gender, " ratio: ", ratio)
|
||||
|
||||
# show_concat = np.concatenate((ref_rgb_8uc3_orisize, ref_matte_fg_8uc3_orisize), axis=1)
|
||||
# resize_ratio = 1024. / max(show_concat.shape[:2])
|
||||
# show_concat = cv2.resize(show_concat, (0, 0), fx=resize_ratio, fy=resize_ratio)
|
||||
# print("gender_res: ", gender_res, " hair_ratio: ", hair_ratio)
|
||||
# cv2.imshow("show_concat", show_concat)
|
||||
# cv2.imshow("ref_matte_pred_8uc1_orisize", ref_matte_pred_8uc1_orisize)
|
||||
# cv2.waitKey()
|
||||
|
||||
ref_rgb_8uc3_768, ref_matting_fg_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768, ref_landmark_f1k2_768 = \
|
||||
self.process_data.get_prepare_ref_768_data(ref_rgb_8uc3_orisize, ref_landmark_1k2_f_orisize, ratio, long=long_flag)
|
||||
|
||||
# cv2.imshow("ref_rgb_8uc3_768", ref_rgb_8uc3_768)
|
||||
# cv2.waitKey()
|
||||
|
||||
return ref_rgb_8uc3_768, ref_matting_fg_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768, ref_landmark_f1k2_768, gender, ratio
|
||||
|
||||
def Generator_reftensor(self, ref_rgb_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768,
|
||||
ref_landmark_f1k2_768):
|
||||
|
||||
"""
|
||||
input:
|
||||
|
||||
图像尺寸基于: 人脸 512, 图像均为3通道
|
||||
ref_rgb_8uc3_512: 参考图, size 512, uint8 (0-255)
|
||||
ref_matting_8uc3_512:参考图 matting alpha 值, uint8 (0-255)
|
||||
ref_baldseg_8uc3_512: 参考图 光头分割, uint8 (0-255)
|
||||
ref_landmark_f1k2_512: 参考图 关键点 1k*2 float32
|
||||
|
||||
output:
|
||||
|
||||
input_another_pose_hair_image: 参考图 条件图, float32 (0-255)
|
||||
|
||||
"""
|
||||
|
||||
# 8 ********************** another pose hair_image **********************
|
||||
another_pose_image = ref_rgb_8uc3_768.copy()
|
||||
|
||||
another_nohair_pose_mask = ref_baldseg_8uc3_768.copy()
|
||||
|
||||
# cv2.imshow("another_nohair_pose_mask", another_nohair_pose_mask)
|
||||
# cv2.waitKey()
|
||||
|
||||
another_nohair_pose_mask[(np.abs(another_nohair_pose_mask - [0, 0, 255]) < 50).all(axis=2)] = [0, 255, 255]
|
||||
another_nohair_pose_mask[(another_nohair_pose_mask == [0, 0, 0]).all(axis=2)] = [255, 255, 255]
|
||||
another_pose_pts137 = landmark_processor.pts_1k_to_137(ref_landmark_f1k2_768).astype(np.int32)
|
||||
cv2.fillPoly(another_nohair_pose_mask,
|
||||
np.concatenate((another_pose_pts137[47:35:-1], another_pose_pts137[56:64],
|
||||
[another_pose_pts137[48], another_pose_pts137[22]]))[
|
||||
np.newaxis, :, :], (255, 255, 0))
|
||||
|
||||
cv2.fillPoly(another_nohair_pose_mask,
|
||||
np.concatenate((another_pose_pts137[22:37], another_pose_pts137[56:47:-1]))[np.newaxis, :, :],
|
||||
(255, 0, 128))
|
||||
|
||||
cv2.fillPoly(another_nohair_pose_mask, another_pose_pts137[88:104][np.newaxis, :, :], (255, 0, 255)) # eye
|
||||
cv2.fillPoly(another_nohair_pose_mask, another_pose_pts137[105:121][np.newaxis, :, :], (255, 0, 255)) # eye
|
||||
# Label nose
|
||||
cv2.fillPoly(another_nohair_pose_mask, another_pose_pts137[64:79][np.newaxis, :, :], (255, 255, 255))
|
||||
# Label eyebrow
|
||||
cv2.fillPoly(another_nohair_pose_mask, another_pose_pts137[121:129][np.newaxis, :, :], (255, 128, 0))
|
||||
cv2.fillPoly(another_nohair_pose_mask, another_pose_pts137[129:137][np.newaxis, :, :], (255, 128, 0))
|
||||
|
||||
another_pose_hair_alpha = ref_matting_8uc3_768.copy() / 255.
|
||||
another_pose_hair_image = (another_pose_image * another_pose_hair_alpha + another_nohair_pose_mask * (
|
||||
1 - another_pose_hair_alpha)).astype(np.uint8)
|
||||
|
||||
input_another_pose_hair_image = another_pose_hair_image.astype(np.float32) / 255
|
||||
|
||||
return input_another_pose_hair_image
|
||||
|
||||
def prepare_single(img_path=None, dst_dir=None, long_flag=False):
|
||||
# img_path = "/home/yangchaojie/Desktop/hairstyle/test_data/1123/pics/test3.jpg"
|
||||
# img_path = "./test_data/ref_imgs/female1.jpg"
|
||||
# dst_dir = "./data/ref_hairstyle/tmp"
|
||||
|
||||
# img_path = "/home/szlc/Downloads/111/111/ddbc6cb6-766c-4f08-b1fd-22c6bab86432.jpg"
|
||||
# dst_dir = "/home/szlc/Downloads/111/res"
|
||||
if not os.path.exists(dst_dir):
|
||||
os.makedirs(dst_dir)
|
||||
prepare_data_process = Prepare_Ref_HairStyle_Data(True, device_id=0)
|
||||
ref_rgb_8uc3_orisize = cv2.imread(img_path)
|
||||
|
||||
# debug = True
|
||||
debug = False
|
||||
|
||||
version = "20221206"
|
||||
start_time = time.time()
|
||||
|
||||
ref_rgb_8uc3_768, ref_matting_fg_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768, ref_landmark_f1k2_768, gender, ratio = \
|
||||
prepare_data_process.get_prepare_ref_768_data(ref_rgb_8uc3_orisize, long_flag)
|
||||
|
||||
|
||||
if not debug:
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_rgb_8uc3_768.png"), ref_rgb_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_matting_fg_8uc3_768.png"), ref_matting_fg_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_matting_8uc3_768.png"), ref_matting_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_baldseg_8uc3_768.png"), ref_baldseg_8uc3_768)
|
||||
np.savetxt(os.path.join(dst_dir, "ref_landmark_f1k2_768.txt"), ref_landmark_f1k2_768)
|
||||
|
||||
input_another_pose_hair_image = prepare_data_process.Generator_reftensor(ref_rgb_8uc3_768, ref_matting_8uc3_768,
|
||||
ref_baldseg_8uc3_768,
|
||||
ref_landmark_f1k2_768)
|
||||
print("cost time: ", time.time() - start_time)
|
||||
if debug:
|
||||
print("gender: ", gender, " ratio: ", ratio)
|
||||
show_concat = np.concatenate((ref_rgb_8uc3_768, ref_matting_fg_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768), axis=1)
|
||||
# cv2.imshow("show_concat", cv2.resize(show_concat, (0, 0), fx=0.6, fy=0.6))
|
||||
# cv2.imshow("input_another_pose_hair_image", input_another_pose_hair_image)
|
||||
# cv2.waitKey()
|
||||
if not debug:
|
||||
np.save(os.path.join(dst_dir, "input_another_pose_hair_image.npy"), input_another_pose_hair_image)
|
||||
|
||||
config_dict = {}
|
||||
|
||||
config_dict['gender'] = gender
|
||||
config_dict['version'] = version
|
||||
config_dict['ratio'] = str(ratio)
|
||||
|
||||
with open(os.path.join(dst_dir, "config.json"), "w") as f:
|
||||
json.dump(config_dict, f)
|
||||
print("写入文件完成...", dst_dir)
|
||||
|
||||
|
||||
def prepare_single_color(img_path=None, dst_dir=None, long_flag=False):
|
||||
|
||||
if not os.path.exists(dst_dir):
|
||||
os.makedirs(dst_dir)
|
||||
prepare_data_process = Prepare_Ref_HairStyle_Data(True, device_id=0)
|
||||
ref_rgb_8uc3_orisize = cv2.imread(img_path)
|
||||
|
||||
# debug = True
|
||||
debug = False
|
||||
|
||||
version = "20221206"
|
||||
start_time = time.time()
|
||||
|
||||
ref_rgb_8uc3_768, ref_matting_fg_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768, ref_landmark_f1k2_768, gender, ratio = \
|
||||
prepare_data_process.get_prepare_ref_768_data(ref_rgb_8uc3_orisize, long_flag)
|
||||
|
||||
|
||||
if not debug:
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_rgb_8uc3_color_768.png"), ref_rgb_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_matting_fg_8uc3_color_768.png"), ref_matting_fg_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_matting_8uc3_color_768.png"), ref_matting_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_baldseg_8uc3_color_768.png"), ref_baldseg_8uc3_768)
|
||||
np.savetxt(os.path.join(dst_dir, "ref_landmark_f1k2_color_768.txt"), ref_landmark_f1k2_768)
|
||||
|
||||
input_another_pose_hair_image = prepare_data_process.Generator_reftensor(ref_rgb_8uc3_768, ref_matting_8uc3_768,
|
||||
ref_baldseg_8uc3_768,
|
||||
ref_landmark_f1k2_768)
|
||||
print("cost time: ", time.time() - start_time)
|
||||
if debug:
|
||||
print("gender: ", gender, " ratio: ", ratio)
|
||||
show_concat = np.concatenate((ref_rgb_8uc3_768, ref_matting_fg_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768), axis=1)
|
||||
# cv2.imshow("show_concat", cv2.resize(show_concat, (0, 0), fx=0.6, fy=0.6))
|
||||
# cv2.imshow("input_another_pose_hair_image", input_another_pose_hair_image)
|
||||
# cv2.waitKey()
|
||||
if not debug:
|
||||
np.save(os.path.join(dst_dir, "input_another_pose_hair_image.npy"), input_another_pose_hair_image)
|
||||
|
||||
config_dict = {}
|
||||
|
||||
config_dict['gender'] = gender
|
||||
config_dict['version'] = version
|
||||
config_dict['ratio'] = str(ratio)
|
||||
|
||||
with open(os.path.join(dst_dir, "config.json"), "w") as f:
|
||||
json.dump(config_dict, f)
|
||||
print("写入文件完成...", dst_dir)
|
||||
|
||||
def prepare_multi():
|
||||
|
||||
img_dir = "/home/yangchaojie/Desktop/hairstyle/test_data/testdata_tj_0309/raw_pics"
|
||||
save_dir = "/home/yangchaojie/Desktop/hairstyle/test_data/testdata_tj_0309/ref_haircolor"
|
||||
# pattern = re.compile(r'^[^\.].*\.jpg$')
|
||||
pattern = re.compile(r'^[^\.].*\.(jpg|JPG)$')
|
||||
for dirpath, dirnames, filenames in os.walk(img_dir, followlinks=True):
|
||||
for filename in filenames:
|
||||
if not pattern.match(filename): continue
|
||||
img_path = os.path.join(dirpath, filename)
|
||||
dst_dir = os.path.join(save_dir, filename[:-4])
|
||||
|
||||
if not os.path.exists(dst_dir):
|
||||
os.makedirs(dst_dir)
|
||||
prepare_data_process = Prepare_Ref_HairStyle_Data(True, device_id=0)
|
||||
ref_rgb_8uc3_orisize = cv2.imread(img_path)
|
||||
|
||||
# debug = True
|
||||
debug = False
|
||||
|
||||
version = "20230309"
|
||||
start_time = time.time()
|
||||
|
||||
ref_rgb_8uc3_768, ref_matting_fg_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768, ref_landmark_f1k2_768, gender, ratio = \
|
||||
prepare_data_process.get_prepare_ref_768_data(ref_rgb_8uc3_orisize)
|
||||
|
||||
|
||||
if not debug:
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_rgb_8uc3_768.png"), ref_rgb_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_matting_fg_8uc3_768.png"), ref_matting_fg_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_matting_8uc3_768.png"), ref_matting_8uc3_768)
|
||||
cv2.imwrite(os.path.join(dst_dir, "ref_baldseg_8uc3_768.png"), ref_baldseg_8uc3_768)
|
||||
np.savetxt(os.path.join(dst_dir, "ref_landmark_f1k2_768.txt"), ref_landmark_f1k2_768)
|
||||
|
||||
input_another_pose_hair_image = prepare_data_process.Generator_reftensor(ref_rgb_8uc3_768, ref_matting_8uc3_768,
|
||||
ref_baldseg_8uc3_768,
|
||||
ref_landmark_f1k2_768)
|
||||
print("cost time: ", time.time() - start_time)
|
||||
if debug:
|
||||
print("gender: ", gender, " ratio: ", ratio)
|
||||
show_concat = np.concatenate((ref_rgb_8uc3_768, ref_matting_fg_8uc3_768, ref_matting_8uc3_768, ref_baldseg_8uc3_768), axis=1)
|
||||
cv2.imshow("show_concat", cv2.resize(show_concat, (0, 0), fx=0.6, fy=0.6))
|
||||
cv2.imshow("input_another_pose_hair_image", input_another_pose_hair_image)
|
||||
cv2.waitKey()
|
||||
if not debug:
|
||||
np.save(os.path.join(dst_dir, "input_another_pose_hair_image.npy"), input_another_pose_hair_image)
|
||||
|
||||
config_dict = {}
|
||||
|
||||
config_dict['gender'] = gender
|
||||
config_dict['version'] = version
|
||||
config_dict['ratio'] = str(ratio)
|
||||
|
||||
with open(os.path.join(dst_dir, "config.json"), "w") as f:
|
||||
json.dump(config_dict, f)
|
||||
print("写入文件完成...", dst_dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
prepare_single()
|
||||
# prepare_multi()
|
||||
Reference in New Issue
Block a user