feat(接口5): 生发机制对齐接口2 + 统一ComfyUI重绘提示词
接口5改造(生发机制与接口2一致,按性别分流): - generate_hairline_pngs: 生发图来源从 _grow_from_texture(局部inpaint) 改为按性别分流——female走 generate_grow_results_swap(swapHair+Flux整帧重绘), male走 generate_grow_results(ComfyUI add_hair) - 新增参数 redraw_max_side/unet_name/v2_defaults(female路径透传) - 接口5 handler 加 flux_model/redraw_max_side Form参数 - 保留接口5独有输出: 3档叠图(middle/high/low)/中心点/face_measure - 已验证: female日志出现"接口2女 管线降分辨率max_side=640"+swap+Flux; male走add_hair.json; generate_grow_image=false正确跳过生发 统一ComfyUI重绘提示词: - "填充遮罩区域的头发,皮肤加一点磨皮,再加一点美颜" → "填充遮罩区域的头发" - 覆盖: _REDRAW_PROMPT/_DEFAULT_PROMPT常量 + app.py各接口Form默认 + 工作流JSON节点60(add_hair/0716add-hair-api/hair_repaint) + 全部测试页输入框
This commit is contained in:
+2
-2
@@ -16,7 +16,7 @@ from . import comfyui
|
||||
|
||||
logger = logging.getLogger("hair.worker")
|
||||
|
||||
_DEFAULT_PROMPT = "填充遮罩区域的头发,皮肤加一点磨皮,再加一点美颜"
|
||||
_DEFAULT_PROMPT = "填充遮罩区域的头发"
|
||||
_REPO = os.path.dirname(os.path.dirname(__file__))
|
||||
_REPAINT_WORKFLOW = os.path.join(_REPO, "0716add-hair-api.json")
|
||||
|
||||
@@ -62,7 +62,7 @@ def run_redraw(image_bytes: bytes, mask_bytes: bytes,
|
||||
Args:
|
||||
image_bytes: 人物图片字节(JPG/PNG)
|
||||
mask_bytes: 遮罩图片字节(支持红/白/alpha 遮罩格式)
|
||||
prompt: 提示词,None 用默认 "填充遮罩区域的头发,皮肤加一点磨皮,再加一点美颜"
|
||||
prompt: 提示词,None 用默认 "填充遮罩区域的头发"
|
||||
timeout: ComfyUI 超时秒数
|
||||
front: True 时任务插到 ComfyUI 队列最前(接口2 时延敏感路径用)
|
||||
unet_name: 非 None 时切换 Flux 模型(如 flux-2-klein-9b-Q5_K_M.gguf),None 用工作流默认
|
||||
|
||||
+37
-18
@@ -46,7 +46,7 @@ _BLACK_TEXTURE_DIR = os.path.join(_REPO, "hairline_texture_black")
|
||||
# 关键:ComfyUI 单卡显存装不下 Flux(7.7G)+qwen CLIP(3.9G) 同驻,靠缓存 CLIP 文本条件避免重载。
|
||||
# prompt 不同会使缓存失效 → 重载 CLIP 并挤出 Flux(每次 +4s)。三接口用同一字符串即可全程命中。
|
||||
# 与 app.py 接口2/接口3 的默认 prompt 保持一致;可用 REDRAW_PROMPT 覆盖。
|
||||
_REDRAW_PROMPT = os.getenv("REDRAW_PROMPT", "填充遮罩区域的头发,皮肤加一点磨皮,再加一点美颜")
|
||||
_REDRAW_PROMPT = os.getenv("REDRAW_PROMPT", "填充遮罩区域的头发")
|
||||
|
||||
# 接口2 女重绘整条管线(swapHair + ComfyUI)送模型前限边。真实照片常达 1257x1495:
|
||||
# 全分辨率 ComfyUI 重绘要 13~21s 且激活显存把模型挤出。女性路径含 swapHair(SD WebUI ~5.3s
|
||||
@@ -410,14 +410,22 @@ def _grow_from_texture(image_bgr: np.ndarray, ctx: dict, white_path: str | None,
|
||||
def generate_hairline_pngs(image_bgr: np.ndarray, gender: str,
|
||||
hair_styles: list[int], use_mask: bool = True,
|
||||
prompt: str | None = None,
|
||||
generate_grow_image: bool = True):
|
||||
generate_grow_image: bool = True,
|
||||
redraw_max_side: int | None = None,
|
||||
unet_name: str | None = None,
|
||||
v2_defaults: dict | None = None):
|
||||
"""接口5:对选中发型返回 middle/high/low 三档发际线透明叠图 + 生发图(同接口2)。
|
||||
|
||||
入参同接口2:先选 gender,再多选 hair_styles(必填,1-indexed 按贴图排序)。
|
||||
每个选中发型返回三档叠图(middle/high/low,RGBA 透明层只含发际线曲线)与一张生发图;
|
||||
三档贴图同名,生发黑模板固定取自 hairline_texture_black/(middle),故生发目标固定 middle 档。
|
||||
use_mask/prompt:同接口2 的生发参数。
|
||||
generate_grow_image(默认 True):是否生成生发图(ComfyUI,最耗时)。False 时跳过生发,
|
||||
|
||||
生发机制(同接口2,按性别分流):
|
||||
- female:generate_grow_results_swap(swapHair + Flux-2 整帧重绘)
|
||||
- male:generate_grow_results(ComfyUI add_hair inpaint)
|
||||
redraw_max_side / unet_name / v2_defaults:female 路径参数,同接口2。
|
||||
male 路径仅用 unet_name;redraw_max_side/v2_defaults 对 male 无意义(忽略)。
|
||||
use_mask/prompt:仅 male 路径生效(同接口2 male)。
|
||||
generate_grow_image(默认 True):是否生成生发图(最耗时)。False 时跳过生发,
|
||||
各发型 grown_png 恒为 None,可大幅降低耗时(仅留三档发际线叠图与中心点)。
|
||||
Returns: {"images":[{hairline_type,order,overlays:{middle,high,low}((H,W,4) RGBA 透明层),grown_png}],
|
||||
"best_centers":{"middle":(x,y),"high":(x,y),"low":(x,y)}};无人脸 None。
|
||||
@@ -439,11 +447,27 @@ def generate_hairline_pngs(image_bgr: np.ndarray, gender: str,
|
||||
# 三档贴图表(同性别、同 key 顺序,因三个文件夹同名)
|
||||
tex_by_level = {lv: get_texture_map(lv)[gender] for lv in _TEXTURE_DIRS}
|
||||
|
||||
# use_mask=False:干净原图+空遮罩与贴图无关,只跑一次 ComfyUI,选中项复用
|
||||
# generate_grow_image=False:完全跳过生发(最耗时),grown_png 恒为 None
|
||||
shared_grown = None
|
||||
if generate_grow_image and not use_mask:
|
||||
shared_grown = _grow_from_texture(image_bgr, ctx, None, use_mask=False, prompt=prompt)
|
||||
# 生发图(同接口2,按性别分流):一次性算出所有选中发型的生发图,按 order 对应回叠图。
|
||||
# female→generate_grow_results_swap(swapHair+Flux-2 整帧重绘);
|
||||
# male→generate_grow_results(ComfyUI add_hair inpaint)。
|
||||
# generate_grow_image=False 时跳过,grown_by_order 为空 dict(各发型 grown_png 恒 None)。
|
||||
grown_by_order: dict[int, bytes | None] = {}
|
||||
if generate_grow_image:
|
||||
try:
|
||||
if gender == "female":
|
||||
items = generate_grow_results_swap(
|
||||
image_bgr, hair_styles, v2_defaults or {},
|
||||
redraw_max_side=redraw_max_side, unet_name=unet_name)
|
||||
else:
|
||||
items = generate_grow_results(
|
||||
image_bgr, gender, use_mask, prompt, hair_styles,
|
||||
unet_name=unet_name)
|
||||
if items is None:
|
||||
return None # 无人脸(同接口2 的 None 语义)
|
||||
for it in items:
|
||||
grown_by_order[it["order"]] = it.get("grown_png")
|
||||
except Exception as e: # noqa: BLE001 整批生发失败不拖垮叠图主结果
|
||||
logger.warning("接口5 生发批量失败(gender=%s):%s", gender, e)
|
||||
|
||||
def _center_of(overlay):
|
||||
"""从某档发际线透明叠图取面部中轴处的发际线中点 (x,y),无像素返回 None。"""
|
||||
@@ -456,18 +480,13 @@ def generate_hairline_pngs(image_bgr: np.ndarray, gender: str,
|
||||
|
||||
images, best_centers = [], None
|
||||
for s in hair_styles: # s = 1-indexed 发型序号
|
||||
key, mid_path = tex_by_level["middle"][s - 1]
|
||||
key, _mid_path = tex_by_level["middle"][s - 1]
|
||||
overlays = {}
|
||||
for lv in _TEXTURE_DIRS:
|
||||
white = load_texture_rgba(tex_by_level[lv][s - 1][1])
|
||||
overlays[lv] = build_overlay_layer(h, w, ctx["points"], ext_faces, uv, white)
|
||||
# 生发:固定 middle 黑模板(generate_grow_image=False 时跳过,恒 None)
|
||||
if not generate_grow_image:
|
||||
grown_png = None
|
||||
elif not use_mask:
|
||||
grown_png = shared_grown
|
||||
else:
|
||||
grown_png = _grow_from_texture(image_bgr, ctx, mid_path, use_mask=True, prompt=prompt)
|
||||
# 生发图:从按性别算好的结果里按 order 取(generate_grow_image=False 时缺省 None)
|
||||
grown_png = grown_by_order.get(s)
|
||||
images.append({"hairline_type": key, "order": s,
|
||||
"overlays": overlays, "grown_png": grown_png})
|
||||
# best_centers:首个选中发型三档(middle/high/low)发际线中点
|
||||
|
||||
Reference in New Issue
Block a user