Files
xsl 443cfa298f 初始化:换发型/换发色/训练发型服务
包含:
- 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密钥已脱敏为环境变量,原文件备份在本地
2026-07-07 13:53:52 +08:00

103 lines
3.9 KiB
Python

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()