Files
colomi 0eb61f3e60 初始化换发型项目: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 排除,
由网盘单独上传。
2026-07-11 18:11:49 +08:00

75 lines
3.0 KiB
Python

import os
import pickle
import torch
from faceseg.u2net import U2NET
from utils import landmark_processor
import cv2
import numpy as np
class FaceSeg:
def __init__(self, gpu_id = 0):
model = U2NET(in_ch=4, out_ch=1)
weights = torch.load('weights/20210927_01.pth', map_location='cpu')
model_dict = model.state_dict()
pretrained_dict = {}
for ix, (k, v) in enumerate(model_dict.items()):
if k in weights and weights[k].data.shape == v.data.shape:
pretrained_dict[k] = weights[k]
else:
print('ignore {}'.format(k))
model_dict.update(pretrained_dict)
model.load_state_dict(model_dict)
print('update success')
model.cuda(gpu_id)
model.eval()
self.model = model
self.last_mask = None
self.output_img_size = 320
self.gpu_id = gpu_id
def inference(self, frame, pt1k, video_mode=False):
image_to_face_mat = landmark_processor.get_transform_mat_full_face(pt1k, self.output_img_size)
face_image = cv2.warpAffine(frame, image_to_face_mat, (self.output_img_size, self.output_img_size), flags=cv2.INTER_LANCZOS4)
if face_image.dtype == np.uint8: face_image = face_image.astype(np.float32) / 255
if video_mode and self.last_mask is not None:
last_small_mask = cv2.warpAffine(self.last_mask, image_to_face_mat,
(self.output_img_size, self.output_img_size), flags=cv2.INTER_LANCZOS4)[:,:,np.newaxis]
input_img = np.concatenate([face_image, last_small_mask], axis=2)
else:
zero_mask = np.zeros((face_image.shape[1], face_image.shape[0], 1), dtype=np.float32)
input_img = np.concatenate([face_image, zero_mask], axis=2)
face_image_tensor = input_img.transpose((2, 0, 1))[np.newaxis]
face_image_tensor = torch.from_numpy(face_image_tensor).cuda(self.gpu_id)
mask = self.model.test(face_image_tensor)
mask = mask[0].detach().cpu().numpy().transpose((1, 2, 0))
origin_mask = cv2.warpAffine(mask, image_to_face_mat, (frame.shape[1], frame.shape[0]),
flags=cv2.WARP_INVERSE_MAP|cv2.INTER_LANCZOS4)[:, :, np.newaxis]
if video_mode: self.last_mask = origin_mask.copy()
return origin_mask
if __name__ == '__main__':
face_segmentor = FaceSeg(gpu_id=0)
testdata_dir = "/mnt/DataDisk/my_projects/faceswap_hq/train_data/example"
for picname in os.listdir(testdata_dir):
img_path = os.path.join(testdata_dir, picname)
pkl_path = img_path[:-4]+".pkl"
if not picname.endswith(".jpg"):
continue
if not os.path.exists(pkl_path):
continue
img = cv2.imread(img_path)
with open(pkl_path, "rb") as fp:
info = pickle.load(fp)
pt1k = info["human_pt1k"]
face_seg_mask = face_segmentor.inference(img, pt1k, video_mode=False)
cv2.imshow("face_seg_mask", face_seg_mask)
cv2.imshow("img", img)
cv2.waitKey()