初始化换发型项目: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,97 @@
|
||||
import os
|
||||
import cv2
|
||||
import glob
|
||||
import numpy as np
|
||||
from utils import landmark_processor
|
||||
|
||||
from face_enhance.face_gan_pt import FaceGAN
|
||||
from time import time
|
||||
|
||||
class FaceEnhancement(object):
|
||||
def __init__(self, size=512, gpu_id=0):
|
||||
self.facegan = FaceGAN(size, gpu_id)
|
||||
self.size = size
|
||||
self.threshold = 0.9
|
||||
|
||||
# the mask for pasting restored faces back
|
||||
self.mask = np.zeros((512, 512), np.float32)
|
||||
cv2.rectangle(self.mask, (26, 26), (486, 486), (1, 1, 1), -1, cv2.LINE_AA)
|
||||
self.mask = cv2.GaussianBlur(self.mask, (101, 101), 11)
|
||||
self.mask = cv2.GaussianBlur(self.mask, (101, 101), 11)
|
||||
|
||||
self.kernel = np.array((
|
||||
[0.0625, 0.125, 0.0625],
|
||||
[0.125, 0.25, 0.125],
|
||||
[0.0625, 0.125, 0.0625]), dtype="float32")
|
||||
|
||||
def process(self, img, landmarks1k):
|
||||
|
||||
assert len(landmarks1k) == 1000
|
||||
|
||||
image_to_face_mat = landmark_processor.get_transform_mat_face_restore(landmarks1k, self.size)
|
||||
tfm_inv = cv2.invertAffineTransform(image_to_face_mat)
|
||||
|
||||
height, width = img.shape[:2]
|
||||
full_mask = np.zeros((height, width), dtype=np.float32)
|
||||
full_img = np.zeros(img.shape, dtype=np.uint8)
|
||||
|
||||
fh, fw = (landmarks1k[0][1]-landmarks1k[154][1]), (landmarks1k[95][0]-landmarks1k[215][0])
|
||||
|
||||
of = cv2.warpAffine(img, image_to_face_mat, (self.size, self.size), flags=cv2.INTER_LANCZOS4, borderMode=cv2.BORDER_CONSTANT, borderValue=[0, 0, 0])
|
||||
|
||||
# enhance the face
|
||||
ef = self.facegan.process(of)
|
||||
tmp_mask = self.mask
|
||||
tmp_mask = cv2.resize(tmp_mask, ef.shape[:2])
|
||||
tmp_mask = cv2.warpAffine(tmp_mask, tfm_inv, (width, height), flags=3)
|
||||
|
||||
if min(fh, fw)<100: # gaussian filter for small faces
|
||||
ef = cv2.filter2D(ef, -1, self.kernel)
|
||||
|
||||
# tmp_img = cv2.warpAffine(ef, tfm_inv, (width, height), flags=3)
|
||||
tmp_img = cv2.warpAffine(ef, tfm_inv, (width, height), dst=img.copy(), borderMode=cv2.BORDER_TRANSPARENT)
|
||||
|
||||
# cv2.imshow("tmp_img: ", tmp_img)
|
||||
|
||||
mask = tmp_mask - full_mask
|
||||
full_mask[np.where(mask>0)] = tmp_mask[np.where(mask>0)]
|
||||
full_img[np.where(mask>0)] = tmp_img[np.where(mask>0)]
|
||||
|
||||
full_mask = full_mask[:, :, np.newaxis]
|
||||
img = cv2.convertScaleAbs(img*(1-full_mask) + full_img*full_mask)
|
||||
|
||||
# cv2.imshow("img: ", img)
|
||||
|
||||
# cv2.waitKey()
|
||||
|
||||
return img
|
||||
|
||||
if __name__=='__main__':
|
||||
|
||||
indir = '/media/DATA_4T/zao_data/tencent_con_0701/ref_c/res_contrast_blur13_notps_yunfu_res'
|
||||
outdir = '/media/DATA_4T/zao_data/tencent_con_0701/ref_c/res_contrast_blur13_notps_yunfu_res_outs2'
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
|
||||
faceenhancer = FaceEnhancement(base_dir="./", size=512, model="GPEN-512", channel_multiplier=2)
|
||||
|
||||
files = sorted(glob.glob(os.path.join(indir, '*.*g')))
|
||||
for n, file in enumerate(files[:]):
|
||||
filename = os.path.basename(file)
|
||||
txtname = file.replace(".jpg", "_landmark1k.txt")
|
||||
|
||||
im = cv2.imread(file, cv2.IMREAD_COLOR) # BGR
|
||||
print(txtname)
|
||||
landmark = np.loadtxt(txtname)
|
||||
if not isinstance(im, np.ndarray): print(filename, 'error'); continue
|
||||
|
||||
start = time()
|
||||
|
||||
img = faceenhancer.process(im, landmark)
|
||||
|
||||
end = time()
|
||||
|
||||
print("Time cost: {:.4f}".format(end - start))
|
||||
|
||||
cv2.imwrite(os.path.join(outdir, '.'.join(filename.split('.')[:-1])+'_2.jpg'), img)
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
'''
|
||||
@paper: GAN Prior Embedded Network for Blind Face Restoration in the Wild (CVPR2021)
|
||||
@author: yangxy (yangtao9009@gmail.com)
|
||||
'''
|
||||
import torch
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
# modelRoot = "/home/yangchaojie/Desktop/hairstyle/hairstyle_infer/weights"
|
||||
modelRoot = "./weights"
|
||||
class FaceGAN(object):
|
||||
def __init__(self, size=512, gpu_id=0):
|
||||
# self.mfile = os.path.join(base_dir, model+'.pth')
|
||||
self.n_mlp = 8
|
||||
self.resolution = size
|
||||
self.device = torch.device('cuda:{}'.format(gpu_id) if gpu_id is not None else 'cpu')
|
||||
|
||||
self.load_model()
|
||||
|
||||
def load_model(self):
|
||||
self.model_dir = modelRoot
|
||||
self.face_gan_model = os.path.join(self.model_dir, "face_enhance_0630.pt")
|
||||
|
||||
self.model = torch.jit.load(self.face_gan_model).to(self.device)
|
||||
|
||||
self.model.eval()
|
||||
|
||||
def process_o(self, img):
|
||||
img = cv2.resize(img, (self.resolution, self.resolution))
|
||||
img_t = self.img2tensor(img)
|
||||
|
||||
with torch.no_grad():
|
||||
out, __ = self.model(img_t)
|
||||
|
||||
out = self.tensor2img(out)
|
||||
|
||||
return out
|
||||
|
||||
def process(self, img):
|
||||
img = cv2.resize(img, (self.resolution, self.resolution))
|
||||
img_t = self.img2tensor(img)
|
||||
|
||||
with torch.no_grad():
|
||||
out = self.forward(img_t)
|
||||
|
||||
out = self.tensor2img(out)
|
||||
|
||||
return out
|
||||
|
||||
def forward(self, img_t):
|
||||
with torch.no_grad():
|
||||
out = self.model(img_t)
|
||||
|
||||
return out
|
||||
|
||||
def img2tensor(self, img):
|
||||
img_t = (torch.from_numpy(img).to(self.device)/255. - 0.5) / 0.5
|
||||
img_t = img_t.permute(2, 0, 1).unsqueeze(0).flip(1) # BGR->RGB
|
||||
return img_t
|
||||
|
||||
def tensor2img(self, image_tensor, pmax=255.0, imtype=np.uint8):
|
||||
image_tensor = image_tensor * 0.5 + 0.5
|
||||
image_tensor = image_tensor.squeeze(0).permute(1, 2, 0).flip(2) # RGB->BGR
|
||||
image_numpy = np.clip(image_tensor.float().cpu().numpy(), 0, 1) * pmax
|
||||
|
||||
return image_numpy.astype(imtype)
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @File : setup.py
|
||||
# @Time : 2020/1/15
|
||||
# @Author : yangchaojie (yangchaojie@immomo.com)
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import numpy
|
||||
import tempfile
|
||||
|
||||
from setuptools import setup
|
||||
from setuptools.extension import Extension
|
||||
|
||||
from Cython.Build import cythonize
|
||||
from Cython.Distutils import build_ext
|
||||
|
||||
import platform
|
||||
|
||||
|
||||
def get_root_path(root):
|
||||
if os.path.dirname(root) in ['', '.']:
|
||||
return os.path.basename(root)
|
||||
else:
|
||||
return get_root_path(os.path.dirname(root))
|
||||
|
||||
|
||||
def copy_file(src, dest):
|
||||
if os.path.exists(dest):
|
||||
return
|
||||
|
||||
if not os.path.exists(os.path.dirname(dest)):
|
||||
os.makedirs(os.path.dirname(dest))
|
||||
if os.path.isdir(src):
|
||||
shutil.copytree(src, dest)
|
||||
else:
|
||||
shutil.copyfile(src, dest)
|
||||
|
||||
|
||||
def touch_init_file():
|
||||
init_file_name = os.path.join(tempfile.mkdtemp(), '__init__.py')
|
||||
with open(init_file_name, 'w'):
|
||||
pass
|
||||
return init_file_name
|
||||
|
||||
|
||||
|
||||
|
||||
def compose_extensions(root='.'):
|
||||
for file_ in os.listdir(root):
|
||||
abs_file = os.path.join(root, file_)
|
||||
|
||||
if os.path.isfile(abs_file):
|
||||
if abs_file.endswith('.py'):
|
||||
extensions.append(Extension(get_root_path(abs_file) + '.*', [abs_file]))
|
||||
elif abs_file.endswith('.c') or abs_file.endswith('.pyc'):
|
||||
continue
|
||||
else:
|
||||
copy_file(abs_file, os.path.join(build_root_dir, abs_file))
|
||||
if abs_file.endswith('__init__.py'):
|
||||
copy_file(init_file, os.path.join(build_root_dir, abs_file))
|
||||
|
||||
else:
|
||||
if os.path.basename(abs_file) in ignore_folders :
|
||||
continue
|
||||
if os.path.basename(abs_file) in conf_folders:
|
||||
copy_file(abs_file, os.path.join(build_root_dir, abs_file))
|
||||
compose_extensions(abs_file)
|
||||
|
||||
|
||||
|
||||
# if __name__ == '__main__':
|
||||
build_root_dir = 'build/lib.' + platform.system().lower() + '-' + platform.machine() + '-' + str(
|
||||
sys.version_info.major) + '.' + str(sys.version_info.minor)
|
||||
|
||||
print(build_root_dir)
|
||||
|
||||
extensions = []
|
||||
ignore_folders = ['build', 'new_ref_zao_color_0818', 'ref_hair_online_0703_local', 'ref_分好类别', '.git']
|
||||
conf_folders = ['conf']
|
||||
|
||||
|
||||
init_file = touch_init_file()
|
||||
print(init_file)
|
||||
|
||||
|
||||
compose_extensions()
|
||||
os.remove(init_file)
|
||||
|
||||
setup(
|
||||
name='moxie_hairstyle',
|
||||
version='1.0',
|
||||
ext_modules=cythonize(
|
||||
extensions,
|
||||
nthreads=16,
|
||||
compiler_directives=dict(always_allow_keywords=True),
|
||||
include_path=[numpy.get_include()]),
|
||||
cmdclass=dict(build_ext=build_ext))
|
||||
|
||||
# python setup.py build_ext
|
||||
Reference in New Issue
Block a user