修改发型为最终发型
This commit is contained in:
@@ -20,11 +20,22 @@ from .render import load_ext_mesh, load_texture_rgba, render_hairline_overlay, b
|
||||
from .mask import build_inpaint_mask, compose_comfy_rgba, mask_from_curve
|
||||
from .marker_detect import detect_marker_hairline, path_to_curve_mask
|
||||
|
||||
import base64
|
||||
import io
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("hair.worker")
|
||||
|
||||
# 接口2 女性发型 key → change_hair hair_id(chang_*)映射:换发型+Flux-2 整帧重绘用。
|
||||
# 与接口12 final 的 5 型一一对应。
|
||||
_FEMALE_KEY_TO_CHANG = {
|
||||
"ellipse": "chang_tuoyuan", # 椭圆
|
||||
"flower": "chang_huaban", # 花瓣
|
||||
"heart": "chang_xinxing", # 心形
|
||||
"straight": "chang_zhixian", # 直线
|
||||
"wave": "chang_bolang", # 波浪
|
||||
}
|
||||
|
||||
_REPO = os.path.dirname(os.path.dirname(__file__))
|
||||
_TEXTURE_DIR = os.path.join(_REPO, "hairline_texture")
|
||||
_BLACK_TEXTURE_DIR = os.path.join(_REPO, "hairline_texture_black")
|
||||
@@ -202,6 +213,60 @@ def generate_grow_results(image_bgr: np.ndarray, gender: str, use_mask: bool = T
|
||||
return results
|
||||
|
||||
|
||||
def generate_grow_results_swap(image_bgr: np.ndarray, hair_styles: list[int] | None,
|
||||
redraw_defaults: dict):
|
||||
"""接口2 女性专用:发际线透明叠图(同 generate_grow_results)+ 换发型+Flux-2 整帧重绘图。
|
||||
|
||||
与 generate_grow_results 的差异仅在 grown 图的来源:这里对每个选中发型把 female key 映射到
|
||||
change_hair 的 chang_* hair_id,调 face_analysis.hairline_grow.generate_hairline_redraw
|
||||
(= 接口12 final 管线,参数用 redraw_defaults),取 `redraw_full`(整帧重绘)作为生发图。
|
||||
|
||||
overlay 仍是发际线曲线透明层(与 generate_grow_results 完全一致)。
|
||||
Returns: list[dict] {"hairline_type","order","overlay","grown_png"(jpg bytes 或 None)};
|
||||
无人脸返回 None。单个发型换发型/重绘失败时 grown_png=None,不抛异常。
|
||||
"""
|
||||
from face_analysis.hairline_grow import generate_hairline_redraw, NoFaceError
|
||||
|
||||
ctx = extract_context(image_bgr)
|
||||
if ctx is None:
|
||||
return None
|
||||
uv, ext_faces = load_ext_mesh()
|
||||
|
||||
textures = get_texture_map()["female"] # [(key, path), ...] 已排序
|
||||
if hair_styles is not None:
|
||||
items = [(s, textures[s - 1]) for s in hair_styles]
|
||||
else:
|
||||
items = list(enumerate(textures, start=1))
|
||||
|
||||
results = []
|
||||
h, w = image_bgr.shape[:2]
|
||||
for order, (key, white_path) in items:
|
||||
white = load_texture_rgba(white_path)
|
||||
overlay = build_overlay_layer(h, w, ctx["points"], ext_faces, uv, white)
|
||||
|
||||
grown_png = None
|
||||
chang_id = _FEMALE_KEY_TO_CHANG.get(key)
|
||||
if chang_id is None:
|
||||
logger.warning("接口2 换发型:female key=%s 无对应 chang_id,跳过生发图", key)
|
||||
else:
|
||||
try:
|
||||
data = generate_hairline_redraw(image_bgr, chang_id, **redraw_defaults)
|
||||
b64 = (data.get("steps") or {}).get("redraw_full_base64") or ""
|
||||
if b64.startswith("data:"):
|
||||
b64 = b64.split(",", 1)[1]
|
||||
grown_png = base64.b64decode(b64) if b64 else None
|
||||
if grown_png is None:
|
||||
logger.warning("接口2 换发型:type=%s 整帧重绘为空(可能 ComfyUI 未生效)", key)
|
||||
except NoFaceError:
|
||||
logger.warning("接口2 换发型:type=%s 未检出人脸", key)
|
||||
except Exception as e: # noqa: BLE001 单张失败不拖垮整请求
|
||||
logger.warning("接口2 换发型图失败 type=%s:%s", key, e)
|
||||
|
||||
results.append({"hairline_type": key, "order": order,
|
||||
"overlay": overlay, "grown_png": grown_png})
|
||||
return results
|
||||
|
||||
|
||||
def _grow_from_texture(image_bgr: np.ndarray, ctx: dict, white_path: str | None,
|
||||
use_mask: bool, prompt: str | None):
|
||||
"""对单个发际线做生发(ComfyUI)。黑模板固定取 hairline_texture_black/(middle),
|
||||
|
||||
Reference in New Issue
Block a user