接口11:发际线生发(接口9遮罩 + change_hair换发型/区域生发 + 按遮罩羽化贴回)+ 分步可视化测试页
- 端点 POST /api/v1/hairline/grow(app.py,纯新增,不影响接口1-5) - 编排模块 face_analysis/hairline_grow.py:复用接口9 遮罩 → HTTP 调 change_hair(8801) → 按遮罩贴回 - 双生成后端 gen_backend:swaphair(换发型LoRA) / hairgrow(区域生发inpaint) - swap_mode:ext_mask(接口9遮罩作换发型遮罩) / as_is;融合 feather/alpha_gradient/seamless - 参数全在测试页可调;可视化按算法文档4步:最终遮罩→生成全帧→严格贴回→接缝融合 - 附启停脚本 scripts/restart_if11_backends.sh、算法文档、测试图 注:change_hair 侧 swapHair 的 ext_mask/denoising_strength 改造在 change_hair 仓库,向后兼容。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1232,6 +1232,79 @@ async def head_band(
|
||||
return err(1007, f"处理失败:{ex}")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 接口 11:发际线生发(接口9 遮罩 + change_hair 换发型 + 按遮罩羽化贴回)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@app.post(
|
||||
"/api/v1/hairline/grow",
|
||||
summary="接口11 发际线生发",
|
||||
tags=["生发"],
|
||||
description=f"""
|
||||
输入一张**发际线较高 / 头发稀少**的正脸图 + **发际线类型 ID**(= change_hair 的 `hair_id`,
|
||||
如 `chang_tuoyuan`/`chang_bolang`/`chang_zhixian`/`chang_xinxing`/`chang_huaban`),
|
||||
输出同一个人、同一发型、按该发际线类型压低发际线后的图片,并返回**每一步可视化**。
|
||||
|
||||
管线(见 `docs/发际线增强算法.md`):
|
||||
1. 用接口9 算法算头发遮罩(含额头闭合区域,外缘内缩 `erode_cm`)。`seg_model` 选
|
||||
BiSeNet/SegFormer,`mask_type` 选 eroded(内缩)/closed(闭合区域)。
|
||||
2. 调 change_hair 换发型服务生成该发际线类型图(返回图已与原图同分辨率同对齐)。
|
||||
`swap_mode=ext_mask`:把接口9 遮罩作为 `ext_mask` 传给换发型,webui 精确重绘该区域
|
||||
(忠于算法文档);`swap_mode=as_is`:不改换发型,贴回时再裁到接口9 遮罩。
|
||||
3. 严格按接口9 遮罩把生成图贴回原图(遮罩外=原图不动)。
|
||||
4. 接缝融合:`blend_method` 选 feather(高斯羽化)/alpha_gradient(距离变换内渐变)/
|
||||
seamless(泊松无缝克隆);`feather_px`、`edge_erode_px` 控制过渡细节。
|
||||
|
||||
{_image_fields_desc}
|
||||
|
||||
返回 `data.steps` 含 `input`/`baseline`/`hair_mask`/`mask_overlay`/`mask`/`swap_raw`/
|
||||
`alpha`/`final` 各步图(`*_base64`,经网关改写为 `*_url`)。
|
||||
""",
|
||||
)
|
||||
async def hairline_grow(
|
||||
image_file: Optional[UploadFile] = File(default=None, description="上传图片文件(JPG/PNG)"),
|
||||
image_url: Optional[str] = Form(default=None, description="图片 URL"),
|
||||
image_base64: Optional[str] = Form(default=None, description="图片 base64(需带 data:image/...;base64, 前缀)"),
|
||||
hairline_id: str = Form(..., description="发际线类型 ID(= change_hair hair_id,如 chang_tuoyuan)"),
|
||||
gen_backend: str = Form(default="swaphair", description="生成后端:swaphair(换发型LoRA) | hairgrow(区域生发inpaint,压低发际线)(默认 swaphair)"),
|
||||
hairgrow_strength: float = Form(default=0.75, description="区域生发强度(仅 hairgrow 后端),默认 0.75"),
|
||||
is_hr: bool = Form(default=False, description="高清模式(换发型输出 1152×1536,否则 576×768)"),
|
||||
seg_model: str = Form(default="segformer", description="头发分割模型:bisenet | segformer(默认 segformer)"),
|
||||
mask_type: str = Form(default="eroded", description="遮罩类型:eroded(内缩) | closed(闭合区域)(默认 eroded)"),
|
||||
erode_cm: float = Form(default=1.2, description="遮罩外缘朝中心151内缩距离(厘米,同接口9),默认 1.2"),
|
||||
swap_mode: str = Form(default="ext_mask", description="换发型取图模式:ext_mask(改造换发型用接口9遮罩) | as_is(不改换发型,贴回再裁)(默认 ext_mask)"),
|
||||
blend_method: str = Form(default="feather", description="接缝融合:feather(高斯羽化) | alpha_gradient(距离渐变) | seamless(泊松无缝)(默认 feather)"),
|
||||
feather_px: int = Form(default=15, description="羽化/渐变过渡宽度(像素),默认 15"),
|
||||
edge_erode_px: int = Form(default=3, description="贴图前遮罩内缩像素(防边缘露皮/光晕),默认 3"),
|
||||
denoising_strength: float = Form(default=0.6, description="换发型 webui 重绘强度(越大生发越激进),默认 0.6"),
|
||||
):
|
||||
"""接口11:发际线生发 + 分步可视化"""
|
||||
raw, e = await resolve_image_bytes(image_file, image_url, image_base64)
|
||||
if e is not None:
|
||||
return e
|
||||
|
||||
image = cv2.imdecode(np.frombuffer(raw, np.uint8), cv2.IMREAD_COLOR)
|
||||
if image is None:
|
||||
return err(1008, "图片格式不支持(仅 JPG / PNG)")
|
||||
|
||||
try:
|
||||
from fastapi.concurrency import run_in_threadpool
|
||||
from face_analysis.hairline_grow import generate_hairline_grow, NoFaceError, SwapError
|
||||
try:
|
||||
data = await run_in_threadpool(
|
||||
generate_hairline_grow, image, hairline_id, is_hr, seg_model,
|
||||
mask_type, erode_cm, swap_mode, blend_method, feather_px, edge_erode_px,
|
||||
denoising_strength, gen_backend, hairgrow_strength)
|
||||
except NoFaceError:
|
||||
return err(1001, "无法识别人像")
|
||||
except SwapError as se:
|
||||
return err(1007, f"换发型失败:{se}")
|
||||
return ok(data)
|
||||
except Exception as ex: # noqa: BLE001
|
||||
logger.exception("接口11 处理异常")
|
||||
return err(1007, f"处理失败:{ex}")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 健康检查
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user