diff --git a/app.py b/app.py index b5424ce..d86bac5 100644 --- a/app.py +++ b/app.py @@ -827,6 +827,7 @@ async def debug_grow_timing( image_url: Optional[str] = Form(default=None), image_base64: Optional[str] = Form(default=None), hair_style: str = Form(default="2", description="发型序号(花瓣=2),逗号分隔多选"), + webui_steps: Optional[int] = Form(default=None, description="swapHair webui img2img 采样步数,None=服务端默认(15),可填10/15/20/25对比"), ): """单图跑接口2女性生发,返回每个步骤的耗时 + 结果图,用于定位性能瓶颈。 @@ -903,7 +904,7 @@ async def debug_grow_timing( t0 = _time.perf_counter() data = await run_in_threadpool( generate_hairline_redraw, redraw_img, chang_id, - hair_mask=hair_mask_redraw, **_V2_FINAL_DEFAULTS) + hair_mask=hair_mask_redraw, webui_steps=webui_steps, **_V2_FINAL_DEFAULTS) t_redraw_pipeline = _time.perf_counter() - t0 _tm = data.get("timings_ms") or {} entry["mask_ms"] = _tm.get("mask", 0) diff --git a/face_analysis/hairline_grow.py b/face_analysis/hairline_grow.py index 6b32fe5..8f8750f 100644 --- a/face_analysis/hairline_grow.py +++ b/face_analysis/hairline_grow.py @@ -508,13 +508,14 @@ def _segment_hair(image_bgr, seg_model, landmarks, w, h): # --------------------------------------------------------------------------- def _call_swap(image_bgr, hairline_id, is_hr, ext_mask_bool, denoising_strength, - inpainting_fill=1, mask_blur=11, mask_dilate_scale=1.0): + inpainting_fill=1, mask_blur=11, mask_dilate_scale=1.0, webui_steps=None): """调 change_hair /api/swapHair/v1,返回与输入同分辨率同对齐的换发型结果(BGR)。 ext_mask_bool 非 None 时作为 ext_mask 传入(swap_mode=ext_mask)。 denoising_strength:webui img2img 重绘强度(越大生发越激进),透传给换发型。 inpainting_fill / mask_blur / mask_dilate_scale:服务端重绘参数(透传给 change_hair, 默认值=服务端原始硬编码值,未传时行为不变)。详见 change_hair 文档。 + webui_steps:webui img2img 采样步数,None 用服务端默认(15)。 """ import requests @@ -530,6 +531,8 @@ def _call_swap(image_bgr, hairline_id, is_hr, ext_mask_bool, denoising_strength, "mask_blur": int(mask_blur), "mask_dilate_scale": float(mask_dilate_scale), } + if webui_steps is not None: + payload["webui_steps"] = int(webui_steps) if ext_mask_bool is not None: mbuf = cv2.imencode(".png", (ext_mask_bool.astype(np.uint8)) * 255)[1] payload["ext_mask"] = "data:image/png;base64," + base64.b64encode(mbuf.tobytes()).decode() @@ -855,7 +858,7 @@ def _grow_core(image_bgr, hairline_id, *, is_hr, seg_model, erode_cm, swap_mode, mb_levels, hairline_push_cm, hairline_edge, blend_method, color_match, color_match_strength, mb_feather_px, transition_band_px, inpainting_fill, mask_blur, mask_dilate_scale, rid, render_viz=True, - hair_mask=None): + hair_mask=None, webui_steps=None): """接口11 共享核心:遮罩(pushed)→生成→硬贴回→接缝融合,产出 ④ final。 不做任何重绘。返回中间产物 dict(供接口11 构造响应、接口12 取 final+重绘带用): @@ -897,7 +900,7 @@ def _grow_core(image_bgr, hairline_id, *, is_hr, seg_model, erode_cm, swap_mode, ext_mask = mask_bool if swap_mode == "ext_mask" else None swap_result = _call_swap(image_bgr, hairline_id, is_hr, ext_mask, denoising_strength, inpainting_fill=inpainting_fill, mask_blur=mask_blur, - mask_dilate_scale=mask_dilate_scale) + mask_dilate_scale=mask_dilate_scale, webui_steps=webui_steps) t_swap = time.time() - t0 # 步骤3:严格按遮罩硬贴回(无融合,用于对比) @@ -935,7 +938,7 @@ def generate_hairline_grow(image_bgr, hairline_id, is_hr=False, seg_model="segfo color_match_strength=1.0, mb_feather_px=1, transition_band_px=-1, inpainting_fill=1, mask_blur=11, mask_dilate_scale=1.0, - rid=None): + rid=None, webui_steps=None): """接口11 完整管线(**不含重绘**,重绘见接口12 generate_hairline_redraw)。 返回可直接进 ok() 的 data dict。未检出人脸抛 NoFaceError。 @@ -957,7 +960,7 @@ def generate_hairline_grow(image_bgr, hairline_id, is_hr=False, seg_model="segfo color_match=color_match, color_match_strength=color_match_strength, mb_feather_px=mb_feather_px, transition_band_px=transition_band_px, inpainting_fill=inpainting_fill, mask_blur=mask_blur, - mask_dilate_scale=mask_dilate_scale, rid=rid) + mask_dilate_scale=mask_dilate_scale, rid=rid, webui_steps=webui_steps) mask_viz = core["mask_viz"] alpha = core["alpha"] w, h = core["w"], core["h"] @@ -1035,7 +1038,7 @@ def generate_hairline_redraw(image_bgr, hairline_id, is_hr=False, seg_model="seg inpainting_fill=1, mask_blur=11, mask_dilate_scale=1.0, comfyui_prompt=None, beauty_alpha=0.6, band_lo_mult=0.5, band_hi_mult=1.5, rid=None, - hair_mask=None): + hair_mask=None, webui_steps=None): """接口12 发际线带重绘。内部先跑接口11 核心拿到 ④ final,再取 ⑤-① 发际线重绘带 (外推↔内推之间、经 baseline 截断只留上部)作遮罩。 @@ -1064,7 +1067,7 @@ def generate_hairline_redraw(image_bgr, hairline_id, is_hr=False, seg_model="seg mb_feather_px=mb_feather_px, transition_band_px=transition_band_px, inpainting_fill=inpainting_fill, mask_blur=mask_blur, mask_dilate_scale=mask_dilate_scale, rid=rid, render_viz=False, - hair_mask=hair_mask) + hair_mask=hair_mask, webui_steps=webui_steps) final = core["final"] mask_viz = core["mask_viz"] w, h = core["w"], core["h"] diff --git a/static/debug_grow_timing.html b/static/debug_grow_timing.html index 1342627..43d643f 100644 --- a/static/debug_grow_timing.html +++ b/static/debug_grow_timing.html @@ -80,6 +80,17 @@ +
+ + +
@@ -115,6 +126,8 @@ async function submitTest(){ const fd = new FormData(); fd.append('image_file', f); fd.append('hair_style', $('hairStyle').value); + const _steps = $('webuiSteps').value; + if(_steps !== '') fd.append('webui_steps', _steps); try{ const r = await fetch(API_BASE+'/api/v1/debug/grow-timing',{