feat(调试): swapHair webui步数暴露到测试页可调
参数透传链路: 测试页→debug接口→generate_hairline_redraw→_grow_core →_call_swap→change_hair swapHair→webui_img2img→build_body_v2 - app.py: 调试接口新增 webui_steps Form 参数 - hairline_grow.py: _call_swap/_grow_core/generate_hairline_grow/generate_hairline_redraw 透传 webui_steps - debug_grow_timing.html: 新增 swap步数 下拉(默认/10/15/20/25/30) 实测 steps 10→25 swap 耗时 4.1s→4.4s,参数确实生效
This commit is contained in:
@@ -827,6 +827,7 @@ async def debug_grow_timing(
|
|||||||
image_url: Optional[str] = Form(default=None),
|
image_url: Optional[str] = Form(default=None),
|
||||||
image_base64: Optional[str] = Form(default=None),
|
image_base64: Optional[str] = Form(default=None),
|
||||||
hair_style: str = Form(default="2", description="发型序号(花瓣=2),逗号分隔多选"),
|
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女性生发,返回每个步骤的耗时 + 结果图,用于定位性能瓶颈。
|
"""单图跑接口2女性生发,返回每个步骤的耗时 + 结果图,用于定位性能瓶颈。
|
||||||
|
|
||||||
@@ -903,7 +904,7 @@ async def debug_grow_timing(
|
|||||||
t0 = _time.perf_counter()
|
t0 = _time.perf_counter()
|
||||||
data = await run_in_threadpool(
|
data = await run_in_threadpool(
|
||||||
generate_hairline_redraw, redraw_img, chang_id,
|
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
|
t_redraw_pipeline = _time.perf_counter() - t0
|
||||||
_tm = data.get("timings_ms") or {}
|
_tm = data.get("timings_ms") or {}
|
||||||
entry["mask_ms"] = _tm.get("mask", 0)
|
entry["mask_ms"] = _tm.get("mask", 0)
|
||||||
|
|||||||
@@ -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,
|
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)。
|
"""调 change_hair /api/swapHair/v1,返回与输入同分辨率同对齐的换发型结果(BGR)。
|
||||||
|
|
||||||
ext_mask_bool 非 None 时作为 ext_mask 传入(swap_mode=ext_mask)。
|
ext_mask_bool 非 None 时作为 ext_mask 传入(swap_mode=ext_mask)。
|
||||||
denoising_strength:webui img2img 重绘强度(越大生发越激进),透传给换发型。
|
denoising_strength:webui img2img 重绘强度(越大生发越激进),透传给换发型。
|
||||||
inpainting_fill / mask_blur / mask_dilate_scale:服务端重绘参数(透传给 change_hair,
|
inpainting_fill / mask_blur / mask_dilate_scale:服务端重绘参数(透传给 change_hair,
|
||||||
默认值=服务端原始硬编码值,未传时行为不变)。详见 change_hair 文档。
|
默认值=服务端原始硬编码值,未传时行为不变)。详见 change_hair 文档。
|
||||||
|
webui_steps:webui img2img 采样步数,None 用服务端默认(15)。
|
||||||
"""
|
"""
|
||||||
import requests
|
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_blur": int(mask_blur),
|
||||||
"mask_dilate_scale": float(mask_dilate_scale),
|
"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:
|
if ext_mask_bool is not None:
|
||||||
mbuf = cv2.imencode(".png", (ext_mask_bool.astype(np.uint8)) * 255)[1]
|
mbuf = cv2.imencode(".png", (ext_mask_bool.astype(np.uint8)) * 255)[1]
|
||||||
payload["ext_mask"] = "data:image/png;base64," + base64.b64encode(mbuf.tobytes()).decode()
|
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,
|
mb_levels, hairline_push_cm, hairline_edge, blend_method, color_match,
|
||||||
color_match_strength, mb_feather_px, transition_band_px,
|
color_match_strength, mb_feather_px, transition_band_px,
|
||||||
inpainting_fill, mask_blur, mask_dilate_scale, rid, render_viz=True,
|
inpainting_fill, mask_blur, mask_dilate_scale, rid, render_viz=True,
|
||||||
hair_mask=None):
|
hair_mask=None, webui_steps=None):
|
||||||
"""接口11 共享核心:遮罩(pushed)→生成→硬贴回→接缝融合,产出 ④ final。
|
"""接口11 共享核心:遮罩(pushed)→生成→硬贴回→接缝融合,产出 ④ final。
|
||||||
|
|
||||||
不做任何重绘。返回中间产物 dict(供接口11 构造响应、接口12 取 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
|
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,
|
swap_result = _call_swap(image_bgr, hairline_id, is_hr, ext_mask, denoising_strength,
|
||||||
inpainting_fill=inpainting_fill, mask_blur=mask_blur,
|
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
|
t_swap = time.time() - t0
|
||||||
|
|
||||||
# 步骤3:严格按遮罩硬贴回(无融合,用于对比)
|
# 步骤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,
|
color_match_strength=1.0, mb_feather_px=1,
|
||||||
transition_band_px=-1,
|
transition_band_px=-1,
|
||||||
inpainting_fill=1, mask_blur=11, mask_dilate_scale=1.0,
|
inpainting_fill=1, mask_blur=11, mask_dilate_scale=1.0,
|
||||||
rid=None):
|
rid=None, webui_steps=None):
|
||||||
"""接口11 完整管线(**不含重绘**,重绘见接口12 generate_hairline_redraw)。
|
"""接口11 完整管线(**不含重绘**,重绘见接口12 generate_hairline_redraw)。
|
||||||
返回可直接进 ok() 的 data dict。未检出人脸抛 NoFaceError。
|
返回可直接进 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,
|
color_match=color_match, color_match_strength=color_match_strength,
|
||||||
mb_feather_px=mb_feather_px, transition_band_px=transition_band_px,
|
mb_feather_px=mb_feather_px, transition_band_px=transition_band_px,
|
||||||
inpainting_fill=inpainting_fill, mask_blur=mask_blur,
|
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"]
|
mask_viz = core["mask_viz"]
|
||||||
alpha = core["alpha"]
|
alpha = core["alpha"]
|
||||||
w, h = core["w"], core["h"]
|
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,
|
inpainting_fill=1, mask_blur=11, mask_dilate_scale=1.0,
|
||||||
comfyui_prompt=None, beauty_alpha=0.6,
|
comfyui_prompt=None, beauty_alpha=0.6,
|
||||||
band_lo_mult=0.5, band_hi_mult=1.5, rid=None,
|
band_lo_mult=0.5, band_hi_mult=1.5, rid=None,
|
||||||
hair_mask=None):
|
hair_mask=None, webui_steps=None):
|
||||||
"""接口12 发际线带重绘。内部先跑接口11 核心拿到 ④ final,再取 ⑤-① 发际线重绘带
|
"""接口12 发际线带重绘。内部先跑接口11 核心拿到 ④ final,再取 ⑤-① 发际线重绘带
|
||||||
(外推↔内推之间、经 baseline 截断只留上部)作遮罩。
|
(外推↔内推之间、经 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,
|
mb_feather_px=mb_feather_px, transition_band_px=transition_band_px,
|
||||||
inpainting_fill=inpainting_fill, mask_blur=mask_blur,
|
inpainting_fill=inpainting_fill, mask_blur=mask_blur,
|
||||||
mask_dilate_scale=mask_dilate_scale, rid=rid, render_viz=False,
|
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"]
|
final = core["final"]
|
||||||
mask_viz = core["mask_viz"]
|
mask_viz = core["mask_viz"]
|
||||||
w, h = core["w"], core["h"]
|
w, h = core["w"], core["h"]
|
||||||
|
|||||||
@@ -80,6 +80,17 @@
|
|||||||
<option value="5">5 波浪</option>
|
<option value="5">5 波浪</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>swap步数</label>
|
||||||
|
<select id="webuiSteps">
|
||||||
|
<option value="">默认(15)</option>
|
||||||
|
<option value="10">10 (最快)</option>
|
||||||
|
<option value="15">15</option>
|
||||||
|
<option value="20">20 (原版)</option>
|
||||||
|
<option value="25">25 (高画质)</option>
|
||||||
|
<option value="30">30</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<button class="btn btn-primary" id="submitBtn" onclick="submitTest()">🚀 开始分析</button>
|
<button class="btn btn-primary" id="submitBtn" onclick="submitTest()">🚀 开始分析</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="statusBar" class="status hidden"></div>
|
<div id="statusBar" class="status hidden"></div>
|
||||||
@@ -115,6 +126,8 @@ async function submitTest(){
|
|||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append('image_file', f);
|
fd.append('image_file', f);
|
||||||
fd.append('hair_style', $('hairStyle').value);
|
fd.append('hair_style', $('hairStyle').value);
|
||||||
|
const _steps = $('webuiSteps').value;
|
||||||
|
if(_steps !== '') fd.append('webui_steps', _steps);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
const r = await fetch(API_BASE+'/api/v1/debug/grow-timing',{
|
const r = await fetch(API_BASE+'/api/v1/debug/grow-timing',{
|
||||||
|
|||||||
Reference in New Issue
Block a user